Merge branch 'master' of ssh://master.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb
* 'master' of ssh://master.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb: (184 commits) V4L/DVB (5563): Radio-maestro.c Replace radio_ioctl to use video_ioctl2 V4L/DVB (5562): Radio-gemtek-pci.c Replace gemtek_pci_ioctl to use video_ioctl2 V4L/DVB (5560): Ivtv: fix incorrect bitwise-and for command flags. V4L/DVB (5558): Opera: use 7-bit i2c addresses V4L/DVB (5557): Cafe_ccic: check return value of pci_enable_device V4L/DVB (5556): Radio-gemtek.c Replace gemtek_ioctl to use video_ioctl2 V4L/DVB (5555): Radio-aimslab.c Replace rt_ioctl to use video_ioctl2 V4L/DVB (5554): Fix: vidioc_g_parm were not zeroing the memory V4L/DVB (5553): Replace typhoon_do_ioctl to use video_ioctl2 V4L/DVB (5552): Plan-b: Switch to refcounting PCI API V4L/DVB (5551): Plan-b: header change V4L/DVB (5550): Radio-sf16fmi.c Replace fmi_do_ioctl to use video_ioctl2 V4L/DVB (5549): Radio-sf16fmr2.c Replace fmr2_do_ioctl to use video_ioctl2 V4L/DVB (5548): Fix v4l2 buffer to the length V4L/DVB (5547): Add ENUM_FRAMESIZES and ENUM_FRAMEINTERVALS ioctls V4L/DVB (5546): Radio-terratec.c Replace tt_do_ioctl to use video_ioctl2 V4L/DVB (5545): Saa7146: Release capture buffers on device close V4L/DVB (5544): Budget-av: Make inversion setting configurable, add KNC ONE V1.0 card V4L/DVB (5543): Tda10023: Add support for frontend TDA10023 V4L/DVB (5542): Budget-av: Remove polarity switching of the clock for DVB-C ...
This commit is contained in:
commit
aa5bc2b58e
222 changed files with 23220 additions and 4504 deletions
|
@ -6,6 +6,18 @@ be removed from this file.
|
|||
|
||||
---------------------------
|
||||
|
||||
What: V4L2 VIDIOC_G_MPEGCOMP and VIDIOC_S_MPEGCOMP
|
||||
When: October 2007
|
||||
Why: Broken attempt to set MPEG compression parameters. These ioctls are
|
||||
not able to implement the wide variety of parameters that can be set
|
||||
by hardware MPEG encoders. A new MPEG control mechanism was created
|
||||
in kernel 2.6.18 that replaces these ioctls. See the V4L2 specification
|
||||
(section 1.9: Extended controls) for more information on this topic.
|
||||
Who: Hans Verkuil <hverkuil@xs4all.nl> and
|
||||
Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: /sys/devices/.../power/state
|
||||
dev->power.power_state
|
||||
dpm_runtime_{suspend,resume)()
|
||||
|
|
|
@ -143,3 +143,5 @@
|
|||
142 -> Sabrent TV-FM (bttv version)
|
||||
143 -> Hauppauge ImpactVCB (bt878) [0070:13eb]
|
||||
144 -> MagicTV
|
||||
145 -> SSAI Security Video Interface [4149:5353]
|
||||
146 -> SSAI Ultrasound Video Interface [414a:5353]
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
36 -> AVerTV 303 (M126) [1461:000a]
|
||||
37 -> Hauppauge Nova-S-Plus DVB-S [0070:9201,0070:9202]
|
||||
38 -> Hauppauge Nova-SE2 DVB-S [0070:9200]
|
||||
39 -> KWorld DVB-S 100 [17de:08b2]
|
||||
39 -> KWorld DVB-S 100 [17de:08b2,1421:0341]
|
||||
40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402]
|
||||
41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802]
|
||||
42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025,1822:0019]
|
||||
|
|
18
Documentation/video4linux/CARDLIST.ivtv
Normal file
18
Documentation/video4linux/CARDLIST.ivtv
Normal file
|
@ -0,0 +1,18 @@
|
|||
1 -> Hauppauge WinTV PVR-250
|
||||
2 -> Hauppauge WinTV PVR-350
|
||||
3 -> Hauppauge WinTV PVR-150 or PVR-500
|
||||
4 -> AVerMedia M179 [1461:a3ce,1461:a3cf]
|
||||
5 -> Yuan MPG600/Kuroutoshikou iTVC16-STVLP [12ab:fff3,12ab:ffff]
|
||||
6 -> Yuan MPG160/Kuroutoshikou iTVC15-STVLP [12ab:0000,10fc:40a0]
|
||||
7 -> Yuan PG600/DiamondMM PVR-550 [ff92:0070,ffab:0600]
|
||||
8 -> Adaptec AVC-2410 [9005:0093]
|
||||
9 -> Adaptec AVC-2010 [9005:0092]
|
||||
10 -> NAGASE TRANSGEAR 5000TV [1461:bfff]
|
||||
11 -> AOpen VA2000MAX-STN6 [0000:ff5f]
|
||||
12 -> YUAN MPG600GR/Kuroutoshikou CX23416GYC-STVLP [12ab:0600,fbab:0600,1154:0523]
|
||||
13 -> I/O Data GV-MVP/RX [10fc:d01e,10fc:d038,10fc:d039]
|
||||
14 -> I/O Data GV-MVP/RX2E [10fc:d025]
|
||||
15 -> GOTVIEW PCI DVD (partial support only) [12ab:0600]
|
||||
16 -> GOTVIEW PCI DVD2 Deluxe [ffac:0600]
|
||||
17 -> Yuan MPC622 [ff01:d998]
|
||||
18 -> Digital Cowboy DCT-MTVP1 [1461:bfff]
|
|
@ -53,7 +53,7 @@
|
|||
52 -> AverMedia AverTV/305 [1461:2108]
|
||||
53 -> ASUS TV-FM 7135 [1043:4845]
|
||||
54 -> LifeView FlyTV Platinum FM / Gold [5168:0214,1489:0214,5168:0304]
|
||||
55 -> LifeView FlyDVB-T DUO [5168:0306]
|
||||
55 -> LifeView FlyDVB-T DUO / MSI TV@nywhere Duo [5168:0306,4E42:0306]
|
||||
56 -> Avermedia AVerTV 307 [1461:a70a]
|
||||
57 -> Avermedia AVerTV GO 007 FM [1461:f31f]
|
||||
58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0351,1421:0370,1421:1370]
|
||||
|
@ -76,7 +76,7 @@
|
|||
75 -> AVerMedia AVerTVHD MCE A180 [1461:1044]
|
||||
76 -> SKNet MonsterTV Mobile [1131:4ee9]
|
||||
77 -> Pinnacle PCTV 40i/50i/110i (saa7133) [11bd:002e]
|
||||
78 -> ASUSTeK P7131 Dual [1043:4862,1043:4876]
|
||||
78 -> ASUSTeK P7131 Dual [1043:4862,1043:4857]
|
||||
79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
|
||||
80 -> ASUS Digimatrix TV [1043:0210]
|
||||
81 -> Philips Tiger reference design [1131:2018]
|
||||
|
@ -107,3 +107,7 @@
|
|||
106 -> Encore ENLTV [1131:2342,1131:2341,3016:2344]
|
||||
107 -> Encore ENLTV-FM [1131:230f]
|
||||
108 -> Terratec Cinergy HT PCI [153b:1175]
|
||||
109 -> Philips Tiger - S Reference design
|
||||
110 -> Avermedia M102 [1461:f31e]
|
||||
111 -> ASUS P7131 4871 [1043:4871]
|
||||
112 -> ASUSTeK P7131 Hybrid [1043:4876]
|
||||
|
|
64
Documentation/video4linux/CARDLIST.usbvision
Normal file
64
Documentation/video4linux/CARDLIST.usbvision
Normal file
|
@ -0,0 +1,64 @@
|
|||
0 -> Xanboo [0a6f:0400]
|
||||
1 -> Belkin USB VideoBus II Adapter [050d:0106]
|
||||
2 -> Belkin Components USB VideoBus [050d:0207]
|
||||
3 -> Belkin USB VideoBus II [050d:0208]
|
||||
4 -> echoFX InterView Lite [0571:0002]
|
||||
5 -> USBGear USBG-V1 resp. HAMA USB [0573:0003]
|
||||
6 -> D-Link V100 [0573:0400]
|
||||
7 -> X10 USB Camera [0573:2000]
|
||||
8 -> Hauppauge WinTV USB Live (PAL B/G) [0573:2d00]
|
||||
9 -> Hauppauge WinTV USB Live Pro (NTSC M/N) [0573:2d01]
|
||||
10 -> Zoran Co. PMD (Nogatech) AV-grabber Manhattan [0573:2101]
|
||||
11 -> Nogatech USB-TV (NTSC) FM [0573:4100]
|
||||
12 -> PNY USB-TV (NTSC) FM [0573:4110]
|
||||
13 -> PixelView PlayTv-USB PRO (PAL) FM [0573:4450]
|
||||
14 -> ZTV ZT-721 2.4GHz USB A/V Receiver [0573:4550]
|
||||
15 -> Hauppauge WinTV USB (NTSC M/N) [0573:4d00]
|
||||
16 -> Hauppauge WinTV USB (PAL B/G) [0573:4d01]
|
||||
17 -> Hauppauge WinTV USB (PAL I) [0573:4d02]
|
||||
18 -> Hauppauge WinTV USB (PAL/SECAM L) [0573:4d03]
|
||||
19 -> Hauppauge WinTV USB (PAL D/K) [0573:4d04]
|
||||
20 -> Hauppauge WinTV USB (NTSC FM) [0573:4d10]
|
||||
21 -> Hauppauge WinTV USB (PAL B/G FM) [0573:4d11]
|
||||
22 -> Hauppauge WinTV USB (PAL I FM) [0573:4d12]
|
||||
23 -> Hauppauge WinTV USB (PAL D/K FM) [0573:4d14]
|
||||
24 -> Hauppauge WinTV USB Pro (NTSC M/N) [0573:4d2a]
|
||||
25 -> Hauppauge WinTV USB Pro (NTSC M/N) V2 [0573:4d2b]
|
||||
26 -> Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L) [0573:4d2c]
|
||||
27 -> Hauppauge WinTV USB Pro (NTSC M/N) V3 [0573:4d20]
|
||||
28 -> Hauppauge WinTV USB Pro (PAL B/G) [0573:4d21]
|
||||
29 -> Hauppauge WinTV USB Pro (PAL I) [0573:4d22]
|
||||
30 -> Hauppauge WinTV USB Pro (PAL/SECAM L) [0573:4d23]
|
||||
31 -> Hauppauge WinTV USB Pro (PAL D/K) [0573:4d24]
|
||||
32 -> Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) [0573:4d25]
|
||||
33 -> Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2 [0573:4d26]
|
||||
34 -> Hauppauge WinTV USB Pro (PAL B/G) V2 [0573:4d27]
|
||||
35 -> Hauppauge WinTV USB Pro (PAL B/G,D/K) [0573:4d28]
|
||||
36 -> Hauppauge WinTV USB Pro (PAL I,D/K) [0573:4d29]
|
||||
37 -> Hauppauge WinTV USB Pro (NTSC M/N FM) [0573:4d30]
|
||||
38 -> Hauppauge WinTV USB Pro (PAL B/G FM) [0573:4d31]
|
||||
39 -> Hauppauge WinTV USB Pro (PAL I FM) [0573:4d32]
|
||||
40 -> Hauppauge WinTV USB Pro (PAL D/K FM) [0573:4d34]
|
||||
41 -> Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM) [0573:4d35]
|
||||
42 -> Hauppauge WinTV USB Pro (Temic PAL B/G FM) [0573:4d36]
|
||||
43 -> Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM) [0573:4d37]
|
||||
44 -> Hauppauge WinTV USB Pro (NTSC M/N FM) V2 [0573:4d38]
|
||||
45 -> Camtel Technology USB TV Genie Pro FM Model TVB330 [0768:0006]
|
||||
46 -> Digital Video Creator I [07d0:0001]
|
||||
47 -> Global Village GV-007 (NTSC) [07d0:0002]
|
||||
48 -> Dazzle Fusion Model DVC-50 Rev 1 (NTSC) [07d0:0003]
|
||||
49 -> Dazzle Fusion Model DVC-80 Rev 1 (PAL) [07d0:0004]
|
||||
50 -> Dazzle Fusion Model DVC-90 Rev 1 (SECAM) [07d0:0005]
|
||||
51 -> Eskape Labs MyTV2Go [07f8:9104]
|
||||
52 -> Pinnacle Studio PCTV USB (PAL) [2304:010d]
|
||||
53 -> Pinnacle Studio PCTV USB (SECAM) [2304:0109]
|
||||
54 -> Pinnacle Studio PCTV USB (PAL) FM [2304:0110]
|
||||
55 -> Miro PCTV USB [2304:0111]
|
||||
56 -> Pinnacle Studio PCTV USB (NTSC) FM [2304:0112]
|
||||
57 -> Pinnacle Studio PCTV USB (PAL) FM V2 [2304:0210]
|
||||
58 -> Pinnacle Studio PCTV USB (NTSC) FM V2 [2304:0212]
|
||||
59 -> Pinnacle Studio PCTV USB (PAL) FM V3 [2304:0214]
|
||||
60 -> Pinnacle Studio Linx Video input cable (NTSC) [2304:0300]
|
||||
61 -> Pinnacle Studio Linx Video input cable (PAL) [2304:0301]
|
||||
62 -> Pinnacle PCTV Bungee USB (PAL) FM [2304:0419]
|
||||
63 -> Hauppauge WinTv-USB [2400:4200]
|
187
Documentation/video4linux/README.ivtv
Normal file
187
Documentation/video4linux/README.ivtv
Normal file
|
@ -0,0 +1,187 @@
|
|||
|
||||
ivtv release notes
|
||||
==================
|
||||
|
||||
This is a v4l2 device driver for the Conexant cx23415/6 MPEG encoder/decoder.
|
||||
The cx23415 can do both encoding and decoding, the cx23416 can only do MPEG
|
||||
encoding. Currently the only card featuring full decoding support is the
|
||||
Hauppauge PVR-350.
|
||||
|
||||
NOTE: this driver requires the latest encoder firmware (version 2.06.039, size
|
||||
376836 bytes). Get the firmware from here:
|
||||
|
||||
http://dl.ivtvdriver.org/ivtv/firmware/firmware.tar.gz
|
||||
|
||||
NOTE: 'normal' TV applications do not work with this driver, you need
|
||||
an application that can handle MPEG input such as mplayer, xine, MythTV,
|
||||
etc.
|
||||
|
||||
The primary goal of the IVTV project is to provide a "clean room" Linux
|
||||
Open Source driver implementation for video capture cards based on the
|
||||
iCompression iTVC15 or Conexant CX23415/CX23416 MPEG Codec.
|
||||
|
||||
Features:
|
||||
* Hardware mpeg2 capture of broadcast video (and sound) via the tuner or
|
||||
S-Video/Composite and audio line-in.
|
||||
* Hardware mpeg2 capture of FM radio where hardware support exists
|
||||
* Supports NTSC, PAL, SECAM with stereo sound
|
||||
* Supports SAP and bilingual transmissions.
|
||||
* Supports raw VBI (closed captions and teletext).
|
||||
* Supports sliced VBI (closed captions and teletext) and is able to insert
|
||||
this into the captured MPEG stream.
|
||||
* Supports raw YUV and PCM input.
|
||||
|
||||
Additional features for the PVR-350 (CX23415 based):
|
||||
* Provides hardware mpeg2 playback
|
||||
* Provides comprehensive OSD (On Screen Display: ie. graphics overlaying the
|
||||
video signal)
|
||||
* Provides a framebuffer (allowing X applications to appear on the video
|
||||
device) (this framebuffer is not yet part of the kernel. In the meantime it
|
||||
is available from www.ivtvdriver.org).
|
||||
* Supports raw YUV output.
|
||||
|
||||
IMPORTANT: In case of problems first read this page:
|
||||
http://www.ivtvdriver.org/index.php/Troubleshooting
|
||||
|
||||
See also:
|
||||
|
||||
Homepage + Wiki
|
||||
http://www.ivtvdriver.org
|
||||
|
||||
IRC
|
||||
irc://irc.freenode.net/ivtv-dev
|
||||
|
||||
----------------------------------------------------------
|
||||
|
||||
Devices
|
||||
=======
|
||||
|
||||
A maximum of 12 ivtv boards are allowed at the moment.
|
||||
|
||||
Cards that don't have a video output capability (i.e. non PVR350 cards)
|
||||
lack the vbi8, vbi16, video16 and video48 devices. They also do not
|
||||
support the framebuffer device /dev/fbx for OSD.
|
||||
|
||||
The radio0 device may or may not be present, depending on whether the
|
||||
card has a radio tuner or not.
|
||||
|
||||
Here is a list of the base v4l devices:
|
||||
crw-rw---- 1 root video 81, 0 Jun 19 22:22 /dev/video0
|
||||
crw-rw---- 1 root video 81, 16 Jun 19 22:22 /dev/video16
|
||||
crw-rw---- 1 root video 81, 24 Jun 19 22:22 /dev/video24
|
||||
crw-rw---- 1 root video 81, 32 Jun 19 22:22 /dev/video32
|
||||
crw-rw---- 1 root video 81, 48 Jun 19 22:22 /dev/video48
|
||||
crw-rw---- 1 root video 81, 64 Jun 19 22:22 /dev/radio0
|
||||
crw-rw---- 1 root video 81, 224 Jun 19 22:22 /dev/vbi0
|
||||
crw-rw---- 1 root video 81, 228 Jun 19 22:22 /dev/vbi8
|
||||
crw-rw---- 1 root video 81, 232 Jun 19 22:22 /dev/vbi16
|
||||
|
||||
Base devices
|
||||
============
|
||||
|
||||
For every extra card you have the numbers increased by one. For example,
|
||||
/dev/video0 is listed as the 'base' encoding capture device so we have:
|
||||
|
||||
/dev/video0 is the encoding capture device for the first card (card 0)
|
||||
/dev/video1 is the encoding capture device for the second card (card 1)
|
||||
/dev/video2 is the encoding capture device for the third card (card 2)
|
||||
|
||||
Note that if the first card doesn't have a feature (eg no decoder, so no
|
||||
video16, the second card will still use video17. The simple rule is 'add
|
||||
the card number to the base device number'. If you have other capture
|
||||
cards (e.g. WinTV PCI) that are detected first, then you have to tell
|
||||
the ivtv module about it so that it will start counting at 1 (or 2, or
|
||||
whatever). Otherwise the device numbers can get confusing. The ivtv
|
||||
'ivtv_first_minor' module option can be used for that.
|
||||
|
||||
|
||||
/dev/video0
|
||||
The encoding capture device(s).
|
||||
Read-only.
|
||||
|
||||
Reading from this device gets you the MPEG1/2 program stream.
|
||||
Example:
|
||||
|
||||
cat /dev/video0 > my.mpg (you need to hit ctrl-c to exit)
|
||||
|
||||
|
||||
/dev/video16
|
||||
The decoder output device(s)
|
||||
Write-only. Only present if the MPEG decoder (i.e. CX23415) exists.
|
||||
|
||||
An mpeg2 stream sent to this device will appear on the selected video
|
||||
display, audio will appear on the line-out/audio out. It is only
|
||||
available for cards that support video out. Example:
|
||||
|
||||
cat my.mpg >/dev/video16
|
||||
|
||||
|
||||
/dev/video24
|
||||
The raw audio capture device(s).
|
||||
Read-only
|
||||
|
||||
The raw audio PCM stereo stream from the currently selected
|
||||
tuner or audio line-in. Reading from this device results in a raw
|
||||
(signed 16 bit Little Endian, 48000 Hz, stereo pcm) capture.
|
||||
This device only captures audio. This should be replaced by an ALSA
|
||||
device in the future.
|
||||
Note that there is no corresponding raw audio output device, this is
|
||||
not supported in the decoder firmware.
|
||||
|
||||
|
||||
/dev/video32
|
||||
The raw video capture device(s)
|
||||
Read-only
|
||||
|
||||
The raw YUV video output from the current video input. The YUV format
|
||||
is non-standard (V4L2_PIX_FMT_HM12).
|
||||
|
||||
Note that the YUV and PCM streams are not synchronized, so they are of
|
||||
limited use.
|
||||
|
||||
|
||||
/dev/video48
|
||||
The raw video display device(s)
|
||||
Write-only. Only present if the MPEG decoder (i.e. CX23415) exists.
|
||||
|
||||
Writes a YUV stream to the decoder of the card.
|
||||
|
||||
|
||||
/dev/radio0
|
||||
The radio tuner device(s)
|
||||
Cannot be read or written.
|
||||
|
||||
Used to enable the radio tuner and tune to a frequency. You cannot
|
||||
read or write audio streams with this device. Once you use this
|
||||
device to tune the radio, use /dev/video24 to read the raw pcm stream
|
||||
or /dev/video0 to get an mpeg2 stream with black video.
|
||||
|
||||
|
||||
/dev/vbi0
|
||||
The 'vertical blank interval' (Teletext, CC, WSS etc) capture device(s)
|
||||
Read-only
|
||||
|
||||
Captures the raw (or sliced) video data sent during the Vertical Blank
|
||||
Interval. This data is used to encode teletext, closed captions, VPS,
|
||||
widescreen signalling, electronic program guide information, and other
|
||||
services.
|
||||
|
||||
|
||||
/dev/vbi8
|
||||
Processed vbi feedback device(s)
|
||||
Read-only. Only present if the MPEG decoder (i.e. CX23415) exists.
|
||||
|
||||
The sliced VBI data embedded in an MPEG stream is reproduced on this
|
||||
device. So while playing back a recording on /dev/video16, you can
|
||||
read the embedded VBI data from /dev/vbi8.
|
||||
|
||||
|
||||
/dev/vbi16
|
||||
The vbi 'display' device(s)
|
||||
Write-only. Only present if the MPEG decoder (i.e. CX23415) exists.
|
||||
|
||||
Can be used to send sliced VBI data to the video-out connector.
|
||||
|
||||
---------------------------------
|
||||
|
||||
Hans Verkuil <hverkuil@xs4all.nl>
|
|
@ -624,11 +624,11 @@ out what values are bad when it hangs.
|
|||
2A00
|
||||
bits 0:2
|
||||
osd colour mode
|
||||
000 = 8 bit indexed
|
||||
001 = 16 bit (565)
|
||||
010 = 15 bit (555)
|
||||
011 = 12 bit (444)
|
||||
100 = 32 bit (8888)
|
||||
101 = 8 bit indexed
|
||||
|
||||
bits 4:5
|
||||
osd display bpp
|
||||
|
@ -676,9 +676,11 @@ out what values are bad when it hangs.
|
|||
completely transparent. When using 565, 555 or 444 colour modes, the
|
||||
colour key is always 16 bits wide. The colour to key on is set in Reg 2A18.
|
||||
|
||||
Local alpha is a per-pixel 256 step transparency, with 0 being transparent
|
||||
and 255 being solid. This is only available in 32 bit & 8 bit indexed
|
||||
colour modes.
|
||||
Local alpha works differently depending on the colour mode. For 32bpp & 8
|
||||
bit indexed, local alpha is a per-pixel 256 step transparency, with 0 being
|
||||
transparent and 255 being solid. For the 16bpp modes 555 & 444, the unused
|
||||
bit(s) act as a simple transparency switch, with 0 being solid & 1 being
|
||||
fully transparent. There is no local alpha support for 16bit 565.
|
||||
|
||||
Global alpha is a 256 step transparency that applies to the entire osd,
|
||||
with 0 being transparent & 255 being solid.
|
||||
|
@ -811,5 +813,5 @@ out what values are bad when it hangs.
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
v0.3 - 2 February 2007 - Ian Armstrong (ian@iarmst.demon.co.uk)
|
||||
v0.4 - 12 March 2007 - Ian Armstrong (ian@iarmst.demon.co.uk)
|
||||
|
||||
|
|
|
@ -663,12 +663,13 @@ Param[0]
|
|||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Name CX2341X_ENC_UNKNOWN
|
||||
Name CX2341X_ENC_SET_VERT_CROP_LINE
|
||||
Enum 219/0xDB
|
||||
Description
|
||||
Unknown API, it's used by Hauppauge though.
|
||||
Something to do with 'Vertical Crop Line'
|
||||
Param[0]
|
||||
0 This is the value Hauppauge uses, Unknown what it means.
|
||||
If saa7114 and raw VBI capture and 60 Hz, then set to 10001.
|
||||
Else 0.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
@ -682,11 +683,9 @@ Param[0]
|
|||
Command number:
|
||||
1=set initial SCR value when starting encoding (works).
|
||||
2=set quality mode (apparently some test setting).
|
||||
3=setup advanced VIM protection handling (supposedly only for the cx23416
|
||||
for raw YUV).
|
||||
Actually it looks like this should be 0 for saa7114/5 based card and 1
|
||||
for cx25840 based cards.
|
||||
4=generate artificial PTS timestamps
|
||||
3=setup advanced VIM protection handling.
|
||||
Always 1 for the cx23416 and 0 for cx23415.
|
||||
4=generate DVD compatible PTS timestamps
|
||||
5=USB flush mode
|
||||
6=something to do with the quantization matrix
|
||||
7=set navigation pack insertion for DVD: adds 0xbf (private stream 2)
|
||||
|
@ -698,7 +697,9 @@ Param[0]
|
|||
9=set history parameters of the video input module
|
||||
10=set input field order of VIM
|
||||
11=set quantization matrix
|
||||
12=reset audio interface
|
||||
12=reset audio interface after channel change or input switch (has no argument).
|
||||
Needed for the cx2584x, not needed for the mspx4xx, but it doesn't seem to
|
||||
do any harm calling it regardless.
|
||||
13=set audio volume delay
|
||||
14=set audio delay
|
||||
|
||||
|
|
|
@ -21,7 +21,11 @@ Enum 66/0x42
|
|||
Description
|
||||
Query OSD format
|
||||
Result[0]
|
||||
0=8bit index, 4=AlphaRGB 8:8:8:8
|
||||
0=8bit index
|
||||
1=16bit RGB 5:6:5
|
||||
2=16bit ARGB 1:5:5:5
|
||||
3=16bit ARGB 1:4:4:4
|
||||
4=32bit ARGB 8:8:8:8
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
@ -30,7 +34,11 @@ Enum 67/0x43
|
|||
Description
|
||||
Assign pixel format
|
||||
Param[0]
|
||||
0=8bit index, 4=AlphaRGB 8:8:8:8
|
||||
0=8bit index
|
||||
1=16bit RGB 5:6:5
|
||||
2=16bit ARGB 1:5:5:5
|
||||
3=16bit ARGB 1:4:4:4
|
||||
4=32bit ARGB 8:8:8:8
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ Index
|
|||
|
||||
1. Copyright
|
||||
============
|
||||
Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>
|
||||
Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>
|
||||
|
||||
|
||||
2. Disclaimer
|
||||
|
@ -216,10 +216,10 @@ Description: Debugging information level, from 0 to 3:
|
|||
1 = critical errors
|
||||
2 = significant informations
|
||||
3 = more verbose messages
|
||||
Level 3 is useful for testing only, when only one device
|
||||
is used. It also shows some more informations about the
|
||||
hardware being detected. This parameter can be changed at
|
||||
runtime thanks to the /sys filesystem interface.
|
||||
Level 3 is useful for testing only. It also shows some more
|
||||
informations about the hardware being detected.
|
||||
This parameter can be changed at runtime thanks to the /sys
|
||||
filesystem interface.
|
||||
Default: 2
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
@ -235,7 +235,7 @@ created in the /sys/class/video4linux/videoX directory. You can set the green
|
|||
channel's gain by writing the desired value to it. The value may range from 0
|
||||
to 15 for the SN9C101 or SN9C102 bridges, from 0 to 127 for the SN9C103,
|
||||
SN9C105 and SN9C120 bridges.
|
||||
Similarly, only for the SN9C103, SN9C105 and SN9120 controllers, blue and red
|
||||
Similarly, only for the SN9C103, SN9C105 and SN9C120 controllers, blue and red
|
||||
gain control files are available in the same directory, for which accepted
|
||||
values may range from 0 to 127.
|
||||
|
||||
|
@ -402,38 +402,49 @@ Vendor ID Product ID
|
|||
0x0c45 0x60bc
|
||||
0x0c45 0x60be
|
||||
0x0c45 0x60c0
|
||||
0x0c45 0x60c2
|
||||
0x0c45 0x60c8
|
||||
0x0c45 0x60cc
|
||||
0x0c45 0x60ea
|
||||
0x0c45 0x60ec
|
||||
0x0c45 0x60ef
|
||||
0x0c45 0x60fa
|
||||
0x0c45 0x60fb
|
||||
0x0c45 0x60fc
|
||||
0x0c45 0x60fe
|
||||
0x0c45 0x6102
|
||||
0x0c45 0x6108
|
||||
0x0c45 0x610f
|
||||
0x0c45 0x6130
|
||||
0x0c45 0x6138
|
||||
0x0c45 0x613a
|
||||
0x0c45 0x613b
|
||||
0x0c45 0x613c
|
||||
0x0c45 0x613e
|
||||
|
||||
The list above does not imply that all those devices work with this driver: up
|
||||
until now only the ones that assemble the following image sensors are
|
||||
supported; kernel messages will always tell you whether this is the case (see
|
||||
"Module loading" paragraph):
|
||||
until now only the ones that assemble the following pairs of SN9C1xx bridges
|
||||
and image sensors are supported; kernel messages will always tell you whether
|
||||
this is the case (see "Module loading" paragraph):
|
||||
|
||||
Model Manufacturer
|
||||
----- ------------
|
||||
HV7131D Hynix Semiconductor, Inc.
|
||||
MI-0343 Micron Technology, Inc.
|
||||
OV7630 OmniVision Technologies, Inc.
|
||||
OV7660 OmniVision Technologies, Inc.
|
||||
PAS106B PixArt Imaging, Inc.
|
||||
PAS202BCA PixArt Imaging, Inc.
|
||||
PAS202BCB PixArt Imaging, Inc.
|
||||
TAS5110C1B Taiwan Advanced Sensor Corporation
|
||||
TAS5130D1B Taiwan Advanced Sensor Corporation
|
||||
Image sensor / SN9C1xx bridge | SN9C10[12] SN9C103 SN9C105 SN9C120
|
||||
-------------------------------------------------------------------------------
|
||||
HV7131D Hynix Semiconductor | Yes No No No
|
||||
HV7131R Hynix Semiconductor | No Yes Yes Yes
|
||||
MI-0343 Micron Technology | Yes No No No
|
||||
MI-0360 Micron Technology | No Yes No No
|
||||
OV7630 OmniVision Technologies | Yes Yes No No
|
||||
OV7660 OmniVision Technologies | No No Yes Yes
|
||||
PAS106B PixArt Imaging | Yes No No No
|
||||
PAS202B PixArt Imaging | Yes Yes No No
|
||||
TAS5110C1B Taiwan Advanced Sensor | Yes No No No
|
||||
TAS5110D Taiwan Advanced Sensor | Yes No No No
|
||||
TAS5130D1B Taiwan Advanced Sensor | Yes No No No
|
||||
|
||||
Some of the available control settings of each image sensor are supported
|
||||
"Yes" means that the pair is supported by the driver, while "No" means that the
|
||||
pair does not exist or is not supported by the driver.
|
||||
|
||||
Only some of the available control settings of each image sensor are supported
|
||||
through the V4L2 interface.
|
||||
|
||||
Donations of new models for further testing and support would be much
|
||||
|
@ -482,8 +493,8 @@ The SN9C1xx PC Camera Controllers can send images in two possible video
|
|||
formats over the USB: either native "Sequential RGB Bayer" or compressed.
|
||||
The compression is used to achieve high frame rates. With regard to the
|
||||
SN9C101, SN9C102 and SN9C103, the compression is based on the Huffman encoding
|
||||
algorithm described below, while the SN9C105 and SN9C120 the compression is
|
||||
based on the JPEG standard.
|
||||
algorithm described below, while with regard to the SN9C105 and SN9C120 the
|
||||
compression is based on the JPEG standard.
|
||||
The current video format may be selected or queried from the user application
|
||||
by calling the VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2
|
||||
API specifications.
|
||||
|
@ -573,4 +584,5 @@ order):
|
|||
- Mizuno Takafumi for the donation of a webcam;
|
||||
- an "anonymous" donator (who didn't want his name to be revealed) for the
|
||||
donation of a webcam.
|
||||
- an anonymous donator for the donation of four webcams.
|
||||
- an anonymous donator for the donation of four webcams and two boards with ten
|
||||
image sensors.
|
||||
|
|
65
Documentation/video4linux/zr364xx.txt
Normal file
65
Documentation/video4linux/zr364xx.txt
Normal file
|
@ -0,0 +1,65 @@
|
|||
Zoran 364xx based USB webcam module version 0.72
|
||||
site: http://royale.zerezo.com/zr364xx/
|
||||
mail: royale@zerezo.com
|
||||
|
||||
introduction:
|
||||
This brings support under Linux for the Aiptek PocketDV 3300 in webcam mode.
|
||||
If you just want to get on your PC the pictures and movies on the camera, you should use the usb-storage module instead.
|
||||
The driver works with several other cameras in webcam mode (see the list below).
|
||||
Maybe this code can work for other JPEG/USB cams based on the Coach chips from Zoran?
|
||||
Possible chipsets are : ZR36430 (ZR36430BGC) and maybe ZR36431, ZR36440, ZR36442...
|
||||
You can try the experience changing the vendor/product ID values (look at the source code).
|
||||
You can get these values by looking at /var/log/messages when you plug your camera, or by typing : cat /proc/bus/usb/devices.
|
||||
If you manage to use your cam with this code, you can send me a mail (royale@zerezo.com) with the name of your cam and a patch if needed.
|
||||
This is a beta release of the driver.
|
||||
Since version 0.70, this driver is only compatible with V4L2 API and 2.6.x kernels.
|
||||
If you need V4L1 or 2.4x kernels support, please use an older version, but the code is not maintained anymore.
|
||||
Good luck!
|
||||
|
||||
install:
|
||||
In order to use this driver, you must compile it with your kernel.
|
||||
Location: Device Drivers -> Multimedia devices -> Video For Linux -> Video Capture Adapters -> V4L USB devices
|
||||
|
||||
usage:
|
||||
modprobe zr364xx debug=X mode=Y
|
||||
- debug : set to 1 to enable verbose debug messages
|
||||
- mode : 0 = 320x240, 1 = 160x120, 2 = 640x480
|
||||
You can then use the camera with V4L2 compatible applications, for example Ekiga.
|
||||
To capture a single image, try this: dd if=/dev/video0 of=test.jpg bs=1 count=1
|
||||
|
||||
links :
|
||||
http://mxhaard.free.fr/ (support for many others cams including some Aiptek PocketDV)
|
||||
http://www.harmwal.nl/pccam880/ (this project also supports cameras based on this chipset)
|
||||
|
||||
supported devices:
|
||||
------ ------- ----------- -----
|
||||
Vendor Product Distributor Model
|
||||
------ ------- ----------- -----
|
||||
0x08ca 0x0109 Aiptek PocketDV 3300
|
||||
0x08ca 0x0109 Maxell Maxcam PRO DV3
|
||||
0x041e 0x4024 Creative PC-CAM 880
|
||||
0x0d64 0x0108 Aiptek Fidelity 3200
|
||||
0x0d64 0x0108 Praktica DCZ 1.3 S
|
||||
0x0d64 0x0108 Genius Digital Camera (?)
|
||||
0x0d64 0x0108 DXG Technology Fashion Cam
|
||||
0x0546 0x3187 Polaroid iON 230
|
||||
0x0d64 0x3108 Praktica Exakta DC 2200
|
||||
0x0d64 0x3108 Genius G-Shot D211
|
||||
0x0595 0x4343 Concord Eye-Q Duo 1300
|
||||
0x0595 0x4343 Concord Eye-Q Duo 2000
|
||||
0x0595 0x4343 Fujifilm EX-10
|
||||
0x0595 0x4343 Ricoh RDC-6000
|
||||
0x0595 0x4343 Digitrex DSC 1300
|
||||
0x0595 0x4343 Firstline FDC 2000
|
||||
0x0bb0 0x500d Concord EyeQ Go Wireless
|
||||
0x0feb 0x2004 CRS Electronic 3.3 Digital Camera
|
||||
0x0feb 0x2004 Packard Bell DSC-300
|
||||
0x055f 0xb500 Mustek MDC 3000
|
||||
0x08ca 0x2062 Aiptek PocketDV 5700
|
||||
0x052b 0x1a18 Chiphead Megapix V12
|
||||
0x04c8 0x0729 Konica Revio 2
|
||||
0x04f2 0xa208 Creative PC-CAM 850
|
||||
0x0784 0x0040 Traveler Slimline X5
|
||||
0x06d6 0x0034 Trust Powerc@m 750
|
||||
0x0a17 0x0062 Pentax Optio 50L
|
||||
|
46
MAINTAINERS
46
MAINTAINERS
|
@ -55,7 +55,7 @@ trivial patch so apply some common sense.
|
|||
|
||||
8. Happy hacking.
|
||||
|
||||
-----------------------------------
|
||||
-----------------------------------
|
||||
|
||||
Maintainers List (try to look for most precise areas first)
|
||||
|
||||
|
@ -873,6 +873,12 @@ W: http://linuxtv.org
|
|||
T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git
|
||||
S: Maintained
|
||||
|
||||
CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER
|
||||
P: Jonathan Corbet
|
||||
M: corbet@lwn.net
|
||||
L: video4linux-list@redhat.com
|
||||
S: Maintained
|
||||
|
||||
CALGARY x86-64 IOMMU
|
||||
P: Muli Ben-Yehuda
|
||||
M: muli@il.ibm.com
|
||||
|
@ -907,7 +913,7 @@ L: linux-cifs-client@lists.samba.org
|
|||
L: samba-technical@lists.samba.org
|
||||
W: http://us1.samba.org/samba/Linux_CIFS_client.html
|
||||
T: git kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
|
||||
S: Supported
|
||||
S: Supported
|
||||
|
||||
CONFIGFS
|
||||
P: Joel Becker
|
||||
|
@ -1549,19 +1555,19 @@ P: Chirag Kantharia
|
|||
M: chirag.kantharia@hp.com
|
||||
L: iss_storagedev@hp.com
|
||||
S: Maintained
|
||||
|
||||
|
||||
HEWLETT-PACKARD SMART2 RAID DRIVER
|
||||
P: Chirag Kantharia
|
||||
M: chirag.kantharia@hp.com
|
||||
L: iss_storagedev@hp.com
|
||||
S: Maintained
|
||||
|
||||
|
||||
HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
|
||||
P: Mike Miller
|
||||
M: mike.miller@hp.com
|
||||
L: iss_storagedev@hp.com
|
||||
S: Supported
|
||||
|
||||
|
||||
HOST AP DRIVER
|
||||
P: Jouni Malinen
|
||||
M: jkmaline@cc.hut.fi
|
||||
|
@ -1673,7 +1679,7 @@ P: Jack Hammer
|
|||
P: Dave Jeffery
|
||||
M: ipslinux@adaptec.com
|
||||
W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html
|
||||
S: Supported
|
||||
S: Supported
|
||||
|
||||
IDE SUBSYSTEM
|
||||
P: Bartlomiej Zolnierkiewicz
|
||||
|
@ -1975,7 +1981,7 @@ M: kai@germaschewski.name
|
|||
P: Sam Ravnborg
|
||||
M: sam@ravnborg.org
|
||||
T: git kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git
|
||||
S: Maintained
|
||||
S: Maintained
|
||||
|
||||
KERNEL JANITORS
|
||||
P: Several
|
||||
|
@ -2155,7 +2161,7 @@ S: Maintained
|
|||
LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks)
|
||||
P: Richard Russon (FlatCap)
|
||||
M: ldm@flatcap.org
|
||||
L: ldm-devel@lists.sourceforge.net
|
||||
L: ldm-devel@lists.sourceforge.net
|
||||
W: http://ldm.sourceforge.net
|
||||
S: Maintained
|
||||
|
||||
|
@ -2504,13 +2510,13 @@ P: Kurt Hackel
|
|||
M: kurt.hackel@oracle.com
|
||||
L: ocfs2-devel@oss.oracle.com
|
||||
W: http://oss.oracle.com/projects/ocfs2/
|
||||
S: Supported
|
||||
S: Supported
|
||||
|
||||
OLYMPIC NETWORK DRIVER
|
||||
P: Peter De Shrijver
|
||||
M: p2@ace.ulyssis.student.kuleuven.ac.be
|
||||
P: Mike Phillips
|
||||
M: mikep@linuxtr.net
|
||||
M: mikep@linuxtr.net
|
||||
L: netdev@vger.kernel.org
|
||||
L: linux-tr@linuxtr.net
|
||||
W: http://www.linuxtr.net
|
||||
|
@ -2526,6 +2532,12 @@ P: Harald Welte
|
|||
M: laforge@gnumonks.org
|
||||
S: Maintained
|
||||
|
||||
OMNIVISION OV7670 SENSOR DRIVER
|
||||
P: Jonathan Corbet
|
||||
M: corbet@lwn.net
|
||||
L: video4linux-list@redhat.com
|
||||
S: Maintained
|
||||
|
||||
ONSTREAM SCSI TAPE DRIVER
|
||||
P: Willem Riede
|
||||
M: osst@riede.org
|
||||
|
@ -3045,7 +3057,7 @@ SIS FRAMEBUFFER DRIVER
|
|||
P: Thomas Winischhofer
|
||||
M: thomas@winischhofer.net
|
||||
W: http://www.winischhofer.net/linuxsisvga.shtml
|
||||
S: Maintained
|
||||
S: Maintained
|
||||
|
||||
SIS USB2VGA DRIVER
|
||||
P: Thomas Winischhofer
|
||||
|
@ -3594,7 +3606,7 @@ L: linux-usb-devel@lists.sourceforge.net
|
|||
W: http://www.connecttech.com
|
||||
S: Supported
|
||||
|
||||
USB SN9C10x DRIVER
|
||||
USB SN9C1xx DRIVER
|
||||
P: Luca Risolia
|
||||
M: luca.risolia@studio.unibo.it
|
||||
L: linux-usb-devel@lists.sourceforge.net
|
||||
|
@ -3649,6 +3661,14 @@ L: linux-usb-devel@lists.sourceforge.net
|
|||
W: http://linux-lc100020.sourceforge.net
|
||||
S: Maintained
|
||||
|
||||
USB ZR364XX DRIVER
|
||||
P: Antoine Jacquet
|
||||
M: royale@zerezo.com
|
||||
L: linux-usb-devel@lists.sourceforge.net
|
||||
L: video4linux-list@redhat.com
|
||||
W: http://royale.zerezo.com/zr364xx/
|
||||
S: Maintained
|
||||
|
||||
USER-MODE LINUX
|
||||
P: Jeff Dike
|
||||
M: jdike@karaya.com
|
||||
|
@ -3656,7 +3676,7 @@ L: user-mode-linux-devel@lists.sourceforge.net
|
|||
L: user-mode-linux-user@lists.sourceforge.net
|
||||
W: http://user-mode-linux.sourceforge.net
|
||||
S: Maintained
|
||||
|
||||
|
||||
FAT/VFAT/MSDOS FILESYSTEM:
|
||||
P: OGAWA Hirofumi
|
||||
M: hirofumi@mail.parknet.co.jp
|
||||
|
|
|
@ -667,7 +667,7 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
|
|||
[ 0x1f ] = KEY_L,
|
||||
[ 0x2b ] = KEY_I,
|
||||
|
||||
[ 0x2d ] = KEY_ZOOM,
|
||||
[ 0x2d ] = KEY_SCREEN,
|
||||
[ 0x1e ] = KEY_ZOOM,
|
||||
[ 0x1b ] = KEY_VOLUMEUP,
|
||||
[ 0x0f ] = KEY_VOLUMEDOWN,
|
||||
|
@ -682,12 +682,12 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
|
|||
|
||||
[ 0x3f ] = KEY_UP,
|
||||
[ 0x3e ] = KEY_DOWN,
|
||||
[ 0x1a ] = KEY_PAUSE,
|
||||
[ 0x1a ] = KEY_ENTER,
|
||||
|
||||
[ 0x1d ] = KEY_MENU,
|
||||
[ 0x19 ] = KEY_PLAY,
|
||||
[ 0x16 ] = KEY_REWIND,
|
||||
[ 0x13 ] = KEY_FORWARD,
|
||||
[ 0x19 ] = KEY_AGAIN,
|
||||
[ 0x16 ] = KEY_PREVIOUSSONG,
|
||||
[ 0x13 ] = KEY_NEXTSONG,
|
||||
[ 0x15 ] = KEY_PAUSE,
|
||||
[ 0x0e ] = KEY_REWIND,
|
||||
[ 0x0d ] = KEY_PLAY,
|
||||
|
@ -1739,7 +1739,7 @@ IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = {
|
|||
|
||||
EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
|
||||
|
||||
/* for the Technotrend 1500 bundled remote: */
|
||||
/* for the Technotrend 1500 bundled remotes (grey and black): */
|
||||
IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
|
||||
[ 0x01 ] = KEY_POWER,
|
||||
[ 0x02 ] = KEY_SHUFFLE, /* ? double-arrow key */
|
||||
|
@ -1774,6 +1774,12 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
|
|||
[ 0x25 ] = KEY_VOLUMEUP,
|
||||
[ 0x26 ] = KEY_VOLUMEDOWN,
|
||||
[ 0x27 ] = KEY_SETUP,
|
||||
[ 0x3a ] = KEY_RECORD, /* these keys are only in the black remote */
|
||||
[ 0x3b ] = KEY_PLAY,
|
||||
[ 0x3c ] = KEY_STOP,
|
||||
[ 0x3d ] = KEY_REWIND,
|
||||
[ 0x3e ] = KEY_PAUSE,
|
||||
[ 0x3f ] = KEY_FORWARD,
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
|
||||
|
|
|
@ -1428,6 +1428,7 @@ static void video_close(struct saa7146_dev *dev, struct file *file)
|
|||
{
|
||||
struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
struct videobuf_queue *q = &fh->video_q;
|
||||
int err;
|
||||
|
||||
if (IS_CAPTURE_ACTIVE(fh) != 0) {
|
||||
|
@ -1436,6 +1437,11 @@ static void video_close(struct saa7146_dev *dev, struct file *file)
|
|||
err = saa7146_stop_preview(fh);
|
||||
}
|
||||
|
||||
// release all capture buffers
|
||||
mutex_lock(&q->lock);
|
||||
videobuf_read_stop(q);
|
||||
mutex_unlock(&q->lock);
|
||||
|
||||
/* hmm, why is this function declared void? */
|
||||
/* return err */
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ config DVB_B2C2_FLEXCOP
|
|||
select DVB_STV0297 if !DVB_FE_CUSTOMISE
|
||||
select DVB_BCM3510 if !DVB_FE_CUSTOMISE
|
||||
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Support for the digital TV receiver chip made by B2C2 Inc. included in
|
||||
Technisats PCI cards and USB boxes.
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "stv0297.h"
|
||||
#include "mt312.h"
|
||||
#include "lgdt330x.h"
|
||||
#include "lgh06xf.h"
|
||||
#include "dvb-pll.h"
|
||||
|
||||
/* lnb control */
|
||||
|
@ -507,7 +506,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
|
|||
/* try the air atsc 3nd generation (lgdt3303) */
|
||||
if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
|
||||
fc->dev_type = FC_AIR_ATSC3;
|
||||
dvb_attach(lgh06xf_attach, fc->fe, &fc->i2c_adap);
|
||||
dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf);
|
||||
info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
|
||||
} else
|
||||
/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
|
||||
|
|
|
@ -127,10 +127,11 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
|
|||
{
|
||||
struct flexcop_pci *fc_pci = dev_id;
|
||||
struct flexcop_device *fc = fc_pci->fc_dev;
|
||||
unsigned long flags;
|
||||
flexcop_ibi_value v;
|
||||
irqreturn_t ret = IRQ_HANDLED;
|
||||
|
||||
spin_lock_irq(&fc_pci->irq_lock);
|
||||
spin_lock_irqsave(&fc_pci->irq_lock,flags);
|
||||
|
||||
v = fc->read_ibi_reg(fc,irq_20c);
|
||||
|
||||
|
@ -194,7 +195,7 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
|
|||
ret = IRQ_NONE;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&fc_pci->irq_lock);
|
||||
spin_unlock_irqrestore(&fc_pci->irq_lock,flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -293,12 +294,12 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
|
|||
}
|
||||
|
||||
pci_set_drvdata(fc_pci->pdev, fc_pci);
|
||||
|
||||
spin_lock_init(&fc_pci->irq_lock);
|
||||
if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
|
||||
IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
|
||||
goto err_pci_iounmap;
|
||||
|
||||
spin_lock_init(&fc_pci->irq_lock);
|
||||
|
||||
|
||||
fc_pci->init_state |= FC_PCI_INIT;
|
||||
return ret;
|
||||
|
|
|
@ -7,7 +7,7 @@ config DVB_BT8XX
|
|||
select DVB_CX24110 if !DVB_FE_CUSTOMISE
|
||||
select DVB_OR51211 if !DVB_FE_CUSTOMISE
|
||||
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
|
||||
select DVB_PLL
|
||||
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
|
||||
select FW_LOADER
|
||||
help
|
||||
|
|
|
@ -393,9 +393,7 @@ static struct cards card_list[] __devinitdata = {
|
|||
{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" },
|
||||
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
|
||||
{ 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" },
|
||||
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" },
|
||||
|
||||
{ 0, -1, NULL }
|
||||
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -610,7 +610,8 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
|
|||
lgdt330x_reset(card);
|
||||
card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
|
||||
if (card->fe != NULL) {
|
||||
dvb_attach(lgh06xf_attach, card->fe, card->i2c_adapter);
|
||||
dvb_attach(dvb_pll_attach, card->fe, 0x61,
|
||||
card->i2c_adapter, &dvb_pll_lg_tdvs_h06xf);
|
||||
dprintk ("dvb_bt8xx: lgdt330x detected\n");
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
#include "cx24110.h"
|
||||
#include "or51211.h"
|
||||
#include "lgdt330x.h"
|
||||
#include "lgh06xf.h"
|
||||
#include "zl10353.h"
|
||||
#include "dvb-pll.h"
|
||||
|
||||
struct dvb_bt8xx_card {
|
||||
struct mutex lock;
|
||||
|
|
|
@ -132,6 +132,11 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
|
|||
if (mutex_lock_interruptible(&dmxdev->mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (dmxdev->exit) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDWR) {
|
||||
if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
|
@ -171,6 +176,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
|
|||
dmxdev->demux->disconnect_frontend(dmxdev->demux);
|
||||
dmxdev->demux->connect_frontend(dmxdev->demux, front);
|
||||
}
|
||||
dvbdev->users++;
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
@ -198,7 +204,16 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
|
|||
vfree(mem);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
/* TODO */
|
||||
dvbdev->users--;
|
||||
if(dvbdev->users==-1 && dmxdev->exit==1) {
|
||||
fops_put(file->f_op);
|
||||
file->f_op = NULL;
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
wake_up(&dvbdev->wait_queue);
|
||||
} else
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -215,6 +230,11 @@ static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
|
|||
return -EINVAL;
|
||||
if (mutex_lock_interruptible(&dmxdev->mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (dmxdev->exit) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = dmxdev->demux->write(dmxdev->demux, buf, count);
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return ret;
|
||||
|
@ -227,6 +247,11 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
|
|||
struct dmxdev *dmxdev = dvbdev->priv;
|
||||
int ret;
|
||||
|
||||
if (dmxdev->exit) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
//mutex_lock(&dmxdev->mutex);
|
||||
ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
|
||||
file->f_flags & O_NONBLOCK,
|
||||
|
@ -665,6 +690,8 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
|
|||
dmxdevfilter->feed.ts = NULL;
|
||||
init_timer(&dmxdevfilter->timer);
|
||||
|
||||
dvbdev->users++;
|
||||
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
@ -943,7 +970,21 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
|
|||
struct dmxdev_filter *dmxdevfilter = file->private_data;
|
||||
struct dmxdev *dmxdev = dmxdevfilter->dev;
|
||||
|
||||
return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
|
||||
int ret;
|
||||
|
||||
ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
|
||||
|
||||
mutex_lock(&dmxdev->mutex);
|
||||
dmxdev->dvbdev->users--;
|
||||
if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
|
||||
fops_put(file->f_op);
|
||||
file->f_op = NULL;
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
wake_up(&dmxdev->dvbdev->wait_queue);
|
||||
} else
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct file_operations dvb_demux_fops = {
|
||||
|
@ -1027,6 +1068,7 @@ static struct file_operations dvb_dvr_fops = {
|
|||
static struct dvb_device dvbdev_dvr = {
|
||||
.priv = NULL,
|
||||
.readers = 1,
|
||||
.users = 1,
|
||||
.fops = &dvb_dvr_fops
|
||||
};
|
||||
|
||||
|
@ -1064,6 +1106,16 @@ EXPORT_SYMBOL(dvb_dmxdev_init);
|
|||
|
||||
void dvb_dmxdev_release(struct dmxdev *dmxdev)
|
||||
{
|
||||
dmxdev->exit=1;
|
||||
if (dmxdev->dvbdev->users > 1) {
|
||||
wait_event(dmxdev->dvbdev->wait_queue,
|
||||
dmxdev->dvbdev->users==1);
|
||||
}
|
||||
if (dmxdev->dvr_dvbdev->users > 1) {
|
||||
wait_event(dmxdev->dvr_dvbdev->wait_queue,
|
||||
dmxdev->dvr_dvbdev->users==1);
|
||||
}
|
||||
|
||||
dvb_unregister_device(dmxdev->dvbdev);
|
||||
dvb_unregister_device(dmxdev->dvr_dvbdev);
|
||||
|
||||
|
|
|
@ -91,6 +91,8 @@ struct dmxdev {
|
|||
|
||||
int filternum;
|
||||
int capabilities;
|
||||
|
||||
unsigned int exit:1;
|
||||
#define DMXDEV_CAP_DUPLEX 1
|
||||
struct dmx_frontend *dvr_orig_fe;
|
||||
|
||||
|
|
|
@ -606,6 +606,7 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
|
|||
return;
|
||||
|
||||
kthread_stop(fepriv->thread);
|
||||
|
||||
init_MUTEX (&fepriv->sem);
|
||||
fepriv->state = FESTATE_IDLE;
|
||||
|
||||
|
@ -1023,6 +1024,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
|
|||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dvb_frontend *fe = dvbdev->priv;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
int ret;
|
||||
|
||||
dprintk ("%s\n", __FUNCTION__);
|
||||
|
||||
|
@ -1032,7 +1034,14 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
|
|||
if (fe->ops.ts_bus_ctrl)
|
||||
fe->ops.ts_bus_ctrl (fe, 0);
|
||||
|
||||
return dvb_generic_release (inode, file);
|
||||
ret = dvb_generic_release (inode, file);
|
||||
|
||||
if (dvbdev->users==-1 && fepriv->exit==1) {
|
||||
fops_put(file->f_op);
|
||||
file->f_op = NULL;
|
||||
wake_up(&dvbdev->wait_queue);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct file_operations dvb_frontend_fops = {
|
||||
|
@ -1092,8 +1101,15 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
|
|||
dprintk ("%s\n", __FUNCTION__);
|
||||
|
||||
mutex_lock(&frontend_mutex);
|
||||
dvb_unregister_device (fepriv->dvbdev);
|
||||
dvb_frontend_stop (fe);
|
||||
mutex_unlock(&frontend_mutex);
|
||||
|
||||
if (fepriv->dvbdev->users < -1)
|
||||
wait_event(fepriv->dvbdev->wait_queue,
|
||||
fepriv->dvbdev->users==-1);
|
||||
|
||||
mutex_lock(&frontend_mutex);
|
||||
dvb_unregister_device (fepriv->dvbdev);
|
||||
|
||||
/* fe is invalid now */
|
||||
kfree(fepriv);
|
||||
|
|
|
@ -1439,11 +1439,36 @@ static int dvb_net_ioctl(struct inode *inode, struct file *file,
|
|||
return dvb_usercopy(inode, file, cmd, arg, dvb_net_do_ioctl);
|
||||
}
|
||||
|
||||
static int dvb_net_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dvb_net *dvbnet = dvbdev->priv;
|
||||
|
||||
if (!dvbdev)
|
||||
return -ENODEV;
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
|
||||
dvbdev->readers++;
|
||||
} else {
|
||||
dvbdev->writers++;
|
||||
}
|
||||
|
||||
dvbdev->users++;
|
||||
|
||||
if(dvbdev->users == 1 && dvbnet->exit==1) {
|
||||
fops_put(file->f_op);
|
||||
file->f_op = NULL;
|
||||
wake_up(&dvbdev->wait_queue);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct file_operations dvb_net_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.ioctl = dvb_net_ioctl,
|
||||
.open = dvb_generic_open,
|
||||
.release = dvb_generic_release,
|
||||
.release = dvb_net_close,
|
||||
};
|
||||
|
||||
static struct dvb_device dvbdev_net = {
|
||||
|
@ -1458,6 +1483,11 @@ void dvb_net_release (struct dvb_net *dvbnet)
|
|||
{
|
||||
int i;
|
||||
|
||||
dvbnet->exit = 1;
|
||||
if (dvbnet->dvbdev->users < 1)
|
||||
wait_event(dvbnet->dvbdev->wait_queue,
|
||||
dvbnet->dvbdev->users==1);
|
||||
|
||||
dvb_unregister_device(dvbnet->dvbdev);
|
||||
|
||||
for (i=0; i<DVB_NET_DEVICES_MAX; i++) {
|
||||
|
|
|
@ -36,6 +36,7 @@ struct dvb_net {
|
|||
struct dvb_device *dvbdev;
|
||||
struct net_device *device[DVB_NET_DEVICES_MAX];
|
||||
int state[DVB_NET_DEVICES_MAX];
|
||||
unsigned int exit:1;
|
||||
struct dmx_demux *demux;
|
||||
};
|
||||
|
||||
|
|
|
@ -233,6 +233,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
|||
dvbdev->adapter = adap;
|
||||
dvbdev->priv = priv;
|
||||
dvbdev->fops = dvbdevfops;
|
||||
init_waitqueue_head (&dvbdev->wait_queue);
|
||||
|
||||
memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
|
||||
dvbdev->fops->owner = adap->module;
|
||||
|
|
|
@ -69,6 +69,7 @@ struct dvb_device {
|
|||
int writers;
|
||||
int users;
|
||||
|
||||
wait_queue_head_t wait_queue;
|
||||
/* don't really need those !? -- FIXME: use video_usercopy */
|
||||
int (*kernel_ioctl)(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg);
|
||||
|
|
|
@ -33,6 +33,7 @@ config DVB_USB_A800
|
|||
config DVB_USB_DIBUSB_MB
|
||||
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
|
||||
depends on DVB_USB
|
||||
select DVB_PLL
|
||||
select DVB_DIB3000MB
|
||||
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
|
@ -88,6 +89,7 @@ config DVB_USB_DIB0700
|
|||
config DVB_USB_UMT_010
|
||||
tristate "HanfTek UMT-010 DVB-T USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_PLL
|
||||
select DVB_DIB3000MC
|
||||
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
|
@ -96,9 +98,9 @@ config DVB_USB_UMT_010
|
|||
config DVB_USB_CXUSB
|
||||
tristate "Conexant USB2.0 hybrid reference design support"
|
||||
depends on DVB_USB
|
||||
select DVB_PLL
|
||||
select DVB_CX22702 if !DVB_FE_CUSTOMISE
|
||||
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
|
||||
select DVB_MT352 if !DVB_FE_CUSTOMISE
|
||||
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
|
@ -140,6 +142,7 @@ config DVB_USB_AU6610
|
|||
config DVB_USB_DIGITV
|
||||
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_PLL
|
||||
select DVB_NXT6000 if !DVB_FE_CUSTOMISE
|
||||
select DVB_MT352 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
|
@ -208,3 +211,10 @@ config DVB_USB_DTT200U
|
|||
The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
|
||||
|
||||
The WT-220U and its clones are pen-sized.
|
||||
|
||||
config DVB_USB_OPERA1
|
||||
tristate "Opera1 DVB-S USB2.0 receiver"
|
||||
depends on DVB_USB
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Opera DVB-S USB2.0 receiver.
|
||||
|
|
|
@ -51,4 +51,8 @@ obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o
|
|||
dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o
|
||||
obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
|
||||
|
||||
dvb-usb-opera-objs = opera1.o
|
||||
obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
|
||||
|
||||
|
||||
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
|
||||
|
|
|
@ -40,7 +40,7 @@ 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, index, usb_buf,
|
||||
USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, usb_buf,
|
||||
sizeof(usb_buf), AU6610_USB_TIMEOUT);
|
||||
|
||||
if (ret < 0)
|
||||
|
@ -124,7 +124,7 @@ static int au6610_identify_state(struct usb_device *udev,
|
|||
}
|
||||
|
||||
static struct zl10353_config au6610_zl10353_config = {
|
||||
.demod_address = 0x1e,
|
||||
.demod_address = 0x0f,
|
||||
.no_tuner = 1,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
@ -140,7 +140,7 @@ static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
|
|||
}
|
||||
|
||||
static struct qt1010_config au6610_qt1010_config = {
|
||||
.i2c_address = 0xc4
|
||||
.i2c_address = 0x62
|
||||
};
|
||||
|
||||
static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
|
||||
#include "cx22702.h"
|
||||
#include "lgdt330x.h"
|
||||
#include "lgh06xf.h"
|
||||
#include "mt352.h"
|
||||
#include "mt352_priv.h"
|
||||
#include "zl10353.h"
|
||||
|
@ -388,7 +387,8 @@ static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
|
|||
|
||||
static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(lgh06xf_attach, adap->fe, &adap->dev->i2c_adap);
|
||||
dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
|
||||
&dvb_pll_lg_tdvs_h06xf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,10 +56,6 @@ static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u
|
|||
if (txlen > 3)
|
||||
index |= tx[3];
|
||||
|
||||
/* think about swapping here */
|
||||
value = le16_to_cpu(value);
|
||||
index = le16_to_cpu(index);
|
||||
|
||||
status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0],
|
||||
USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define USB_VID_ADSTECH 0x06e1
|
||||
#define USB_VID_ALCOR_MICRO 0x058f
|
||||
#define USB_VID_ANCHOR 0x0547
|
||||
#define USB_VID_ANUBIS_ELECTRONIC 0x10fd
|
||||
#define USB_VID_AVERMEDIA 0x07ca
|
||||
#define USB_VID_COMPRO 0x185b
|
||||
#define USB_VID_COMPRO_UNK 0x145f
|
||||
|
@ -31,6 +32,7 @@
|
|||
#define USB_VID_LITEON 0x04ca
|
||||
#define USB_VID_MEDION 0x1660
|
||||
#define USB_VID_MSI 0x0db0
|
||||
#define USB_VID_OPERA1 0x695c
|
||||
#define USB_VID_PINNACLE 0x2304
|
||||
#define USB_VID_VISIONPLUS 0x13d3
|
||||
#define USB_VID_TWINHAN 0x1822
|
||||
|
@ -127,6 +129,7 @@
|
|||
#define USB_PID_KYE_DVB_T_WARM 0x701f
|
||||
#define USB_PID_PCTV_200E 0x020e
|
||||
#define USB_PID_PCTV_400E 0x020f
|
||||
#define USB_PID_PCTV_450E 0x0222
|
||||
#define USB_PID_LITEON_DVB_T_COLD 0xf000
|
||||
#define USB_PID_LITEON_DVB_T_WARM 0xf001
|
||||
#define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360
|
||||
|
@ -139,6 +142,9 @@
|
|||
#define USB_PID_GENPIX_8PSK_COLD 0x0200
|
||||
#define USB_PID_GENPIX_8PSK_WARM 0x0201
|
||||
#define USB_PID_SIGMATEK_DVB_110 0x6610
|
||||
#define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513
|
||||
#define USB_PID_OPERA1_COLD 0x2830
|
||||
#define USB_PID_OPERA1_WARM 0x3829
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "qt1010.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_gl861_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);
|
||||
|
||||
|
@ -20,7 +20,7 @@ static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
|||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u16 index;
|
||||
u16 value = addr << 8;
|
||||
u16 value = addr << (8 + 1);
|
||||
int wo = (rbuf == NULL || rlen == 0); /* write-only */
|
||||
u8 req, type;
|
||||
|
||||
|
@ -101,7 +101,7 @@ static int gl861_identify_state(struct usb_device *udev,
|
|||
}
|
||||
|
||||
static struct zl10353_config gl861_zl10353_config = {
|
||||
.demod_address = 0x1e,
|
||||
.demod_address = 0x0f,
|
||||
.no_tuner = 1,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
@ -117,7 +117,7 @@ static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
|
|||
}
|
||||
|
||||
static struct qt1010_config gl861_qt1010_config = {
|
||||
.i2c_address = 0xc4
|
||||
.i2c_address = 0x62
|
||||
};
|
||||
|
||||
static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "mt352.h"
|
||||
#include "mt352_priv.h"
|
||||
#include "qt1010.h"
|
||||
#include "tda1004x.h"
|
||||
#include "tda827x.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_m920x_debug;
|
||||
|
@ -47,11 +49,15 @@ static inline int m9206_read(struct usb_device *udev, u8 request, u16 value,\
|
|||
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
request, USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
value, index, data, size, 2000);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
printk(KERN_INFO "m920x_read = error: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret != size)
|
||||
if (ret != size) {
|
||||
deb_rc("m920x_read = no data\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -64,19 +70,22 @@ static inline int m9206_write(struct usb_device *udev, u8 request,
|
|||
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
request, USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
value, index, NULL, 0, 2000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int m9206_rc_init(struct usb_device *udev)
|
||||
static int m9206_init(struct dvb_usb_device *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Remote controller init. */
|
||||
if ((ret = m9206_write(udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0)
|
||||
return ret;
|
||||
if (d->props.rc_query) {
|
||||
if ((ret = m9206_write(d->udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = m9206_write(udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0)
|
||||
return ret;
|
||||
if ((ret = m9206_write(d->udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -87,16 +96,15 @@ static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
int i, ret = 0;
|
||||
u8 rc_state[2];
|
||||
|
||||
|
||||
if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
|
||||
goto unlock;
|
||||
|
||||
if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
|
||||
goto unlock;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++)
|
||||
if (megasky_rc_keys[i].data == rc_state[1]) {
|
||||
*event = megasky_rc_keys[i].event;
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++)
|
||||
if (d->props.rc_key_map[i].data == rc_state[1]) {
|
||||
*event = d->props.rc_key_map[i].event;
|
||||
|
||||
switch(rc_state[0]) {
|
||||
case 0x80:
|
||||
|
@ -137,53 +145,51 @@ static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
|||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct m9206_state *m = d->priv;
|
||||
int i;
|
||||
int i, j;
|
||||
int ret = 0;
|
||||
|
||||
if (!num)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0)
|
||||
if (msg[i].flags & (I2C_M_NO_RD_ACK|I2C_M_IGNORE_NAK|I2C_M_TEN) ||
|
||||
msg[i].len == 0) {
|
||||
/* For a 0 byte message, I think sending the address to index 0x80|0x40
|
||||
* would be the correct thing to do. However, zero byte messages are
|
||||
* only used for probing, and since we don't know how to get the slave's
|
||||
* ack, we can't probe. */
|
||||
ret = -ENOTSUPP;
|
||||
goto unlock;
|
||||
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[0], 0x0)) != 0)
|
||||
goto unlock;
|
||||
|
||||
if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) {
|
||||
int i2c_i;
|
||||
|
||||
for (i2c_i = 0; i2c_i < M9206_I2C_MAX; i2c_i++)
|
||||
if (msg[i].addr == m->i2c_r[i2c_i].addr)
|
||||
break;
|
||||
|
||||
if (i2c_i >= M9206_I2C_MAX) {
|
||||
deb_rc("No magic for i2c addr!\n");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
/* Send START & address/RW bit */
|
||||
if (!(msg[i].flags & I2C_M_NOSTART)) {
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0), 0x80)) != 0)
|
||||
goto unlock;
|
||||
/* Should check for ack here, if we knew how. */
|
||||
}
|
||||
if (msg[i].flags & I2C_M_RD) {
|
||||
for (j = 0; j < msg[i].len; j++) {
|
||||
/* Last byte of transaction? Send STOP, otherwise send ACK. */
|
||||
int stop = (i+1 == num && j+1 == msg[i].len)?0x40:0x01;
|
||||
if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x20|stop, &msg[i].buf[j], 1)) != 0)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, m->i2c_r[i2c_i].magic, 0x80)) != 0)
|
||||
goto unlock;
|
||||
|
||||
if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0)
|
||||
goto unlock;
|
||||
|
||||
i++;
|
||||
} else {
|
||||
if (msg[i].len != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[1], 0x40)) != 0)
|
||||
goto unlock;
|
||||
for (j = 0; j < msg[i].len; j++) {
|
||||
/* Last byte of transaction? Then send STOP. */
|
||||
int stop = (i+1 == num && j+1 == msg[i].len)?0x40:0x00;
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[j], stop)) != 0)
|
||||
goto unlock;
|
||||
/* Should check for ack here too. */
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = i;
|
||||
unlock:
|
||||
ret = num;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
|
||||
return ret;
|
||||
|
@ -324,6 +330,7 @@ static int m9206_firmware_download(struct usb_device *udev,
|
|||
i += size;
|
||||
}
|
||||
if (i != fw->size) {
|
||||
deb_rc("bad firmware file!\n");
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
@ -342,10 +349,10 @@ static int m9206_firmware_download(struct usb_device *udev,
|
|||
}
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int megasky_identify_state(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
static int m920x_identify_state(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
{
|
||||
struct usb_host_interface *alt;
|
||||
|
||||
|
@ -381,20 +388,15 @@ static int megasky_mt352_demod_init(struct dvb_frontend *fe)
|
|||
}
|
||||
|
||||
static struct mt352_config megasky_mt352_config = {
|
||||
.demod_address = 0x1e,
|
||||
.demod_address = 0x0f,
|
||||
.no_tuner = 1,
|
||||
.demod_init = megasky_mt352_demod_init,
|
||||
};
|
||||
|
||||
static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
|
||||
deb_rc("megasky_frontend_attach!\n");
|
||||
|
||||
m->i2c_r[M9206_I2C_DEMOD].addr = megasky_mt352_config.demod_address;
|
||||
m->i2c_r[M9206_I2C_DEMOD].magic = 0x1f;
|
||||
|
||||
if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) == NULL)
|
||||
return -EIO;
|
||||
|
||||
|
@ -402,16 +404,11 @@ static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap)
|
|||
}
|
||||
|
||||
static struct qt1010_config megasky_qt1010_config = {
|
||||
.i2c_address = 0xc4
|
||||
.i2c_address = 0x62
|
||||
};
|
||||
|
||||
static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
|
||||
m->i2c_r[M9206_I2C_TUNER].addr = megasky_qt1010_config.i2c_address;
|
||||
m->i2c_r[M9206_I2C_TUNER].magic = 0xc5;
|
||||
|
||||
if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap,
|
||||
&megasky_qt1010_config) == NULL)
|
||||
return -ENODEV;
|
||||
|
@ -419,8 +416,40 @@ static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct tda1004x_config digivox_tda10046_config = {
|
||||
.demod_address = 0x08,
|
||||
.invert = 0,
|
||||
.invert_oclk = 0,
|
||||
.ts_mode = TDA10046_TS_SERIAL,
|
||||
.xtal_freq = TDA10046_XTAL_16M,
|
||||
.if_freq = TDA10046_FREQ_045,
|
||||
.agc_config = TDA10046_AGC_TDA827X,
|
||||
.gpio_config = TDA10046_GPTRI,
|
||||
.request_firmware = NULL,
|
||||
};
|
||||
|
||||
static int digivox_tda10046_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
deb_rc("digivox_tda10046_frontend_attach!\n");
|
||||
|
||||
if ((adap->fe = dvb_attach(tda10046_attach, &digivox_tda10046_config,
|
||||
&adap->dev->i2c_adap)) == NULL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int digivox_tda8275_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (dvb_attach(tda827x_attach, adap->fe, 0x60, &adap->dev->i2c_adap,
|
||||
NULL) == NULL)
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties megasky_properties;
|
||||
static struct dvb_usb_device_properties digivox_mini_ii_properties;
|
||||
|
||||
static int m920x_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
|
@ -429,30 +458,36 @@ static int m920x_probe(struct usb_interface *intf,
|
|||
struct usb_host_interface *alt;
|
||||
int ret;
|
||||
|
||||
if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) {
|
||||
deb_rc("probed!\n");
|
||||
deb_rc("Probed!\n");
|
||||
|
||||
alt = usb_altnum_to_altsetting(intf, 1);
|
||||
if (alt == NULL) {
|
||||
deb_rc("not alt found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) ||
|
||||
((ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties, THIS_MODULE, &d)) == 0))
|
||||
goto found;
|
||||
|
||||
ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return ret;
|
||||
|
||||
deb_rc("Changed to alternate setting!\n");
|
||||
|
||||
if ((ret = m9206_rc_init(d->udev)) != 0)
|
||||
return ret;
|
||||
found:
|
||||
alt = usb_altnum_to_altsetting(intf, 1);
|
||||
if (alt == NULL) {
|
||||
deb_rc("No alt found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = m9206_init(d)) != 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct usb_device_id m920x_table [] = {
|
||||
{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
|
||||
{ USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC,
|
||||
USB_PID_MSI_DIGI_VOX_MINI_II) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, m920x_table);
|
||||
|
@ -471,7 +506,7 @@ static struct dvb_usb_device_properties megasky_properties = {
|
|||
|
||||
.size_of_priv = sizeof(struct m9206_state),
|
||||
|
||||
.identify_state = megasky_identify_state,
|
||||
.identify_state = m920x_identify_state,
|
||||
.num_adapters = 1,
|
||||
.adapter = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
|
||||
|
@ -502,6 +537,50 @@ static struct dvb_usb_device_properties megasky_properties = {
|
|||
{ "MSI Mega Sky 580 DVB-T USB2.0",
|
||||
{ &m920x_table[0], NULL },
|
||||
{ NULL },
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties digivox_mini_ii_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.firmware = "dvb-usb-digivox-02.fw",
|
||||
.download_firmware = m9206_firmware_download,
|
||||
|
||||
.size_of_priv = sizeof(struct m9206_state),
|
||||
|
||||
.identify_state = m920x_identify_state,
|
||||
.num_adapters = 1,
|
||||
.adapter = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
|
||||
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
|
||||
.pid_filter_count = 8,
|
||||
.pid_filter = m9206_pid_filter,
|
||||
.pid_filter_ctrl = m9206_pid_filter_ctrl,
|
||||
|
||||
.frontend_attach = digivox_tda10046_frontend_attach,
|
||||
.tuner_attach = digivox_tda8275_tuner_attach,
|
||||
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 8,
|
||||
.endpoint = 0x81,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 0x4000,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.i2c_algo = &m9206_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "MSI DIGI VOX mini II DVB-T USB2.0",
|
||||
{ &m920x_table[1], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -19,17 +19,49 @@
|
|||
|
||||
#define M9206_MAX_FILTERS 8
|
||||
|
||||
#define M9206_I2C_TUNER 0
|
||||
#define M9206_I2C_DEMOD 1
|
||||
#define M9206_I2C_MAX 2
|
||||
/*
|
||||
sequences found in logs:
|
||||
[index value]
|
||||
0x80 write addr
|
||||
(0x00 out byte)*
|
||||
0x40 out byte
|
||||
|
||||
0x80 write addr
|
||||
(0x00 out byte)*
|
||||
0x80 read addr
|
||||
(0x21 in byte)*
|
||||
0x60 in byte
|
||||
|
||||
this sequence works:
|
||||
0x80 read addr
|
||||
(0x21 in byte)*
|
||||
0x60 in byte
|
||||
|
||||
Guess at API of the I2C function:
|
||||
I2C operation is done one byte at a time with USB control messages. The
|
||||
index the messages is sent to is made up of a set of flags that control
|
||||
the I2C bus state:
|
||||
0x80: Send START condition. After a START condition, one would normally
|
||||
always send the 7-bit slave I2C address as the 7 MSB, followed by
|
||||
the read/write bit as the LSB.
|
||||
0x40: Send STOP condition. This should be set on the last byte of an
|
||||
I2C transaction.
|
||||
0x20: Read a byte from the slave. As opposed to writing a byte to the
|
||||
slave. The slave will normally not produce any data unless you
|
||||
set the R/W bit to 1 when sending the slave's address after the
|
||||
START condition.
|
||||
0x01: Respond with ACK, as opposed to a NACK. For a multi-byte read,
|
||||
the master should send an ACK, that is pull SDA low during the 9th
|
||||
clock cycle, after every byte but the last. This flags only makes
|
||||
sense when bit 0x20 is set, indicating a read.
|
||||
|
||||
What any other bits might mean, or how to get the slave's ACK/NACK
|
||||
response to a write, is unknown.
|
||||
*/
|
||||
|
||||
struct m9206_state {
|
||||
u16 filters[M9206_MAX_FILTERS];
|
||||
int filtering_enabled;
|
||||
int rep_count;
|
||||
struct {
|
||||
unsigned char addr;
|
||||
unsigned char magic;
|
||||
}i2c_r[M9206_I2C_MAX];
|
||||
};
|
||||
#endif
|
||||
|
|
581
drivers/media/dvb/dvb-usb/opera1.c
Normal file
581
drivers/media/dvb/dvb-usb/opera1.c
Normal file
|
@ -0,0 +1,581 @@
|
|||
/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card
|
||||
*
|
||||
* Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org)
|
||||
* Copyright (C) 2006 Marco Gittler (g.marco@freenet.de)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
|
||||
#include "opera1.h"
|
||||
#include "stv0299.h"
|
||||
|
||||
#define OPERA_READ_MSG 0
|
||||
#define OPERA_WRITE_MSG 1
|
||||
#define OPERA_I2C_TUNER 0xd1
|
||||
|
||||
#define READ_FX2_REG_REQ 0xba
|
||||
#define READ_MAC_ADDR 0x08
|
||||
#define OPERA_WRITE_FX2 0xbb
|
||||
#define OPERA_TUNER_REQ 0xb1
|
||||
#define REG_1F_SYMBOLRATE_BYTE0 0x1f
|
||||
#define REG_20_SYMBOLRATE_BYTE1 0x20
|
||||
#define REG_21_SYMBOLRATE_BYTE2 0x21
|
||||
|
||||
#define ADDR_B600_VOLTAGE_13V (0x02)
|
||||
#define ADDR_B601_VOLTAGE_18V (0x03)
|
||||
#define ADDR_B1A6_STREAM_CTRL (0x04)
|
||||
#define ADDR_B880_READ_REMOTE (0x05)
|
||||
|
||||
struct opera1_state {
|
||||
u32 last_key_pressed;
|
||||
};
|
||||
struct opera_rc_keys {
|
||||
u32 keycode;
|
||||
u32 event;
|
||||
};
|
||||
|
||||
int dvb_usb_opera1_debug;
|
||||
module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,
|
||||
"set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."
|
||||
DVB_USB_DEBUG_STATUS);
|
||||
|
||||
static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
|
||||
u8 * data, u16 len, int flags)
|
||||
{
|
||||
int ret;
|
||||
u8 r;
|
||||
u8 u8buf[len];
|
||||
|
||||
unsigned int pipe = (flags == OPERA_READ_MSG) ?
|
||||
usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0);
|
||||
u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
|
||||
|
||||
if (flags == OPERA_WRITE_MSG)
|
||||
memcpy(u8buf, data, len);
|
||||
ret =
|
||||
usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
|
||||
value, 0x0, u8buf, len, 2000);
|
||||
|
||||
if (request == OPERA_TUNER_REQ) {
|
||||
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
||||
OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
|
||||
0x01, 0x0, &r, 1, 2000)<1 || r!=0x08)
|
||||
return 0;
|
||||
}
|
||||
if (flags == OPERA_READ_MSG)
|
||||
memcpy(data, u8buf, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
|
||||
static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr,
|
||||
u8 * buf, u16 len)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 request;
|
||||
u16 value;
|
||||
|
||||
if (!dev) {
|
||||
info("no usb_device");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (mutex_lock_interruptible(&dev->usb_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
switch (addr>>1){
|
||||
case ADDR_B600_VOLTAGE_13V:
|
||||
request=0xb6;
|
||||
value=0x00;
|
||||
break;
|
||||
case ADDR_B601_VOLTAGE_18V:
|
||||
request=0xb6;
|
||||
value=0x01;
|
||||
break;
|
||||
case ADDR_B1A6_STREAM_CTRL:
|
||||
request=0xb1;
|
||||
value=0xa6;
|
||||
break;
|
||||
case ADDR_B880_READ_REMOTE:
|
||||
request=0xb8;
|
||||
value=0x80;
|
||||
break;
|
||||
default:
|
||||
request=0xb1;
|
||||
value=addr;
|
||||
}
|
||||
ret = opera1_xilinx_rw(dev->udev, request,
|
||||
value, buf, len,
|
||||
addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG);
|
||||
|
||||
mutex_unlock(&dev->usb_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i = 0, tmp = 0;
|
||||
|
||||
if (!d)
|
||||
return -ENODEV;
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if ((tmp = opera1_usb_i2c_msgxfer(d,
|
||||
(msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0),
|
||||
msg[i].buf,
|
||||
msg[i].len
|
||||
)!= msg[i].len)) {
|
||||
break;
|
||||
}
|
||||
if (dvb_usb_opera1_debug & 0x10)
|
||||
info("sending i2c mesage %d %d", tmp, msg[i].len);
|
||||
}
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 opera1_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm opera1_i2c_algo = {
|
||||
.master_xfer = opera1_i2c_xfer,
|
||||
.functionality = opera1_i2c_func,
|
||||
};
|
||||
|
||||
static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||
{
|
||||
static u8 command_13v[1]={0x00};
|
||||
static u8 command_18v[1]={0x01};
|
||||
struct i2c_msg msg[] = {
|
||||
{.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1},
|
||||
};
|
||||
struct dvb_usb_adapter *udev_adap =
|
||||
(struct dvb_usb_adapter *)(fe->dvb->priv);
|
||||
if (voltage == SEC_VOLTAGE_18) {
|
||||
msg[0].addr = ADDR_B601_VOLTAGE_18V;
|
||||
msg[0].buf = command_18v;
|
||||
}
|
||||
i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
|
||||
u32 ratio)
|
||||
{
|
||||
stv0299_writereg(fe, 0x13, 0x98);
|
||||
stv0299_writereg(fe, 0x14, 0x95);
|
||||
stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff);
|
||||
stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff);
|
||||
stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0);
|
||||
return 0;
|
||||
|
||||
}
|
||||
static u8 opera1_inittab[] = {
|
||||
0x00, 0xa1,
|
||||
0x01, 0x15,
|
||||
0x02, 0x00,
|
||||
0x03, 0x00,
|
||||
0x04, 0x7d,
|
||||
0x05, 0x05,
|
||||
0x06, 0x02,
|
||||
0x07, 0x00,
|
||||
0x0b, 0x00,
|
||||
0x0c, 0x01,
|
||||
0x0d, 0x81,
|
||||
0x0e, 0x44,
|
||||
0x0f, 0x19,
|
||||
0x10, 0x3f,
|
||||
0x11, 0x84,
|
||||
0x12, 0xda,
|
||||
0x13, 0x98,
|
||||
0x14, 0x95,
|
||||
0x15, 0xc9,
|
||||
0x16, 0xeb,
|
||||
0x17, 0x00,
|
||||
0x18, 0x19,
|
||||
0x19, 0x8b,
|
||||
0x1a, 0x00,
|
||||
0x1b, 0x82,
|
||||
0x1c, 0x7f,
|
||||
0x1d, 0x00,
|
||||
0x1e, 0x00,
|
||||
REG_1F_SYMBOLRATE_BYTE0, 0x06,
|
||||
REG_20_SYMBOLRATE_BYTE1, 0x50,
|
||||
REG_21_SYMBOLRATE_BYTE2, 0x10,
|
||||
0x22, 0x00,
|
||||
0x23, 0x00,
|
||||
0x24, 0x37,
|
||||
0x25, 0xbc,
|
||||
0x26, 0x00,
|
||||
0x27, 0x00,
|
||||
0x28, 0x00,
|
||||
0x29, 0x1e,
|
||||
0x2a, 0x14,
|
||||
0x2b, 0x1f,
|
||||
0x2c, 0x09,
|
||||
0x2d, 0x0a,
|
||||
0x2e, 0x00,
|
||||
0x2f, 0x00,
|
||||
0x30, 0x00,
|
||||
0x31, 0x1f,
|
||||
0x32, 0x19,
|
||||
0x33, 0xfc,
|
||||
0x34, 0x13,
|
||||
0xff, 0xff,
|
||||
};
|
||||
|
||||
static struct stv0299_config opera1_stv0299_config = {
|
||||
.demod_address = 0xd0>>1,
|
||||
.min_delay_ms = 100,
|
||||
.mclk = 88000000UL,
|
||||
.invert = 1,
|
||||
.skip_reinit = 0,
|
||||
.lock_output = STV0229_LOCKOUTPUT_0,
|
||||
.volt13_op0_op1 = STV0299_VOLT13_OP0,
|
||||
.inittab = opera1_inittab,
|
||||
.set_symbol_rate = opera1_stv0299_set_symbol_rate,
|
||||
};
|
||||
|
||||
static int opera1_frontend_attach(struct dvb_usb_adapter *d)
|
||||
{
|
||||
if ((d->fe =
|
||||
dvb_attach(stv0299_attach, &opera1_stv0299_config,
|
||||
&d->dev->i2c_adap)) != NULL) {
|
||||
d->fe->ops.set_voltage = opera1_set_voltage;
|
||||
return 0;
|
||||
}
|
||||
info("not attached stv0299");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(
|
||||
dvb_pll_attach, adap->fe, 0xc0>>1,
|
||||
&adap->dev->i2c_adap, &dvb_pll_opera1
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
u8 val = onoff ? 0x01 : 0x00;
|
||||
|
||||
if (dvb_usb_opera1_debug)
|
||||
info("power %s", onoff ? "on" : "off");
|
||||
return opera1_xilinx_rw(d->udev, 0xb7, val,
|
||||
&val, 1, OPERA_WRITE_MSG);
|
||||
}
|
||||
|
||||
static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
static u8 buf_start[2] = { 0xff, 0x03 };
|
||||
static u8 buf_stop[2] = { 0xff, 0x00 };
|
||||
struct i2c_msg start_tuner[] = {
|
||||
{.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2},
|
||||
};
|
||||
if (dvb_usb_opera1_debug)
|
||||
info("streaming %s", onoff ? "on" : "off");
|
||||
i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
|
||||
int onoff)
|
||||
{
|
||||
u8 b_pid[3];
|
||||
struct i2c_msg msg[] = {
|
||||
{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
|
||||
};
|
||||
if (dvb_usb_opera1_debug)
|
||||
info("pidfilter index: %d pid: %d %s", index, pid,
|
||||
onoff ? "on" : "off");
|
||||
b_pid[0] = (2 * index) + 4;
|
||||
b_pid[1] = onoff ? (pid & 0xff) : (0x00);
|
||||
b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00);
|
||||
i2c_transfer(&adap->dev->i2c_adap, msg, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
int u = 0x04;
|
||||
u8 b_pid[3];
|
||||
struct i2c_msg msg[] = {
|
||||
{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
|
||||
};
|
||||
if (dvb_usb_opera1_debug)
|
||||
info("%s hw-pidfilter", onoff ? "enable" : "disable");
|
||||
for (; u < 0x7e; u += 2) {
|
||||
b_pid[0] = u;
|
||||
b_pid[1] = 0;
|
||||
b_pid[2] = 0x80;
|
||||
i2c_transfer(&adap->dev->i2c_adap, msg, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_rc_key opera1_rc_keys[] = {
|
||||
{0x5f, 0xa0, KEY_1},
|
||||
{0x51, 0xaf, KEY_2},
|
||||
{0x5d, 0xa2, KEY_3},
|
||||
{0x41, 0xbe, KEY_4},
|
||||
{0x0b, 0xf5, KEY_5},
|
||||
{0x43, 0xbd, KEY_6},
|
||||
{0x47, 0xb8, KEY_7},
|
||||
{0x49, 0xb6, KEY_8},
|
||||
{0x05, 0xfa, KEY_9},
|
||||
{0x45, 0xba, KEY_0},
|
||||
{0x09, 0xf6, KEY_UP}, /*chanup */
|
||||
{0x1b, 0xe5, KEY_DOWN}, /*chandown */
|
||||
{0x5d, 0xa3, KEY_LEFT}, /*voldown */
|
||||
{0x5f, 0xa1, KEY_RIGHT}, /*volup */
|
||||
{0x07, 0xf8, KEY_SPACE}, /*tab */
|
||||
{0x1f, 0xe1, KEY_ENTER}, /*play ok */
|
||||
{0x1b, 0xe4, KEY_Z}, /*zoom */
|
||||
{0x59, 0xa6, KEY_M}, /*mute */
|
||||
{0x5b, 0xa5, KEY_F}, /*tv/f */
|
||||
{0x19, 0xe7, KEY_R}, /*rec */
|
||||
{0x01, 0xfe, KEY_S}, /*Stop */
|
||||
{0x03, 0xfd, KEY_P}, /*pause */
|
||||
{0x03, 0xfc, KEY_W}, /*<- -> */
|
||||
{0x07, 0xf9, KEY_C}, /*capture */
|
||||
{0x47, 0xb9, KEY_Q}, /*exit */
|
||||
{0x43, 0xbc, KEY_O}, /*power */
|
||||
|
||||
};
|
||||
|
||||
static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
|
||||
{
|
||||
struct opera1_state *opst = dev->priv;
|
||||
u8 rcbuffer[32];
|
||||
const u16 startmarker1 = 0x10ed;
|
||||
const u16 startmarker2 = 0x11ec;
|
||||
struct i2c_msg read_remote[] = {
|
||||
{.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32},
|
||||
};
|
||||
int i = 0;
|
||||
u32 send_key = 0;
|
||||
|
||||
if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) {
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (rcbuffer[i])
|
||||
send_key |= 1;
|
||||
if (i < 31)
|
||||
send_key = send_key << 1;
|
||||
}
|
||||
if (send_key & 0x8000)
|
||||
send_key = (send_key << 1) | (send_key >> 15 & 0x01);
|
||||
|
||||
if (send_key == 0xffff && opst->last_key_pressed != 0) {
|
||||
*state = REMOTE_KEY_REPEAT;
|
||||
*event = opst->last_key_pressed;
|
||||
return 0;
|
||||
}
|
||||
for (; send_key != 0;) {
|
||||
if (send_key >> 16 == startmarker2) {
|
||||
break;
|
||||
} else if (send_key >> 16 == startmarker1) {
|
||||
send_key =
|
||||
(send_key & 0xfffeffff) | (startmarker1 << 16);
|
||||
break;
|
||||
} else
|
||||
send_key >>= 1;
|
||||
}
|
||||
|
||||
if (send_key == 0)
|
||||
return 0;
|
||||
|
||||
send_key = (send_key & 0xffff) | 0x0100;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(opera1_rc_keys); i++) {
|
||||
if ((opera1_rc_keys[i].custom * 256 +
|
||||
opera1_rc_keys[i].data) == (send_key & 0xffff)) {
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
*event = opera1_rc_keys[i].event;
|
||||
opst->last_key_pressed =
|
||||
opera1_rc_keys[i].event;
|
||||
break;
|
||||
}
|
||||
opst->last_key_pressed = 0;
|
||||
}
|
||||
} else
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_device_id opera1_table[] = {
|
||||
{USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)},
|
||||
{USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, opera1_table);
|
||||
|
||||
static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
|
||||
{
|
||||
u8 command[] = { READ_MAC_ADDR };
|
||||
opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG);
|
||||
opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG);
|
||||
return 0;
|
||||
}
|
||||
static int opera1_xilinx_load_firmware(struct usb_device *dev,
|
||||
const char *filename)
|
||||
{
|
||||
const struct firmware *fw = NULL;
|
||||
u8 *b, *p;
|
||||
int ret = 0, i;
|
||||
u8 testval;
|
||||
info("start downloading fpga firmware");
|
||||
|
||||
if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
|
||||
err("did not find the firmware file. (%s) "
|
||||
"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
|
||||
filename);
|
||||
return ret;
|
||||
} else {
|
||||
p = kmalloc(fw->size, GFP_KERNEL);
|
||||
opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG);
|
||||
if (p != NULL && testval != 0x67) {
|
||||
|
||||
u8 reset = 0, fpga_command = 0;
|
||||
memcpy(p, fw->data, fw->size);
|
||||
/* clear fpga ? */
|
||||
opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
|
||||
OPERA_WRITE_MSG);
|
||||
for (i = 0; p[i] != 0 && i < fw->size;) {
|
||||
b = (u8 *) p + i;
|
||||
if (opera1_xilinx_rw
|
||||
(dev, OPERA_WRITE_FX2, 0x0, b + 1, b[0],
|
||||
OPERA_WRITE_MSG) != b[0]
|
||||
) {
|
||||
err("error while transferring firmware");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
i = i + 1 + b[0];
|
||||
}
|
||||
/* restart the CPU */
|
||||
if (ret || opera1_xilinx_rw
|
||||
(dev, 0xa0, 0xe600, &reset, 1,
|
||||
OPERA_WRITE_MSG) != 1) {
|
||||
err("could not restart the USB controller CPU.");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
kfree(p);
|
||||
}
|
||||
}
|
||||
if (fw) {
|
||||
release_firmware(fw);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_properties opera1_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-opera-01.fw",
|
||||
.size_of_priv = sizeof(struct opera1_state),
|
||||
|
||||
.power_ctrl = opera1_power_ctrl,
|
||||
.i2c_algo = &opera1_i2c_algo,
|
||||
|
||||
.rc_key_map = opera1_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(opera1_rc_keys),
|
||||
.rc_interval = 200,
|
||||
.rc_query = opera1_rc_query,
|
||||
.read_mac_address = opera1_read_mac_address,
|
||||
.generic_bulk_ctrl_endpoint = 0x00,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = opera1_frontend_attach,
|
||||
.streaming_ctrl = opera1_streaming_ctrl,
|
||||
.tuner_attach = opera1_tuner_attach,
|
||||
.caps =
|
||||
DVB_USB_ADAP_HAS_PID_FILTER |
|
||||
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter = opera1_pid_filter,
|
||||
.pid_filter_ctrl = opera1_pid_filter_control,
|
||||
.pid_filter_count = 252,
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 10,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{"Opera1 DVB-S USB2.0",
|
||||
{&opera1_table[0], NULL},
|
||||
{&opera1_table[1], NULL},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static int opera1_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
|
||||
udev->descriptor.idVendor == USB_VID_OPERA1 &&
|
||||
(d == NULL
|
||||
|| opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga.fw") != 0)
|
||||
) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, &d) != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_driver opera1_driver = {
|
||||
.name = "opera1",
|
||||
.probe = opera1_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = opera1_table,
|
||||
};
|
||||
|
||||
static int __init opera1_module_init(void)
|
||||
{
|
||||
int result = 0;
|
||||
if ((result = usb_register(&opera1_driver))) {
|
||||
err("usb_register failed. Error number %d", result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void __exit opera1_module_exit(void)
|
||||
{
|
||||
usb_deregister(&opera1_driver);
|
||||
}
|
||||
|
||||
module_init(opera1_module_init);
|
||||
module_exit(opera1_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org");
|
||||
MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de");
|
||||
MODULE_DESCRIPTION("Driver for Opera1 DVB-S device");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
9
drivers/media/dvb/dvb-usb/opera1.h
Normal file
9
drivers/media/dvb/dvb-usb/opera1.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef _OPERA1_H_
|
||||
#define _OPERA1_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "opera"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_opera1_debug;
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args)
|
||||
#endif
|
|
@ -184,6 +184,7 @@ static int ttusb2_probe(struct usb_interface *intf,
|
|||
|
||||
static struct usb_device_id ttusb2_table [] = {
|
||||
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
|
||||
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, ttusb2_table);
|
||||
|
@ -227,12 +228,16 @@ static struct dvb_usb_device_properties ttusb2_properties = {
|
|||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.num_device_descs = 2,
|
||||
.devices = {
|
||||
{ "Pinnacle 400e DVB-S USB2.0",
|
||||
{ &ttusb2_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Pinnacle 450e DVB-S USB2.0",
|
||||
{ &ttusb2_table[1], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -205,6 +205,13 @@ config DVB_TDA10021
|
|||
help
|
||||
A DVB-C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA10023
|
||||
tristate "Philips TDA10023 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A DVB-C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STV0297
|
||||
tristate "ST STV0297 based"
|
||||
depends on DVB_CORE && I2C
|
||||
|
@ -280,8 +287,12 @@ comment "Tuners/PLL support"
|
|||
depends on DVB_CORE
|
||||
|
||||
config DVB_PLL
|
||||
tristate
|
||||
tristate "Generic I2C PLL based tuners"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
This module driver a number of tuners based on PLL chips with a
|
||||
common I2C interface. Say Y when you want to support these tuners.
|
||||
|
||||
config DVB_TDA826X
|
||||
tristate "Philips TDA826X silicon tuner"
|
||||
|
@ -290,6 +301,13 @@ config DVB_TDA826X
|
|||
help
|
||||
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_TDA827X
|
||||
tristate "Philips TDA827X silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A DVB-T silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_TUNER_QT1010
|
||||
tristate "Quantek QT1010 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
|
@ -304,14 +322,6 @@ config DVB_TUNER_MT2060
|
|||
help
|
||||
A driver for the silicon IF tuner MT2060 from Microtune.
|
||||
|
||||
config DVB_TUNER_LGH06XF
|
||||
tristate "LG TDVS-H06xF ATSC tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
select DVB_PLL
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A driver for the LG TDVS-H06xF ATSC tuner family.
|
||||
|
||||
comment "Miscellaneous devices"
|
||||
depends on DVB_CORE
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ obj-$(CONFIG_DVB_MT352) += mt352.o
|
|||
obj-$(CONFIG_DVB_ZL10353) += zl10353.o
|
||||
obj-$(CONFIG_DVB_CX22702) += cx22702.o
|
||||
obj-$(CONFIG_DVB_TDA10021) += tda10021.o
|
||||
obj-$(CONFIG_DVB_TDA10023) += tda10023.o
|
||||
obj-$(CONFIG_DVB_STV0297) += stv0297.o
|
||||
obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
|
||||
obj-$(CONFIG_DVB_OR51211) += or51211.o
|
||||
|
@ -37,7 +38,7 @@ obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
|
|||
obj-$(CONFIG_DVB_ISL6421) += isl6421.o
|
||||
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
|
||||
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
|
||||
obj-$(CONFIG_DVB_TDA827X) += tda827x.o
|
||||
obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
|
||||
obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
|
||||
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
|
||||
obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o
|
||||
|
|
|
@ -27,17 +27,29 @@
|
|||
/* ----------------------------------------------------------- */
|
||||
/* descriptions */
|
||||
|
||||
/* Set AGC TOP value to 103 dBuV:
|
||||
0x80 = Control Byte
|
||||
0x40 = 250 uA charge pump (irrelevant)
|
||||
0x18 = Aux Byte to follow
|
||||
0x06 = 64.5 kHz divider (irrelevant)
|
||||
0x01 = Disable Vt (aka sleep)
|
||||
|
||||
0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA)
|
||||
0x50 = AGC Take over point = 103 dBuV */
|
||||
static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
|
||||
|
||||
struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
|
||||
.name = "Thomson dtt7579",
|
||||
.min = 177000000,
|
||||
.max = 858000000,
|
||||
.count = 5,
|
||||
.iffreq= 36166667,
|
||||
.sleepdata = (u8[]){ 2, 0xb4, 0x03 },
|
||||
.count = 4,
|
||||
.entries = {
|
||||
{ 0, 36166667, 166666, 0xb4, 0x03 }, /* go sleep */
|
||||
{ 443250000, 36166667, 166666, 0xb4, 0x02 },
|
||||
{ 542000000, 36166667, 166666, 0xb4, 0x08 },
|
||||
{ 771000000, 36166667, 166666, 0xbc, 0x08 },
|
||||
{ 999999999, 36166667, 166666, 0xf4, 0x08 },
|
||||
{ 443250000, 166667, 0xb4, 0x02 },
|
||||
{ 542000000, 166667, 0xb4, 0x08 },
|
||||
{ 771000000, 166667, 0xbc, 0x08 },
|
||||
{ 999999999, 166667, 0xf4, 0x08 },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_thomson_dtt7579);
|
||||
|
@ -46,11 +58,12 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
|
|||
.name = "Thomson dtt7610",
|
||||
.min = 44000000,
|
||||
.max = 958000000,
|
||||
.iffreq= 44000000,
|
||||
.count = 3,
|
||||
.entries = {
|
||||
{ 157250000, 44000000, 62500, 0x8e, 0x39 },
|
||||
{ 454000000, 44000000, 62500, 0x8e, 0x3a },
|
||||
{ 999999999, 44000000, 62500, 0x8e, 0x3c },
|
||||
{ 157250000, 62500, 0x8e, 0x39 },
|
||||
{ 454000000, 62500, 0x8e, 0x3a },
|
||||
{ 999999999, 62500, 0x8e, 0x3c },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
|
||||
|
@ -66,14 +79,15 @@ struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
|
|||
.min = 177000000,
|
||||
.max = 896000000,
|
||||
.setbw = thomson_dtt759x_bw,
|
||||
.count = 6,
|
||||
.iffreq= 36166667,
|
||||
.sleepdata = (u8[]){ 2, 0x84, 0x03 },
|
||||
.count = 5,
|
||||
.entries = {
|
||||
{ 0, 36166667, 166666, 0x84, 0x03 },
|
||||
{ 264000000, 36166667, 166666, 0xb4, 0x02 },
|
||||
{ 470000000, 36166667, 166666, 0xbc, 0x02 },
|
||||
{ 735000000, 36166667, 166666, 0xbc, 0x08 },
|
||||
{ 835000000, 36166667, 166666, 0xf4, 0x08 },
|
||||
{ 999999999, 36166667, 166666, 0xfc, 0x08 },
|
||||
{ 264000000, 166667, 0xb4, 0x02 },
|
||||
{ 470000000, 166667, 0xbc, 0x02 },
|
||||
{ 735000000, 166667, 0xbc, 0x08 },
|
||||
{ 835000000, 166667, 0xf4, 0x08 },
|
||||
{ 999999999, 166667, 0xfc, 0x08 },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_thomson_dtt759x);
|
||||
|
@ -82,14 +96,15 @@ struct dvb_pll_desc dvb_pll_lg_z201 = {
|
|||
.name = "LG z201",
|
||||
.min = 174000000,
|
||||
.max = 862000000,
|
||||
.count = 6,
|
||||
.iffreq= 36166667,
|
||||
.sleepdata = (u8[]){ 2, 0xbc, 0x03 },
|
||||
.count = 5,
|
||||
.entries = {
|
||||
{ 0, 36166667, 166666, 0xbc, 0x03 },
|
||||
{ 157500000, 36166667, 166666, 0xbc, 0x01 },
|
||||
{ 443250000, 36166667, 166666, 0xbc, 0x02 },
|
||||
{ 542000000, 36166667, 166666, 0xbc, 0x04 },
|
||||
{ 830000000, 36166667, 166666, 0xf4, 0x04 },
|
||||
{ 999999999, 36166667, 166666, 0xfc, 0x04 },
|
||||
{ 157500000, 166667, 0xbc, 0x01 },
|
||||
{ 443250000, 166667, 0xbc, 0x02 },
|
||||
{ 542000000, 166667, 0xbc, 0x04 },
|
||||
{ 830000000, 166667, 0xf4, 0x04 },
|
||||
{ 999999999, 166667, 0xfc, 0x04 },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_lg_z201);
|
||||
|
@ -98,11 +113,12 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = {
|
|||
.name = "Microtune 4042 FI5",
|
||||
.min = 57000000,
|
||||
.max = 858000000,
|
||||
.iffreq= 44000000,
|
||||
.count = 3,
|
||||
.entries = {
|
||||
{ 162000000, 44000000, 62500, 0x8e, 0xa1 },
|
||||
{ 457000000, 44000000, 62500, 0x8e, 0x91 },
|
||||
{ 999999999, 44000000, 62500, 0x8e, 0x31 },
|
||||
{ 162000000, 62500, 0x8e, 0xa1 },
|
||||
{ 457000000, 62500, 0x8e, 0x91 },
|
||||
{ 999999999, 62500, 0x8e, 0x31 },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_microtune_4042);
|
||||
|
@ -112,11 +128,13 @@ struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
|
|||
.name = "Thomson dtt761x",
|
||||
.min = 57000000,
|
||||
.max = 863000000,
|
||||
.iffreq= 44000000,
|
||||
.count = 3,
|
||||
.initdata = tua603x_agc103,
|
||||
.entries = {
|
||||
{ 147000000, 44000000, 62500, 0x8e, 0x39 },
|
||||
{ 417000000, 44000000, 62500, 0x8e, 0x3a },
|
||||
{ 999999999, 44000000, 62500, 0x8e, 0x3c },
|
||||
{ 147000000, 62500, 0x8e, 0x39 },
|
||||
{ 417000000, 62500, 0x8e, 0x3a },
|
||||
{ 999999999, 62500, 0x8e, 0x3c },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
|
||||
|
@ -125,17 +143,18 @@ struct dvb_pll_desc dvb_pll_unknown_1 = {
|
|||
.name = "unknown 1", /* used by dntv live dvb-t */
|
||||
.min = 174000000,
|
||||
.max = 862000000,
|
||||
.iffreq= 36166667,
|
||||
.count = 9,
|
||||
.entries = {
|
||||
{ 150000000, 36166667, 166666, 0xb4, 0x01 },
|
||||
{ 173000000, 36166667, 166666, 0xbc, 0x01 },
|
||||
{ 250000000, 36166667, 166666, 0xb4, 0x02 },
|
||||
{ 400000000, 36166667, 166666, 0xbc, 0x02 },
|
||||
{ 420000000, 36166667, 166666, 0xf4, 0x02 },
|
||||
{ 470000000, 36166667, 166666, 0xfc, 0x02 },
|
||||
{ 600000000, 36166667, 166666, 0xbc, 0x08 },
|
||||
{ 730000000, 36166667, 166666, 0xf4, 0x08 },
|
||||
{ 999999999, 36166667, 166666, 0xfc, 0x08 },
|
||||
{ 150000000, 166667, 0xb4, 0x01 },
|
||||
{ 173000000, 166667, 0xbc, 0x01 },
|
||||
{ 250000000, 166667, 0xb4, 0x02 },
|
||||
{ 400000000, 166667, 0xbc, 0x02 },
|
||||
{ 420000000, 166667, 0xf4, 0x02 },
|
||||
{ 470000000, 166667, 0xfc, 0x02 },
|
||||
{ 600000000, 166667, 0xbc, 0x08 },
|
||||
{ 730000000, 166667, 0xf4, 0x08 },
|
||||
{ 999999999, 166667, 0xfc, 0x08 },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_unknown_1);
|
||||
|
@ -147,11 +166,12 @@ struct dvb_pll_desc dvb_pll_tua6010xs = {
|
|||
.name = "Infineon TUA6010XS",
|
||||
.min = 44250000,
|
||||
.max = 858000000,
|
||||
.iffreq= 36125000,
|
||||
.count = 3,
|
||||
.entries = {
|
||||
{ 115750000, 36125000, 62500, 0x8e, 0x03 },
|
||||
{ 403250000, 36125000, 62500, 0x8e, 0x06 },
|
||||
{ 999999999, 36125000, 62500, 0x8e, 0x85 },
|
||||
{ 115750000, 62500, 0x8e, 0x03 },
|
||||
{ 403250000, 62500, 0x8e, 0x06 },
|
||||
{ 999999999, 62500, 0x8e, 0x85 },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_tua6010xs);
|
||||
|
@ -161,12 +181,13 @@ struct dvb_pll_desc dvb_pll_env57h1xd5 = {
|
|||
.name = "Panasonic ENV57H1XD5",
|
||||
.min = 44250000,
|
||||
.max = 858000000,
|
||||
.iffreq= 36125000,
|
||||
.count = 4,
|
||||
.entries = {
|
||||
{ 153000000, 36291666, 166666, 0xc2, 0x41 },
|
||||
{ 470000000, 36291666, 166666, 0xc2, 0x42 },
|
||||
{ 526000000, 36291666, 166666, 0xc2, 0x84 },
|
||||
{ 999999999, 36291666, 166666, 0xc2, 0xa4 },
|
||||
{ 153000000, 166667, 0xc2, 0x41 },
|
||||
{ 470000000, 166667, 0xc2, 0x42 },
|
||||
{ 526000000, 166667, 0xc2, 0x84 },
|
||||
{ 999999999, 166667, 0xc2, 0xa4 },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_env57h1xd5);
|
||||
|
@ -185,20 +206,21 @@ struct dvb_pll_desc dvb_pll_tda665x = {
|
|||
.min = 44250000,
|
||||
.max = 858000000,
|
||||
.setbw = tda665x_bw,
|
||||
.iffreq= 36166667,
|
||||
.count = 12,
|
||||
.entries = {
|
||||
{ 93834000, 36249333, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ },
|
||||
{ 123834000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
|
||||
{ 161000000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
|
||||
{ 163834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
|
||||
{ 253834000, 36249333, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ },
|
||||
{ 383834000, 36249333, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ },
|
||||
{ 443834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
|
||||
{ 444000000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
|
||||
{ 583834000, 36249333, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ },
|
||||
{ 793834000, 36249333, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ },
|
||||
{ 444834000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
|
||||
{ 861000000, 36249333, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ },
|
||||
{ 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ },
|
||||
{ 123834000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
|
||||
{ 161000000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
|
||||
{ 163834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
|
||||
{ 253834000, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ },
|
||||
{ 383834000, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ },
|
||||
{ 443834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
|
||||
{ 444000000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
|
||||
{ 583834000, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ },
|
||||
{ 793834000, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ },
|
||||
{ 444834000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
|
||||
{ 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ },
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_tda665x);
|
||||
|
@ -216,12 +238,13 @@ struct dvb_pll_desc dvb_pll_tua6034 = {
|
|||
.name = "Infineon TUA6034",
|
||||
.min = 44250000,
|
||||
.max = 858000000,
|
||||
.iffreq= 36166667,
|
||||
.count = 3,
|
||||
.setbw = tua6034_bw,
|
||||
.entries = {
|
||||
{ 174500000, 36166667, 62500, 0xce, 0x01 },
|
||||
{ 230000000, 36166667, 62500, 0xce, 0x02 },
|
||||
{ 999999999, 36166667, 62500, 0xce, 0x04 },
|
||||
{ 174500000, 62500, 0xce, 0x01 },
|
||||
{ 230000000, 62500, 0xce, 0x02 },
|
||||
{ 999999999, 62500, 0xce, 0x04 },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_tua6034);
|
||||
|
@ -233,11 +256,13 @@ struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
|
|||
.name = "LG TDVS-H06xF",
|
||||
.min = 54000000,
|
||||
.max = 863000000,
|
||||
.iffreq= 44000000,
|
||||
.initdata = tua603x_agc103,
|
||||
.count = 3,
|
||||
.entries = {
|
||||
{ 165000000, 44000000, 62500, 0xce, 0x01 },
|
||||
{ 450000000, 44000000, 62500, 0xce, 0x02 },
|
||||
{ 999999999, 44000000, 62500, 0xce, 0x04 },
|
||||
{ 165000000, 62500, 0xce, 0x01 },
|
||||
{ 450000000, 62500, 0xce, 0x02 },
|
||||
{ 999999999, 62500, 0xce, 0x04 },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
|
||||
|
@ -255,16 +280,17 @@ struct dvb_pll_desc dvb_pll_fmd1216me = {
|
|||
.name = "Philips FMD1216ME",
|
||||
.min = 50870000,
|
||||
.max = 858000000,
|
||||
.iffreq= 36125000,
|
||||
.setbw = fmd1216me_bw,
|
||||
.count = 7,
|
||||
.entries = {
|
||||
{ 143870000, 36213333, 166667, 0xbc, 0x41 },
|
||||
{ 158870000, 36213333, 166667, 0xf4, 0x41 },
|
||||
{ 329870000, 36213333, 166667, 0xbc, 0x42 },
|
||||
{ 441870000, 36213333, 166667, 0xf4, 0x42 },
|
||||
{ 625870000, 36213333, 166667, 0xbc, 0x44 },
|
||||
{ 803870000, 36213333, 166667, 0xf4, 0x44 },
|
||||
{ 999999999, 36213333, 166667, 0xfc, 0x44 },
|
||||
{ 143870000, 166667, 0xbc, 0x41 },
|
||||
{ 158870000, 166667, 0xf4, 0x41 },
|
||||
{ 329870000, 166667, 0xbc, 0x42 },
|
||||
{ 441870000, 166667, 0xf4, 0x42 },
|
||||
{ 625870000, 166667, 0xbc, 0x44 },
|
||||
{ 803870000, 166667, 0xf4, 0x44 },
|
||||
{ 999999999, 166667, 0xfc, 0x44 },
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_fmd1216me);
|
||||
|
@ -282,13 +308,14 @@ struct dvb_pll_desc dvb_pll_tded4 = {
|
|||
.name = "ALPS TDED4",
|
||||
.min = 47000000,
|
||||
.max = 863000000,
|
||||
.iffreq= 36166667,
|
||||
.setbw = tded4_bw,
|
||||
.count = 4,
|
||||
.entries = {
|
||||
{ 153000000, 36166667, 166667, 0x85, 0x01 },
|
||||
{ 470000000, 36166667, 166667, 0x85, 0x02 },
|
||||
{ 823000000, 36166667, 166667, 0x85, 0x08 },
|
||||
{ 999999999, 36166667, 166667, 0x85, 0x88 },
|
||||
{ 153000000, 166667, 0x85, 0x01 },
|
||||
{ 470000000, 166667, 0x85, 0x02 },
|
||||
{ 823000000, 166667, 0x85, 0x08 },
|
||||
{ 999999999, 166667, 0x85, 0x88 },
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_tded4);
|
||||
|
@ -300,12 +327,13 @@ struct dvb_pll_desc dvb_pll_tdhu2 = {
|
|||
.name = "ALPS TDHU2",
|
||||
.min = 54000000,
|
||||
.max = 864000000,
|
||||
.iffreq= 44000000,
|
||||
.count = 4,
|
||||
.entries = {
|
||||
{ 162000000, 44000000, 62500, 0x85, 0x01 },
|
||||
{ 426000000, 44000000, 62500, 0x85, 0x02 },
|
||||
{ 782000000, 44000000, 62500, 0x85, 0x08 },
|
||||
{ 999999999, 44000000, 62500, 0x85, 0x88 },
|
||||
{ 162000000, 62500, 0x85, 0x01 },
|
||||
{ 426000000, 62500, 0x85, 0x02 },
|
||||
{ 782000000, 62500, 0x85, 0x08 },
|
||||
{ 999999999, 62500, 0x85, 0x88 },
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_tdhu2);
|
||||
|
@ -317,11 +345,12 @@ struct dvb_pll_desc dvb_pll_tuv1236d = {
|
|||
.name = "Philips TUV1236D",
|
||||
.min = 54000000,
|
||||
.max = 864000000,
|
||||
.iffreq= 44000000,
|
||||
.count = 3,
|
||||
.entries = {
|
||||
{ 157250000, 44000000, 62500, 0xc6, 0x41 },
|
||||
{ 454000000, 44000000, 62500, 0xc6, 0x42 },
|
||||
{ 999999999, 44000000, 62500, 0xc6, 0x44 },
|
||||
{ 157250000, 62500, 0xc6, 0x41 },
|
||||
{ 454000000, 62500, 0xc6, 0x42 },
|
||||
{ 999999999, 62500, 0xc6, 0x44 },
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_tuv1236d);
|
||||
|
@ -333,14 +362,15 @@ struct dvb_pll_desc dvb_pll_samsung_tbmv = {
|
|||
.name = "Samsung TBMV30111IN / TBMV30712IN1",
|
||||
.min = 54000000,
|
||||
.max = 860000000,
|
||||
.iffreq= 44000000,
|
||||
.count = 6,
|
||||
.entries = {
|
||||
{ 172000000, 44000000, 166666, 0xb4, 0x01 },
|
||||
{ 214000000, 44000000, 166666, 0xb4, 0x02 },
|
||||
{ 467000000, 44000000, 166666, 0xbc, 0x02 },
|
||||
{ 721000000, 44000000, 166666, 0xbc, 0x08 },
|
||||
{ 841000000, 44000000, 166666, 0xf4, 0x08 },
|
||||
{ 999999999, 44000000, 166666, 0xfc, 0x02 },
|
||||
{ 172000000, 166667, 0xb4, 0x01 },
|
||||
{ 214000000, 166667, 0xb4, 0x02 },
|
||||
{ 467000000, 166667, 0xbc, 0x02 },
|
||||
{ 721000000, 166667, 0xbc, 0x08 },
|
||||
{ 841000000, 166667, 0xf4, 0x08 },
|
||||
{ 999999999, 166667, 0xfc, 0x02 },
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_samsung_tbmv);
|
||||
|
@ -352,12 +382,13 @@ struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
|
|||
.name = "Philips SD1878",
|
||||
.min = 950000,
|
||||
.max = 2150000,
|
||||
.iffreq= 249, /* zero-IF, offset 249 is to round up */
|
||||
.count = 4,
|
||||
.entries = {
|
||||
{ 1250000, 499, 500, 0xc4, 0x00},
|
||||
{ 1550000, 499, 500, 0xc4, 0x40},
|
||||
{ 2050000, 499, 500, 0xc4, 0x80},
|
||||
{ 2150000, 499, 500, 0xc4, 0xc0},
|
||||
{ 1250000, 500, 0xc4, 0x00},
|
||||
{ 1550000, 500, 0xc4, 0x40},
|
||||
{ 2050000, 500, 0xc4, 0x80},
|
||||
{ 2150000, 500, 0xc4, 0xc0},
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261);
|
||||
|
@ -388,18 +419,19 @@ struct dvb_pll_desc dvb_pll_philips_td1316 = {
|
|||
.name = "Philips TD1316",
|
||||
.min = 87000000,
|
||||
.max = 895000000,
|
||||
.iffreq= 36166667,
|
||||
.setbw = td1316_bw,
|
||||
.count = 9,
|
||||
.entries = {
|
||||
{ 93834000, 36166000, 166666, 0xca, 0x60},
|
||||
{ 123834000, 36166000, 166666, 0xca, 0xa0},
|
||||
{ 163834000, 36166000, 166666, 0xca, 0xc0},
|
||||
{ 253834000, 36166000, 166666, 0xca, 0x60},
|
||||
{ 383834000, 36166000, 166666, 0xca, 0xa0},
|
||||
{ 443834000, 36166000, 166666, 0xca, 0xc0},
|
||||
{ 583834000, 36166000, 166666, 0xca, 0x60},
|
||||
{ 793834000, 36166000, 166666, 0xca, 0xa0},
|
||||
{ 858834000, 36166000, 166666, 0xca, 0xe0},
|
||||
{ 93834000, 166667, 0xca, 0x60},
|
||||
{ 123834000, 166667, 0xca, 0xa0},
|
||||
{ 163834000, 166667, 0xca, 0xc0},
|
||||
{ 253834000, 166667, 0xca, 0x60},
|
||||
{ 383834000, 166667, 0xca, 0xa0},
|
||||
{ 443834000, 166667, 0xca, 0xc0},
|
||||
{ 583834000, 166667, 0xca, 0x60},
|
||||
{ 793834000, 166667, 0xca, 0xa0},
|
||||
{ 858834000, 166667, 0xca, 0xe0},
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_philips_td1316);
|
||||
|
@ -409,15 +441,41 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
|
|||
.name = "Thomson FE6600",
|
||||
.min = 44250000,
|
||||
.max = 858000000,
|
||||
.iffreq= 36125000,
|
||||
.count = 4,
|
||||
.entries = {
|
||||
{ 250000000, 36213333, 166667, 0xb4, 0x12 },
|
||||
{ 455000000, 36213333, 166667, 0xfe, 0x11 },
|
||||
{ 775500000, 36213333, 166667, 0xbc, 0x18 },
|
||||
{ 999999999, 36213333, 166667, 0xf4, 0x18 },
|
||||
{ 250000000, 166667, 0xb4, 0x12 },
|
||||
{ 455000000, 166667, 0xfe, 0x11 },
|
||||
{ 775500000, 166667, 0xbc, 0x18 },
|
||||
{ 999999999, 166667, 0xf4, 0x18 },
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
|
||||
static void opera1_bw(u8 *buf, u32 freq, int bandwidth)
|
||||
{
|
||||
if (bandwidth == BANDWIDTH_8_MHZ)
|
||||
buf[2] |= 0x08;
|
||||
}
|
||||
|
||||
struct dvb_pll_desc dvb_pll_opera1 = {
|
||||
.name = "Opera Tuner",
|
||||
.min = 900000,
|
||||
.max = 2250000,
|
||||
.iffreq= 0,
|
||||
.setbw = opera1_bw,
|
||||
.count = 8,
|
||||
.entries = {
|
||||
{ 1064000, 500, 0xe5, 0xc6 },
|
||||
{ 1169000, 500, 0xe5, 0xe6 },
|
||||
{ 1299000, 500, 0xe5, 0x24 },
|
||||
{ 1444000, 500, 0xe5, 0x44 },
|
||||
{ 1606000, 500, 0xe5, 0x64 },
|
||||
{ 1777000, 500, 0xe5, 0x84 },
|
||||
{ 1941000, 500, 0xe5, 0xa4 },
|
||||
{ 2250000, 500, 0xe5, 0xc4 },
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL(dvb_pll_opera1);
|
||||
|
||||
struct dvb_pll_priv {
|
||||
/* i2c details */
|
||||
|
@ -459,7 +517,8 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
|
|||
if (i == desc->count)
|
||||
return -EINVAL;
|
||||
|
||||
div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
|
||||
div = (freq + desc->iffreq + desc->entries[i].stepsize/2) /
|
||||
desc->entries[i].stepsize;
|
||||
buf[0] = div >> 8;
|
||||
buf[1] = div & 0xff;
|
||||
buf[2] = desc->entries[i].config;
|
||||
|
@ -473,7 +532,7 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
|
|||
desc->name, div, buf[0], buf[1], buf[2], buf[3]);
|
||||
|
||||
// calculate the frequency we set it to
|
||||
return (div * desc->entries[i].stepsize) - desc->entries[i].offset;
|
||||
return (div * desc->entries[i].stepsize) - desc->iffreq;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_pll_configure);
|
||||
|
||||
|
@ -487,35 +546,27 @@ static int dvb_pll_release(struct dvb_frontend *fe)
|
|||
static int dvb_pll_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dvb_pll_priv *priv = fe->tuner_priv;
|
||||
u8 buf[4];
|
||||
struct i2c_msg msg =
|
||||
{ .addr = priv->pll_i2c_address, .flags = 0,
|
||||
.buf = buf, .len = sizeof(buf) };
|
||||
int i;
|
||||
int result;
|
||||
|
||||
if (priv->i2c == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < priv->pll_desc->count; i++) {
|
||||
if (priv->pll_desc->entries[i].limit == 0)
|
||||
break;
|
||||
}
|
||||
if (i == priv->pll_desc->count)
|
||||
if (priv->pll_desc->sleepdata) {
|
||||
struct i2c_msg msg = { .flags = 0,
|
||||
.addr = priv->pll_i2c_address,
|
||||
.buf = priv->pll_desc->sleepdata + 1,
|
||||
.len = priv->pll_desc->sleepdata[0] };
|
||||
|
||||
int result;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
|
||||
buf[0] = 0;
|
||||
buf[1] = 0;
|
||||
buf[2] = priv->pll_desc->entries[i].config;
|
||||
buf[3] = priv->pll_desc->entries[i].cb;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* Shouldn't be called when initdata is NULL, maybe BUG()? */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dvb_pll_set_params(struct dvb_frontend *fe,
|
||||
|
@ -599,9 +650,35 @@ static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_pll_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dvb_pll_priv *priv = fe->tuner_priv;
|
||||
|
||||
if (priv->i2c == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (priv->pll_desc->initdata) {
|
||||
struct i2c_msg msg = { .flags = 0,
|
||||
.addr = priv->pll_i2c_address,
|
||||
.buf = priv->pll_desc->initdata + 1,
|
||||
.len = priv->pll_desc->initdata[0] };
|
||||
|
||||
int result;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* Shouldn't be called when initdata is NULL, maybe BUG()? */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct dvb_tuner_ops dvb_pll_tuner_ops = {
|
||||
.release = dvb_pll_release,
|
||||
.sleep = dvb_pll_sleep,
|
||||
.init = dvb_pll_init,
|
||||
.set_params = dvb_pll_set_params,
|
||||
.calc_regs = dvb_pll_calc_regs,
|
||||
.get_frequency = dvb_pll_get_frequency,
|
||||
|
@ -640,9 +717,14 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
|
|||
memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
|
||||
strncpy(fe->ops.tuner_ops.info.name, desc->name, 128);
|
||||
strncpy(fe->ops.tuner_ops.info.name, desc->name,
|
||||
sizeof(fe->ops.tuner_ops.info.name));
|
||||
fe->ops.tuner_ops.info.frequency_min = desc->min;
|
||||
fe->ops.tuner_ops.info.frequency_min = desc->max;
|
||||
if (!desc->initdata)
|
||||
fe->ops.tuner_ops.init = NULL;
|
||||
if (!desc->sleepdata)
|
||||
fe->ops.tuner_ops.sleep = NULL;
|
||||
|
||||
fe->tuner_priv = priv;
|
||||
return fe;
|
||||
|
|
|
@ -12,11 +12,13 @@ struct dvb_pll_desc {
|
|||
char *name;
|
||||
u32 min;
|
||||
u32 max;
|
||||
u32 iffreq;
|
||||
void (*setbw)(u8 *buf, u32 freq, int bandwidth);
|
||||
u8 *initdata;
|
||||
u8 *sleepdata;
|
||||
int count;
|
||||
struct {
|
||||
u32 limit;
|
||||
u32 offset;
|
||||
u32 stepsize;
|
||||
u8 config;
|
||||
u8 cb;
|
||||
|
@ -46,6 +48,7 @@ extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261;
|
|||
extern struct dvb_pll_desc dvb_pll_philips_td1316;
|
||||
|
||||
extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
|
||||
extern struct dvb_pll_desc dvb_pll_opera1;
|
||||
|
||||
extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
|
||||
u32 freq, int bandwidth);
|
||||
|
@ -59,9 +62,20 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
|
|||
* @param desc dvb_pll_desc to use.
|
||||
* @return Frontend pointer on success, NULL on failure
|
||||
*/
|
||||
#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
|
||||
int pll_addr,
|
||||
struct i2c_adapter *i2c,
|
||||
struct dvb_pll_desc *desc);
|
||||
#else
|
||||
static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
|
||||
int pll_addr,
|
||||
struct i2c_adapter *i2c,
|
||||
struct dvb_pll_desc *desc)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -475,7 +475,7 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status)
|
|||
*status |= FE_HAS_CARRIER;
|
||||
break;
|
||||
default:
|
||||
printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
|
||||
printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -534,7 +534,7 @@ static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
|
||||
printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
* lgh06xf.c - ATSC Tuner support for LG TDVS-H06xF
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "dvb-pll.h"
|
||||
#include "lgh06xf.h"
|
||||
|
||||
#define LG_H06XF_PLL_I2C_ADDR 0x61
|
||||
|
||||
struct lgh06xf_priv {
|
||||
struct i2c_adapter *i2c;
|
||||
u32 frequency;
|
||||
};
|
||||
|
||||
static int lgh06xf_release(struct dvb_frontend *fe)
|
||||
{
|
||||
kfree(fe->tuner_priv);
|
||||
fe->tuner_priv = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgh06xf_set_params(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters* params)
|
||||
{
|
||||
struct lgh06xf_priv *priv = fe->tuner_priv;
|
||||
u8 buf[4];
|
||||
struct i2c_msg msg = { .addr = LG_H06XF_PLL_I2C_ADDR, .flags = 0,
|
||||
.buf = buf, .len = sizeof(buf) };
|
||||
u32 frequency;
|
||||
int result;
|
||||
|
||||
if ((result = dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf,
|
||||
params->frequency, 0)) < 0)
|
||||
return result;
|
||||
else
|
||||
frequency = result;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
|
||||
printk(KERN_WARNING "lgh06xf: %s error "
|
||||
"(addr %02x <- %02x, result = %i)\n",
|
||||
__FUNCTION__, buf[0], buf[1], result);
|
||||
if (result < 0)
|
||||
return result;
|
||||
else
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
/* Set the Auxiliary Byte. */
|
||||
buf[0] = buf[2];
|
||||
buf[0] &= ~0x20;
|
||||
buf[0] |= 0x18;
|
||||
buf[1] = 0x50;
|
||||
msg.len = 2;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
|
||||
printk(KERN_WARNING "lgh06xf: %s error "
|
||||
"(addr %02x <- %02x, result = %i)\n",
|
||||
__FUNCTION__, buf[0], buf[1], result);
|
||||
if (result < 0)
|
||||
return result;
|
||||
else
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
priv->frequency = frequency;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgh06xf_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
struct lgh06xf_priv *priv = fe->tuner_priv;
|
||||
*frequency = priv->frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_tuner_ops lgh06xf_tuner_ops = {
|
||||
.release = lgh06xf_release,
|
||||
.set_params = lgh06xf_set_params,
|
||||
.get_frequency = lgh06xf_get_frequency,
|
||||
};
|
||||
|
||||
struct dvb_frontend* lgh06xf_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct lgh06xf_priv *priv = NULL;
|
||||
|
||||
priv = kzalloc(sizeof(struct lgh06xf_priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return NULL;
|
||||
|
||||
priv->i2c = i2c;
|
||||
|
||||
memcpy(&fe->ops.tuner_ops, &lgh06xf_tuner_ops,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
|
||||
strlcpy(fe->ops.tuner_ops.info.name, dvb_pll_lg_tdvs_h06xf.name,
|
||||
sizeof(fe->ops.tuner_ops.info.name));
|
||||
|
||||
fe->ops.tuner_ops.info.frequency_min = dvb_pll_lg_tdvs_h06xf.min;
|
||||
fe->ops.tuner_ops.info.frequency_max = dvb_pll_lg_tdvs_h06xf.max;
|
||||
|
||||
fe->tuner_priv = priv;
|
||||
return fe;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(lgh06xf_attach);
|
||||
|
||||
MODULE_DESCRIPTION("LG TDVS-H06xF ATSC Tuner support");
|
||||
MODULE_AUTHOR("Michael Krufky");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* lgh06xf.h - ATSC Tuner support for LG TDVS-H06xF
|
||||
*
|
||||
* 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 _LGH06XF_H_
|
||||
#define _LGH06XF_H_
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#if defined(CONFIG_DVB_TUNER_LGH06XF) || (defined(CONFIG_DVB_TUNER_LGH06XF_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_TUNER_LGH06XF */
|
||||
|
||||
#endif /* _LGH06XF_H_ */
|
|
@ -1,6 +1,9 @@
|
|||
/*
|
||||
* Support for OR51132 (pcHDTV HD-3000) - VSB/QAM
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2007 Trent Piepho <xyzzy@speakeasy.org>
|
||||
*
|
||||
* Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
|
||||
*
|
||||
* Based on code from Jack Kelliher (kelliher@xmission.com)
|
||||
|
@ -69,46 +72,70 @@ struct or51132_state
|
|||
u32 current_frequency;
|
||||
};
|
||||
|
||||
static int i2c_writebytes (struct or51132_state* state, u8 reg, u8 *buf, int len)
|
||||
|
||||
/* Write buffer to demod */
|
||||
static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len)
|
||||
{
|
||||
int err;
|
||||
struct i2c_msg msg;
|
||||
msg.addr = reg;
|
||||
msg.flags = 0;
|
||||
msg.len = len;
|
||||
msg.buf = buf;
|
||||
struct i2c_msg msg = { .addr = state->config->demod_address,
|
||||
.flags = 0, .buf = (u8*)buf, .len = len };
|
||||
|
||||
/* msleep(20); */ /* doesn't appear to be necessary */
|
||||
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
|
||||
printk(KERN_WARNING "or51132: i2c_writebytes error (addr %02x, err == %i)\n", reg, err);
|
||||
printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n",
|
||||
msg.addr, msg.len, err);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 i2c_readbytes (struct or51132_state* state, u8 reg, u8* buf, int len)
|
||||
/* Write constant bytes, e.g. or51132_writebytes(state, 0x04, 0x42, 0x00);
|
||||
Less code and more efficient that loading a buffer on the stack with
|
||||
the bytes to send and then calling or51132_writebuf() on that. */
|
||||
#define or51132_writebytes(state, data...) \
|
||||
({ const static u8 _data[] = {data}; \
|
||||
or51132_writebuf(state, _data, sizeof(_data)); })
|
||||
|
||||
/* Read data from demod into buffer. Returns 0 on success. */
|
||||
static int or51132_readbuf(struct or51132_state *state, u8 *buf, int len)
|
||||
{
|
||||
int err;
|
||||
struct i2c_msg msg;
|
||||
msg.addr = reg;
|
||||
msg.flags = I2C_M_RD;
|
||||
msg.len = len;
|
||||
msg.buf = buf;
|
||||
struct i2c_msg msg = { .addr = state->config->demod_address,
|
||||
.flags = I2C_M_RD, .buf = buf, .len = len };
|
||||
|
||||
/* msleep(20); */ /* doesn't appear to be necessary */
|
||||
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
|
||||
printk(KERN_WARNING "or51132: i2c_readbytes error (addr %02x, err == %i)\n", reg, err);
|
||||
printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n",
|
||||
msg.addr, msg.len, err);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reads a 16-bit demod register. Returns <0 on error. */
|
||||
static int or51132_readreg(struct or51132_state *state, u8 reg)
|
||||
{
|
||||
u8 buf[2] = { 0x04, reg };
|
||||
struct i2c_msg msg[2] = {
|
||||
{.addr = state->config->demod_address, .flags = 0,
|
||||
.buf = buf, .len = 2 },
|
||||
{.addr = state->config->demod_address, .flags = I2C_M_RD,
|
||||
.buf = buf, .len = 2 }};
|
||||
int err;
|
||||
|
||||
if ((err = i2c_transfer(state->i2c, msg, 2)) != 2) {
|
||||
printk(KERN_WARNING "or51132: I2C error reading register %d: %d\n",
|
||||
reg, err);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return le16_to_cpup((u16*)buf);
|
||||
}
|
||||
|
||||
static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
|
||||
{
|
||||
struct or51132_state* state = fe->demodulator_priv;
|
||||
static u8 run_buf[] = {0x7F,0x01};
|
||||
const static u8 run_buf[] = {0x7F,0x01};
|
||||
u8 rec_buf[8];
|
||||
u8 cmd_buf[3];
|
||||
u32 firmwareAsize, firmwareBsize;
|
||||
int i,ret;
|
||||
|
||||
|
@ -121,30 +148,21 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
|
|||
dprintk("FirmwareB is %i bytes\n",firmwareBsize);
|
||||
|
||||
/* Upload firmware */
|
||||
if ((ret = i2c_writebytes(state,state->config->demod_address,
|
||||
&fw->data[8],firmwareAsize))) {
|
||||
if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) {
|
||||
printk(KERN_WARNING "or51132: load_firmware error 1\n");
|
||||
return ret;
|
||||
}
|
||||
msleep(1); /* 1ms */
|
||||
if ((ret = i2c_writebytes(state,state->config->demod_address,
|
||||
&fw->data[8+firmwareAsize],firmwareBsize))) {
|
||||
if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize],
|
||||
firmwareBsize))) {
|
||||
printk(KERN_WARNING "or51132: load_firmware error 2\n");
|
||||
return ret;
|
||||
}
|
||||
msleep(1); /* 1ms */
|
||||
|
||||
if ((ret = i2c_writebytes(state,state->config->demod_address,
|
||||
run_buf,2))) {
|
||||
if ((ret = or51132_writebuf(state, run_buf, 2))) {
|
||||
printk(KERN_WARNING "or51132: load_firmware error 3\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait at least 5 msec */
|
||||
msleep(20); /* 10ms */
|
||||
|
||||
if ((ret = i2c_writebytes(state,state->config->demod_address,
|
||||
run_buf,2))) {
|
||||
if ((ret = or51132_writebuf(state, run_buf, 2))) {
|
||||
printk(KERN_WARNING "or51132: load_firmware error 4\n");
|
||||
return ret;
|
||||
}
|
||||
|
@ -154,43 +172,25 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
|
|||
|
||||
/* Read back ucode version to besure we loaded correctly and are really up and running */
|
||||
/* Get uCode version */
|
||||
cmd_buf[0] = 0x10;
|
||||
cmd_buf[1] = 0x10;
|
||||
cmd_buf[2] = 0x00;
|
||||
msleep(20); /* 20ms */
|
||||
if ((ret = i2c_writebytes(state,state->config->demod_address,
|
||||
cmd_buf,3))) {
|
||||
if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) {
|
||||
printk(KERN_WARNING "or51132: load_firmware error a\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cmd_buf[0] = 0x04;
|
||||
cmd_buf[1] = 0x17;
|
||||
msleep(20); /* 20ms */
|
||||
if ((ret = i2c_writebytes(state,state->config->demod_address,
|
||||
cmd_buf,2))) {
|
||||
if ((ret = or51132_writebytes(state, 0x04, 0x17))) {
|
||||
printk(KERN_WARNING "or51132: load_firmware error b\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cmd_buf[0] = 0x00;
|
||||
cmd_buf[1] = 0x00;
|
||||
msleep(20); /* 20ms */
|
||||
if ((ret = i2c_writebytes(state,state->config->demod_address,
|
||||
cmd_buf,2))) {
|
||||
if ((ret = or51132_writebytes(state, 0x00, 0x00))) {
|
||||
printk(KERN_WARNING "or51132: load_firmware error c\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for(i=0;i<4;i++) {
|
||||
msleep(20); /* 20ms */
|
||||
for (i=0;i<4;i++) {
|
||||
/* Once upon a time, this command might have had something
|
||||
to do with getting the firmware version, but it's
|
||||
not used anymore:
|
||||
{0x04,0x00,0x30,0x00,i+1} */
|
||||
/* Read 8 bytes, two bytes at a time */
|
||||
if ((ret = i2c_readbytes(state,state->config->demod_address,
|
||||
&rec_buf[i*2],2))) {
|
||||
if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) {
|
||||
printk(KERN_WARNING
|
||||
"or51132: load_firmware error d - %d\n",i);
|
||||
return ret;
|
||||
|
@ -204,12 +204,7 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
|
|||
rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f,
|
||||
rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f);
|
||||
|
||||
cmd_buf[0] = 0x10;
|
||||
cmd_buf[1] = 0x00;
|
||||
cmd_buf[2] = 0x00;
|
||||
msleep(20); /* 20ms */
|
||||
if ((ret = i2c_writebytes(state,state->config->demod_address,
|
||||
cmd_buf,3))) {
|
||||
if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) {
|
||||
printk(KERN_WARNING "or51132: load_firmware error e\n");
|
||||
return ret;
|
||||
}
|
||||
|
@ -241,70 +236,55 @@ static int or51132_sleep(struct dvb_frontend* fe)
|
|||
static int or51132_setmode(struct dvb_frontend* fe)
|
||||
{
|
||||
struct or51132_state* state = fe->demodulator_priv;
|
||||
unsigned char cmd_buf[3];
|
||||
u8 cmd_buf1[3] = {0x04, 0x01, 0x5f};
|
||||
u8 cmd_buf2[3] = {0x1c, 0x00, 0 };
|
||||
|
||||
dprintk("setmode %d\n",(int)state->current_modulation);
|
||||
/* set operation mode in Receiver 1 register; */
|
||||
cmd_buf[0] = 0x04;
|
||||
cmd_buf[1] = 0x01;
|
||||
|
||||
switch (state->current_modulation) {
|
||||
case QAM_256:
|
||||
case QAM_64:
|
||||
case QAM_AUTO:
|
||||
/* Auto-deinterleave; MPEG ser, MPEG2tr, phase noise-high*/
|
||||
cmd_buf[2] = 0x5F;
|
||||
break;
|
||||
case VSB_8:
|
||||
/* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high*/
|
||||
cmd_buf[2] = 0x50;
|
||||
/* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high */
|
||||
cmd_buf1[2] = 0x50;
|
||||
/* REC MODE inv IF spectrum, Normal */
|
||||
cmd_buf2[1] = 0x03;
|
||||
/* Channel MODE ATSC/VSB8 */
|
||||
cmd_buf2[2] = 0x06;
|
||||
break;
|
||||
/* All QAM modes are:
|
||||
Auto-deinterleave; MPEGser, MPEG2tr, phase noise-high
|
||||
REC MODE Normal Carrier Lock */
|
||||
case QAM_AUTO:
|
||||
/* Channel MODE Auto QAM64/256 */
|
||||
cmd_buf2[2] = 0x4f;
|
||||
break;
|
||||
case QAM_256:
|
||||
/* Channel MODE QAM256 */
|
||||
cmd_buf2[2] = 0x45;
|
||||
break;
|
||||
case QAM_64:
|
||||
/* Channel MODE QAM64 */
|
||||
cmd_buf2[2] = 0x43;
|
||||
break;
|
||||
default:
|
||||
printk("setmode:Modulation set to unsupported value\n");
|
||||
};
|
||||
if (i2c_writebytes(state,state->config->demod_address,
|
||||
cmd_buf,3)) {
|
||||
printk(KERN_WARNING "or51132: set_mode error 1\n");
|
||||
return -1;
|
||||
printk(KERN_WARNING
|
||||
"or51132: setmode: Modulation set to unsupported value (%d)\n",
|
||||
state->current_modulation);
|
||||
return -EINVAL;
|
||||
}
|
||||
dprintk("or51132: set #1 to %02x\n", cmd_buf[2]);
|
||||
|
||||
/* Set Receiver 1 register */
|
||||
if (or51132_writebuf(state, cmd_buf1, 3)) {
|
||||
printk(KERN_WARNING "or51132: set_mode error 1\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
dprintk("set #1 to %02x\n", cmd_buf1[2]);
|
||||
|
||||
/* Set operation mode in Receiver 6 register */
|
||||
cmd_buf[0] = 0x1C;
|
||||
switch (state->current_modulation) {
|
||||
case QAM_AUTO:
|
||||
/* REC MODE Normal Carrier Lock */
|
||||
cmd_buf[1] = 0x00;
|
||||
/* Channel MODE Auto QAM64/256 */
|
||||
cmd_buf[2] = 0x4f;
|
||||
break;
|
||||
case QAM_256:
|
||||
/* REC MODE Normal Carrier Lock */
|
||||
cmd_buf[1] = 0x00;
|
||||
/* Channel MODE QAM256 */
|
||||
cmd_buf[2] = 0x45;
|
||||
break;
|
||||
case QAM_64:
|
||||
/* REC MODE Normal Carrier Lock */
|
||||
cmd_buf[1] = 0x00;
|
||||
/* Channel MODE QAM64 */
|
||||
cmd_buf[2] = 0x43;
|
||||
break;
|
||||
case VSB_8:
|
||||
/* REC MODE inv IF spectrum, Normal */
|
||||
cmd_buf[1] = 0x03;
|
||||
/* Channel MODE ATSC/VSB8 */
|
||||
cmd_buf[2] = 0x06;
|
||||
break;
|
||||
default:
|
||||
printk("setmode: Modulation set to unsupported value\n");
|
||||
};
|
||||
msleep(20); /* 20ms */
|
||||
if (i2c_writebytes(state,state->config->demod_address,
|
||||
cmd_buf,3)) {
|
||||
if (or51132_writebuf(state, cmd_buf2, 3)) {
|
||||
printk(KERN_WARNING "or51132: set_mode error 2\n");
|
||||
return -1;
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
dprintk("or51132: set #6 to 0x%02x%02x\n", cmd_buf[1], cmd_buf[2]);
|
||||
dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -401,28 +381,23 @@ static int or51132_get_parameters(struct dvb_frontend* fe,
|
|||
struct dvb_frontend_parameters *param)
|
||||
{
|
||||
struct or51132_state* state = fe->demodulator_priv;
|
||||
u8 buf[2];
|
||||
int status;
|
||||
int retry = 1;
|
||||
|
||||
start:
|
||||
/* Receiver Status */
|
||||
buf[0]=0x04;
|
||||
buf[1]=0x00;
|
||||
msleep(30); /* 30ms */
|
||||
if (i2c_writebytes(state,state->config->demod_address,buf,2)) {
|
||||
printk(KERN_WARNING "or51132: get_parameters write error\n");
|
||||
if ((status = or51132_readreg(state, 0x00)) < 0) {
|
||||
printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
msleep(30); /* 30ms */
|
||||
if (i2c_readbytes(state,state->config->demod_address,buf,2)) {
|
||||
printk(KERN_WARNING "or51132: get_parameters read error\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
switch(buf[0]) {
|
||||
switch(status&0xff) {
|
||||
case 0x06: param->u.vsb.modulation = VSB_8; break;
|
||||
case 0x43: param->u.vsb.modulation = QAM_64; break;
|
||||
case 0x45: param->u.vsb.modulation = QAM_256; break;
|
||||
default:
|
||||
if (retry--) goto start;
|
||||
printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
|
||||
buf[0]);
|
||||
status&0xff);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
|
@ -438,32 +413,21 @@ static int or51132_get_parameters(struct dvb_frontend* fe,
|
|||
static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
|
||||
{
|
||||
struct or51132_state* state = fe->demodulator_priv;
|
||||
unsigned char rec_buf[2];
|
||||
unsigned char snd_buf[2];
|
||||
*status = 0;
|
||||
int reg;
|
||||
|
||||
/* Receiver Status */
|
||||
snd_buf[0]=0x04;
|
||||
snd_buf[1]=0x00;
|
||||
msleep(30); /* 30ms */
|
||||
if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
|
||||
printk(KERN_WARNING "or51132: read_status write error\n");
|
||||
return -1;
|
||||
if ((reg = or51132_readreg(state, 0x00)) < 0) {
|
||||
printk(KERN_WARNING "or51132: read_status: error reading receiver status: %d\n", reg);
|
||||
*status = 0;
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
msleep(30); /* 30ms */
|
||||
if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
|
||||
printk(KERN_WARNING "or51132: read_status read error\n");
|
||||
return -1;
|
||||
}
|
||||
dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]);
|
||||
dprintk("%s: read_status %04x\n", __FUNCTION__, reg);
|
||||
|
||||
if (rec_buf[1] & 0x01) { /* Receiver Lock */
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
*status |= FE_HAS_CARRIER;
|
||||
*status |= FE_HAS_VITERBI;
|
||||
*status |= FE_HAS_SYNC;
|
||||
*status |= FE_HAS_LOCK;
|
||||
}
|
||||
if (reg & 0x0100) /* Receiver Lock */
|
||||
*status = FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|
|
||||
FE_HAS_SYNC|FE_HAS_LOCK;
|
||||
else
|
||||
*status = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -506,47 +470,30 @@ static u32 calculate_snr(u32 mse, u32 c)
|
|||
static int or51132_read_snr(struct dvb_frontend* fe, u16* snr)
|
||||
{
|
||||
struct or51132_state* state = fe->demodulator_priv;
|
||||
u8 rec_buf[2];
|
||||
u8 snd_buf[2];
|
||||
u32 noise;
|
||||
u32 c;
|
||||
u32 usK;
|
||||
int noise, reg;
|
||||
u32 c, usK = 0;
|
||||
int retry = 1;
|
||||
|
||||
/* Register is same for VSB or QAM firmware */
|
||||
snd_buf[0]=0x04;
|
||||
snd_buf[1]=0x02; /* SNR after Equalizer */
|
||||
msleep(30); /* 30ms */
|
||||
if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
|
||||
printk(KERN_WARNING "or51132: snr write error\n");
|
||||
start:
|
||||
/* SNR after Equalizer */
|
||||
noise = or51132_readreg(state, 0x02);
|
||||
if (noise < 0) {
|
||||
printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
msleep(30); /* 30ms */
|
||||
if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
|
||||
printk(KERN_WARNING "or51132: snr read error\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
noise = rec_buf[0] | (rec_buf[1] << 8);
|
||||
dprintk("read_snr noise %x %x (%i)\n",rec_buf[0],rec_buf[1],noise);
|
||||
dprintk("read_snr noise (%d)\n", noise);
|
||||
|
||||
/* Read status, contains modulation type for QAM_AUTO and
|
||||
NTSC filter for VSB */
|
||||
snd_buf[0]=0x04;
|
||||
snd_buf[1]=0x00; /* Status register */
|
||||
msleep(30); /* 30ms */
|
||||
if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
|
||||
printk(KERN_WARNING "or51132: status write error\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
msleep(30); /* 30ms */
|
||||
if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
|
||||
printk(KERN_WARNING "or51132: status read error\n");
|
||||
reg = or51132_readreg(state, 0x00);
|
||||
if (reg < 0) {
|
||||
printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
usK = 0;
|
||||
switch (rec_buf[0]) {
|
||||
switch (reg&0xff) {
|
||||
case 0x06:
|
||||
usK = (rec_buf[1] & 0x10) ? 0x03000000 : 0;
|
||||
if (reg & 0x1000) usK = 3 << 24;
|
||||
/* Fall through to QAM64 case */
|
||||
case 0x43:
|
||||
c = 150204167;
|
||||
|
@ -555,11 +502,12 @@ static int or51132_read_snr(struct dvb_frontend* fe, u16* snr)
|
|||
c = 150290396;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "or51132: unknown status 0x%02x\n", rec_buf[0]);
|
||||
printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff);
|
||||
if (retry--) goto start;
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
dprintk("%s: modulation %02x, NTSC rej O%s\n", __FUNCTION__,
|
||||
rec_buf[0], rec_buf[1]&0x10?"n":"ff");
|
||||
reg&0xff, reg&0x1000?"n":"ff");
|
||||
|
||||
/* Calculate SNR using noise, c, and NTSC rejection correction */
|
||||
state->snr = calculate_snr(noise, c) - usK;
|
||||
|
@ -671,6 +619,7 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
|||
|
||||
MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver");
|
||||
MODULE_AUTHOR("Kirk Lapray");
|
||||
MODULE_AUTHOR("Trent Piepho");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL(or51132_attach);
|
||||
|
|
|
@ -30,13 +30,13 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "tda10021.h"
|
||||
#include "tda1002x.h"
|
||||
|
||||
|
||||
struct tda10021_state {
|
||||
struct i2c_adapter* i2c;
|
||||
/* configuration settings */
|
||||
const struct tda10021_config* config;
|
||||
const struct tda1002x_config* config;
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
u8 pwm;
|
||||
|
@ -53,9 +53,6 @@ struct tda10021_state {
|
|||
static int verbose;
|
||||
|
||||
#define XIN 57840000UL
|
||||
#define DISABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0)
|
||||
#define ENABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0)
|
||||
#define HAS_INVERSION(reg0) (!(reg0 & 0x20))
|
||||
|
||||
#define FIN (XIN >> 4)
|
||||
|
||||
|
@ -64,7 +61,7 @@ static u8 tda10021_inittab[0x40]=
|
|||
{
|
||||
0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
|
||||
0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
|
||||
0xb8, 0x3f, 0xa0, 0x00, 0xcd, 0x01, 0x00, 0xff,
|
||||
0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
|
||||
0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
|
||||
|
@ -97,7 +94,8 @@ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
|
|||
int ret;
|
||||
|
||||
ret = i2c_transfer (state->i2c, msg, 2);
|
||||
if (ret != 2)
|
||||
// Don't print an error message if the id is read.
|
||||
if (ret != 2 && reg != 0x1a)
|
||||
printk("DVB: TDA10021: %s: readreg error (ret == %i)\n",
|
||||
__FUNCTION__, ret);
|
||||
return b1[0];
|
||||
|
@ -136,10 +134,10 @@ static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0,
|
|||
{
|
||||
reg0 |= state->reg0 & 0x63;
|
||||
|
||||
if (INVERSION_ON == inversion)
|
||||
ENABLE_INVERSION(reg0);
|
||||
else if (INVERSION_OFF == inversion)
|
||||
DISABLE_INVERSION(reg0);
|
||||
if ((INVERSION_ON == inversion) ^ (state->config->invert == 0))
|
||||
reg0 &= ~0x20;
|
||||
else
|
||||
reg0 |= 0x20;
|
||||
|
||||
_tda10021_writereg (state, 0x00, reg0 & 0xfe);
|
||||
_tda10021_writereg (state, 0x00, reg0 | 0x01);
|
||||
|
@ -201,16 +199,6 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
|
||||
{
|
||||
struct tda10021_state* state = fe->demodulator_priv;
|
||||
|
||||
if (len != 2)
|
||||
return -EINVAL;
|
||||
|
||||
return _tda10021_writereg(state, buf[0], buf[1]);
|
||||
}
|
||||
|
||||
static int tda10021_init (struct dvb_frontend *fe)
|
||||
{
|
||||
struct tda10021_state* state = fe->demodulator_priv;
|
||||
|
@ -258,6 +246,9 @@ static int tda10021_set_parameters (struct dvb_frontend *fe,
|
|||
if (qam < 0 || qam > 5)
|
||||
return -EINVAL;
|
||||
|
||||
if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF)
|
||||
return -EINVAL;
|
||||
|
||||
//printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
|
||||
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
|
@ -366,7 +357,7 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
|
|||
-((s32)p->u.qam.symbol_rate * afc) >> 10);
|
||||
}
|
||||
|
||||
p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF;
|
||||
p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF;
|
||||
p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
|
||||
|
||||
p->u.qam.fec_inner = FEC_NONE;
|
||||
|
@ -408,11 +399,12 @@ static void tda10021_release(struct dvb_frontend* fe)
|
|||
|
||||
static struct dvb_frontend_ops tda10021_ops;
|
||||
|
||||
struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
|
||||
struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
|
||||
struct i2c_adapter* i2c,
|
||||
u8 pwm)
|
||||
{
|
||||
struct tda10021_state* state = NULL;
|
||||
u8 id;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kmalloc(sizeof(struct tda10021_state), GFP_KERNEL);
|
||||
|
@ -425,7 +417,11 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
|
|||
state->reg0 = tda10021_inittab[0];
|
||||
|
||||
/* check if the demod is there */
|
||||
if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
|
||||
id = tda10021_readreg(state, 0x1a);
|
||||
if ((id & 0xf0) != 0x70) goto error;
|
||||
|
||||
printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
|
||||
state->config->demod_address, id);
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
|
||||
|
@ -447,7 +443,7 @@ static struct dvb_frontend_ops tda10021_ops = {
|
|||
.frequency_max = 858000000,
|
||||
.symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */
|
||||
.symbol_rate_max = (XIN/2)/4, /* SACLK/4 */
|
||||
#if 0
|
||||
#if 0
|
||||
.frequency_tolerance = ???,
|
||||
.symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */
|
||||
#endif
|
||||
|
@ -461,7 +457,6 @@ static struct dvb_frontend_ops tda10021_ops = {
|
|||
|
||||
.init = tda10021_init,
|
||||
.sleep = tda10021_sleep,
|
||||
.write = tda10021_write,
|
||||
.i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
|
||||
|
||||
.set_frontend = tda10021_set_parameters,
|
||||
|
|
540
drivers/media/dvb/frontends/tda10023.c
Normal file
540
drivers/media/dvb/frontends/tda10023.c
Normal file
|
@ -0,0 +1,540 @@
|
|||
/*
|
||||
TDA10023 - DVB-C decoder
|
||||
(as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card)
|
||||
|
||||
Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de)
|
||||
Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com)
|
||||
|
||||
Remotely based on tda10021.c
|
||||
Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
|
||||
Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
|
||||
Support for TDA10021
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "tda1002x.h"
|
||||
|
||||
|
||||
struct tda10023_state {
|
||||
struct i2c_adapter* i2c;
|
||||
/* configuration settings */
|
||||
const struct tda1002x_config* config;
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
u8 pwm;
|
||||
u8 reg0;
|
||||
};
|
||||
|
||||
|
||||
#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 };
|
||||
u8 b1 [] = { 0 };
|
||||
struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
|
||||
{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
|
||||
int ret;
|
||||
|
||||
ret = i2c_transfer (state->i2c, msg, 2);
|
||||
if (ret != 2)
|
||||
printk("DVB: TDA10023: %s: readreg error (ret == %i)\n",
|
||||
__FUNCTION__, ret);
|
||||
return b1[0];
|
||||
}
|
||||
|
||||
static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data)
|
||||
{
|
||||
u8 buf[] = { reg, data };
|
||||
struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
|
||||
int ret;
|
||||
|
||||
ret = i2c_transfer (state->i2c, &msg, 1);
|
||||
if (ret != 1)
|
||||
printk("DVB: TDA10023(%d): %s, writereg error "
|
||||
"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
|
||||
state->frontend.dvb->num, __FUNCTION__, reg, data, ret);
|
||||
|
||||
return (ret != 1) ? -EREMOTEIO : 0;
|
||||
}
|
||||
|
||||
|
||||
static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data)
|
||||
{
|
||||
if (mask==0xff)
|
||||
return tda10023_writereg(state, reg, data);
|
||||
else {
|
||||
u8 val;
|
||||
val=tda10023_readreg(state,reg);
|
||||
val&=~mask;
|
||||
val|=(data&mask);
|
||||
return tda10023_writereg(state, reg, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void tda10023_writetab(struct tda10023_state* state, u8* tab)
|
||||
{
|
||||
u8 r,m,v;
|
||||
while (1) {
|
||||
r=*tab++;
|
||||
m=*tab++;
|
||||
v=*tab++;
|
||||
if (r==0xff) {
|
||||
if (m==0xff)
|
||||
break;
|
||||
else
|
||||
msleep(m);
|
||||
}
|
||||
else
|
||||
tda10023_writebit(state,r,m,v);
|
||||
}
|
||||
}
|
||||
|
||||
//get access to tuner
|
||||
static int lock_tuner(struct tda10023_state* state)
|
||||
{
|
||||
u8 buf[2] = { 0x0f, 0xc0 };
|
||||
struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
|
||||
|
||||
if(i2c_transfer(state->i2c, &msg, 1) != 1)
|
||||
{
|
||||
printk("tda10023: lock tuner fails\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//release access from tuner
|
||||
static int unlock_tuner(struct tda10023_state* state)
|
||||
{
|
||||
u8 buf[2] = { 0x0f, 0x40 };
|
||||
struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
|
||||
|
||||
if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
|
||||
{
|
||||
printk("tda10023: unlock tuner fails\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0)
|
||||
{
|
||||
reg0 |= state->reg0 & 0x63;
|
||||
|
||||
tda10023_writereg (state, 0x00, reg0 & 0xfe);
|
||||
tda10023_writereg (state, 0x00, reg0 | 0x01);
|
||||
|
||||
state->reg0 = reg0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
|
||||
{
|
||||
s32 BDR;
|
||||
s32 BDRI;
|
||||
s16 SFIL=0;
|
||||
u16 NDEC = 0;
|
||||
|
||||
if (sr > (SYSCLK/(2*4)))
|
||||
sr=SYSCLK/(2*4);
|
||||
|
||||
if (sr<870000)
|
||||
sr=870000;
|
||||
|
||||
if (sr < (u32)(SYSCLK/98.40)) {
|
||||
NDEC=3;
|
||||
SFIL=1;
|
||||
} else if (sr<(u32)(SYSCLK/64.0)) {
|
||||
NDEC=3;
|
||||
SFIL=0;
|
||||
} else if (sr<(u32)(SYSCLK/49.2)) {
|
||||
NDEC=2;
|
||||
SFIL=1;
|
||||
} else if (sr<(u32)(SYSCLK/32.0)) {
|
||||
NDEC=2;
|
||||
SFIL=0;
|
||||
} else if (sr<(u32)(SYSCLK/24.6)) {
|
||||
NDEC=1;
|
||||
SFIL=1;
|
||||
} else if (sr<(u32)(SYSCLK/16.0)) {
|
||||
NDEC=1;
|
||||
SFIL=0;
|
||||
} else if (sr<(u32)(SYSCLK/12.3)) {
|
||||
NDEC=0;
|
||||
SFIL=1;
|
||||
}
|
||||
|
||||
BDRI=SYSCLK*16;
|
||||
BDRI>>=NDEC;
|
||||
BDRI +=sr/2;
|
||||
BDRI /=sr;
|
||||
|
||||
if (BDRI>255)
|
||||
BDRI=255;
|
||||
|
||||
{
|
||||
u64 BDRX;
|
||||
|
||||
BDRX=1<<(24+NDEC);
|
||||
BDRX*=sr;
|
||||
do_div(BDRX,SYSCLK); // BDRX/=SYSCLK;
|
||||
|
||||
BDR=(s32)BDRX;
|
||||
}
|
||||
// printk("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);
|
||||
tda10023_writereg (state, 0x0c, (BDR>>16)&31);
|
||||
tda10023_writereg (state, 0x0d, BDRI);
|
||||
tda10023_writereg (state, 0x3d, (SFIL<<7));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_init (struct dvb_frontend *fe)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
|
||||
dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num);
|
||||
|
||||
tda10023_writetab(state, tda10023_inittab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_set_parameters (struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
|
||||
static int qamvals[6][6] = {
|
||||
// QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD
|
||||
{ (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM
|
||||
{ (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM
|
||||
{ (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM
|
||||
{ (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM
|
||||
{ (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM
|
||||
{ (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM
|
||||
};
|
||||
|
||||
int qam = p->u.qam.modulation;
|
||||
|
||||
if (qam < 0 || qam > 5)
|
||||
return -EINVAL;
|
||||
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
fe->ops.tuner_ops.set_params(fe, p);
|
||||
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
tda10023_set_symbolrate (state, p->u.qam.symbol_rate);
|
||||
tda10023_writereg (state, 0x05, qamvals[qam][1]);
|
||||
tda10023_writereg (state, 0x08, qamvals[qam][2]);
|
||||
tda10023_writereg (state, 0x09, qamvals[qam][3]);
|
||||
tda10023_writereg (state, 0xb4, qamvals[qam][4]);
|
||||
tda10023_writereg (state, 0xb6, qamvals[qam][5]);
|
||||
|
||||
// tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32));
|
||||
// tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20));
|
||||
tda10023_writebit (state, 0x04, 0x40, 0x40);
|
||||
tda10023_setup_reg0 (state, qamvals[qam][0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
int sync;
|
||||
|
||||
*status = 0;
|
||||
|
||||
//0x11[1] == CARLOCK -> Carrier locked
|
||||
//0x11[2] == FSYNC -> Frame synchronisation
|
||||
//0x11[3] == FEL -> Front End locked
|
||||
//0x11[6] == NODVB -> DVB Mode Information
|
||||
sync = tda10023_readreg (state, 0x11);
|
||||
|
||||
if (sync & 2)
|
||||
*status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
|
||||
|
||||
if (sync & 4)
|
||||
*status |= FE_HAS_SYNC|FE_HAS_VITERBI;
|
||||
|
||||
if (sync & 8)
|
||||
*status |= FE_HAS_LOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
u8 a,b,c;
|
||||
a=tda10023_readreg(state, 0x14);
|
||||
b=tda10023_readreg(state, 0x15);
|
||||
c=tda10023_readreg(state, 0x16)&0xf;
|
||||
tda10023_writebit (state, 0x10, 0xc0, 0x00);
|
||||
|
||||
*ber = a | (b<<8)| (c<<16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
u8 ifgain=tda10023_readreg(state, 0x2f);
|
||||
|
||||
u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16;
|
||||
// Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90
|
||||
if (gain>0x90)
|
||||
gain=gain+2*(gain-0x90);
|
||||
if (gain>255)
|
||||
gain=255;
|
||||
|
||||
*strength = (gain<<8)|gain;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
|
||||
u8 quality = ~tda10023_readreg(state, 0x18);
|
||||
*snr = (quality << 8) | quality;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
u8 a,b,c,d;
|
||||
a= tda10023_readreg (state, 0x74);
|
||||
b= tda10023_readreg (state, 0x75);
|
||||
c= tda10023_readreg (state, 0x76);
|
||||
d= tda10023_readreg (state, 0x77);
|
||||
*ucblocks = a | (b<<8)|(c<<16)|(d<<24);
|
||||
|
||||
tda10023_writebit (state, 0x10, 0x20,0x00);
|
||||
tda10023_writebit (state, 0x10, 0x20,0x20);
|
||||
tda10023_writebit (state, 0x13, 0x01, 0x00);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
int sync,inv;
|
||||
s8 afc = 0;
|
||||
|
||||
sync = tda10023_readreg(state, 0x11);
|
||||
afc = tda10023_readreg(state, 0x19);
|
||||
inv = tda10023_readreg(state, 0x04);
|
||||
|
||||
if (verbose) {
|
||||
/* AFC only valid when carrier has been recovered */
|
||||
printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" :
|
||||
"DVB: TDA10023(%d): [AFC (%d) %dHz]\n",
|
||||
state->frontend.dvb->num, afc,
|
||||
-((s32)p->u.qam.symbol_rate * afc) >> 10);
|
||||
}
|
||||
|
||||
p->inversion = (inv&0x20?0:1);
|
||||
p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
|
||||
|
||||
p->u.qam.fec_inner = FEC_NONE;
|
||||
p->frequency = ((p->frequency + 31250) / 62500) * 62500;
|
||||
|
||||
if (sync & 2)
|
||||
p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_sleep(struct dvb_frontend* fe)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
|
||||
tda10023_writereg (state, 0x1b, 0x02); /* pdown ADC */
|
||||
tda10023_writereg (state, 0x00, 0x80); /* standby */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
|
||||
if (enable) {
|
||||
lock_tuner(state);
|
||||
} else {
|
||||
unlock_tuner(state);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tda10023_release(struct dvb_frontend* fe)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops tda10023_ops;
|
||||
|
||||
struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
|
||||
struct i2c_adapter* i2c,
|
||||
u8 pwm)
|
||||
{
|
||||
struct tda10023_state* state = NULL;
|
||||
int i;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kmalloc(sizeof(struct tda10023_state), GFP_KERNEL);
|
||||
if (state == NULL) goto error;
|
||||
|
||||
/* 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 < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) {
|
||||
if (tda10023_inittab[i] == 0x00) {
|
||||
state->reg0 = tda10023_inittab[i+2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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->frontend.demodulator_priv = state;
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops tda10023_ops = {
|
||||
|
||||
.info = {
|
||||
.name = "Philips TDA10023 DVB-C",
|
||||
.type = FE_QAM,
|
||||
.frequency_stepsize = 62500,
|
||||
.frequency_min = 51000000,
|
||||
.frequency_max = 858000000,
|
||||
.symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */
|
||||
.symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */
|
||||
.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 |
|
||||
FE_CAN_FEC_AUTO
|
||||
},
|
||||
|
||||
.release = tda10023_release,
|
||||
|
||||
.init = tda10023_init,
|
||||
.sleep = tda10023_sleep,
|
||||
.i2c_gate_ctrl = tda10023_i2c_gate_ctrl,
|
||||
|
||||
.set_frontend = tda10023_set_parameters,
|
||||
.get_frontend = tda10023_get_frontend,
|
||||
|
||||
.read_status = tda10023_read_status,
|
||||
.read_ber = tda10023_read_ber,
|
||||
.read_signal_strength = tda10023_read_signal_strength,
|
||||
.read_snr = tda10023_read_snr,
|
||||
.read_ucblocks = tda10023_read_ucblocks,
|
||||
};
|
||||
|
||||
|
||||
MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver");
|
||||
MODULE_AUTHOR("Georg Acher, Hartmut Birr");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL(tda10023_attach);
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
TDA10021 - Single Chip Cable Channel Receiver driver module
|
||||
used on the the Siemens DVB-C cards
|
||||
TDA10021/TDA10023 - Single Chip Cable Channel Receiver driver module
|
||||
used on the the Siemens DVB-C cards
|
||||
|
||||
Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
|
||||
Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
|
||||
|
@ -21,22 +21,23 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef TDA10021_H
|
||||
#define TDA10021_H
|
||||
#ifndef TDA1002x_H
|
||||
#define TDA1002x_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
struct tda10021_config
|
||||
struct tda1002x_config
|
||||
{
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
u8 invert;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
|
||||
extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
|
||||
struct i2c_adapter* i2c, u8 pwm);
|
||||
#else
|
||||
static inline struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
|
||||
static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
|
||||
struct i2c_adapter* i2c, u8 pwm)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
|
||||
|
@ -44,12 +45,16 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda10021_config*
|
|||
}
|
||||
#endif // CONFIG_DVB_TDA10021
|
||||
|
||||
static inline int tda10021_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
|
||||
int r = 0;
|
||||
u8 buf[] = {reg, val};
|
||||
if (fe->ops.write)
|
||||
r = fe->ops.write(fe, buf, 2);
|
||||
return r;
|
||||
#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);
|
||||
#else
|
||||
static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
|
||||
struct i2c_adapter* i2c, u8 pwm)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
#endif // CONFIG_DVB_TDA10023
|
||||
|
||||
#endif // TDA10021_H
|
||||
#endif // TDA1002x_H
|
|
@ -40,20 +40,6 @@
|
|||
#include "dvb_frontend.h"
|
||||
#include "tda1004x.h"
|
||||
|
||||
enum tda1004x_demod {
|
||||
TDA1004X_DEMOD_TDA10045,
|
||||
TDA1004X_DEMOD_TDA10046,
|
||||
};
|
||||
|
||||
struct tda1004x_state {
|
||||
struct i2c_adapter* i2c;
|
||||
const struct tda1004x_config* config;
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
/* private demod data */
|
||||
enum tda1004x_demod demod_type;
|
||||
};
|
||||
|
||||
static int debug;
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
|
@ -507,12 +493,25 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
|
|||
tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80);
|
||||
}
|
||||
tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
|
||||
/* set GPIO 1 and 3 */
|
||||
if (state->config->gpio_config != TDA10046_GPTRI) {
|
||||
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33);
|
||||
tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f);
|
||||
}
|
||||
/* let the clocks recover from sleep */
|
||||
msleep(5);
|
||||
msleep(10);
|
||||
|
||||
/* The PLLs need to be reprogrammed after sleep */
|
||||
tda10046_init_plls(fe);
|
||||
tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0);
|
||||
|
||||
/* don't re-upload unless necessary */
|
||||
if (tda1004x_check_upload_ok(state) == 0)
|
||||
return 0;
|
||||
|
||||
printk(KERN_INFO "tda1004x: trying to boot from eeprom\n");
|
||||
tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
|
||||
msleep(300);
|
||||
/* don't re-upload unless necessary */
|
||||
if (tda1004x_check_upload_ok(state) == 0)
|
||||
return 0;
|
||||
|
@ -522,20 +521,23 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
|
|||
printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
|
||||
ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
|
||||
return ret;
|
||||
/* remain compatible to old bug: try to load with tda10045 image name */
|
||||
ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
|
||||
return ret;
|
||||
} else {
|
||||
printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n",
|
||||
TDA10046_DEFAULT_FIRMWARE);
|
||||
}
|
||||
}
|
||||
tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
|
||||
ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
|
||||
release_firmware(fw);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/* boot from firmware eeprom */
|
||||
printk(KERN_INFO "tda1004x: booting from eeprom\n");
|
||||
tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
|
||||
msleep(300);
|
||||
printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n");
|
||||
return -EIO;
|
||||
}
|
||||
tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
|
||||
ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
|
||||
release_firmware(fw);
|
||||
return tda1004x_check_upload_ok(state);
|
||||
}
|
||||
|
||||
|
@ -638,37 +640,33 @@ static int tda10046_init(struct dvb_frontend* fe)
|
|||
switch (state->config->agc_config) {
|
||||
case TDA10046_AGC_DEFAULT:
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
|
||||
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
|
||||
tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities
|
||||
break;
|
||||
case TDA10046_AGC_IFO_AUTO_NEG:
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
|
||||
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
|
||||
tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities
|
||||
break;
|
||||
case TDA10046_AGC_IFO_AUTO_POS:
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
|
||||
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities
|
||||
tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00); // set AGC polarities
|
||||
break;
|
||||
case TDA10046_AGC_TDA827X_GP11:
|
||||
case TDA10046_AGC_TDA827X:
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
|
||||
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
|
||||
break;
|
||||
case TDA10046_AGC_TDA827X_GP00:
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
|
||||
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
|
||||
break;
|
||||
case TDA10046_AGC_TDA827X_GP01:
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
|
||||
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x62); // set AGC polarities
|
||||
tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities
|
||||
break;
|
||||
}
|
||||
if (state->config->ts_mode == 0) {
|
||||
tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40);
|
||||
tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
|
||||
} else {
|
||||
tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80);
|
||||
tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10,
|
||||
state->config->invert_oclk << 4);
|
||||
}
|
||||
tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
|
||||
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
|
||||
tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // }
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
|
||||
tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // }
|
||||
|
@ -678,7 +676,6 @@ static int tda10046_init(struct dvb_frontend* fe)
|
|||
tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
|
||||
tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
|
||||
// tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes
|
||||
tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -705,7 +702,8 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
|
|||
// set frequency
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
fe->ops.tuner_ops.set_params(fe, fe_params);
|
||||
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
// Hardcoded to use auto as much as possible on the TDA10045 as it
|
||||
|
@ -1165,6 +1163,7 @@ static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
|
|||
static int tda1004x_sleep(struct dvb_frontend* fe)
|
||||
{
|
||||
struct tda1004x_state* state = fe->demodulator_priv;
|
||||
int gpio_conf;
|
||||
|
||||
switch (state->demod_type) {
|
||||
case TDA1004X_DEMOD_TDA10045:
|
||||
|
@ -1174,6 +1173,13 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
|
|||
case TDA1004X_DEMOD_TDA10046:
|
||||
/* set outputs to tristate */
|
||||
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
|
||||
/* invert GPIO 1 and 3 if desired*/
|
||||
gpio_conf = state->config->gpio_config;
|
||||
if (gpio_conf >= TDA10046_GP00_I)
|
||||
tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f,
|
||||
(gpio_conf & 0x0f) ^ 0x0a);
|
||||
|
||||
tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0);
|
||||
tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -35,9 +35,23 @@ enum tda10046_agc {
|
|||
TDA10046_AGC_DEFAULT, /* original configuration */
|
||||
TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */
|
||||
TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */
|
||||
TDA10046_AGC_TDA827X_GP11, /* IF AGC only, special setup for tda827x */
|
||||
TDA10046_AGC_TDA827X_GP00, /* same as above, but GPIOs 0 */
|
||||
TDA10046_AGC_TDA827X_GP01, /* same as above, but GPIO3=0 GPIO1=1*/
|
||||
TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */
|
||||
};
|
||||
|
||||
/* Many (hybrid) boards use GPIO 1 and 3
|
||||
GPIO1 analog - dvb switch
|
||||
GPIO3 firmware eeprom address switch
|
||||
*/
|
||||
enum tda10046_gpio {
|
||||
TDA10046_GPTRI = 0x00, /* All GPIOs tristate */
|
||||
TDA10046_GP00 = 0x40, /* GPIO3=0, GPIO1=0 */
|
||||
TDA10046_GP01 = 0x42, /* GPIO3=0, GPIO1=1 */
|
||||
TDA10046_GP10 = 0x48, /* GPIO3=1, GPIO1=0 */
|
||||
TDA10046_GP11 = 0x4a, /* GPIO3=1, GPIO1=1 */
|
||||
TDA10046_GP00_I = 0x80, /* GPIO3=0, GPIO1=0, invert in sleep mode*/
|
||||
TDA10046_GP01_I = 0x82, /* GPIO3=0, GPIO1=1, invert in sleep mode */
|
||||
TDA10046_GP10_I = 0x88, /* GPIO3=1, GPIO1=0, invert in sleep mode */
|
||||
TDA10046_GP11_I = 0x8a, /* GPIO3=1, GPIO1=1, invert in sleep mode */
|
||||
};
|
||||
|
||||
enum tda10046_if {
|
||||
|
@ -47,6 +61,11 @@ enum tda10046_if {
|
|||
TDA10046_FREQ_052, /* low IF, 5.1667 MHZ for tda9889 */
|
||||
};
|
||||
|
||||
enum tda10046_tsout {
|
||||
TDA10046_TS_PARALLEL = 0x00, /* parallel transport stream, default */
|
||||
TDA10046_TS_SERIAL = 0x01, /* serial transport stream */
|
||||
};
|
||||
|
||||
struct tda1004x_config
|
||||
{
|
||||
/* the demodulator's i2c address */
|
||||
|
@ -58,6 +77,9 @@ struct tda1004x_config
|
|||
/* Does the OCLK signal need inverted? */
|
||||
u8 invert_oclk;
|
||||
|
||||
/* parallel or serial transport stream */
|
||||
enum tda10046_tsout ts_mode;
|
||||
|
||||
/* Xtal frequency, 4 or 16MHz*/
|
||||
enum tda10046_xtal xtal_freq;
|
||||
|
||||
|
@ -67,11 +89,35 @@ struct tda1004x_config
|
|||
/* AGC configuration */
|
||||
enum tda10046_agc agc_config;
|
||||
|
||||
/* setting of GPIO1 and 3 */
|
||||
enum tda10046_gpio gpio_config;
|
||||
|
||||
/* slave address and configuration of the tuner */
|
||||
u8 tuner_address;
|
||||
u8 tuner_config;
|
||||
u8 antenna_switch;
|
||||
|
||||
/* if the board uses another I2c Bridge (tda8290), its address */
|
||||
u8 i2c_gate;
|
||||
|
||||
/* request firmware for device */
|
||||
/* set this to NULL if the card has a firmware EEPROM */
|
||||
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
|
||||
};
|
||||
|
||||
enum tda1004x_demod {
|
||||
TDA1004X_DEMOD_TDA10045,
|
||||
TDA1004X_DEMOD_TDA10046,
|
||||
};
|
||||
|
||||
struct tda1004x_state {
|
||||
struct i2c_adapter* i2c;
|
||||
const struct tda1004x_config* config;
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
/* private demod data */
|
||||
enum tda1004x_demod demod_type;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
|
||||
struct i2c_adapter* i2c);
|
||||
|
|
512
drivers/media/dvb/frontends/tda827x.c
Normal file
512
drivers/media/dvb/frontends/tda827x.c
Normal file
|
@ -0,0 +1,512 @@
|
|||
/*
|
||||
*
|
||||
* (c) 2005 Hartmut Hackmann
|
||||
* (c) 2007 Michael Krufky
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#include "tda827x.h"
|
||||
|
||||
static int debug = 0;
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) printk(KERN_DEBUG "tda827x: " args); \
|
||||
} while (0)
|
||||
|
||||
struct tda827x_priv {
|
||||
int i2c_addr;
|
||||
struct i2c_adapter *i2c_adap;
|
||||
struct tda827x_config *cfg;
|
||||
u32 frequency;
|
||||
u32 bandwidth;
|
||||
};
|
||||
|
||||
struct tda827x_data {
|
||||
u32 lomax;
|
||||
u8 spd;
|
||||
u8 bs;
|
||||
u8 bp;
|
||||
u8 cp;
|
||||
u8 gc3;
|
||||
u8 div1p5;
|
||||
};
|
||||
|
||||
static const struct tda827x_data tda827x_dvbt[] = {
|
||||
{ .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
|
||||
{ .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
|
||||
{ .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
|
||||
{ .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
|
||||
{ .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
|
||||
{ .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
|
||||
{ .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0},
|
||||
{ .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
|
||||
{ .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
|
||||
{ .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
|
||||
{ .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
|
||||
{ .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
|
||||
{ .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
|
||||
{ .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
|
||||
{ .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
|
||||
{ .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
|
||||
{ .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
|
||||
{ .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
|
||||
};
|
||||
|
||||
static int tda827xo_set_params(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct tda827x_priv *priv = fe->tuner_priv;
|
||||
u8 buf[14];
|
||||
|
||||
struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
|
||||
.buf = buf, .len = sizeof(buf) };
|
||||
int i, tuner_freq, if_freq;
|
||||
u32 N;
|
||||
|
||||
dprintk("%s:\n", __FUNCTION__);
|
||||
switch (params->u.ofdm.bandwidth) {
|
||||
case BANDWIDTH_6_MHZ:
|
||||
if_freq = 4000000;
|
||||
break;
|
||||
case BANDWIDTH_7_MHZ:
|
||||
if_freq = 4500000;
|
||||
break;
|
||||
default: /* 8 MHz or Auto */
|
||||
if_freq = 5000000;
|
||||
break;
|
||||
}
|
||||
tuner_freq = params->frequency + if_freq;
|
||||
|
||||
i = 0;
|
||||
while (tda827x_dvbt[i].lomax < tuner_freq) {
|
||||
if(tda827x_dvbt[i + 1].lomax == 0)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2);
|
||||
buf[0] = 0;
|
||||
buf[1] = (N>>8) | 0x40;
|
||||
buf[2] = N & 0xff;
|
||||
buf[3] = 0;
|
||||
buf[4] = 0x52;
|
||||
buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) +
|
||||
(tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp;
|
||||
buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f;
|
||||
buf[7] = 0xbf;
|
||||
buf[8] = 0x2a;
|
||||
buf[9] = 0x05;
|
||||
buf[10] = 0xff;
|
||||
buf[11] = 0x00;
|
||||
buf[12] = 0x00;
|
||||
buf[13] = 0x40;
|
||||
|
||||
msg.len = 14;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
|
||||
printk("%s: could not write to tuner at addr: 0x%02x\n",
|
||||
__FUNCTION__, priv->i2c_addr << 1);
|
||||
return -EIO;
|
||||
}
|
||||
msleep(500);
|
||||
/* correct CP value */
|
||||
buf[0] = 0x30;
|
||||
buf[1] = 0x50 + tda827x_dvbt[i].cp;
|
||||
msg.len = 2;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
priv->frequency = tuner_freq - if_freq; // FIXME
|
||||
priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda827xo_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct tda827x_priv *priv = fe->tuner_priv;
|
||||
static u8 buf[] = { 0x30, 0xd0 };
|
||||
struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
|
||||
.buf = buf, .len = sizeof(buf) };
|
||||
|
||||
dprintk("%s:\n", __FUNCTION__);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
if (priv->cfg && priv->cfg->sleep)
|
||||
priv->cfg->sleep(fe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
struct tda827xa_data {
|
||||
u32 lomax;
|
||||
u8 svco;
|
||||
u8 spd;
|
||||
u8 scr;
|
||||
u8 sbs;
|
||||
u8 gc3;
|
||||
};
|
||||
|
||||
static const struct tda827xa_data tda827xa_dvbt[] = {
|
||||
{ .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
|
||||
{ .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
|
||||
{ .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
|
||||
{ .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
|
||||
{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
|
||||
{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
|
||||
{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
|
||||
{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
|
||||
{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
|
||||
{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
|
||||
{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
|
||||
{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
|
||||
{ .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
|
||||
{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
|
||||
{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
|
||||
{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
|
||||
{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
|
||||
{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
|
||||
{ .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
|
||||
{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
|
||||
{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
|
||||
{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
|
||||
{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
|
||||
{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
|
||||
{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
|
||||
{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
|
||||
{ .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
|
||||
};
|
||||
|
||||
static int tda827xa_set_params(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct tda827x_priv *priv = fe->tuner_priv;
|
||||
u8 buf[11];
|
||||
|
||||
struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
|
||||
.buf = buf, .len = sizeof(buf) };
|
||||
|
||||
int i, tuner_freq, if_freq;
|
||||
u32 N;
|
||||
|
||||
dprintk("%s:\n", __FUNCTION__);
|
||||
if (priv->cfg && priv->cfg->lna_gain)
|
||||
priv->cfg->lna_gain(fe, 1);
|
||||
msleep(20);
|
||||
|
||||
switch (params->u.ofdm.bandwidth) {
|
||||
case BANDWIDTH_6_MHZ:
|
||||
if_freq = 4000000;
|
||||
break;
|
||||
case BANDWIDTH_7_MHZ:
|
||||
if_freq = 4500000;
|
||||
break;
|
||||
default: /* 8 MHz or Auto */
|
||||
if_freq = 5000000;
|
||||
break;
|
||||
}
|
||||
tuner_freq = params->frequency + if_freq;
|
||||
|
||||
i = 0;
|
||||
while (tda827xa_dvbt[i].lomax < tuner_freq) {
|
||||
if(tda827xa_dvbt[i + 1].lomax == 0)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd;
|
||||
buf[0] = 0; // subaddress
|
||||
buf[1] = N >> 8;
|
||||
buf[2] = N & 0xff;
|
||||
buf[3] = 0;
|
||||
buf[4] = 0x16;
|
||||
buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) +
|
||||
tda827xa_dvbt[i].sbs;
|
||||
buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4);
|
||||
buf[7] = 0x1c;
|
||||
buf[8] = 0x06;
|
||||
buf[9] = 0x24;
|
||||
buf[10] = 0x00;
|
||||
msg.len = 11;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
|
||||
printk("%s: could not write to tuner at addr: 0x%02x\n",
|
||||
__FUNCTION__, priv->i2c_addr << 1);
|
||||
return -EIO;
|
||||
}
|
||||
buf[0] = 0x90;
|
||||
buf[1] = 0xff;
|
||||
buf[2] = 0x60;
|
||||
buf[3] = 0x00;
|
||||
buf[4] = 0x59; // lpsel, for 6MHz + 2
|
||||
msg.len = 5;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
buf[0] = 0xa0;
|
||||
buf[1] = 0x40;
|
||||
msg.len = 2;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
msleep(11);
|
||||
msg.flags = I2C_M_RD;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
msg.flags = 0;
|
||||
|
||||
buf[1] >>= 4;
|
||||
dprintk("tda8275a AGC2 gain is: %d\n", buf[1]);
|
||||
if ((buf[1]) < 2) {
|
||||
if (priv->cfg && priv->cfg->lna_gain)
|
||||
priv->cfg->lna_gain(fe, 0);
|
||||
buf[0] = 0x60;
|
||||
buf[1] = 0x0c;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
}
|
||||
|
||||
buf[0] = 0xc0;
|
||||
buf[1] = 0x99; // lpsel, for 6MHz + 2
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
buf[0] = 0x60;
|
||||
buf[1] = 0x3c;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
/* correct CP value */
|
||||
buf[0] = 0x30;
|
||||
buf[1] = 0x10 + tda827xa_dvbt[i].scr;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
msleep(163);
|
||||
buf[0] = 0xc0;
|
||||
buf[1] = 0x39; // lpsel, for 6MHz + 2
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
msleep(3);
|
||||
/* freeze AGC1 */
|
||||
buf[0] = 0x50;
|
||||
buf[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
priv->frequency = tuner_freq - if_freq; // FIXME
|
||||
priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda827xa_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct tda827x_priv *priv = fe->tuner_priv;
|
||||
static u8 buf[] = { 0x30, 0x90 };
|
||||
struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
|
||||
.buf = buf, .len = sizeof(buf) };
|
||||
|
||||
dprintk("%s:\n", __FUNCTION__);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
if (priv->cfg && priv->cfg->sleep)
|
||||
priv->cfg->sleep(fe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda827x_release(struct dvb_frontend *fe)
|
||||
{
|
||||
kfree(fe->tuner_priv);
|
||||
fe->tuner_priv = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
struct tda827x_priv *priv = fe->tuner_priv;
|
||||
*frequency = priv->frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
|
||||
{
|
||||
struct tda827x_priv *priv = fe->tuner_priv;
|
||||
*bandwidth = priv->bandwidth;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda827x_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct tda827x_priv *priv = fe->tuner_priv;
|
||||
dprintk("%s:\n", __FUNCTION__);
|
||||
if (priv->cfg && priv->cfg->init)
|
||||
priv->cfg->init(fe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda827x_probe_version(struct dvb_frontend *fe);
|
||||
|
||||
static int tda827x_initial_init(struct dvb_frontend *fe)
|
||||
{
|
||||
int ret;
|
||||
ret = tda827x_probe_version(fe);
|
||||
if (ret)
|
||||
return ret;
|
||||
return fe->ops.tuner_ops.init(fe);
|
||||
}
|
||||
|
||||
static int tda827x_initial_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
int ret;
|
||||
ret = tda827x_probe_version(fe);
|
||||
if (ret)
|
||||
return ret;
|
||||
return fe->ops.tuner_ops.sleep(fe);
|
||||
}
|
||||
|
||||
static struct dvb_tuner_ops tda827xo_tuner_ops = {
|
||||
.info = {
|
||||
.name = "Philips TDA827X",
|
||||
.frequency_min = 55000000,
|
||||
.frequency_max = 860000000,
|
||||
.frequency_step = 250000
|
||||
},
|
||||
.release = tda827x_release,
|
||||
.init = tda827x_initial_init,
|
||||
.sleep = tda827x_initial_sleep,
|
||||
.set_params = tda827xo_set_params,
|
||||
.get_frequency = tda827x_get_frequency,
|
||||
.get_bandwidth = tda827x_get_bandwidth,
|
||||
};
|
||||
|
||||
static struct dvb_tuner_ops tda827xa_tuner_ops = {
|
||||
.info = {
|
||||
.name = "Philips TDA827XA",
|
||||
.frequency_min = 44000000,
|
||||
.frequency_max = 906000000,
|
||||
.frequency_step = 62500
|
||||
},
|
||||
.release = tda827x_release,
|
||||
.init = tda827x_init,
|
||||
.sleep = tda827xa_sleep,
|
||||
.set_params = tda827xa_set_params,
|
||||
.get_frequency = tda827x_get_frequency,
|
||||
.get_bandwidth = tda827x_get_bandwidth,
|
||||
};
|
||||
|
||||
static int tda827x_probe_version(struct dvb_frontend *fe)
|
||||
{ u8 data;
|
||||
struct tda827x_priv *priv = fe->tuner_priv;
|
||||
struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD,
|
||||
.buf = &data, .len = 1 };
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
|
||||
printk("%s: could not read from tuner at addr: 0x%02x\n",
|
||||
__FUNCTION__, msg.addr << 1);
|
||||
return -EIO;
|
||||
}
|
||||
if ((data & 0x3c) == 0) {
|
||||
dprintk("tda827x tuner found\n");
|
||||
fe->ops.tuner_ops.init = tda827x_init;
|
||||
fe->ops.tuner_ops.sleep = tda827xo_sleep;
|
||||
} else {
|
||||
dprintk("tda827xa tuner found\n");
|
||||
memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
|
||||
struct i2c_adapter *i2c,
|
||||
struct tda827x_config *cfg)
|
||||
{
|
||||
struct tda827x_priv *priv = NULL;
|
||||
|
||||
dprintk("%s:\n", __FUNCTION__);
|
||||
priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return NULL;
|
||||
|
||||
priv->i2c_addr = addr;
|
||||
priv->i2c_adap = i2c;
|
||||
priv->cfg = cfg;
|
||||
memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));
|
||||
|
||||
fe->tuner_priv = priv;
|
||||
|
||||
return fe;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(tda827x_attach);
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
|
||||
MODULE_DESCRIPTION("DVB TDA827x driver");
|
||||
MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>");
|
||||
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
62
drivers/media/dvb/frontends/tda827x.h
Normal file
62
drivers/media/dvb/frontends/tda827x.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
DVB Driver for Philips tda827x / tda827xa Silicon tuners
|
||||
|
||||
(c) 2005 Hartmut Hackmann
|
||||
(c) 2007 Michael Krufky
|
||||
|
||||
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_TDA827X_H__
|
||||
#define __DVB_TDA827X_H__
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
struct tda827x_config
|
||||
{
|
||||
void (*lna_gain) (struct dvb_frontend *fe, int high);
|
||||
int (*init) (struct dvb_frontend *fe);
|
||||
int (*sleep) (struct dvb_frontend *fe);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Attach a tda827x tuner to the supplied frontend structure.
|
||||
*
|
||||
* @param fe Frontend to attach to.
|
||||
* @param addr i2c address of the tuner.
|
||||
* @param i2c i2c adapter to use.
|
||||
* @param cfg optional callback function pointers.
|
||||
* @return FE pointer on success, NULL on failure.
|
||||
*/
|
||||
#if defined(CONFIG_DVB_TDA827X) || (defined(CONFIG_DVB_TDA827X_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr,
|
||||
struct i2c_adapter *i2c,
|
||||
struct tda827x_config *cfg);
|
||||
#else
|
||||
static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe,
|
||||
int addr,
|
||||
struct i2c_adapter *i2c,
|
||||
struct tda827x_config *cfg)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
#endif // CONFIG_DVB_TDA827X
|
||||
|
||||
#endif // __DVB_TDA827X_H__
|
|
@ -2,7 +2,6 @@ config DVB_PLUTO2
|
|||
tristate "Pluto2 cards"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
select I2C_ALGOBIT
|
||||
select DVB_PLL
|
||||
select DVB_TDA1004X
|
||||
help
|
||||
Support for PCI cards based on the Pluto2 FPGA like the Satelco
|
||||
|
|
|
@ -3,7 +3,6 @@ config DVB_AV7110
|
|||
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
|
||||
select FW_LOADER if !DVB_AV7110_FIRMWARE
|
||||
select VIDEO_SAA7146_VV
|
||||
select DVB_PLL
|
||||
select DVB_VES1820 if !DVB_FE_CUSTOMISE
|
||||
select DVB_VES1X93 if !DVB_FE_CUSTOMISE
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
|
@ -62,13 +61,13 @@ config DVB_BUDGET
|
|||
tristate "Budget cards"
|
||||
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
|
||||
select VIDEO_SAA7146
|
||||
select DVB_PLL
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
select DVB_VES1X93 if !DVB_FE_CUSTOMISE
|
||||
select DVB_VES1820 if !DVB_FE_CUSTOMISE
|
||||
select DVB_L64781 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA8083 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
|
||||
select DVB_S5H1420 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA826X if !DVB_FE_CUSTOMISE
|
||||
|
@ -87,7 +86,6 @@ config DVB_BUDGET_CI
|
|||
tristate "Budget cards with onboard CI connector"
|
||||
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
|
||||
select VIDEO_SAA7146
|
||||
select DVB_PLL
|
||||
select DVB_STV0297 if !DVB_FE_CUSTOMISE
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
|
||||
|
@ -114,6 +112,7 @@ config DVB_BUDGET_AV
|
|||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUA6100 if !DVB_FE_CUSTOMISE
|
||||
select FW_LOADER
|
||||
help
|
||||
|
@ -130,7 +129,6 @@ config DVB_BUDGET_PATCH
|
|||
tristate "AV7110 cards with Budget Patch"
|
||||
depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
|
||||
select DVB_AV7110
|
||||
select DVB_PLL
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
select DVB_VES1X93 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA8083 if !DVB_FE_CUSTOMISE
|
||||
|
|
|
@ -219,7 +219,10 @@ static void recover_arm(struct av7110 *av7110)
|
|||
av7110->recover(av7110);
|
||||
|
||||
restart_feeds(av7110);
|
||||
av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
|
||||
|
||||
#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
|
||||
av7110_check_ir_config(av7110, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void av7110_arm_sync(struct av7110 *av7110)
|
||||
|
@ -250,6 +253,10 @@ static int arm_thread(void *data)
|
|||
if (!av7110->arm_ready)
|
||||
continue;
|
||||
|
||||
#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
|
||||
av7110_check_ir_config(av7110, false);
|
||||
#endif
|
||||
|
||||
if (mutex_lock_interruptible(&av7110->dcomlock))
|
||||
break;
|
||||
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
|
||||
|
@ -667,8 +674,8 @@ static void gpioirq(unsigned long data)
|
|||
return;
|
||||
|
||||
case DATA_IRCOMMAND:
|
||||
if (av7110->ir_handler)
|
||||
av7110->ir_handler(av7110,
|
||||
if (av7110->ir.ir_handler)
|
||||
av7110->ir.ir_handler(av7110,
|
||||
swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4)));
|
||||
iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
|
||||
break;
|
||||
|
@ -1907,8 +1914,10 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
|
|||
if (av7110->fe_synced == synced)
|
||||
return 0;
|
||||
|
||||
if (av7110->playing)
|
||||
if (av7110->playing) {
|
||||
av7110->fe_synced = synced;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mutex_lock_interruptible(&av7110->pid_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/socket.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
|
@ -66,6 +67,27 @@ struct dvb_video_events {
|
|||
};
|
||||
|
||||
|
||||
struct av7110;
|
||||
|
||||
/* infrared remote control */
|
||||
struct infrared {
|
||||
u16 key_map[256];
|
||||
struct input_dev *input_dev;
|
||||
char input_phys[32];
|
||||
struct timer_list keyup_timer;
|
||||
struct tasklet_struct ir_tasklet;
|
||||
void (*ir_handler)(struct av7110 *av7110, u32 ircom);
|
||||
u32 ir_command;
|
||||
u32 ir_config;
|
||||
u32 device_mask;
|
||||
u8 protocol;
|
||||
u8 inversion;
|
||||
u16 last_key;
|
||||
u16 last_toggle;
|
||||
u8 delay_timer_finished;
|
||||
};
|
||||
|
||||
|
||||
/* place to store all the necessary device information */
|
||||
struct av7110 {
|
||||
|
||||
|
@ -227,10 +249,7 @@ struct av7110 {
|
|||
u16 wssMode;
|
||||
u16 wssData;
|
||||
|
||||
u32 ir_config;
|
||||
u32 ir_command;
|
||||
void (*ir_handler)(struct av7110 *av7110, u32 ircom);
|
||||
struct tasklet_struct ir_tasklet;
|
||||
struct infrared ir;
|
||||
|
||||
/* firmware stuff */
|
||||
unsigned char *bin_fw;
|
||||
|
@ -268,6 +287,7 @@ struct av7110 {
|
|||
extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
|
||||
u16 subpid, u16 pcrpid);
|
||||
|
||||
extern int av7110_check_ir_config(struct av7110 *av7110, int force);
|
||||
extern int av7110_ir_init(struct av7110 *av7110);
|
||||
extern void av7110_ir_exit(struct av7110 *av7110);
|
||||
|
||||
|
|
|
@ -1009,7 +1009,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
|
|||
if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
|
||||
ret = av7110_av_stop(av7110, RP_VIDEO);
|
||||
else
|
||||
ret = vidcom(av7110, VIDEO_CMD_STOP,
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_STOP,
|
||||
av7110->videostate.video_blank ? 0 : 1);
|
||||
if (!ret)
|
||||
av7110->trickmode = TRICK_NONE;
|
||||
|
@ -1019,7 +1019,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
|
|||
av7110->trickmode = TRICK_NONE;
|
||||
if (av7110->videostate.play_state == VIDEO_FREEZED) {
|
||||
av7110->videostate.play_state = VIDEO_PLAYING;
|
||||
ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
@ -1034,7 +1034,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
|
|||
ret = av7110_av_start_play(av7110, RP_VIDEO);
|
||||
}
|
||||
if (!ret)
|
||||
ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
|
||||
if (!ret)
|
||||
av7110->videostate.play_state = VIDEO_PLAYING;
|
||||
break;
|
||||
|
@ -1044,7 +1044,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
|
|||
if (av7110->playing & RP_VIDEO)
|
||||
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
|
||||
else
|
||||
ret = vidcom(av7110, VIDEO_CMD_FREEZE, 1);
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1);
|
||||
if (!ret)
|
||||
av7110->trickmode = TRICK_FREEZE;
|
||||
break;
|
||||
|
@ -1053,7 +1053,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
|
|||
if (av7110->playing & RP_VIDEO)
|
||||
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
|
||||
if (!ret)
|
||||
ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
|
||||
if (!ret) {
|
||||
av7110->videostate.play_state = VIDEO_PLAYING;
|
||||
av7110->trickmode = TRICK_NONE;
|
||||
|
@ -1136,7 +1136,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
|
|||
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
|
||||
__Scan_I, 2, AV_PES, 0);
|
||||
else
|
||||
ret = vidcom(av7110, VIDEO_CMD_FFWD, arg);
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg);
|
||||
if (!ret) {
|
||||
av7110->trickmode = TRICK_FAST;
|
||||
av7110->videostate.play_state = VIDEO_PLAYING;
|
||||
|
@ -1147,13 +1147,13 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
|
|||
if (av7110->playing&RP_VIDEO) {
|
||||
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
|
||||
if (!ret)
|
||||
ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
|
||||
} else {
|
||||
ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
|
||||
if (!ret)
|
||||
ret = vidcom(av7110, VIDEO_CMD_STOP, 0);
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0);
|
||||
if (!ret)
|
||||
ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
|
||||
}
|
||||
if (!ret) {
|
||||
av7110->trickmode = TRICK_SLOW;
|
||||
|
@ -1182,10 +1182,10 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
|
|||
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
|
||||
__Slow, 2, 0, 0);
|
||||
if (!ret)
|
||||
ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
|
||||
}
|
||||
if (av7110->trickmode == TRICK_FREEZE)
|
||||
ret = vidcom(av7110, VIDEO_CMD_STOP, 1);
|
||||
ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -216,11 +216,11 @@ enum av7110_command_type {
|
|||
#define VID_CENTRE_CUT_PREF 0x05 /* PanScan with zero vector */
|
||||
|
||||
/* MPEG video decoder commands */
|
||||
#define VIDEO_CMD_STOP 0x000e
|
||||
#define VIDEO_CMD_PLAY 0x000d
|
||||
#define VIDEO_CMD_FREEZE 0x0102
|
||||
#define VIDEO_CMD_FFWD 0x0016
|
||||
#define VIDEO_CMD_SLOW 0x0022
|
||||
#define AV_VIDEO_CMD_STOP 0x000e
|
||||
#define AV_VIDEO_CMD_PLAY 0x000d
|
||||
#define AV_VIDEO_CMD_FREEZE 0x0102
|
||||
#define AV_VIDEO_CMD_FFWD 0x0016
|
||||
#define AV_VIDEO_CMD_SLOW 0x0022
|
||||
|
||||
/* MPEG audio decoder commands */
|
||||
#define AUDIO_CMD_MUTE 0x0001
|
||||
|
|
|
@ -1,8 +1,31 @@
|
|||
/*
|
||||
* Driver for the remote control of SAA7146 based AV7110 cards
|
||||
*
|
||||
* Copyright (C) 1999-2003 Holger Waechtler <holger@convergence.de>
|
||||
* Copyright (C) 2003-2007 Oliver Endriss <o.endriss@gmx.de>
|
||||
*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/bitops.h>
|
||||
|
@ -10,18 +33,37 @@
|
|||
#include "av7110.h"
|
||||
#include "av7110_hw.h"
|
||||
|
||||
#define UP_TIMEOUT (HZ*7/25)
|
||||
|
||||
/* enable ir debugging by or'ing debug with 16 */
|
||||
#define AV_CNT 4
|
||||
|
||||
#define IR_RC5 0
|
||||
#define IR_RCMM 1
|
||||
#define IR_RC5_EXT 2 /* internal only */
|
||||
|
||||
#define IR_ALL 0xffffffff
|
||||
|
||||
#define UP_TIMEOUT (HZ*7/25)
|
||||
|
||||
|
||||
/* Note: enable ir debugging by or'ing debug with 16 */
|
||||
|
||||
static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM};
|
||||
module_param_array(ir_protocol, int, NULL, 0644);
|
||||
MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)");
|
||||
|
||||
static int ir_inversion[AV_CNT];
|
||||
module_param_array(ir_inversion, int, NULL, 0644);
|
||||
MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted");
|
||||
|
||||
static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL };
|
||||
module_param_array(ir_device_mask, uint, NULL, 0644);
|
||||
MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)");
|
||||
|
||||
|
||||
static int av_cnt;
|
||||
static struct av7110 *av_list[4];
|
||||
static struct input_dev *input_dev;
|
||||
static char input_phys[32];
|
||||
static struct av7110 *av_list[AV_CNT];
|
||||
|
||||
static u8 delay_timer_finished;
|
||||
|
||||
static u16 key_map [256] = {
|
||||
static u16 default_key_map [256] = {
|
||||
KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
|
||||
KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
|
||||
KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
@ -45,141 +87,194 @@ static u16 key_map [256] = {
|
|||
};
|
||||
|
||||
|
||||
static void av7110_emit_keyup(unsigned long data)
|
||||
/* key-up timer */
|
||||
static void av7110_emit_keyup(unsigned long parm)
|
||||
{
|
||||
if (!data || !test_bit(data, input_dev->key))
|
||||
struct infrared *ir = (struct infrared *) parm;
|
||||
|
||||
if (!ir || !test_bit(ir->last_key, ir->input_dev->key))
|
||||
return;
|
||||
|
||||
input_report_key(input_dev, data, 0);
|
||||
input_sync(input_dev);
|
||||
input_report_key(ir->input_dev, ir->last_key, 0);
|
||||
input_sync(ir->input_dev);
|
||||
}
|
||||
|
||||
|
||||
static struct timer_list keyup_timer = { .function = av7110_emit_keyup };
|
||||
|
||||
|
||||
/* tasklet */
|
||||
static void av7110_emit_key(unsigned long parm)
|
||||
{
|
||||
struct av7110 *av7110 = (struct av7110 *) parm;
|
||||
u32 ir_config = av7110->ir_config;
|
||||
u32 ircom = av7110->ir_command;
|
||||
struct infrared *ir = (struct infrared *) parm;
|
||||
u32 ircom = ir->ir_command;
|
||||
u8 data;
|
||||
u8 addr;
|
||||
static u16 old_toggle = 0;
|
||||
u16 new_toggle;
|
||||
u16 toggle;
|
||||
u16 keycode;
|
||||
|
||||
/* extract device address and data */
|
||||
switch (ir_config & 0x0003) {
|
||||
case 0: /* RC5: 5 bits device address, 6 bits data */
|
||||
switch (ir->protocol) {
|
||||
case IR_RC5: /* RC5: 5 bits device address, 6 bits data */
|
||||
data = ircom & 0x3f;
|
||||
addr = (ircom >> 6) & 0x1f;
|
||||
toggle = ircom & 0x0800;
|
||||
break;
|
||||
|
||||
case 1: /* RCMM: 8(?) bits device address, 8(?) bits data */
|
||||
case IR_RCMM: /* RCMM: ? bits device address, ? bits data */
|
||||
data = ircom & 0xff;
|
||||
addr = (ircom >> 8) & 0xff;
|
||||
addr = (ircom >> 8) & 0x1f;
|
||||
toggle = ircom & 0x8000;
|
||||
break;
|
||||
|
||||
case 2: /* extended RC5: 5 bits device address, 7 bits data */
|
||||
case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */
|
||||
data = ircom & 0x3f;
|
||||
addr = (ircom >> 6) & 0x1f;
|
||||
/* invert 7th data bit for backward compatibility with RC5 keymaps */
|
||||
if (!(ircom & 0x1000))
|
||||
data |= 0x40;
|
||||
toggle = ircom & 0x0800;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("invalid ir_config %x\n", ir_config);
|
||||
printk("%s invalid protocol %x\n", __FUNCTION__, ir->protocol);
|
||||
return;
|
||||
}
|
||||
|
||||
keycode = key_map[data];
|
||||
input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data);
|
||||
input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
|
||||
|
||||
dprintk(16, "code %08x -> addr %i data 0x%02x -> keycode %i\n",
|
||||
ircom, addr, data, keycode);
|
||||
keycode = ir->key_map[data];
|
||||
|
||||
/* check device address (if selected) */
|
||||
if (ir_config & 0x4000)
|
||||
if (addr != ((ir_config >> 16) & 0xff))
|
||||
return;
|
||||
dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n",
|
||||
__FUNCTION__, ircom, addr, data, keycode);
|
||||
|
||||
/* check device address */
|
||||
if (!(ir->device_mask & (1 << addr)))
|
||||
return;
|
||||
|
||||
if (!keycode) {
|
||||
printk ("%s: unknown key 0x%02x!!\n", __FUNCTION__, data);
|
||||
printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n",
|
||||
__FUNCTION__, ircom, addr, data);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ir_config & 0x0003) == 1)
|
||||
new_toggle = 0; /* RCMM */
|
||||
else
|
||||
new_toggle = (ircom & 0x800); /* RC5, extended RC5 */
|
||||
|
||||
if (timer_pending(&keyup_timer)) {
|
||||
del_timer(&keyup_timer);
|
||||
if (keyup_timer.data != keycode || new_toggle != old_toggle) {
|
||||
delay_timer_finished = 0;
|
||||
input_event(input_dev, EV_KEY, keyup_timer.data, 0);
|
||||
input_event(input_dev, EV_KEY, keycode, 1);
|
||||
input_sync(input_dev);
|
||||
} else if (delay_timer_finished) {
|
||||
input_event(input_dev, EV_KEY, keycode, 2);
|
||||
input_sync(input_dev);
|
||||
if (timer_pending(&ir->keyup_timer)) {
|
||||
del_timer(&ir->keyup_timer);
|
||||
if (ir->last_key != keycode || toggle != ir->last_toggle) {
|
||||
ir->delay_timer_finished = 0;
|
||||
input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
|
||||
input_event(ir->input_dev, EV_KEY, keycode, 1);
|
||||
input_sync(ir->input_dev);
|
||||
} else if (ir->delay_timer_finished) {
|
||||
input_event(ir->input_dev, EV_KEY, keycode, 2);
|
||||
input_sync(ir->input_dev);
|
||||
}
|
||||
} else {
|
||||
delay_timer_finished = 0;
|
||||
input_event(input_dev, EV_KEY, keycode, 1);
|
||||
input_sync(input_dev);
|
||||
ir->delay_timer_finished = 0;
|
||||
input_event(ir->input_dev, EV_KEY, keycode, 1);
|
||||
input_sync(ir->input_dev);
|
||||
}
|
||||
|
||||
keyup_timer.expires = jiffies + UP_TIMEOUT;
|
||||
keyup_timer.data = keycode;
|
||||
ir->last_key = keycode;
|
||||
ir->last_toggle = toggle;
|
||||
|
||||
add_timer(&keyup_timer);
|
||||
ir->keyup_timer.expires = jiffies + UP_TIMEOUT;
|
||||
add_timer(&ir->keyup_timer);
|
||||
|
||||
old_toggle = new_toggle;
|
||||
}
|
||||
|
||||
static void input_register_keys(void)
|
||||
|
||||
/* register with input layer */
|
||||
static void input_register_keys(struct infrared *ir)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(input_dev->keybit, 0, sizeof(input_dev->keybit));
|
||||
set_bit(EV_KEY, ir->input_dev->evbit);
|
||||
set_bit(EV_REP, ir->input_dev->evbit);
|
||||
set_bit(EV_MSC, ir->input_dev->evbit);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key_map); i++) {
|
||||
if (key_map[i] > KEY_MAX)
|
||||
key_map[i] = 0;
|
||||
else if (key_map[i] > KEY_RESERVED)
|
||||
set_bit(key_map[i], input_dev->keybit);
|
||||
set_bit(MSC_RAW, ir->input_dev->mscbit);
|
||||
set_bit(MSC_SCAN, ir->input_dev->mscbit);
|
||||
|
||||
memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) {
|
||||
if (ir->key_map[i] > KEY_MAX)
|
||||
ir->key_map[i] = 0;
|
||||
else if (ir->key_map[i] > KEY_RESERVED)
|
||||
set_bit(ir->key_map[i], ir->input_dev->keybit);
|
||||
}
|
||||
|
||||
ir->input_dev->keycode = ir->key_map;
|
||||
ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
|
||||
ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
|
||||
}
|
||||
|
||||
|
||||
static void input_repeat_key(unsigned long data)
|
||||
/* called by the input driver after rep[REP_DELAY] ms */
|
||||
static void input_repeat_key(unsigned long parm)
|
||||
{
|
||||
/* called by the input driver after rep[REP_DELAY] ms */
|
||||
delay_timer_finished = 1;
|
||||
struct infrared *ir = (struct infrared *) parm;
|
||||
|
||||
ir->delay_timer_finished = 1;
|
||||
}
|
||||
|
||||
|
||||
static int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
|
||||
/* check for configuration changes */
|
||||
int av7110_check_ir_config(struct av7110 *av7110, int force)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
int modified = force;
|
||||
int ret = -ENODEV;
|
||||
|
||||
dprintk(4, "%p\n", av7110);
|
||||
if (av7110) {
|
||||
ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config);
|
||||
av7110->ir_config = ir_config;
|
||||
for (i = 0; i < av_cnt; i++)
|
||||
if (av7110 == av_list[i])
|
||||
break;
|
||||
|
||||
if (i < av_cnt && av7110) {
|
||||
if ((av7110->ir.protocol & 1) != ir_protocol[i] ||
|
||||
av7110->ir.inversion != ir_inversion[i])
|
||||
modified = true;
|
||||
|
||||
if (modified) {
|
||||
/* protocol */
|
||||
if (ir_protocol[i]) {
|
||||
ir_protocol[i] = 1;
|
||||
av7110->ir.protocol = IR_RCMM;
|
||||
av7110->ir.ir_config = 0x0001;
|
||||
} else if (FW_VERSION(av7110->arm_app) >= 0x2620) {
|
||||
av7110->ir.protocol = IR_RC5_EXT;
|
||||
av7110->ir.ir_config = 0x0002;
|
||||
} else {
|
||||
av7110->ir.protocol = IR_RC5;
|
||||
av7110->ir.ir_config = 0x0000;
|
||||
}
|
||||
/* inversion */
|
||||
if (ir_inversion[i]) {
|
||||
ir_inversion[i] = 1;
|
||||
av7110->ir.ir_config |= 0x8000;
|
||||
}
|
||||
av7110->ir.inversion = ir_inversion[i];
|
||||
/* update ARM */
|
||||
ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1,
|
||||
av7110->ir.ir_config);
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
/* address */
|
||||
if (av7110->ir.device_mask != ir_device_mask[i])
|
||||
av7110->ir.device_mask = ir_device_mask[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* /proc/av7110_ir interface */
|
||||
static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
char *page;
|
||||
int size = 4 + 256 * sizeof(u16);
|
||||
u32 ir_config;
|
||||
int size = sizeof ir_config + sizeof av_list[0]->ir.key_map;
|
||||
int i;
|
||||
|
||||
if (count < size)
|
||||
|
@ -194,71 +289,86 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
memcpy(&ir_config, page, 4);
|
||||
memcpy(&key_map, page + 4, 256 * sizeof(u16));
|
||||
memcpy(&ir_config, page, sizeof ir_config);
|
||||
|
||||
for (i = 0; i < av_cnt; i++) {
|
||||
/* keymap */
|
||||
memcpy(av_list[i]->ir.key_map, page + sizeof ir_config,
|
||||
sizeof(av_list[i]->ir.key_map));
|
||||
/* protocol, inversion, address */
|
||||
ir_protocol[i] = ir_config & 0x0001;
|
||||
ir_inversion[i] = ir_config & 0x8000 ? 1 : 0;
|
||||
if (ir_config & 0x4000)
|
||||
ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f);
|
||||
else
|
||||
ir_device_mask[i] = IR_ALL;
|
||||
/* update configuration */
|
||||
av7110_check_ir_config(av_list[i], false);
|
||||
input_register_keys(&av_list[i]->ir);
|
||||
}
|
||||
vfree(page);
|
||||
if (FW_VERSION(av_list[0]->arm_app) >= 0x2620 && !(ir_config & 0x0001))
|
||||
ir_config |= 0x0002; /* enable extended RC5 */
|
||||
for (i = 0; i < av_cnt; i++)
|
||||
av7110_setup_irc_config(av_list[i], ir_config);
|
||||
input_register_keys();
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* interrupt handler */
|
||||
static void ir_handler(struct av7110 *av7110, u32 ircom)
|
||||
{
|
||||
dprintk(4, "ircommand = %08x\n", ircom);
|
||||
av7110->ir_command = ircom;
|
||||
tasklet_schedule(&av7110->ir_tasklet);
|
||||
dprintk(4, "ir command = %08x\n", ircom);
|
||||
av7110->ir.ir_command = ircom;
|
||||
tasklet_schedule(&av7110->ir.ir_tasklet);
|
||||
}
|
||||
|
||||
|
||||
int __devinit av7110_ir_init(struct av7110 *av7110)
|
||||
{
|
||||
struct input_dev *input_dev;
|
||||
static struct proc_dir_entry *e;
|
||||
int err;
|
||||
|
||||
if (av_cnt >= ARRAY_SIZE(av_list))
|
||||
return -ENOSPC;
|
||||
|
||||
av7110_setup_irc_config(av7110, 0x0001);
|
||||
av_list[av_cnt++] = av7110;
|
||||
av7110_check_ir_config(av7110, true);
|
||||
|
||||
init_timer(&av7110->ir.keyup_timer);
|
||||
av7110->ir.keyup_timer.function = av7110_emit_keyup;
|
||||
av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir;
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
av7110->ir.input_dev = input_dev;
|
||||
snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys),
|
||||
"pci-%s/ir0", pci_name(av7110->dev->pci));
|
||||
|
||||
input_dev->name = "DVB on-card IR receiver";
|
||||
|
||||
input_dev->phys = av7110->ir.input_phys;
|
||||
input_dev->id.bustype = BUS_PCI;
|
||||
input_dev->id.version = 2;
|
||||
if (av7110->dev->pci->subsystem_vendor) {
|
||||
input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
|
||||
input_dev->id.product = av7110->dev->pci->subsystem_device;
|
||||
} else {
|
||||
input_dev->id.vendor = av7110->dev->pci->vendor;
|
||||
input_dev->id.product = av7110->dev->pci->device;
|
||||
}
|
||||
input_dev->cdev.dev = &av7110->dev->pci->dev;
|
||||
/* initial keymap */
|
||||
memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
|
||||
input_register_keys(&av7110->ir);
|
||||
err = input_register_device(input_dev);
|
||||
if (err) {
|
||||
input_free_device(input_dev);
|
||||
return err;
|
||||
}
|
||||
input_dev->timer.function = input_repeat_key;
|
||||
input_dev->timer.data = (unsigned long) &av7110->ir;
|
||||
|
||||
if (av_cnt == 1) {
|
||||
init_timer(&keyup_timer);
|
||||
keyup_timer.data = 0;
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(input_phys, sizeof(input_phys),
|
||||
"pci-%s/ir0", pci_name(av7110->dev->pci));
|
||||
|
||||
input_dev->name = "DVB on-card IR receiver";
|
||||
|
||||
input_dev->phys = input_phys;
|
||||
input_dev->id.bustype = BUS_PCI;
|
||||
input_dev->id.version = 1;
|
||||
if (av7110->dev->pci->subsystem_vendor) {
|
||||
input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
|
||||
input_dev->id.product = av7110->dev->pci->subsystem_device;
|
||||
} else {
|
||||
input_dev->id.vendor = av7110->dev->pci->vendor;
|
||||
input_dev->id.product = av7110->dev->pci->device;
|
||||
}
|
||||
input_dev->cdev.dev = &av7110->dev->pci->dev;
|
||||
set_bit(EV_KEY, input_dev->evbit);
|
||||
set_bit(EV_REP, input_dev->evbit);
|
||||
input_register_keys();
|
||||
err = input_register_device(input_dev);
|
||||
if (err) {
|
||||
input_free_device(input_dev);
|
||||
return err;
|
||||
}
|
||||
input_dev->timer.function = input_repeat_key;
|
||||
|
||||
e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL);
|
||||
if (e) {
|
||||
e->write_proc = av7110_ir_write_proc;
|
||||
|
@ -266,8 +376,8 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
|
|||
}
|
||||
}
|
||||
|
||||
tasklet_init(&av7110->ir_tasklet, av7110_emit_key, (unsigned long) av7110);
|
||||
av7110->ir_handler = ir_handler;
|
||||
tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir);
|
||||
av7110->ir.ir_handler = ir_handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -280,8 +390,10 @@ void __devexit av7110_ir_exit(struct av7110 *av7110)
|
|||
if (av_cnt == 0)
|
||||
return;
|
||||
|
||||
av7110->ir_handler = NULL;
|
||||
tasklet_kill(&av7110->ir_tasklet);
|
||||
del_timer_sync(&av7110->ir.keyup_timer);
|
||||
av7110->ir.ir_handler = NULL;
|
||||
tasklet_kill(&av7110->ir.ir_tasklet);
|
||||
|
||||
for (i = 0; i < av_cnt; i++)
|
||||
if (av_list[i] == av7110) {
|
||||
av_list[i] = av_list[av_cnt-1];
|
||||
|
@ -289,14 +401,13 @@ void __devexit av7110_ir_exit(struct av7110 *av7110)
|
|||
break;
|
||||
}
|
||||
|
||||
if (av_cnt == 1) {
|
||||
del_timer_sync(&keyup_timer);
|
||||
if (av_cnt == 1)
|
||||
remove_proc_entry("av7110_ir", NULL);
|
||||
input_unregister_device(input_dev);
|
||||
}
|
||||
|
||||
input_unregister_device(av7110->ir.input_dev);
|
||||
|
||||
av_cnt--;
|
||||
}
|
||||
|
||||
//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>");
|
||||
//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>");
|
||||
//MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
#include "budget.h"
|
||||
#include "stv0299.h"
|
||||
#include "tda10021.h"
|
||||
#include "tda1002x.h"
|
||||
#include "tda1004x.h"
|
||||
#include "tua6100.h"
|
||||
#include "dvb-pll.h"
|
||||
|
@ -66,9 +66,6 @@ struct budget_av {
|
|||
int slot_status;
|
||||
struct dvb_ca_en50221 ca;
|
||||
u8 reinitialise_demod:1;
|
||||
u8 tda10021_poclkp:1;
|
||||
u8 tda10021_ts_enabled;
|
||||
int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
|
||||
};
|
||||
|
||||
static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);
|
||||
|
@ -234,12 +231,6 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
|
|||
if (budget_av->reinitialise_demod)
|
||||
dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
|
||||
|
||||
/* set tda10021 back to original clock configuration on reset */
|
||||
if (budget_av->tda10021_poclkp) {
|
||||
tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
|
||||
budget_av->tda10021_ts_enabled = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -256,11 +247,6 @@ static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
|
|||
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
|
||||
budget_av->slot_status = SLOTSTATUS_NONE;
|
||||
|
||||
/* set tda10021 back to original clock configuration when cam removed */
|
||||
if (budget_av->tda10021_poclkp) {
|
||||
tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
|
||||
budget_av->tda10021_ts_enabled = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -276,12 +262,6 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
|
|||
|
||||
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
|
||||
|
||||
/* tda10021 seems to need a different TS clock config when data is routed to the CAM */
|
||||
if (budget_av->tda10021_poclkp) {
|
||||
tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
|
||||
budget_av->tda10021_ts_enabled = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -631,37 +611,62 @@ static struct stv0299_config cinergy_1200s_1894_0010_config = {
|
|||
static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct budget *budget = (struct budget *) fe->dvb->priv;
|
||||
u8 buf[4];
|
||||
u8 buf[6];
|
||||
struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
|
||||
int i;
|
||||
|
||||
#define CU1216_IF 36125000
|
||||
#define TUNER_MUL 62500
|
||||
|
||||
u32 div = (params->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
|
||||
u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
|
||||
|
||||
buf[0] = (div >> 8) & 0x7f;
|
||||
buf[1] = div & 0xff;
|
||||
buf[2] = 0x86;
|
||||
buf[2] = 0xce;
|
||||
buf[3] = (params->frequency < 150000000 ? 0x01 :
|
||||
params->frequency < 445000000 ? 0x02 : 0x04);
|
||||
buf[4] = 0xde;
|
||||
buf[5] = 0x20;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
|
||||
return -EIO;
|
||||
|
||||
/* wait for the pll lock */
|
||||
msg.flags = I2C_M_RD;
|
||||
msg.len = 1;
|
||||
for (i = 0; i < 20; i++) {
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40))
|
||||
break;
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
/* switch the charge pump to the lower current */
|
||||
msg.flags = 0;
|
||||
msg.len = 2;
|
||||
msg.buf = &buf[2];
|
||||
buf[2] &= ~0x40;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tda10021_config philips_cu1216_config = {
|
||||
static struct tda1002x_config philips_cu1216_config = {
|
||||
.demod_address = 0x0c,
|
||||
.invert = 1,
|
||||
};
|
||||
|
||||
static struct tda10021_config philips_cu1216_config_altaddress = {
|
||||
static struct tda1002x_config philips_cu1216_config_altaddress = {
|
||||
.demod_address = 0x0d,
|
||||
.invert = 0,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct budget *budget = (struct budget *) fe->dvb->priv;
|
||||
|
@ -908,41 +913,28 @@ static u8 read_pwm(struct budget_av *budget_av)
|
|||
return pwm;
|
||||
}
|
||||
|
||||
#define SUBID_DVBS_KNC1 0x0010
|
||||
#define SUBID_DVBS_KNC1_PLUS 0x0011
|
||||
#define SUBID_DVBS_TYPHOON 0x4f56
|
||||
#define SUBID_DVBS_CINERGY1200 0x1154
|
||||
#define SUBID_DVBS_CYNERGY1200N 0x1155
|
||||
#define SUBID_DVBS_KNC1 0x0010
|
||||
#define SUBID_DVBS_KNC1_PLUS 0x0011
|
||||
#define SUBID_DVBS_TYPHOON 0x4f56
|
||||
#define SUBID_DVBS_CINERGY1200 0x1154
|
||||
#define SUBID_DVBS_CYNERGY1200N 0x1155
|
||||
#define SUBID_DVBS_TV_STAR 0x0014
|
||||
#define SUBID_DVBS_TV_STAR_CI 0x0016
|
||||
#define SUBID_DVBS_EASYWATCH_1 0x001a
|
||||
#define SUBID_DVBS_EASYWATCH 0x001e
|
||||
|
||||
#define SUBID_DVBS_TV_STAR 0x0014
|
||||
#define SUBID_DVBS_TV_STAR_CI 0x0016
|
||||
#define SUBID_DVBS_EASYWATCH_1 0x001a
|
||||
#define SUBID_DVBS_EASYWATCH 0x001e
|
||||
#define SUBID_DVBC_EASYWATCH 0x002a
|
||||
#define SUBID_DVBC_KNC1 0x0020
|
||||
#define SUBID_DVBC_KNC1_PLUS 0x0021
|
||||
#define SUBID_DVBC_CINERGY1200 0x1156
|
||||
#define SUBID_DVBC_EASYWATCH 0x002a
|
||||
#define SUBID_DVBC_EASYWATCH_MK3 0x002c
|
||||
#define SUBID_DVBC_KNC1 0x0020
|
||||
#define SUBID_DVBC_KNC1_PLUS 0x0021
|
||||
#define SUBID_DVBC_KNC1_MK3 0x0022
|
||||
#define SUBID_DVBC_KNC1_PLUS_MK3 0x0023
|
||||
#define SUBID_DVBC_CINERGY1200 0x1156
|
||||
#define SUBID_DVBC_CINERGY1200_MK3 0x1176
|
||||
|
||||
#define SUBID_DVBT_KNC1_PLUS 0x0031
|
||||
#define SUBID_DVBT_KNC1 0x0030
|
||||
#define SUBID_DVBT_CINERGY1200 0x1157
|
||||
|
||||
|
||||
static int tda10021_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
{
|
||||
struct budget_av* budget_av = fe->dvb->priv;
|
||||
int result;
|
||||
|
||||
result = budget_av->tda10021_set_frontend(fe, p);
|
||||
if (budget_av->tda10021_ts_enabled) {
|
||||
tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
|
||||
} else {
|
||||
tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#define SUBID_DVBT_KNC1_PLUS 0x0031
|
||||
#define SUBID_DVBT_KNC1 0x0030
|
||||
#define SUBID_DVBT_CINERGY1200 0x1157
|
||||
|
||||
static void frontend_init(struct budget_av *budget_av)
|
||||
{
|
||||
|
@ -961,6 +953,7 @@ static void frontend_init(struct budget_av *budget_av)
|
|||
case SUBID_DVBC_KNC1_PLUS:
|
||||
case SUBID_DVBT_KNC1_PLUS:
|
||||
case SUBID_DVBC_EASYWATCH:
|
||||
case SUBID_DVBC_KNC1_PLUS_MK3:
|
||||
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
|
||||
break;
|
||||
}
|
||||
|
@ -1017,6 +1010,7 @@ static void frontend_init(struct budget_av *budget_av)
|
|||
case SUBID_DVBC_CINERGY1200:
|
||||
case SUBID_DVBC_EASYWATCH:
|
||||
budget_av->reinitialise_demod = 1;
|
||||
budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
|
||||
fe = dvb_attach(tda10021_attach, &philips_cu1216_config,
|
||||
&budget_av->budget.i2c_adap,
|
||||
read_pwm(budget_av));
|
||||
|
@ -1025,9 +1019,20 @@ static void frontend_init(struct budget_av *budget_av)
|
|||
&budget_av->budget.i2c_adap,
|
||||
read_pwm(budget_av));
|
||||
if (fe) {
|
||||
budget_av->tda10021_poclkp = 1;
|
||||
budget_av->tda10021_set_frontend = fe->ops.set_frontend;
|
||||
fe->ops.set_frontend = tda10021_set_frontend;
|
||||
fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUBID_DVBC_EASYWATCH_MK3:
|
||||
case SUBID_DVBC_CINERGY1200_MK3:
|
||||
case SUBID_DVBC_KNC1_MK3:
|
||||
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));
|
||||
if (fe) {
|
||||
fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
|
||||
}
|
||||
break;
|
||||
|
@ -1260,12 +1265,16 @@ MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
|
|||
MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
|
||||
MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
|
||||
MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
|
||||
MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
|
||||
MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
|
||||
MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
|
||||
MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3);
|
||||
MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3);
|
||||
MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
|
||||
MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
|
||||
MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
|
||||
MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
|
||||
MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3);
|
||||
MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
|
||||
|
||||
static struct pci_device_id pci_tbl[] = {
|
||||
|
@ -1279,13 +1288,17 @@ static struct pci_device_id pci_tbl[] = {
|
|||
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
|
||||
MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
|
||||
MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
|
||||
MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
|
||||
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
|
||||
MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
|
||||
MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022),
|
||||
MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023),
|
||||
MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
|
||||
MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031),
|
||||
MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
|
||||
MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155),
|
||||
MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
|
||||
MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176),
|
||||
MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
|
||||
{
|
||||
.vendor = 0,
|
||||
|
|
|
@ -73,21 +73,15 @@
|
|||
#define SLOTSTATUS_READY 8
|
||||
#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
|
||||
|
||||
/* Milliseconds during which key presses are regarded as key repeat and during
|
||||
* which the debounce logic is active
|
||||
/*
|
||||
* Milliseconds during which a key is regarded as pressed.
|
||||
* If an identical command arrives within this time, the timer will start over.
|
||||
*/
|
||||
#define IR_REPEAT_TIMEOUT 350
|
||||
#define IR_KEYPRESS_TIMEOUT 250
|
||||
|
||||
/* RC5 device wildcard */
|
||||
#define IR_DEVICE_ANY 255
|
||||
|
||||
/* Some remotes sends multiple sequences per keypress (e.g. Zenith sends two),
|
||||
* this setting allows the superflous sequences to be ignored
|
||||
*/
|
||||
static int debounce = 0;
|
||||
module_param(debounce, int, 0644);
|
||||
MODULE_PARM_DESC(debounce, "ignore repeated IR sequences (default: 0 = ignore no sequences)");
|
||||
|
||||
static int rc5_device = -1;
|
||||
module_param(rc5_device, int, 0644);
|
||||
MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
|
||||
|
@ -99,10 +93,14 @@ MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
|
|||
struct budget_ci_ir {
|
||||
struct input_dev *dev;
|
||||
struct tasklet_struct msp430_irq_tasklet;
|
||||
struct timer_list timer_keyup;
|
||||
char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
|
||||
char phys[32];
|
||||
struct ir_input_state state;
|
||||
int rc5_device;
|
||||
u32 last_raw;
|
||||
u32 ir_key;
|
||||
bool have_command;
|
||||
};
|
||||
|
||||
struct budget_ci {
|
||||
|
@ -125,13 +123,8 @@ static void msp430_ir_interrupt(unsigned long data)
|
|||
{
|
||||
struct budget_ci *budget_ci = (struct budget_ci *) data;
|
||||
struct input_dev *dev = budget_ci->ir.dev;
|
||||
static int bounces = 0;
|
||||
int device;
|
||||
int toggle;
|
||||
static int prev_toggle = -1;
|
||||
static u32 ir_key;
|
||||
static int state = 0;
|
||||
u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
|
||||
u32 raw;
|
||||
|
||||
/*
|
||||
* The msp430 chip can generate two different bytes, command and device
|
||||
|
@ -143,7 +136,7 @@ static void msp430_ir_interrupt(unsigned long data)
|
|||
* bytes and one or more device bytes. For the repeated bytes, the
|
||||
* highest bit (X) is set. The first command byte is always generated
|
||||
* before the first device byte. Other than that, no specific order
|
||||
* seems to apply.
|
||||
* seems to apply. To make life interesting, bytes can also be lost.
|
||||
*
|
||||
* Only when we have a command and device byte, a keypress is
|
||||
* generated.
|
||||
|
@ -152,53 +145,35 @@ static void msp430_ir_interrupt(unsigned long data)
|
|||
if (ir_debug)
|
||||
printk("budget_ci: received byte 0x%02x\n", command);
|
||||
|
||||
/* Is this a repeated byte? */
|
||||
if (command & 0x80)
|
||||
return;
|
||||
/* Remove repeat bit, we use every command */
|
||||
command = command & 0x7f;
|
||||
|
||||
/* Is this a RC5 command byte? */
|
||||
if (command & 0x40) {
|
||||
state = 1;
|
||||
ir_key = command & 0x3f;
|
||||
budget_ci->ir.have_command = true;
|
||||
budget_ci->ir.ir_key = command & 0x3f;
|
||||
return;
|
||||
}
|
||||
|
||||
/* It's a RC5 device byte */
|
||||
if (!state)
|
||||
if (!budget_ci->ir.have_command)
|
||||
return;
|
||||
state = 0;
|
||||
device = command & 0x1f;
|
||||
toggle = command & 0x20;
|
||||
budget_ci->ir.have_command = false;
|
||||
|
||||
if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && budget_ci->ir.rc5_device != device)
|
||||
if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
|
||||
budget_ci->ir.rc5_device != (command & 0x1f))
|
||||
return;
|
||||
|
||||
/* Ignore repeated key sequences if requested */
|
||||
if (toggle == prev_toggle && ir_key == dev->repeat_key &&
|
||||
bounces > 0 && timer_pending(&dev->timer)) {
|
||||
if (ir_debug)
|
||||
printk("budget_ci: debounce logic ignored IR command\n");
|
||||
bounces--;
|
||||
return;
|
||||
}
|
||||
prev_toggle = toggle;
|
||||
|
||||
/* Are we still waiting for a keyup event? */
|
||||
if (del_timer(&dev->timer))
|
||||
ir_input_nokey(dev, &budget_ci->ir.state);
|
||||
|
||||
/* Generate keypress */
|
||||
if (ir_debug)
|
||||
printk("budget_ci: generating keypress 0x%02x\n", ir_key);
|
||||
ir_input_keydown(dev, &budget_ci->ir.state, ir_key, (ir_key & (command << 8)));
|
||||
|
||||
/* Do we want to delay the keyup event? */
|
||||
if (debounce) {
|
||||
bounces = debounce;
|
||||
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(IR_REPEAT_TIMEOUT));
|
||||
} else {
|
||||
/* Is this a repeated key sequence? (same device, command, toggle) */
|
||||
raw = budget_ci->ir.ir_key | (command << 8);
|
||||
if (budget_ci->ir.last_raw != raw || !timer_pending(&budget_ci->ir.timer_keyup)) {
|
||||
ir_input_nokey(dev, &budget_ci->ir.state);
|
||||
ir_input_keydown(dev, &budget_ci->ir.state,
|
||||
budget_ci->ir.ir_key, raw);
|
||||
budget_ci->ir.last_raw = raw;
|
||||
}
|
||||
|
||||
mod_timer(&budget_ci->ir.timer_keyup, jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT));
|
||||
}
|
||||
|
||||
static int msp430_ir_init(struct budget_ci *budget_ci)
|
||||
|
@ -271,16 +246,21 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
|||
break;
|
||||
}
|
||||
|
||||
/* initialise the key-up debounce timeout handler */
|
||||
input_dev->timer.function = msp430_ir_keyup;
|
||||
input_dev->timer.data = (unsigned long) &budget_ci->ir;
|
||||
|
||||
/* initialise the key-up timeout handler */
|
||||
init_timer(&budget_ci->ir.timer_keyup);
|
||||
budget_ci->ir.timer_keyup.function = msp430_ir_keyup;
|
||||
budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir;
|
||||
budget_ci->ir.last_raw = 0xffff; /* An impossible value */
|
||||
error = input_register_device(input_dev);
|
||||
if (error) {
|
||||
printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
|
||||
goto out2;
|
||||
}
|
||||
|
||||
/* note: these must be after input_register_device */
|
||||
input_dev->rep[REP_DELAY] = 400;
|
||||
input_dev->rep[REP_PERIOD] = 250;
|
||||
|
||||
tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
|
||||
(unsigned long) budget_ci);
|
||||
|
||||
|
@ -304,10 +284,8 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci)
|
|||
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
|
||||
tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
|
||||
|
||||
if (del_timer(&dev->timer)) {
|
||||
ir_input_nokey(dev, &budget_ci->ir.state);
|
||||
input_sync(dev);
|
||||
}
|
||||
del_timer_sync(&dev->timer);
|
||||
ir_input_nokey(dev, &budget_ci->ir.state);
|
||||
|
||||
input_unregister_device(dev);
|
||||
}
|
||||
|
|
|
@ -41,11 +41,14 @@
|
|||
|
||||
#define TS_WIDTH (2 * TS_SIZE)
|
||||
#define TS_WIDTH_ACTIVY TS_SIZE
|
||||
#define TS_WIDTH_DVBC TS_SIZE
|
||||
#define TS_HEIGHT_MASK 0xf00
|
||||
#define TS_HEIGHT_MASK_ACTIVY 0xc00
|
||||
#define TS_HEIGHT_MASK_DVBC 0xe00
|
||||
#define TS_MIN_BUFSIZE_K 188
|
||||
#define TS_MAX_BUFSIZE_K 1410
|
||||
#define TS_MAX_BUFSIZE_K_ACTIVY 564
|
||||
#define TS_MAX_BUFSIZE_K_DVBC 1316
|
||||
#define BUFFER_WARNING_WAIT (30*HZ)
|
||||
|
||||
int budget_debug;
|
||||
|
@ -106,6 +109,19 @@ static int start_ts_capture(struct budget *budget)
|
|||
saa7146_write(dev, MC2, (MASK_10 | MASK_26));
|
||||
saa7146_write(dev, BRS_CTRL, 0x60000000);
|
||||
break;
|
||||
case BUDGET_CIN1200C_MK3:
|
||||
case BUDGET_KNC1C_MK3:
|
||||
case BUDGET_KNC1CP_MK3:
|
||||
if (budget->video_port == BUDGET_VIDEO_PORTA) {
|
||||
saa7146_write(dev, DD1_INIT, 0x06000200);
|
||||
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
|
||||
saa7146_write(dev, BRS_CTRL, 0x00000000);
|
||||
} else {
|
||||
saa7146_write(dev, DD1_INIT, 0x00000600);
|
||||
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
|
||||
saa7146_write(dev, BRS_CTRL, 0x60000000);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (budget->video_port == BUDGET_VIDEO_PORTA) {
|
||||
saa7146_write(dev, DD1_INIT, 0x06000200);
|
||||
|
@ -122,7 +138,13 @@ static int start_ts_capture(struct budget *budget)
|
|||
mdelay(10);
|
||||
|
||||
saa7146_write(dev, BASE_ODD3, 0);
|
||||
saa7146_write(dev, BASE_EVEN3, 0);
|
||||
if (budget->buffer_size > budget->buffer_height * budget->buffer_width) {
|
||||
// using odd/even buffers
|
||||
saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width);
|
||||
} else {
|
||||
// using a single buffer
|
||||
saa7146_write(dev, BASE_EVEN3, 0);
|
||||
}
|
||||
saa7146_write(dev, PROT_ADDR3, budget->buffer_size);
|
||||
saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90);
|
||||
|
||||
|
@ -399,11 +421,25 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
|
|||
budget->card = bi;
|
||||
budget->dev = (struct saa7146_dev *) dev;
|
||||
|
||||
if (budget->card->type == BUDGET_FS_ACTIVY) {
|
||||
switch(budget->card->type) {
|
||||
case BUDGET_FS_ACTIVY:
|
||||
budget->buffer_width = TS_WIDTH_ACTIVY;
|
||||
max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY;
|
||||
height_mask = TS_HEIGHT_MASK_ACTIVY;
|
||||
} else {
|
||||
break;
|
||||
|
||||
case BUDGET_KNC1C:
|
||||
case BUDGET_KNC1CP:
|
||||
case BUDGET_CIN1200C:
|
||||
case BUDGET_KNC1C_MK3:
|
||||
case BUDGET_KNC1CP_MK3:
|
||||
case BUDGET_CIN1200C_MK3:
|
||||
budget->buffer_width = TS_WIDTH_DVBC;
|
||||
max_bufsize = TS_MAX_BUFSIZE_K_DVBC;
|
||||
height_mask = TS_HEIGHT_MASK_DVBC;
|
||||
break;
|
||||
|
||||
default:
|
||||
budget->buffer_width = TS_WIDTH;
|
||||
max_bufsize = TS_MAX_BUFSIZE_K;
|
||||
height_mask = TS_HEIGHT_MASK;
|
||||
|
@ -415,14 +451,22 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
|
|||
dma_buffer_size = max_bufsize;
|
||||
|
||||
budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width;
|
||||
budget->buffer_height &= height_mask;
|
||||
budget->buffer_size = budget->buffer_height * budget->buffer_width;
|
||||
if (budget->buffer_height > 0xfff) {
|
||||
budget->buffer_height /= 2;
|
||||
budget->buffer_height &= height_mask;
|
||||
budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width;
|
||||
} else {
|
||||
budget->buffer_height &= height_mask;
|
||||
budget->buffer_size = budget->buffer_height * budget->buffer_width;
|
||||
}
|
||||
budget->buffer_warning_threshold = budget->buffer_size * 80/100;
|
||||
budget->buffer_warnings = 0;
|
||||
budget->buffer_warning_time = jiffies;
|
||||
|
||||
dprintk(2, "%s: width = %d, height = %d\n",
|
||||
budget->dev->name, budget->buffer_width, budget->buffer_height);
|
||||
dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n",
|
||||
budget->dev->name,
|
||||
budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single",
|
||||
budget->buffer_width, budget->buffer_height);
|
||||
printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
|
||||
|
||||
if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) {
|
||||
|
|
|
@ -99,6 +99,9 @@ static struct saa7146_pci_extension_data x_var = { \
|
|||
#define BUDGET_KNC1CP 12
|
||||
#define BUDGET_KNC1TP 13
|
||||
#define BUDGET_TVSTAR 14
|
||||
#define BUDGET_CIN1200C_MK3 15
|
||||
#define BUDGET_KNC1C_MK3 16
|
||||
#define BUDGET_KNC1CP_MK3 17
|
||||
|
||||
#define BUDGET_VIDEO_PORTA 0
|
||||
#define BUDGET_VIDEO_PORTB 1
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
config DVB_TTUSB_BUDGET
|
||||
tristate "Technotrend/Hauppauge Nova-USB devices"
|
||||
depends on DVB_CORE && USB && I2C
|
||||
select DVB_PLL
|
||||
select DVB_CX22700 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
|
||||
select DVB_VES1820 if !DVB_FE_CUSTOMISE
|
||||
|
|
|
@ -231,129 +231,149 @@ static struct v4l2_queryctrl radio_qctrl[] = {
|
|||
}
|
||||
};
|
||||
|
||||
static int rt_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct rt_device *rt=dev->priv;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-aimslab", sizeof (v->driver));
|
||||
strlcpy(v->card, "RadioTrack", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
v->rangelow=(87*16000);
|
||||
v->rangehigh=(108*16000);
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=0xFFFF*rt_getsigstr(rt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
rt->curfreq = f->frequency;
|
||||
rt_setfreq(rt, rt->curfreq);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = rt->curfreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=rt->muted;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value=rt->curvol * 6554;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
rt_mute(rt);
|
||||
} else {
|
||||
rt_setvol(rt,rt->curvol);
|
||||
}
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
rt_setvol(rt,ctrl->value);
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
rt_do_ioctl);
|
||||
}
|
||||
strlcpy(v->driver, "radio-aimslab", sizeof(v->driver));
|
||||
strlcpy(v->card, "RadioTrack", sizeof(v->card));
|
||||
sprintf(v->bus_info, "ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, rt_do_ioctl);
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct rt_device *rt = dev->priv;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = (87*16000);
|
||||
v->rangehigh = (108*16000);
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal = 0xffff*rt_getsigstr(rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct rt_device *rt = dev->priv;
|
||||
|
||||
rt->curfreq = f->frequency;
|
||||
rt_setfreq(rt, rt->curfreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct rt_device *rt = dev->priv;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = rt->curfreq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct rt_device *rt = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = rt->muted;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value = rt->curvol * 6554;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct rt_device *rt = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value)
|
||||
rt_mute(rt);
|
||||
else
|
||||
rt_setvol(rt,rt->curvol);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
rt_setvol(rt,ctrl->value);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio (struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rt_device rtrack_unit;
|
||||
|
@ -362,7 +382,7 @@ static const struct file_operations rtrack_fops = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = rt_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
@ -374,6 +394,18 @@ static struct video_device rtrack_radio=
|
|||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &rtrack_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
};
|
||||
|
||||
static int __init rtrack_init(void)
|
||||
|
|
|
@ -192,131 +192,158 @@ static inline unsigned int gemtek_pci_getsignal( struct gemtek_pci_card *card )
|
|||
return ( inb( card->iobase ) & 0x08 ) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
strlcpy(v->driver, "radio-gemtek-pci", sizeof(v->driver));
|
||||
strlcpy(v->card, "GemTek PCI Radio", sizeof(v->card));
|
||||
sprintf(v->bus_info, "ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct gemtek_pci_card *card = dev->priv;
|
||||
|
||||
switch ( cmd ) {
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-gemtek-pci", sizeof (v->driver));
|
||||
strlcpy(v->card, "GemTek PCI Radio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
v->rangelow = GEMTEK_PCI_RANGE_LOW;
|
||||
v->rangehigh = GEMTEK_PCI_RANGE_HIGH;
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=0xFFFF*gemtek_pci_getsignal( card );
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) ||
|
||||
(f->frequency > GEMTEK_PCI_RANGE_HIGH) )
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
gemtek_pci_setfrequency( card, f->frequency );
|
||||
card->current_frequency = f->frequency;
|
||||
card->mute = false;
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=card->mute;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (card->mute)
|
||||
ctrl->value=0;
|
||||
else
|
||||
ctrl->value=65535;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
gemtek_pci_mute(card);
|
||||
} else {
|
||||
gemtek_pci_unmute(card);
|
||||
}
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (ctrl->value) {
|
||||
gemtek_pci_unmute(card);
|
||||
} else {
|
||||
gemtek_pci_mute(card);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
gemtek_pci_do_ioctl);
|
||||
}
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = GEMTEK_PCI_RANGE_LOW;
|
||||
v->rangehigh = GEMTEK_PCI_RANGE_HIGH;
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal = 0xffff * gemtek_pci_getsignal(card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gemtek_pci_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, gemtek_pci_do_ioctl);
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct gemtek_pci_card *card = dev->priv;
|
||||
|
||||
if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) ||
|
||||
(f->frequency > GEMTEK_PCI_RANGE_HIGH) )
|
||||
return -EINVAL;
|
||||
gemtek_pci_setfrequency(card, f->frequency);
|
||||
card->current_frequency = f->frequency;
|
||||
card->mute = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct gemtek_pci_card *card = dev->priv;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = card->current_frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct gemtek_pci_card *card = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = card->mute;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (card->mute)
|
||||
ctrl->value = 0;
|
||||
else
|
||||
ctrl->value = 65535;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct gemtek_pci_card *card = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value)
|
||||
gemtek_pci_mute(card);
|
||||
else
|
||||
gemtek_pci_unmute(card);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (ctrl->value)
|
||||
gemtek_pci_unmute(card);
|
||||
else
|
||||
gemtek_pci_mute(card);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
|
@ -342,7 +369,7 @@ static const struct file_operations gemtek_pci_fops = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = gemtek_pci_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
@ -353,6 +380,18 @@ static struct video_device vdev_template = {
|
|||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &gemtek_pci_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
};
|
||||
|
||||
static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id )
|
||||
|
|
|
@ -161,137 +161,157 @@ static int gemtek_getsigstr(struct gemtek_device *dev)
|
|||
return 1; /* signal present */
|
||||
}
|
||||
|
||||
static int gemtek_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct gemtek_device *rt=dev->priv;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-gemtek", sizeof (v->driver));
|
||||
strlcpy(v->card, "GemTek", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
v->rangelow=(87*16000);
|
||||
v->rangehigh=(108*16000);
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=0xFFFF*gemtek_getsigstr(rt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
rt->curfreq = f->frequency;
|
||||
/* needs to be called twice in order for getsigstr to work */
|
||||
gemtek_setfreq(rt, rt->curfreq);
|
||||
gemtek_setfreq(rt, rt->curfreq);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = rt->curfreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=rt->muted;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (rt->muted)
|
||||
ctrl->value=0;
|
||||
else
|
||||
ctrl->value=65535;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
gemtek_mute(rt);
|
||||
} else {
|
||||
gemtek_unmute(rt);
|
||||
}
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (ctrl->value) {
|
||||
gemtek_unmute(rt);
|
||||
} else {
|
||||
gemtek_mute(rt);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
gemtek_do_ioctl);
|
||||
}
|
||||
strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
|
||||
strlcpy(v->card, "GemTek", sizeof(v->card));
|
||||
sprintf(v->bus_info, "ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gemtek_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, gemtek_do_ioctl);
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct gemtek_device *rt = dev->priv;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = (87*16000);
|
||||
v->rangehigh = (108*16000);
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal = 0xffff*gemtek_getsigstr(rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct gemtek_device *rt = dev->priv;
|
||||
|
||||
rt->curfreq = f->frequency;
|
||||
/* needs to be called twice in order for getsigstr to work */
|
||||
gemtek_setfreq(rt, rt->curfreq);
|
||||
gemtek_setfreq(rt, rt->curfreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct gemtek_device *rt = dev->priv;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = rt->curfreq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct gemtek_device *rt = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = rt->muted;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (rt->muted)
|
||||
ctrl->value = 0;
|
||||
else
|
||||
ctrl->value = 65535;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct gemtek_device *rt = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value)
|
||||
gemtek_mute(rt);
|
||||
else
|
||||
gemtek_unmute(rt);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (ctrl->value)
|
||||
gemtek_unmute(rt);
|
||||
else
|
||||
gemtek_mute(rt);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio (struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct gemtek_device gemtek_unit;
|
||||
|
@ -300,7 +320,7 @@ static const struct file_operations gemtek_fops = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = gemtek_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
@ -312,6 +332,18 @@ static struct video_device gemtek_radio=
|
|||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &gemtek_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
};
|
||||
|
||||
static int __init gemtek_init(void)
|
||||
|
|
|
@ -75,8 +75,6 @@ static struct v4l2_queryctrl radio_qctrl[] = {
|
|||
static int radio_nr = -1;
|
||||
module_param(radio_nr, int, 0);
|
||||
|
||||
static int radio_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
|
||||
static void maestro_remove(struct pci_dev *pdev);
|
||||
|
||||
|
@ -102,18 +100,11 @@ static const struct file_operations maestro_fops = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = radio_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
||||
static struct video_device maestro_radio = {
|
||||
.name = "Maestro radio",
|
||||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &maestro_fops,
|
||||
};
|
||||
|
||||
struct radio_device {
|
||||
u16 io, /* base of Maestro card radio io (GPIO_DATA)*/
|
||||
muted, /* VIDEO_AUDIO_MUTE */
|
||||
|
@ -190,142 +181,153 @@ static void radio_bits_set(struct radio_device *dev, u32 data)
|
|||
msleep(125);
|
||||
}
|
||||
|
||||
static inline int radio_function(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct radio_device *card = video_get_drvdata(dev);
|
||||
|
||||
switch (cmd) {
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-maestro", sizeof (v->driver));
|
||||
strlcpy(v->card, "Maestro Radio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"PCI");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
(void)radio_bits_get(card);
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
v->rangelow = FREQ_LO;
|
||||
v->rangehigh = FREQ_HI;
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
if(card->stereo)
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
else
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=card->tuned;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
|
||||
return -EINVAL;
|
||||
radio_bits_set(card, FREQ2BITS(f->frequency));
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = BITS2FREQ(radio_bits_get(card));
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=card->muted;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
{
|
||||
register u16 io = card->io;
|
||||
register u16 omask = inw(io + IO_MASK);
|
||||
outw(~STR_WREN, io + IO_MASK);
|
||||
outw((card->muted = ctrl->value ) ?
|
||||
STR_WREN : 0, io);
|
||||
udelay(4);
|
||||
outw(omask, io + IO_MASK);
|
||||
msleep(125);
|
||||
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
radio_function);
|
||||
}
|
||||
strlcpy(v->driver, "radio-maestro", sizeof(v->driver));
|
||||
strlcpy(v->card, "Maestro Radio", sizeof(v->card));
|
||||
sprintf(v->bus_info, "PCI");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int radio_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct radio_device *card = video_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&card->lock);
|
||||
ret = video_usercopy(inode, file, cmd, arg, radio_function);
|
||||
mutex_unlock(&card->lock);
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return ret;
|
||||
(void)radio_bits_get(card);
|
||||
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = FREQ_LO;
|
||||
v->rangehigh = FREQ_HI;
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
if(card->stereo)
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
else
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal = card->tuned;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct radio_device *card = video_get_drvdata(dev);
|
||||
|
||||
if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
|
||||
return -EINVAL;
|
||||
radio_bits_set(card, FREQ2BITS(f->frequency));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct radio_device *card = video_get_drvdata(dev);
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = BITS2FREQ(radio_bits_get(card));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct radio_device *card = video_get_drvdata(dev);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = card->muted;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct radio_device *card = video_get_drvdata(dev);
|
||||
register u16 io = card->io;
|
||||
register u16 omask = inw(io + IO_MASK);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
outw(~STR_WREN, io + IO_MASK);
|
||||
outw((card->muted = ctrl->value ) ?
|
||||
STR_WREN : 0, io);
|
||||
udelay(4);
|
||||
outw(omask, io + IO_MASK);
|
||||
msleep(125);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 __devinit radio_power_on(struct radio_device *dev)
|
||||
|
@ -352,6 +354,24 @@ static u16 __devinit radio_power_on(struct radio_device *dev)
|
|||
return (ofreq == radio_bits_get(dev));
|
||||
}
|
||||
|
||||
static struct video_device maestro_radio = {
|
||||
.name = "Maestro radio",
|
||||
.type = VID_TYPE_TUNER,
|
||||
.fops = &maestro_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
};
|
||||
|
||||
static int __devinit maestro_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
|
|
|
@ -122,6 +122,26 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver));
|
||||
strlcpy(v->card, "RadioTrack II", sizeof(v->card));
|
||||
sprintf(v->bus_info, "ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt_getsigstr(struct rt_device *dev)
|
||||
{
|
||||
if (inb(io) & 2) /* bit set = no signal present */
|
||||
|
@ -129,135 +149,136 @@ static int rt_getsigstr(struct rt_device *dev)
|
|||
return 1; /* signal present */
|
||||
}
|
||||
|
||||
static int rt_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct rt_device *rt=dev->priv;
|
||||
struct rt_device *rt = dev->priv;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-rtrack2", sizeof (v->driver));
|
||||
strlcpy(v->card, "RadioTrack II", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
v->rangelow=(88*16000);
|
||||
v->rangehigh=(108*16000);
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=0xFFFF*rt_getsigstr(rt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
rt->curfreq = f->frequency;
|
||||
rt_setfreq(rt, rt->curfreq);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = rt->curfreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=rt->muted;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (rt->muted)
|
||||
ctrl->value=0;
|
||||
else
|
||||
ctrl->value=65535;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
rt_mute(rt);
|
||||
} else {
|
||||
rt_unmute(rt);
|
||||
}
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (ctrl->value) {
|
||||
rt_unmute(rt);
|
||||
} else {
|
||||
rt_mute(rt);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
rt_do_ioctl);
|
||||
}
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = (88*16000);
|
||||
v->rangehigh = (108*16000);
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal = 0xFFFF*rt_getsigstr(rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, rt_do_ioctl);
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct rt_device *rt = dev->priv;
|
||||
|
||||
rt->curfreq = f->frequency;
|
||||
rt_setfreq(rt, rt->curfreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct rt_device *rt = dev->priv;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = rt->curfreq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct rt_device *rt = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = rt->muted;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (rt->muted)
|
||||
ctrl->value = 0;
|
||||
else
|
||||
ctrl->value = 65535;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct rt_device *rt = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value)
|
||||
rt_mute(rt);
|
||||
else
|
||||
rt_unmute(rt);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
if (ctrl->value)
|
||||
rt_unmute(rt);
|
||||
else
|
||||
rt_mute(rt);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rt_device rtrack2_unit;
|
||||
|
@ -266,7 +287,7 @@ static const struct file_operations rtrack2_fops = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = rt_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
@ -278,6 +299,18 @@ static struct video_device rtrack2_radio=
|
|||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &rtrack2_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
};
|
||||
|
||||
static int __init rtrack2_init(void)
|
||||
|
|
|
@ -130,137 +130,155 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
|
|||
return (res & 2) ? 0 : 0xFFFF;
|
||||
}
|
||||
|
||||
static int fmi_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmi_device *fmi=dev->priv;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-sf16fmi", sizeof (v->driver));
|
||||
strlcpy(v->card, "SF16-FMx radio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
int mult;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
|
||||
v->rangelow = RSF16_MINFREQ/mult;
|
||||
v->rangehigh = RSF16_MAXFREQ/mult;
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
|
||||
v->capability=fmi->flags&V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
v->signal = fmi_getsigstr(fmi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
|
||||
f->frequency *= 1000;
|
||||
if (f->frequency < RSF16_MINFREQ ||
|
||||
f->frequency > RSF16_MAXFREQ )
|
||||
return -EINVAL;
|
||||
/*rounding in steps of 800 to match th freq
|
||||
that will be used */
|
||||
fmi->curfreq = (f->frequency/800)*800;
|
||||
fmi_setfreq(fmi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = fmi->curfreq;
|
||||
if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
|
||||
f->frequency /= 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=fmi->curvol;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
{
|
||||
if (ctrl->value)
|
||||
fmi_mute(fmi->port);
|
||||
else
|
||||
fmi_unmute(fmi->port);
|
||||
|
||||
fmi->curvol=ctrl->value;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
fmi_do_ioctl);
|
||||
}
|
||||
strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
|
||||
strlcpy(v->card, "SF16-FMx radio", sizeof(v->card));
|
||||
sprintf(v->bus_info, "ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fmi_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, fmi_do_ioctl);
|
||||
int mult;
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmi_device *fmi = dev->priv;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
|
||||
v->rangelow = RSF16_MINFREQ/mult;
|
||||
v->rangehigh = RSF16_MAXFREQ/mult;
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
|
||||
v->capability = fmi->flags&V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
v->signal = fmi_getsigstr(fmi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmi_device *fmi = dev->priv;
|
||||
|
||||
if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
|
||||
f->frequency *= 1000;
|
||||
if (f->frequency < RSF16_MINFREQ ||
|
||||
f->frequency > RSF16_MAXFREQ )
|
||||
return -EINVAL;
|
||||
/*rounding in steps of 800 to match th freq
|
||||
that will be used */
|
||||
fmi->curfreq = (f->frequency/800)*800;
|
||||
fmi_setfreq(fmi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmi_device *fmi = dev->priv;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = fmi->curfreq;
|
||||
if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
|
||||
f->frequency /= 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmi_device *fmi = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = fmi->curvol;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmi_device *fmi = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value)
|
||||
fmi_mute(fmi->port);
|
||||
else
|
||||
fmi_unmute(fmi->port);
|
||||
fmi->curvol = ctrl->value;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fmi_device fmi_unit;
|
||||
|
@ -269,7 +287,7 @@ static const struct file_operations fmi_fops = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = fmi_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
@ -281,6 +299,18 @@ static struct video_device fmi_radio=
|
|||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &fmi_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
};
|
||||
|
||||
/* ladis: this is my card. does any other types exist? */
|
||||
|
|
|
@ -226,186 +226,204 @@ static int fmr2_setvolume(struct fmr2_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fmr2_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver));
|
||||
strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card));
|
||||
sprintf(v->bus_info, "ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
int mult;
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmr2_device *fmr2 = dev->priv;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
|
||||
v->rangelow = RSF16_MINFREQ/mult;
|
||||
v->rangehigh = RSF16_MAXFREQ/mult;
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
|
||||
v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
|
||||
V4L2_TUNER_MODE_MONO;
|
||||
mutex_lock(&lock);
|
||||
v->signal = fmr2_getsigstr(fmr2);
|
||||
mutex_unlock(&lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmr2_device *fmr2 = dev->priv;
|
||||
debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d "
|
||||
"stereo %d type %d\n",
|
||||
fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute,
|
||||
fmr2->stereo, fmr2->card_type));
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-sf16fmr2", sizeof (v->driver));
|
||||
strlcpy(v->card, "SF16-FMR2 radio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
int mult;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
|
||||
v->rangelow = RSF16_MINFREQ/mult;
|
||||
v->rangehigh = RSF16_MAXFREQ/mult;
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
|
||||
v->capability=fmr2->flags&V4L2_TUNER_CAP_LOW;
|
||||
|
||||
v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
|
||||
V4L2_TUNER_MODE_MONO;
|
||||
mutex_lock(&lock);
|
||||
v->signal = fmr2_getsigstr(fmr2);
|
||||
mutex_unlock(&lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
|
||||
f->frequency *= 1000;
|
||||
if (f->frequency < RSF16_MINFREQ ||
|
||||
f->frequency > RSF16_MAXFREQ )
|
||||
return -EINVAL;
|
||||
/*rounding in steps of 200 to match th freq
|
||||
that will be used */
|
||||
fmr2->curfreq = (f->frequency/200)*200;
|
||||
|
||||
/* set card freq (if not muted) */
|
||||
if (fmr2->curvol && !fmr2->mute)
|
||||
{
|
||||
mutex_lock(&lock);
|
||||
fmr2_setfreq(fmr2);
|
||||
mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = fmr2->curfreq;
|
||||
if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
|
||||
f->frequency /= 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if ((fmr2->card_type != 11)
|
||||
&& V4L2_CID_AUDIO_VOLUME)
|
||||
radio_qctrl[i].step=65535;
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=fmr2->mute;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value=fmr2->curvol;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
fmr2->mute=ctrl->value;
|
||||
if (fmr2->card_type != 11) {
|
||||
if (!fmr2->mute) {
|
||||
fmr2->curvol = 65535;
|
||||
} else {
|
||||
fmr2->curvol = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
fmr2->curvol = ctrl->value;
|
||||
if (fmr2->card_type != 11) {
|
||||
if (fmr2->curvol) {
|
||||
fmr2->curvol = 65535;
|
||||
fmr2->mute = 0;
|
||||
} else {
|
||||
fmr2->curvol = 0;
|
||||
fmr2->mute = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (fmr2->curvol && !fmr2->mute)
|
||||
printk(KERN_DEBUG "unmute\n");
|
||||
else
|
||||
printk(KERN_DEBUG "mute\n");
|
||||
#endif
|
||||
mutex_lock(&lock);
|
||||
if (fmr2->curvol && !fmr2->mute) {
|
||||
fmr2_setvolume(fmr2);
|
||||
fmr2_setfreq(fmr2);
|
||||
} else
|
||||
fmr2_mute(fmr2->port);
|
||||
mutex_unlock(&lock);
|
||||
return (0);
|
||||
}
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
fmr2_do_ioctl);
|
||||
if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
|
||||
f->frequency *= 1000;
|
||||
if (f->frequency < RSF16_MINFREQ ||
|
||||
f->frequency > RSF16_MAXFREQ )
|
||||
return -EINVAL;
|
||||
/*rounding in steps of 200 to match th freq
|
||||
that will be used */
|
||||
fmr2->curfreq = (f->frequency/200)*200;
|
||||
|
||||
/* set card freq (if not muted) */
|
||||
if (fmr2->curvol && !fmr2->mute) {
|
||||
mutex_lock(&lock);
|
||||
fmr2_setfreq(fmr2);
|
||||
mutex_unlock(&lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fmr2_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl);
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmr2_device *fmr2 = dev->priv;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = fmr2->curfreq;
|
||||
if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
|
||||
f->frequency /= 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmr2_device *fmr2 = dev->priv;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if ((fmr2->card_type != 11)
|
||||
&& V4L2_CID_AUDIO_VOLUME)
|
||||
radio_qctrl[i].step = 65535;
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmr2_device *fmr2 = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = fmr2->mute;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value = fmr2->curvol;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct fmr2_device *fmr2 = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
fmr2->mute = ctrl->value;
|
||||
if (fmr2->card_type != 11) {
|
||||
if (!fmr2->mute)
|
||||
fmr2->curvol = 65535;
|
||||
else
|
||||
fmr2->curvol = 0;
|
||||
}
|
||||
break;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
fmr2->curvol = ctrl->value;
|
||||
if (fmr2->card_type != 11) {
|
||||
if (fmr2->curvol) {
|
||||
fmr2->curvol = 65535;
|
||||
fmr2->mute = 0;
|
||||
} else {
|
||||
fmr2->curvol = 0;
|
||||
fmr2->mute = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (fmr2->curvol && !fmr2->mute)
|
||||
printk(KERN_DEBUG "unmute\n");
|
||||
else
|
||||
printk(KERN_DEBUG "mute\n");
|
||||
#endif
|
||||
|
||||
mutex_lock(&lock);
|
||||
if (fmr2->curvol && !fmr2->mute) {
|
||||
fmr2_setvolume(fmr2);
|
||||
fmr2_setfreq(fmr2);
|
||||
} else
|
||||
fmr2_mute(fmr2->port);
|
||||
mutex_unlock(&lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fmr2_device fmr2_unit;
|
||||
|
@ -414,7 +432,7 @@ static const struct file_operations fmr2_fops = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = fmr2_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
@ -426,6 +444,18 @@ static struct video_device fmr2_radio=
|
|||
. type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &fmr2_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
};
|
||||
|
||||
static int __init fmr2_init(void)
|
||||
|
|
|
@ -205,135 +205,152 @@ static int tt_getsigstr(struct tt_device *dev) /* TODO */
|
|||
return 1; /* signal present */
|
||||
}
|
||||
|
||||
|
||||
/* implement the video4linux api */
|
||||
|
||||
static int tt_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct tt_device *tt=dev->priv;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-terratec", sizeof (v->driver));
|
||||
strlcpy(v->card, "ActiveRadio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
v->rangelow=(87*16000);
|
||||
v->rangehigh=(108*16000);
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=0xFFFF*tt_getsigstr(tt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
tt->curfreq = f->frequency;
|
||||
tt_setfreq(tt, tt->curfreq);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = tt->curfreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (tt->muted)
|
||||
ctrl->value=1;
|
||||
else
|
||||
ctrl->value=0;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value=tt->curvol * 6554;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
tt_mute(tt);
|
||||
} else {
|
||||
tt_setvol(tt,tt->curvol);
|
||||
}
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
tt_setvol(tt,ctrl->value);
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
tt_do_ioctl);
|
||||
}
|
||||
strlcpy(v->driver, "radio-terratec", sizeof(v->driver));
|
||||
strlcpy(v->card, "ActiveRadio", sizeof(v->card));
|
||||
sprintf(v->bus_info, "ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tt_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, tt_do_ioctl);
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct tt_device *tt = dev->priv;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = (87*16000);
|
||||
v->rangehigh = (108*16000);
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal = 0xFFFF*tt_getsigstr(tt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct tt_device *tt = dev->priv;
|
||||
|
||||
tt->curfreq = f->frequency;
|
||||
tt_setfreq(tt, tt->curfreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct tt_device *tt = dev->priv;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = tt->curfreq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct tt_device *tt = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (tt->muted)
|
||||
ctrl->value = 1;
|
||||
else
|
||||
ctrl->value = 0;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value = tt->curvol * 6554;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct tt_device *tt = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value)
|
||||
tt_mute(tt);
|
||||
else
|
||||
tt_setvol(tt,tt->curvol);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
tt_setvol(tt,ctrl->value);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tt_device terratec_unit;
|
||||
|
@ -342,7 +359,7 @@ static const struct file_operations terratec_fops = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = tt_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
@ -354,6 +371,18 @@ static struct video_device terratec_radio=
|
|||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &terratec_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
};
|
||||
|
||||
static int __init terratec_init(void)
|
||||
|
|
|
@ -192,144 +192,154 @@ static void tr_setfreq(unsigned long f)
|
|||
write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
|
||||
}
|
||||
|
||||
static int tr_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-trust", sizeof (v->driver));
|
||||
strlcpy(v->card, "Trust FM Radio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
v->rangelow=(87.5*16000);
|
||||
v->rangehigh=(108*16000);
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
if(tr_getstereo())
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
else
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=tr_getsigstr();
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
curfreq = f->frequency;
|
||||
tr_setfreq(curfreq);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = curfreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=curmute;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value= curvol * 2048;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_BASS:
|
||||
ctrl->value= curbass * 4370;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_TREBLE:
|
||||
ctrl->value= curtreble * 4370;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
tr_setmute(ctrl->value);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
tr_setvol(ctrl->value);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_BASS:
|
||||
tr_setbass(ctrl->value);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_TREBLE:
|
||||
tr_settreble(ctrl->value);
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
tr_do_ioctl);
|
||||
}
|
||||
strlcpy(v->driver, "radio-trust", sizeof(v->driver));
|
||||
strlcpy(v->card, "Trust FM Radio", sizeof(v->card));
|
||||
sprintf(v->bus_info, "ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tr_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, tr_do_ioctl);
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = (87.5*16000);
|
||||
v->rangehigh = (108*16000);
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
if (tr_getstereo())
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
else
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal = tr_getsigstr();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
curfreq = f->frequency;
|
||||
tr_setfreq(curfreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = curfreq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = curmute;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value = curvol * 2048;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_BASS:
|
||||
ctrl->value = curbass * 4370;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_TREBLE:
|
||||
ctrl->value = curtreble * 4370;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
tr_setmute(ctrl->value);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
tr_setvol(ctrl->value);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_BASS:
|
||||
tr_setbass(ctrl->value);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_TREBLE:
|
||||
tr_settreble(ctrl->value);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations trust_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = tr_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
@ -341,6 +351,18 @@ static struct video_device trust_radio=
|
|||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &trust_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
};
|
||||
|
||||
static int __init trust_init(void)
|
||||
|
|
|
@ -93,8 +93,6 @@ static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency);
|
|||
static void typhoon_mute(struct typhoon_device *dev);
|
||||
static void typhoon_unmute(struct typhoon_device *dev);
|
||||
static int typhoon_setvol(struct typhoon_device *dev, int vol);
|
||||
static int typhoon_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
|
||||
static int typhoon_get_info(char *buf, char **start, off_t offset, int len);
|
||||
#endif
|
||||
|
@ -186,129 +184,148 @@ static int typhoon_setvol(struct typhoon_device *dev, int vol)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
strlcpy(v->driver, "radio-typhoon", sizeof(v->driver));
|
||||
strlcpy(v->card, "Typhoon Radio", sizeof(v->card));
|
||||
sprintf(v->bus_info, "ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int typhoon_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = (87.5*16000);
|
||||
v->rangehigh = (108*16000);
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal = 0xFFFF; /* We can't get the signal strength */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct typhoon_device *typhoon = dev->priv;
|
||||
|
||||
switch (cmd) {
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-typhoon", sizeof (v->driver));
|
||||
strlcpy(v->card, "Typhoon Radio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
v->rangelow=(87.5*16000);
|
||||
v->rangehigh=(108*16000);
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal = 0xFFFF; /* We can't get the signal strength */
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
typhoon->curfreq = f->frequency;
|
||||
typhoon_setfreq(typhoon, typhoon->curfreq);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = typhoon->curfreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=typhoon->muted;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value=typhoon->curvol;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
typhoon_mute(typhoon);
|
||||
} else {
|
||||
typhoon_unmute(typhoon);
|
||||
}
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
typhoon_setvol(typhoon, ctrl->value);
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
typhoon_do_ioctl);
|
||||
}
|
||||
typhoon->curfreq = f->frequency;
|
||||
typhoon_setfreq(typhoon, typhoon->curfreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int typhoon_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, typhoon_do_ioctl);
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct typhoon_device *typhoon = dev->priv;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = typhoon->curfreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct typhoon_device *typhoon = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = typhoon->muted;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value = typhoon->curvol;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl (struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct typhoon_device *typhoon = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value)
|
||||
typhoon_mute(typhoon);
|
||||
else
|
||||
typhoon_unmute(typhoon);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
typhoon_setvol(typhoon, ctrl->value);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct typhoon_device typhoon_unit =
|
||||
|
@ -322,7 +339,7 @@ static const struct file_operations typhoon_fops = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = typhoon_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
@ -334,6 +351,18 @@ static struct video_device typhoon_radio =
|
|||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &typhoon_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
|
||||
|
|
|
@ -230,121 +230,123 @@ static int zol_is_stereo (struct zol_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int zol_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver));
|
||||
strlcpy(v->card, "Zoltrix Radio", sizeof(v->card));
|
||||
sprintf(v->bus_info, "ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct zol_device *zol = dev->priv;
|
||||
|
||||
switch (cmd) {
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-zoltrix", sizeof (v->driver));
|
||||
strlcpy(v->card, "Zoltrix Radio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = (88*16000);
|
||||
v->rangehigh = (108*16000);
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
if (zol_is_stereo(zol))
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
else
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal = 0xFFFF*zol_getsigstr(zol);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct zol_device *zol = dev->priv;
|
||||
|
||||
zol->curfreq = f->frequency;
|
||||
zol_setfreq(zol, zol->curfreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct zol_device *zol = dev->priv;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = zol->curfreq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct zol_device *zol = dev->priv;
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = zol->muted;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value = zol->curvol * 4096;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
v->rangelow=(88*16000);
|
||||
v->rangehigh=(108*16000);
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
if(zol_is_stereo(zol))
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
else
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=0xFFFF*zol_getsigstr(zol);
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct zol_device *zol = dev->priv;
|
||||
|
||||
return 0;
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value)
|
||||
zol_mute(zol);
|
||||
else {
|
||||
zol_unmute(zol);
|
||||
zol_setvol(zol,zol->curvol);
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
zol->curfreq = f->frequency;
|
||||
zol_setfreq(zol, zol->curfreq);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = zol->curfreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=zol->muted;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value=zol->curvol * 4096;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
zol_mute(zol);
|
||||
} else {
|
||||
zol_unmute(zol);
|
||||
zol_setvol(zol,zol->curvol);
|
||||
}
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
zol_setvol(zol,ctrl->value/4096);
|
||||
return (0);
|
||||
}
|
||||
zol->stereo = 1;
|
||||
zol_setfreq(zol, zol->curfreq);
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
zol_setvol(zol,ctrl->value/4096);
|
||||
return 0;
|
||||
}
|
||||
zol->stereo = 1;
|
||||
zol_setfreq(zol, zol->curfreq);
|
||||
#if 0
|
||||
/* FIXME: Implement stereo/mono switch on V4L2 */
|
||||
if (v->mode & VIDEO_SOUND_STEREO) {
|
||||
|
@ -356,19 +358,39 @@ static int zol_do_ioctl(struct inode *inode, struct file *file,
|
|||
zol_setfreq(zol, zol->curfreq);
|
||||
}
|
||||
#endif
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
zol_do_ioctl);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int zol_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, zol_do_ioctl);
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct zol_device zoltrix_unit;
|
||||
|
@ -378,7 +400,7 @@ static const struct file_operations zoltrix_fops =
|
|||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = zol_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
@ -390,6 +412,18 @@ static struct video_device zoltrix_radio =
|
|||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &zoltrix_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
};
|
||||
|
||||
static int __init zoltrix_init(void)
|
||||
|
|
|
@ -647,6 +647,8 @@ config VIDEO_HEXIUM_GEMINI
|
|||
|
||||
source "drivers/media/video/cx88/Kconfig"
|
||||
|
||||
source "drivers/media/video/ivtv/Kconfig"
|
||||
|
||||
config VIDEO_M32R_AR
|
||||
tristate "AR devices"
|
||||
depends on M32R && VIDEO_V4L1
|
||||
|
@ -761,6 +763,18 @@ source "drivers/media/video/zc0301/Kconfig"
|
|||
|
||||
source "drivers/media/video/pwc/Kconfig"
|
||||
|
||||
config USB_ZR364XX
|
||||
tristate "USB ZR364XX Camera support"
|
||||
depends on USB && VIDEO_V4L2
|
||||
---help---
|
||||
Say Y here if you want to connect this type of camera to your
|
||||
computer's USB port.
|
||||
See <file:Documentation/video4linux/zr364xx.txt> for more info
|
||||
and list of supported cameras.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called zr364xx.
|
||||
|
||||
endmenu # V4L USB devices
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -61,6 +61,7 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
|
|||
obj-$(CONFIG_VIDEO_MEYE) += meye.o
|
||||
obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
|
||||
obj-$(CONFIG_VIDEO_CX88) += cx88/
|
||||
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
|
||||
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
|
||||
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
|
||||
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
|
||||
|
@ -99,6 +100,7 @@ obj-$(CONFIG_USB_OV511) += ov511.o
|
|||
obj-$(CONFIG_USB_SE401) += se401.o
|
||||
obj-$(CONFIG_USB_STV680) += stv680.o
|
||||
obj-$(CONFIG_USB_W9968CF) += w9968cf.o
|
||||
obj-$(CONFIG_USB_ZR364XX) += zr364xx.o
|
||||
|
||||
obj-$(CONFIG_USB_SN9C102) += sn9c102/
|
||||
obj-$(CONFIG_USB_ET61X251) += et61x251/
|
||||
|
|
|
@ -291,6 +291,9 @@ static struct CARD {
|
|||
|
||||
{ 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" },
|
||||
|
||||
{ 0x53534149, BTTV_BOARD_SSAI_SECURITY, "SSAI Security Video Interface" },
|
||||
{ 0x5353414a, BTTV_BOARD_SSAI_ULTRASOUND, "SSAI Ultrasound Video Interface" },
|
||||
|
||||
/* likely broken, vendor id doesn't match the other magic views ...
|
||||
* { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
|
||||
|
||||
|
@ -2907,6 +2910,28 @@ struct tvcard bttv_tvcards[] = {
|
|||
.has_radio = 1,
|
||||
.has_remote = 1,
|
||||
},
|
||||
[BTTV_BOARD_SSAI_SECURITY] = {
|
||||
.name = "SSAI Security Video Interface",
|
||||
.video_inputs = 4,
|
||||
.audio_inputs = 0,
|
||||
.tuner = -1,
|
||||
.svhs = -1,
|
||||
.muxsel = { 0, 1, 2, 3 },
|
||||
.tuner_type = -1,
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
.radio_addr = ADDR_UNSET,
|
||||
},
|
||||
[BTTV_BOARD_SSAI_ULTRASOUND] = {
|
||||
.name = "SSAI Ultrasound Video Interface",
|
||||
.video_inputs = 2,
|
||||
.audio_inputs = 0,
|
||||
.tuner = -1,
|
||||
.svhs = 1,
|
||||
.muxsel = { 2, 0, 1, 3 },
|
||||
.tuner_type = -1,
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
.radio_addr = ADDR_UNSET,
|
||||
},
|
||||
};
|
||||
|
||||
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
|
||||
|
@ -2970,20 +2995,20 @@ void __devinit bttv_idcard(struct bttv *btv)
|
|||
|
||||
if (UNSET != audiomux[0]) {
|
||||
gpiobits = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) {
|
||||
bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i];
|
||||
gpiobits |= audiomux[i];
|
||||
}
|
||||
} else {
|
||||
gpiobits = audioall;
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) {
|
||||
bttv_tvcards[btv->c.type].gpiomux[i] = audioall;
|
||||
}
|
||||
}
|
||||
bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits;
|
||||
printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=",
|
||||
btv->c.nr,bttv_tvcards[btv->c.type].gpiomask);
|
||||
for (i = 0; i < 5; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) {
|
||||
printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]);
|
||||
}
|
||||
printk("\n");
|
||||
|
@ -3638,7 +3663,7 @@ static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
|
|||
|
||||
for (n = 0; n < microlen; n++) {
|
||||
bits = micro[n];
|
||||
for ( i = 0 ; i < 8 ; i++ ) {
|
||||
for (i = 0 ; i < 8 ; i++) {
|
||||
gpio_bits(BTTV_ALT_DCLK,0);
|
||||
if (bits & 0x01)
|
||||
gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA);
|
||||
|
@ -3691,7 +3716,7 @@ static void __devinit osprey_eeprom(struct bttv *btv)
|
|||
/* this might be an antique... check for MMAC label in eeprom */
|
||||
if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
|
||||
unsigned char checksum = 0;
|
||||
for (i =0; i<21; i++)
|
||||
for (i = 0; i < 21; i++)
|
||||
checksum += ee[i];
|
||||
if (checksum != ee[21])
|
||||
return;
|
||||
|
@ -3703,12 +3728,13 @@ static void __devinit osprey_eeprom(struct bttv *btv)
|
|||
unsigned short type;
|
||||
int offset = 4*16;
|
||||
|
||||
for(; offset < 8*16; offset += 16) {
|
||||
for (; offset < 8*16; offset += 16) {
|
||||
unsigned short checksum = 0;
|
||||
/* verify the checksum */
|
||||
for(i = 0; i<14; i++) checksum += ee[i+offset];
|
||||
checksum = ~checksum; /* no idea why */
|
||||
if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
|
||||
for (i = 0; i < 14; i++)
|
||||
checksum += ee[i+offset];
|
||||
checksum = ~checksum; /* no idea why */
|
||||
if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
|
||||
((checksum & 0x0FF) == ee[offset+15])) {
|
||||
break;
|
||||
}
|
||||
|
@ -3721,7 +3747,6 @@ static void __devinit osprey_eeprom(struct bttv *btv)
|
|||
type = (ee[offset+4]<<8) | (ee[offset+5]);
|
||||
|
||||
switch(type) {
|
||||
|
||||
/* 848 based */
|
||||
case 0x0004:
|
||||
btv->c.type = BTTV_BOARD_OSPREY1x0_848;
|
||||
|
@ -4149,8 +4174,7 @@ static int tea5757_read(struct bttv *btv)
|
|||
}
|
||||
|
||||
dprintk("bttv%d: tea5757:",btv->c.nr);
|
||||
for(i = 0; i < 24; i++)
|
||||
{
|
||||
for (i = 0; i < 24; i++) {
|
||||
udelay(5);
|
||||
bus_high(btv,btv->mbox_clk);
|
||||
udelay(5);
|
||||
|
@ -4182,8 +4206,7 @@ static int tea5757_write(struct bttv *btv, int value)
|
|||
dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value);
|
||||
bus_low(btv,btv->mbox_clk);
|
||||
bus_high(btv,btv->mbox_we);
|
||||
for(i = 0; i < 25; i++)
|
||||
{
|
||||
for (i = 0; i < 25; i++) {
|
||||
if (reg & 0x1000000)
|
||||
bus_high(btv,btv->mbox_data);
|
||||
else
|
||||
|
@ -4755,7 +4778,7 @@ static void kodicom4400r_init(struct bttv *btv)
|
|||
gpio_write(1 << 9); /* reset MUX */
|
||||
gpio_write(0);
|
||||
/* Preset camera 0 to the 4 controllers */
|
||||
for (ix=0; ix<4; ix++) {
|
||||
for (ix = 0; ix < 4; ix++) {
|
||||
sw_status[ix] = ix;
|
||||
kodicom4400r_write(btv, ix, ix, 1);
|
||||
}
|
||||
|
|
|
@ -163,6 +163,24 @@ static ssize_t show_card(struct class_device *cd, char *buf)
|
|||
}
|
||||
static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* dvb auto-load setup */
|
||||
#if defined(CONFIG_MODULES) && defined(MODULE)
|
||||
static void request_module_async(struct work_struct *work)
|
||||
{
|
||||
request_module("dvb-bt8xx");
|
||||
}
|
||||
|
||||
static void request_modules(struct bttv *dev)
|
||||
{
|
||||
INIT_WORK(&dev->request_module_wk, request_module_async);
|
||||
schedule_work(&dev->request_module_wk);
|
||||
}
|
||||
#else
|
||||
#define request_modules(dev)
|
||||
#endif /* CONFIG_MODULES */
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* static data */
|
||||
|
||||
|
@ -4769,9 +4787,11 @@ static int __devinit bttv_probe(struct pci_dev *dev,
|
|||
disclaim_video_lines(btv);
|
||||
}
|
||||
|
||||
/* add subdevices */
|
||||
if (bttv_tvcards[btv->c.type].has_dvb)
|
||||
/* add subdevices and autoload dvb-bt8xx if needed */
|
||||
if (bttv_tvcards[btv->c.type].has_dvb) {
|
||||
bttv_sub_add_device(&btv->c, "dvb");
|
||||
request_modules(btv);
|
||||
}
|
||||
|
||||
bttv_input_init(btv);
|
||||
|
||||
|
|
|
@ -71,7 +71,6 @@ struct bus_type bttv_sub_bus_type = {
|
|||
.probe = bttv_sub_probe,
|
||||
.remove = bttv_sub_remove,
|
||||
};
|
||||
EXPORT_SYMBOL(bttv_sub_bus_type);
|
||||
|
||||
static void release_sub_device(struct device *dev)
|
||||
{
|
||||
|
@ -152,7 +151,6 @@ void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits)
|
|||
btwrite(data,BT848_GPIO_OUT_EN);
|
||||
spin_unlock_irqrestore(&btv->gpio_lock,flags);
|
||||
}
|
||||
EXPORT_SYMBOL(bttv_gpio_inout);
|
||||
|
||||
u32 bttv_gpio_read(struct bttv_core *core)
|
||||
{
|
||||
|
@ -162,7 +160,6 @@ u32 bttv_gpio_read(struct bttv_core *core)
|
|||
value = btread(BT848_GPIO_DATA);
|
||||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL(bttv_gpio_read);
|
||||
|
||||
void bttv_gpio_write(struct bttv_core *core, u32 value)
|
||||
{
|
||||
|
@ -170,7 +167,6 @@ void bttv_gpio_write(struct bttv_core *core, u32 value)
|
|||
|
||||
btwrite(value,BT848_GPIO_DATA);
|
||||
}
|
||||
EXPORT_SYMBOL(bttv_gpio_write);
|
||||
|
||||
void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits)
|
||||
{
|
||||
|
@ -185,7 +181,6 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits)
|
|||
btwrite(data,BT848_GPIO_DATA);
|
||||
spin_unlock_irqrestore(&btv->gpio_lock,flags);
|
||||
}
|
||||
EXPORT_SYMBOL(bttv_gpio_bits);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
|
|
@ -412,7 +412,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
|
|||
unsigned char buf;
|
||||
int i,rc;
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
|
||||
c->addr = i;
|
||||
rc = i2c_master_recv(c,&buf,0);
|
||||
if (rc < 0)
|
||||
|
|
|
@ -33,32 +33,16 @@
|
|||
|
||||
#include "bttvp.h"
|
||||
|
||||
EXPORT_SYMBOL(bttv_get_cardinfo);
|
||||
EXPORT_SYMBOL(bttv_get_pcidev);
|
||||
EXPORT_SYMBOL(bttv_get_id);
|
||||
EXPORT_SYMBOL(bttv_gpio_enable);
|
||||
EXPORT_SYMBOL(bttv_read_gpio);
|
||||
EXPORT_SYMBOL(bttv_write_gpio);
|
||||
EXPORT_SYMBOL(bttv_get_gpio_queue);
|
||||
EXPORT_SYMBOL(bttv_i2c_call);
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* Exported functions - for other modules which want to access the */
|
||||
/* gpio ports (IR for example) */
|
||||
/* see bttv.h for comments */
|
||||
|
||||
int bttv_get_cardinfo(unsigned int card, int *type, unsigned *cardid)
|
||||
{
|
||||
printk("The bttv_* interface is obsolete and will go away,\n"
|
||||
"please use the new, sysfs based interface instead.\n");
|
||||
if (card >= bttv_num) {
|
||||
return -1;
|
||||
}
|
||||
*type = bttvs[card].c.type;
|
||||
*cardid = bttvs[card].cardid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pci_dev* bttv_get_pcidev(unsigned int card)
|
||||
{
|
||||
if (card >= bttv_num)
|
||||
|
@ -66,16 +50,6 @@ struct pci_dev* bttv_get_pcidev(unsigned int card)
|
|||
return bttvs[card].c.pci;
|
||||
}
|
||||
|
||||
int bttv_get_id(unsigned int card)
|
||||
{
|
||||
printk("The bttv_* interface is obsolete and will go away,\n"
|
||||
"please use the new, sysfs based interface instead.\n");
|
||||
if (card >= bttv_num) {
|
||||
return -1;
|
||||
}
|
||||
return bttvs[card].c.type;
|
||||
}
|
||||
|
||||
|
||||
int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
|
||||
{
|
||||
|
@ -130,28 +104,6 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
wait_queue_head_t* bttv_get_gpio_queue(unsigned int card)
|
||||
{
|
||||
struct bttv *btv;
|
||||
|
||||
if (card >= bttv_num) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
btv = &bttvs[card];
|
||||
if (bttvs[card].shutdown) {
|
||||
return NULL;
|
||||
}
|
||||
return &btv->gpioq;
|
||||
}
|
||||
|
||||
void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg)
|
||||
{
|
||||
if (card >= bttv_num)
|
||||
return;
|
||||
bttv_call_i2c_clients(&bttvs[card], cmd, arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
|
|
|
@ -168,6 +168,8 @@
|
|||
#define BTTV_BOARD_SABRENT_TVFM 0x8e
|
||||
#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f
|
||||
#define BTTV_BOARD_MACHTV_MAGICTV 0x90
|
||||
#define BTTV_BOARD_SSAI_SECURITY 0x91
|
||||
#define BTTV_BOARD_SSAI_ULTRASOUND 0x92
|
||||
|
||||
/* more card-specific defines */
|
||||
#define PT2254_L_CHANNEL 0x10
|
||||
|
@ -260,17 +262,8 @@ extern int bttv_handle_chipset(struct bttv *btv);
|
|||
/* this obsolete -- please use the sysfs-based
|
||||
interface below for new code */
|
||||
|
||||
/* returns card type + card ID (for bt878-based ones)
|
||||
for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN
|
||||
returns negative value if error occurred
|
||||
*/
|
||||
extern int bttv_get_cardinfo(unsigned int card, int *type,
|
||||
unsigned int *cardid);
|
||||
extern struct pci_dev* bttv_get_pcidev(unsigned int card);
|
||||
|
||||
/* obsolete, use bttv_get_cardinfo instead */
|
||||
extern int bttv_get_id(unsigned int card);
|
||||
|
||||
/* sets GPOE register (BT848_GPIO_OUT_EN) to new value:
|
||||
data | (current_GPOE_value & ~mask)
|
||||
returns negative value if error occurred
|
||||
|
@ -290,20 +283,6 @@ extern int bttv_read_gpio(unsigned int card, unsigned long *data);
|
|||
extern int bttv_write_gpio(unsigned int card,
|
||||
unsigned long mask, unsigned long data);
|
||||
|
||||
/* returns pointer to task queue which can be used as parameter to
|
||||
interruptible_sleep_on
|
||||
in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated
|
||||
(wake_up_interruptible) and following call to the function bttv_read_gpio
|
||||
should return new value of GPDATA,
|
||||
returns NULL value if error occurred or queue is not available
|
||||
WARNING: because there is no buffer for GPIO data, one MUST
|
||||
process data ASAP
|
||||
*/
|
||||
extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
|
||||
|
||||
/* call i2c clients
|
||||
*/
|
||||
extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -434,6 +434,9 @@ struct bttv {
|
|||
unsigned int users;
|
||||
struct bttv_fh init;
|
||||
|
||||
/* used to make dvb-bt8xx autoloadable */
|
||||
struct work_struct request_module_wk;
|
||||
|
||||
/* Default (0) and current (1) video capturing and overlay
|
||||
cropping parameters in bttv_tvnorm.cropcap units. Protected
|
||||
by bttv.lock. */
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* sensor.
|
||||
*
|
||||
* Copyright 2006 One Laptop Per Child Association, Inc.
|
||||
* Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
|
||||
*
|
||||
* Written by Jonathan Corbet, corbet@lwn.net.
|
||||
*
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/list.h>
|
||||
|
@ -36,7 +38,7 @@
|
|||
|
||||
#include "cafe_ccic-regs.h"
|
||||
|
||||
#define CAFE_VERSION 0x000001
|
||||
#define CAFE_VERSION 0x000002
|
||||
|
||||
|
||||
/*
|
||||
|
@ -164,7 +166,7 @@ struct cafe_camera
|
|||
struct tasklet_struct s_tasklet;
|
||||
|
||||
/* Current operating parameters */
|
||||
enum v4l2_chip_ident sensor_type; /* Currently ov7670 only */
|
||||
u32 sensor_type; /* Currently ov7670 only */
|
||||
struct v4l2_pix_format pix_format;
|
||||
|
||||
/* Locks */
|
||||
|
@ -704,7 +706,13 @@ static void cafe_ctlr_init(struct cafe_camera *cam)
|
|||
cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
|
||||
cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
|
||||
cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
|
||||
/*
|
||||
* Here we must wait a bit for the controller to come around.
|
||||
*/
|
||||
spin_unlock_irqrestore(&cam->dev_lock, flags);
|
||||
mdelay(5); /* FIXME revisit this */
|
||||
spin_lock_irqsave(&cam->dev_lock, flags);
|
||||
|
||||
cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
|
||||
cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN);
|
||||
/*
|
||||
|
@ -772,9 +780,9 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam)
|
|||
* Control 1 is power down, set to 0 to operate.
|
||||
*/
|
||||
cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
|
||||
mdelay(1); /* Marvell says 1ms will do it */
|
||||
// mdelay(1); /* Marvell says 1ms will do it */
|
||||
cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
|
||||
mdelay(1); /* Enough? */
|
||||
// mdelay(1); /* Enough? */
|
||||
spin_unlock_irqrestore(&cam->dev_lock, flags);
|
||||
}
|
||||
|
||||
|
@ -818,6 +826,7 @@ static int __cafe_cam_reset(struct cafe_camera *cam)
|
|||
*/
|
||||
static int cafe_cam_init(struct cafe_camera *cam)
|
||||
{
|
||||
struct v4l2_chip_ident chip = { V4L2_CHIP_MATCH_I2C_ADDR, 0, 0, 0 };
|
||||
int ret;
|
||||
|
||||
mutex_lock(&cam->s_mutex);
|
||||
|
@ -827,9 +836,11 @@ static int cafe_cam_init(struct cafe_camera *cam)
|
|||
ret = __cafe_cam_reset(cam);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type);
|
||||
chip.match_chip = cam->sensor->addr;
|
||||
ret = __cafe_cam_cmd(cam, VIDIOC_G_CHIP_IDENT, &chip);
|
||||
if (ret)
|
||||
goto out;
|
||||
cam->sensor_type = chip.ident;
|
||||
// if (cam->sensor->addr != OV7xx0_SID) {
|
||||
if (cam->sensor_type != V4L2_IDENT_OV7670) {
|
||||
cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr);
|
||||
|
@ -1792,18 +1803,19 @@ static void cafe_frame_tasklet(unsigned long data)
|
|||
if (list_empty(&cam->sb_avail))
|
||||
break; /* Leave it valid, hope for better later */
|
||||
clear_bit(bufno, &cam->flags);
|
||||
/*
|
||||
* We could perhaps drop the spinlock during this
|
||||
* big copy. Something to consider.
|
||||
*/
|
||||
sbuf = list_entry(cam->sb_avail.next,
|
||||
struct cafe_sio_buffer, list);
|
||||
/*
|
||||
* Drop the lock during the big copy. This *should* be safe...
|
||||
*/
|
||||
spin_unlock_irqrestore(&cam->dev_lock, flags);
|
||||
memcpy(sbuf->buffer, cam->dma_bufs[bufno],
|
||||
cam->pix_format.sizeimage);
|
||||
sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage;
|
||||
sbuf->v4lbuf.sequence = cam->buf_seq[bufno];
|
||||
sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
|
||||
sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
|
||||
spin_lock_irqsave(&cam->dev_lock, flags);
|
||||
list_move_tail(&sbuf->list, &cam->sb_full);
|
||||
}
|
||||
if (! list_empty(&cam->sb_full))
|
||||
|
@ -2107,6 +2119,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
|
|||
cam->v4ldev = cafe_v4l_template;
|
||||
cam->v4ldev.debug = 0;
|
||||
// cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG;
|
||||
cam->v4ldev.dev = &pdev->dev;
|
||||
ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1);
|
||||
if (ret)
|
||||
goto out_smbus;
|
||||
|
@ -2176,10 +2189,52 @@ static void cafe_pci_remove(struct pci_dev *pdev)
|
|||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* Basic power management.
|
||||
*/
|
||||
static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
{
|
||||
struct cafe_camera *cam = cafe_find_by_pdev(pdev);
|
||||
int ret;
|
||||
|
||||
ret = pci_save_state(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
cafe_ctlr_stop_dma(cam);
|
||||
cafe_ctlr_power_down(cam);
|
||||
pci_disable_device(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cafe_pci_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct cafe_camera *cam = cafe_find_by_pdev(pdev);
|
||||
int ret = 0;
|
||||
|
||||
ret = pci_restore_state(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret) {
|
||||
cam_warn(cam, "Unable to re-enable device on resume!\n");
|
||||
return ret;
|
||||
}
|
||||
cafe_ctlr_init(cam);
|
||||
cafe_ctlr_power_up(cam);
|
||||
set_bit(CF_CONFIG_NEEDED, &cam->flags);
|
||||
if (cam->state == S_SPECREAD)
|
||||
cam->state = S_IDLE; /* Don't bother restarting */
|
||||
else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING)
|
||||
ret = cafe_read_setup(cam, cam->state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
|
||||
static struct pci_device_id cafe_ids[] = {
|
||||
{ PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */
|
||||
{ PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */
|
||||
{ PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */
|
||||
{ 0, }
|
||||
|
@ -2192,6 +2247,10 @@ static struct pci_driver cafe_pci_driver = {
|
|||
.id_table = cafe_ids,
|
||||
.probe = cafe_pci_probe,
|
||||
.remove = cafe_pci_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = cafe_pci_suspend,
|
||||
.resume = cafe_pci_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -62,7 +62,6 @@ static int cpia_pp_close(void *privdata);
|
|||
#define PPCPIA_PARPORT_OFF -2
|
||||
#define PPCPIA_PARPORT_NONE -1
|
||||
|
||||
#ifdef MODULE
|
||||
static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
|
||||
static char *parport[PARPORT_MAX] = {NULL,};
|
||||
|
||||
|
@ -72,11 +71,6 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
module_param_array(parport, charp, NULL, 0);
|
||||
MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp.");
|
||||
#else
|
||||
static int parport_nr[PARPORT_MAX] __initdata =
|
||||
{[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
|
||||
static int parport_ptr = 0;
|
||||
#endif
|
||||
|
||||
struct pp_cam_entry {
|
||||
struct pardevice *pdev;
|
||||
|
@ -141,7 +135,6 @@ static void cpia_pp_run_callback(struct work_struct *work)
|
|||
cam = container_of(work, struct pp_cam_entry, cb_task);
|
||||
cb_func = cam->cb_func;
|
||||
cb_data = cam->cb_data;
|
||||
work_release(work);
|
||||
|
||||
cb_func(cb_data);
|
||||
}
|
||||
|
@ -682,7 +675,7 @@ static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), vo
|
|||
if(cam->port->irq != PARPORT_IRQ_NONE) {
|
||||
cam->cb_func = cb;
|
||||
cam->cb_data = cbdata;
|
||||
INIT_WORK_NAR(&cam->cb_task, cpia_pp_run_callback);
|
||||
INIT_WORK(&cam->cb_task, cpia_pp_run_callback);
|
||||
} else {
|
||||
retval = -1;
|
||||
}
|
||||
|
@ -820,7 +813,7 @@ static struct parport_driver cpia_pp_driver = {
|
|||
.detach = cpia_pp_detach,
|
||||
};
|
||||
|
||||
static int cpia_pp_init(void)
|
||||
static int __init cpia_pp_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
|
||||
CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
|
||||
|
@ -839,8 +832,7 @@ static int cpia_pp_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
int init_module(void)
|
||||
static int __init cpia_init(void)
|
||||
{
|
||||
if (parport[0]) {
|
||||
/* The user gave some parameters. Let's see what they were. */
|
||||
|
@ -867,38 +859,11 @@ int init_module(void)
|
|||
return cpia_pp_init();
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
static void __exit cpia_cleanup(void)
|
||||
{
|
||||
parport_unregister_driver (&cpia_pp_driver);
|
||||
parport_unregister_driver(&cpia_pp_driver);
|
||||
return;
|
||||
}
|
||||
|
||||
#else /* !MODULE */
|
||||
|
||||
static int __init cpia_pp_setup(char *str)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!strncmp(str, "parport", 7)) {
|
||||
int n = simple_strtoul(str + 7, NULL, 10);
|
||||
if (parport_ptr < PARPORT_MAX) {
|
||||
parport_nr[parport_ptr++] = n;
|
||||
} else {
|
||||
LOG("too many ports, %s ignored.\n", str);
|
||||
}
|
||||
} else if (!strcmp(str, "auto")) {
|
||||
parport_nr[0] = PPCPIA_PARPORT_AUTO;
|
||||
} else if (!strcmp(str, "none")) {
|
||||
parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
|
||||
}
|
||||
|
||||
err=cpia_pp_init();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("cpia_pp=", cpia_pp_setup);
|
||||
|
||||
#endif /* !MODULE */
|
||||
module_init(cpia_init);
|
||||
module_exit(cpia_cleanup);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/i2c-id.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
|
||||
MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
|
||||
MODULE_AUTHOR("Martin Vaughan");
|
||||
|
@ -103,6 +104,9 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
|
|||
cs53l32a_write(client, 0x05, (u8) ctrl->value);
|
||||
break;
|
||||
|
||||
case VIDIOC_G_CHIP_IDENT:
|
||||
return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0);
|
||||
|
||||
case VIDIOC_LOG_STATUS:
|
||||
{
|
||||
u8 v = cs53l32a_read(client, 0x01);
|
||||
|
|
|
@ -51,6 +51,7 @@ const u32 cx2341x_mpeg_ctrls[] = {
|
|||
V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
|
||||
V4L2_CID_MPEG_AUDIO_EMPHASIS,
|
||||
V4L2_CID_MPEG_AUDIO_CRC,
|
||||
V4L2_CID_MPEG_AUDIO_MUTE,
|
||||
V4L2_CID_MPEG_VIDEO_ENCODING,
|
||||
V4L2_CID_MPEG_VIDEO_ASPECT,
|
||||
V4L2_CID_MPEG_VIDEO_B_FRAMES,
|
||||
|
@ -60,6 +61,8 @@ const u32 cx2341x_mpeg_ctrls[] = {
|
|||
V4L2_CID_MPEG_VIDEO_BITRATE,
|
||||
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
|
||||
V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
|
||||
V4L2_CID_MPEG_VIDEO_MUTE,
|
||||
V4L2_CID_MPEG_VIDEO_MUTE_YUV,
|
||||
V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
|
||||
V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
|
||||
V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
|
||||
|
@ -71,6 +74,7 @@ const u32 cx2341x_mpeg_ctrls[] = {
|
|||
V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
|
||||
V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
|
||||
V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
|
||||
V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
|
||||
0
|
||||
};
|
||||
|
||||
|
@ -102,6 +106,9 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
|
|||
case V4L2_CID_MPEG_AUDIO_CRC:
|
||||
ctrl->value = params->audio_crc;
|
||||
break;
|
||||
case V4L2_CID_MPEG_AUDIO_MUTE:
|
||||
ctrl->value = params->audio_mute;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_ENCODING:
|
||||
ctrl->value = params->video_encoding;
|
||||
break;
|
||||
|
@ -129,6 +136,12 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
|
|||
case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
|
||||
ctrl->value = params->video_temporal_decimation;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_MUTE:
|
||||
ctrl->value = params->video_mute;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
|
||||
ctrl->value = params->video_mute_yuv;
|
||||
break;
|
||||
case V4L2_CID_MPEG_STREAM_TYPE:
|
||||
ctrl->value = params->stream_type;
|
||||
break;
|
||||
|
@ -168,6 +181,9 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
|
|||
case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
|
||||
ctrl->value = params->video_chroma_median_filter_bottom;
|
||||
break;
|
||||
case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
|
||||
ctrl->value = params->stream_insert_nav_packets;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -201,6 +217,9 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
|
|||
case V4L2_CID_MPEG_AUDIO_CRC:
|
||||
params->audio_crc = ctrl->value;
|
||||
break;
|
||||
case V4L2_CID_MPEG_AUDIO_MUTE:
|
||||
params->audio_mute = ctrl->value;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_ASPECT:
|
||||
params->video_aspect = ctrl->value;
|
||||
break;
|
||||
|
@ -243,6 +262,12 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
|
|||
case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
|
||||
params->video_temporal_decimation = ctrl->value;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_MUTE:
|
||||
params->video_mute = (ctrl->value != 0);
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
|
||||
params->video_mute_yuv = ctrl->value;
|
||||
break;
|
||||
case V4L2_CID_MPEG_STREAM_TYPE:
|
||||
params->stream_type = ctrl->value;
|
||||
params->video_encoding =
|
||||
|
@ -290,6 +315,9 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
|
|||
case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
|
||||
params->video_chroma_median_filter_bottom = ctrl->value;
|
||||
break;
|
||||
case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
|
||||
params->stream_insert_nav_packets = ctrl->value;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -336,6 +364,9 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma
|
|||
case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
|
||||
name = "Median Chroma Filter Minimum";
|
||||
break;
|
||||
case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
|
||||
name = "Insert Navigation Packets";
|
||||
break;
|
||||
|
||||
default:
|
||||
return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
|
||||
|
@ -350,6 +381,12 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma
|
|||
min = 0;
|
||||
step = 1;
|
||||
break;
|
||||
case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
|
||||
qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
|
||||
min = 0;
|
||||
max = 1;
|
||||
step = 1;
|
||||
break;
|
||||
default:
|
||||
qctrl->type = V4L2_CTRL_TYPE_INTEGER;
|
||||
break;
|
||||
|
@ -505,6 +542,9 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
|
|||
qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
|
||||
return 0;
|
||||
|
||||
case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
|
||||
return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0);
|
||||
|
||||
default:
|
||||
return v4l2_ctrl_query_fill_std(qctrl);
|
||||
|
||||
|
@ -656,6 +696,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
|
|||
/* stream */
|
||||
.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
|
||||
.stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
|
||||
.stream_insert_nav_packets = 0,
|
||||
|
||||
/* audio */
|
||||
.audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
|
||||
|
@ -665,6 +706,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
|
|||
.audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
|
||||
.audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
|
||||
.audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
|
||||
.audio_mute = 0,
|
||||
|
||||
/* video */
|
||||
.video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
|
||||
|
@ -676,6 +718,8 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
|
|||
.video_bitrate = 6000000,
|
||||
.video_bitrate_peak = 8000000,
|
||||
.video_temporal_decimation = 0,
|
||||
.video_mute = 0,
|
||||
.video_mute_yuv = 0x008080, /* YCbCr value for black */
|
||||
|
||||
/* encoding filters */
|
||||
.video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
|
||||
|
@ -779,6 +823,10 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
|
|||
err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
|
||||
if (err) return err;
|
||||
}
|
||||
if (old == NULL || old->audio_mute != new->audio_mute) {
|
||||
err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
|
||||
if (err) return err;
|
||||
}
|
||||
if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
|
||||
old->video_bitrate != new->video_bitrate ||
|
||||
old->video_bitrate_peak != new->video_bitrate_peak) {
|
||||
|
@ -826,6 +874,15 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
|
|||
new->video_temporal_decimation);
|
||||
if (err) return err;
|
||||
}
|
||||
if (old == NULL || old->video_mute != new->video_mute ||
|
||||
(new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) {
|
||||
err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8));
|
||||
if (err) return err;
|
||||
}
|
||||
if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) {
|
||||
err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets);
|
||||
if (err) return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -854,18 +911,22 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
|
|||
int temporal = p->video_temporal_filter;
|
||||
|
||||
/* Stream */
|
||||
printk(KERN_INFO "%s: Stream: %s\n",
|
||||
printk(KERN_INFO "%s: Stream: %s",
|
||||
prefix,
|
||||
cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
|
||||
if (p->stream_insert_nav_packets)
|
||||
printk(" (with navigation packets)");
|
||||
printk("\n");
|
||||
printk(KERN_INFO "%s: VBI Format: %s\n",
|
||||
prefix,
|
||||
cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
|
||||
|
||||
/* Video */
|
||||
printk(KERN_INFO "%s: Video: %dx%d, %d fps\n",
|
||||
printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n",
|
||||
prefix,
|
||||
p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
|
||||
p->is_50hz ? 25 : 30);
|
||||
p->is_50hz ? 25 : 30,
|
||||
(p->video_mute) ? " (muted)" : "");
|
||||
printk(KERN_INFO "%s: Video: %s, %s, %s, %d",
|
||||
prefix,
|
||||
cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
|
||||
|
@ -886,12 +947,13 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
|
|||
}
|
||||
|
||||
/* Audio */
|
||||
printk(KERN_INFO "%s: Audio: %s, %s, %s, %s",
|
||||
printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s",
|
||||
prefix,
|
||||
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
|
||||
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
|
||||
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
|
||||
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE));
|
||||
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
|
||||
p->audio_mute ? " (muted)" : "");
|
||||
if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
|
||||
printk(", %s",
|
||||
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/videodev2.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <media/cx25840.h>
|
||||
|
||||
#include "cx25840-core.h"
|
||||
|
@ -827,9 +828,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
|
|||
cx25840_initialize(client, 0);
|
||||
break;
|
||||
|
||||
case VIDIOC_INT_G_CHIP_IDENT:
|
||||
*(enum v4l2_chip_ident *)arg = state->id;
|
||||
break;
|
||||
case VIDIOC_G_CHIP_IDENT:
|
||||
return v4l2_chip_ident_i2c_client(client, arg, state->id, state->rev);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -847,7 +847,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
|
|||
{
|
||||
struct i2c_client *client;
|
||||
struct cx25840_state *state;
|
||||
enum v4l2_chip_ident id;
|
||||
u32 id;
|
||||
u16 device_id;
|
||||
|
||||
/* Check if the adapter supports the needed features
|
||||
|
@ -902,6 +902,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
|
|||
state->audmode = V4L2_TUNER_MODE_LANG1;
|
||||
state->vbi_line_offset = 8;
|
||||
state->id = id;
|
||||
state->rev = device_id;
|
||||
|
||||
i2c_attach_client(client);
|
||||
|
||||
|
|
|
@ -43,7 +43,8 @@ struct cx25840_state {
|
|||
u32 audclk_freq;
|
||||
int audmode;
|
||||
int vbi_line_offset;
|
||||
enum v4l2_chip_ident id;
|
||||
u32 id;
|
||||
u32 rev;
|
||||
int is_cx25836;
|
||||
};
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/cx25840.h>
|
||||
|
|
|
@ -53,7 +53,6 @@ config VIDEO_CX88_DVB
|
|||
select DVB_OR51132 if !DVB_FE_CUSTOMISE
|
||||
select DVB_CX22702 if !DVB_FE_CUSTOMISE
|
||||
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
|
||||
select DVB_NXT200X if !DVB_FE_CUSTOMISE
|
||||
select DVB_CX24123 if !DVB_FE_CUSTOMISE
|
||||
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
|
||||
|
|
|
@ -232,7 +232,8 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip)
|
|||
cx_write(MO_AUD_INTSTAT, status);
|
||||
if (debug > 1 || (status & mask & ~0xff))
|
||||
cx88_print_irqbits(core->name, "irq aud",
|
||||
cx88_aud_irqs, status, mask);
|
||||
cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs),
|
||||
status, mask);
|
||||
/* risc op code error */
|
||||
if (status & (1 << 16)) {
|
||||
printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name);
|
||||
|
@ -413,11 +414,9 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
|
|||
|
||||
dprintk(1,"Setting buffer\n");
|
||||
|
||||
buf = kmalloc(sizeof(*buf),GFP_KERNEL);
|
||||
buf = kzalloc(sizeof(*buf),GFP_KERNEL);
|
||||
if (NULL == buf)
|
||||
return -ENOMEM;
|
||||
memset(buf,0,sizeof(*buf));
|
||||
|
||||
|
||||
buf->vb.memory = V4L2_MEMORY_MMAP;
|
||||
buf->vb.width = chip->period_size;
|
||||
|
@ -682,7 +681,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!pci_dma_supported(pci,0xffffffff)) {
|
||||
if (!pci_dma_supported(pci,DMA_32BIT_MASK)) {
|
||||
dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
|
||||
err = -EIO;
|
||||
cx88_core_put(core,pci);
|
||||
|
|
|
@ -885,6 +885,12 @@ struct cx88_board cx88_boards[] = {
|
|||
.input = {{
|
||||
.type = CX88_VMUX_DVB,
|
||||
.vmux = 0,
|
||||
},{
|
||||
.type = CX88_VMUX_COMPOSITE1,
|
||||
.vmux = 1,
|
||||
},{
|
||||
.type = CX88_VMUX_SVIDEO,
|
||||
.vmux = 2,
|
||||
}},
|
||||
.mpeg = CX88_MPEG_DVB,
|
||||
},
|
||||
|
@ -1537,10 +1543,10 @@ struct cx88_subid cx88_subids[] = {
|
|||
},{
|
||||
.subvendor = 0x17de,
|
||||
.subdevice = 0x0840,
|
||||
.card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
|
||||
},{
|
||||
.subvendor = 0x1421,
|
||||
.subdevice = 0x0305,
|
||||
.card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
|
||||
},{
|
||||
.subvendor = 0x1421,
|
||||
.subdevice = 0x0305,
|
||||
.card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
|
||||
},{
|
||||
.subvendor = 0x18ac,
|
||||
|
@ -1631,6 +1637,10 @@ struct cx88_subid cx88_subids[] = {
|
|||
.subvendor = 0x0070,
|
||||
.subdevice = 0x1402,
|
||||
.card = CX88_BOARD_HAUPPAUGE_HVR3000,
|
||||
},{
|
||||
.subvendor = 0x1421,
|
||||
.subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
|
||||
.card = CX88_BOARD_KWORLD_DVBS_100,
|
||||
},
|
||||
};
|
||||
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
|
||||
|
@ -1786,7 +1796,7 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
|
|||
{ 0x03, 0x0C },
|
||||
};
|
||||
|
||||
for (i = 0; i < 13; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(init_bufs); i++) {
|
||||
msg.buf = init_bufs[i];
|
||||
msg.len = (i != 12 ? 5 : 2);
|
||||
err = i2c_transfer(&core->i2c_adap, &msg, 1);
|
||||
|
@ -1913,12 +1923,21 @@ void cx88_card_setup(struct cx88_core *core)
|
|||
if (0 == core->i2c_rc) {
|
||||
/* enable tuner */
|
||||
int i;
|
||||
static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
|
||||
static const u8 buffer [][2] = {
|
||||
{0x10,0x12},
|
||||
{0x13,0x04},
|
||||
{0x16,0x00},
|
||||
{0x14,0x04},
|
||||
{0x17,0x00}
|
||||
};
|
||||
core->i2c_client.addr = 0x0a;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
if (2 != i2c_master_send(&core->i2c_client,&buffer[i*2],2))
|
||||
printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
|
||||
for (i = 0; i < ARRAY_SIZE(buffer); i++)
|
||||
if (2 != i2c_master_send(&core->i2c_client,
|
||||
buffer[i],2))
|
||||
printk(KERN_WARNING
|
||||
"%s: Unable to enable "
|
||||
"tuner(%i).\n",
|
||||
core->name, i);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -489,12 +489,12 @@ static char *cx88_pci_irqs[32] = {
|
|||
};
|
||||
|
||||
void cx88_print_irqbits(char *name, char *tag, char **strings,
|
||||
u32 bits, u32 mask)
|
||||
int len, u32 bits, u32 mask)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
|
||||
for (i = 0; i < 32; i++) {
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!(bits & (1 << i)))
|
||||
continue;
|
||||
if (strings[i])
|
||||
|
@ -520,8 +520,8 @@ int cx88_core_irq(struct cx88_core *core, u32 status)
|
|||
}
|
||||
if (!handled)
|
||||
cx88_print_irqbits(core->name, "irq pci",
|
||||
cx88_pci_irqs, status,
|
||||
core->pci_irqmask);
|
||||
cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs),
|
||||
status, core->pci_irqmask);
|
||||
return handled;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
#include "cx22702.h"
|
||||
#include "or51132.h"
|
||||
#include "lgdt330x.h"
|
||||
#include "lgh06xf.h"
|
||||
#include "nxt200x.h"
|
||||
#include "cx24123.h"
|
||||
#include "isl6421.h"
|
||||
|
@ -476,6 +475,8 @@ static int dvb_register(struct cx8802_dev *dev)
|
|||
case CX88_BOARD_WINFAST_DTV2000H:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR1100:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR1300:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR3000:
|
||||
dev->dvb.frontend = dvb_attach(cx22702_attach,
|
||||
&hauppauge_hvr_config,
|
||||
&dev->core->i2c_adap);
|
||||
|
@ -631,8 +632,9 @@ static int dvb_register(struct cx8802_dev *dev)
|
|||
&fusionhdtv_5_gold,
|
||||
&dev->core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
dvb_attach(lgh06xf_attach, dev->dvb.frontend,
|
||||
&dev->core->i2c_adap);
|
||||
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
|
||||
&dev->core->i2c_adap,
|
||||
&dvb_pll_lg_tdvs_h06xf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -650,8 +652,9 @@ static int dvb_register(struct cx8802_dev *dev)
|
|||
&pchdtv_hd5500,
|
||||
&dev->core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
dvb_attach(lgh06xf_attach, dev->dvb.frontend,
|
||||
&dev->core->i2c_adap);
|
||||
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
|
||||
&dev->core->i2c_adap,
|
||||
&dvb_pll_lg_tdvs_h06xf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -692,24 +695,6 @@ static int dvb_register(struct cx8802_dev *dev)
|
|||
dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_HAUPPAUGE_HVR1300:
|
||||
dev->dvb.frontend = dvb_attach(cx22702_attach,
|
||||
&hauppauge_hvr_config,
|
||||
&dev->core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
|
||||
&dev->core->i2c_adap, &dvb_pll_fmd1216me);
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_HAUPPAUGE_HVR3000:
|
||||
dev->dvb.frontend = dvb_attach(cx22702_attach,
|
||||
&hauppauge_hvr_config,
|
||||
&dev->core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
|
||||
&dev->core->i2c_adap, &dvb_pll_fmd1216me);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
|
||||
dev->core->name);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue