Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (362 commits) V4L-DVB: cx88-dvb: remove extra attribution for core V4L/DVB: v4l: soc_camera: fix bound checking of mbus_fmt[] index V4L/DVB: Add support for SMT7020 to cx88 V4L/DVB: radio-si470x: Use UTF-8 encoding on a comment V4L/DVB: MAINTAINERS: Telegent tlg2300 section fix V4L/DVB: gspca_stv06xx: Add support for camera button V4L/DVB: gspca_ov519: add support for the button on ov511 based cams V4L/DVB: gspca_ov519: Add support for the button on ov518 based cams V4L/DVB: gspca_ov519: add support for the button on ov519 based cams V4L/DVB: gspca_main: Fix a compile error when CONFIG_INPUT is not set V4L/DVB: gspca_main: some input error handling fixes V4L/DVB: gspca_main: Allow use of input device creation code for non int. inputs V4L/DVB: gspca_pac7302: much improved exposure control V4L/DVB: gspca_sonixb: Make sonixb driver handle pas106 and pas202 cameras V4L/DVB: gspca_sonixb: pas106: fixup bright ctrl and add gain and exposure ctrls V4L/DVB: Documentation: gspca.txt: update known mr97310a cams V4L/DVB: gspca_mr97310a: add support for the Sakar 1638x CyberPix V4L/DVB: gscpa_sonixb: limit ov7630 max framerate at 640x480 V4L/DVB: gspca_sonixb: pas202: fixup brightness ctrl and add gain and exposure ctrls V4L/DVB: gscpa_sonixb: Differentiate between sensors with a coarse and fine expo ctrl ...
This commit is contained in:
commit
2b8c70b217
|
@ -589,7 +589,8 @@ number of a video input as in &v4l2-input; field
|
|||
<entry></entry>
|
||||
<entry>A place holder for future extensions and custom
|
||||
(driver defined) buffer types
|
||||
<constant>V4L2_BUF_TYPE_PRIVATE</constant> and higher.</entry>
|
||||
<constant>V4L2_BUF_TYPE_PRIVATE</constant> and higher. Applications
|
||||
should set this to 0.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
|
|
@ -54,12 +54,10 @@ to enqueue an empty (capturing) or filled (output) buffer in the
|
|||
driver's incoming queue. The semantics depend on the selected I/O
|
||||
method.</para>
|
||||
|
||||
<para>To enqueue a <link linkend="mmap">memory mapped</link>
|
||||
buffer applications set the <structfield>type</structfield> field of a
|
||||
&v4l2-buffer; to the same buffer type as previously &v4l2-format;
|
||||
<structfield>type</structfield> and &v4l2-requestbuffers;
|
||||
<structfield>type</structfield>, the <structfield>memory</structfield>
|
||||
field to <constant>V4L2_MEMORY_MMAP</constant> and the
|
||||
<para>To enqueue a buffer applications set the <structfield>type</structfield>
|
||||
field of a &v4l2-buffer; to the same buffer type as was previously used
|
||||
with &v4l2-format; <structfield>type</structfield> and &v4l2-requestbuffers;
|
||||
<structfield>type</structfield>. Applications must also set the
|
||||
<structfield>index</structfield> field. Valid index numbers range from
|
||||
zero to the number of buffers allocated with &VIDIOC-REQBUFS;
|
||||
(&v4l2-requestbuffers; <structfield>count</structfield>) minus one. The
|
||||
|
@ -70,8 +68,19 @@ intended for output (<structfield>type</structfield> is
|
|||
<constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant>) applications must also
|
||||
initialize the <structfield>bytesused</structfield>,
|
||||
<structfield>field</structfield> and
|
||||
<structfield>timestamp</structfield> fields. See <xref
|
||||
linkend="buffer" /> for details. When
|
||||
<structfield>timestamp</structfield> fields, see <xref
|
||||
linkend="buffer" /> for details.
|
||||
Applications must also set <structfield>flags</structfield> to 0. If a driver
|
||||
supports capturing from specific video inputs and you want to specify a video
|
||||
input, then <structfield>flags</structfield> should be set to
|
||||
<constant>V4L2_BUF_FLAG_INPUT</constant> and the field
|
||||
<structfield>input</structfield> must be initialized to the desired input.
|
||||
The <structfield>reserved</structfield> field must be set to 0.
|
||||
</para>
|
||||
|
||||
<para>To enqueue a <link linkend="mmap">memory mapped</link>
|
||||
buffer applications set the <structfield>memory</structfield>
|
||||
field to <constant>V4L2_MEMORY_MMAP</constant>. When
|
||||
<constant>VIDIOC_QBUF</constant> is called with a pointer to this
|
||||
structure the driver sets the
|
||||
<constant>V4L2_BUF_FLAG_MAPPED</constant> and
|
||||
|
@ -81,14 +90,10 @@ structure the driver sets the
|
|||
&EINVAL;.</para>
|
||||
|
||||
<para>To enqueue a <link linkend="userp">user pointer</link>
|
||||
buffer applications set the <structfield>type</structfield> field of a
|
||||
&v4l2-buffer; to the same buffer type as previously &v4l2-format;
|
||||
<structfield>type</structfield> and &v4l2-requestbuffers;
|
||||
<structfield>type</structfield>, the <structfield>memory</structfield>
|
||||
field to <constant>V4L2_MEMORY_USERPTR</constant> and the
|
||||
buffer applications set the <structfield>memory</structfield>
|
||||
field to <constant>V4L2_MEMORY_USERPTR</constant>, the
|
||||
<structfield>m.userptr</structfield> field to the address of the
|
||||
buffer and <structfield>length</structfield> to its size. When the
|
||||
buffer is intended for output additional fields must be set as above.
|
||||
buffer and <structfield>length</structfield> to its size.
|
||||
When <constant>VIDIOC_QBUF</constant> is called with a pointer to this
|
||||
structure the driver sets the <constant>V4L2_BUF_FLAG_QUEUED</constant>
|
||||
flag and clears the <constant>V4L2_BUF_FLAG_MAPPED</constant> and
|
||||
|
@ -96,13 +101,14 @@ flag and clears the <constant>V4L2_BUF_FLAG_MAPPED</constant> and
|
|||
<structfield>flags</structfield> field, or it returns an error code.
|
||||
This ioctl locks the memory pages of the buffer in physical memory,
|
||||
they cannot be swapped out to disk. Buffers remain locked until
|
||||
dequeued, until the &VIDIOC-STREAMOFF; or &VIDIOC-REQBUFS; ioctl are
|
||||
dequeued, until the &VIDIOC-STREAMOFF; or &VIDIOC-REQBUFS; ioctl is
|
||||
called, or until the device is closed.</para>
|
||||
|
||||
<para>Applications call the <constant>VIDIOC_DQBUF</constant>
|
||||
ioctl to dequeue a filled (capturing) or displayed (output) buffer
|
||||
from the driver's outgoing queue. They just set the
|
||||
<structfield>type</structfield> and <structfield>memory</structfield>
|
||||
<structfield>type</structfield>, <structfield>memory</structfield>
|
||||
and <structfield>reserved</structfield>
|
||||
fields of a &v4l2-buffer; as above, when <constant>VIDIOC_DQBUF</constant>
|
||||
is called with a pointer to this structure the driver fills the
|
||||
remaining fields or returns an error code.</para>
|
||||
|
|
|
@ -54,12 +54,13 @@ buffer at any time after buffers have been allocated with the
|
|||
&VIDIOC-REQBUFS; ioctl.</para>
|
||||
|
||||
<para>Applications set the <structfield>type</structfield> field
|
||||
of a &v4l2-buffer; to the same buffer type as previously
|
||||
of a &v4l2-buffer; to the same buffer type as was previously used with
|
||||
&v4l2-format; <structfield>type</structfield> and &v4l2-requestbuffers;
|
||||
<structfield>type</structfield>, and the <structfield>index</structfield>
|
||||
field. Valid index numbers range from zero
|
||||
to the number of buffers allocated with &VIDIOC-REQBUFS;
|
||||
(&v4l2-requestbuffers; <structfield>count</structfield>) minus one.
|
||||
The <structfield>reserved</structfield> field should to set to 0.
|
||||
After calling <constant>VIDIOC_QUERYBUF</constant> with a pointer to
|
||||
this structure drivers return an error code or fill the rest of
|
||||
the structure.</para>
|
||||
|
@ -68,8 +69,8 @@ the structure.</para>
|
|||
<constant>V4L2_BUF_FLAG_MAPPED</constant>,
|
||||
<constant>V4L2_BUF_FLAG_QUEUED</constant> and
|
||||
<constant>V4L2_BUF_FLAG_DONE</constant> flags will be valid. The
|
||||
<structfield>memory</structfield> field will be set to
|
||||
<constant>V4L2_MEMORY_MMAP</constant>, the <structfield>m.offset</structfield>
|
||||
<structfield>memory</structfield> field will be set to the current
|
||||
I/O method, the <structfield>m.offset</structfield>
|
||||
contains the offset of the buffer from the start of the device memory,
|
||||
the <structfield>length</structfield> field its size. The driver may
|
||||
or may not set the remaining fields and flags, they are meaningless in
|
||||
|
|
|
@ -54,23 +54,23 @@ I/O. Memory mapped buffers are located in device memory and must be
|
|||
allocated with this ioctl before they can be mapped into the
|
||||
application's address space. User buffers are allocated by
|
||||
applications themselves, and this ioctl is merely used to switch the
|
||||
driver into user pointer I/O mode.</para>
|
||||
driver into user pointer I/O mode and to setup some internal structures.</para>
|
||||
|
||||
<para>To allocate device buffers applications initialize three
|
||||
fields of a <structname>v4l2_requestbuffers</structname> structure.
|
||||
<para>To allocate device buffers applications initialize all
|
||||
fields of the <structname>v4l2_requestbuffers</structname> structure.
|
||||
They set the <structfield>type</structfield> field to the respective
|
||||
stream or buffer type, the <structfield>count</structfield> field to
|
||||
the desired number of buffers, and <structfield>memory</structfield>
|
||||
must be set to <constant>V4L2_MEMORY_MMAP</constant>. When the ioctl
|
||||
is called with a pointer to this structure the driver attempts to
|
||||
allocate the requested number of buffers and stores the actual number
|
||||
the desired number of buffers, <structfield>memory</structfield>
|
||||
must be set to the requested I/O method and the reserved array
|
||||
must be zeroed. When the ioctl
|
||||
is called with a pointer to this structure the driver will attempt to allocate
|
||||
the requested number of buffers and it stores the actual number
|
||||
allocated in the <structfield>count</structfield> field. It can be
|
||||
smaller than the number requested, even zero, when the driver runs out
|
||||
of free memory. A larger number is possible when the driver requires
|
||||
more buffers to function correctly.<footnote>
|
||||
<para>For example video output requires at least two buffers,
|
||||
of free memory. A larger number is also possible when the driver requires
|
||||
more buffers to function correctly. For example video output requires at least two buffers,
|
||||
one displayed and one filled by the application.</para>
|
||||
</footnote> When memory mapping I/O is not supported the ioctl
|
||||
<para>When the I/O method is not supported the ioctl
|
||||
returns an &EINVAL;.</para>
|
||||
|
||||
<para>Applications can call <constant>VIDIOC_REQBUFS</constant>
|
||||
|
@ -81,14 +81,6 @@ in progress, an implicit &VIDIOC-STREAMOFF;. <!-- mhs: I see no
|
|||
reason why munmap()ping one or even all buffers must imply
|
||||
streamoff.--></para>
|
||||
|
||||
<para>To negotiate user pointer I/O, applications initialize only
|
||||
the <structfield>type</structfield> field and set
|
||||
<structfield>memory</structfield> to
|
||||
<constant>V4L2_MEMORY_USERPTR</constant>. When the ioctl is called
|
||||
with a pointer to this structure the driver prepares for user pointer
|
||||
I/O, when this I/O method is not supported the ioctl returns an
|
||||
&EINVAL;.</para>
|
||||
|
||||
<table pgwide="1" frame="none" id="v4l2-requestbuffers">
|
||||
<title>struct <structname>v4l2_requestbuffers</structname></title>
|
||||
<tgroup cols="3">
|
||||
|
@ -97,9 +89,7 @@ I/O, when this I/O method is not supported the ioctl returns an
|
|||
<row>
|
||||
<entry>__u32</entry>
|
||||
<entry><structfield>count</structfield></entry>
|
||||
<entry>The number of buffers requested or granted. This
|
||||
field is only used when <structfield>memory</structfield> is set to
|
||||
<constant>V4L2_MEMORY_MMAP</constant>.</entry>
|
||||
<entry>The number of buffers requested or granted.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>&v4l2-buf-type;</entry>
|
||||
|
@ -120,7 +110,7 @@ as the &v4l2-format; <structfield>type</structfield> field. See <xref
|
|||
<entry><structfield>reserved</structfield>[2]</entry>
|
||||
<entry>A place holder for future extensions and custom
|
||||
(driver defined) buffer types <constant>V4L2_BUF_TYPE_PRIVATE</constant> and
|
||||
higher.</entry>
|
||||
higher. This array should be zeroed by applications.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
|
|
@ -26,7 +26,7 @@ use IO::Handle;
|
|||
"dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
|
||||
"or51211", "or51132_qam", "or51132_vsb", "bluebird",
|
||||
"opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
|
||||
"af9015");
|
||||
"af9015", "ngene");
|
||||
|
||||
# Check args
|
||||
syntax() if (scalar(@ARGV) != 1);
|
||||
|
@ -39,7 +39,7 @@ for ($i=0; $i < scalar(@components); $i++) {
|
|||
die $@ if $@;
|
||||
print STDERR <<EOF;
|
||||
Firmware(s) $outfile extracted successfully.
|
||||
Now copy it(they) to either /usr/lib/hotplug/firmware or /lib/firmware
|
||||
Now copy it(them) to either /usr/lib/hotplug/firmware or /lib/firmware
|
||||
(depending on configuration of firmware hotplug).
|
||||
EOF
|
||||
exit(0);
|
||||
|
@ -549,6 +549,24 @@ sub af9015 {
|
|||
close INFILE;
|
||||
}
|
||||
|
||||
sub ngene {
|
||||
my $url = "http://www.digitaldevices.de/download/";
|
||||
my $file1 = "ngene_15.fw";
|
||||
my $hash1 = "d798d5a757121174f0dbc5f2833c0c85";
|
||||
my $file2 = "ngene_17.fw";
|
||||
my $hash2 = "26b687136e127b8ac24b81e0eeafc20b";
|
||||
|
||||
checkstandard();
|
||||
|
||||
wgetfile($file1, $url . $file1);
|
||||
verify($file1, $hash1);
|
||||
|
||||
wgetfile($file2, $url . $file2);
|
||||
verify($file2, $hash2);
|
||||
|
||||
"$file1, $file2";
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# Utilities
|
||||
|
||||
|
@ -667,6 +685,7 @@ sub delzero{
|
|||
sub syntax() {
|
||||
print STDERR "syntax: get_dvb_firmware <component>\n";
|
||||
print STDERR "Supported components:\n";
|
||||
@components = sort @components;
|
||||
for($i=0; $i < scalar(@components); $i++) {
|
||||
print STDERR "\t" . $components[$i] . "\n";
|
||||
}
|
||||
|
|
|
@ -26,3 +26,4 @@
|
|||
25 -> Compro VideoMate E800 [1858:e800]
|
||||
26 -> Hauppauge WinTV-HVR1290 [0070:8551]
|
||||
27 -> Mygica X8558 PRO DMB-TH [14f1:8578]
|
||||
28 -> LEADTEK WinFast PxTV1200 [107d:6f22]
|
||||
|
|
|
@ -174,3 +174,4 @@
|
|||
173 -> Zolid Hybrid TV Tuner PCI [1131:2004]
|
||||
174 -> Asus Europa Hybrid OEM [1043:4847]
|
||||
175 -> Leadtek Winfast DTV1000S [107d:6655]
|
||||
176 -> Beholder BeholdTV 505 RDS [0000:5051]
|
||||
|
|
|
@ -81,3 +81,4 @@ tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough
|
|||
tuner=81 - Partsnic (Daewoo) PTI-5NF05
|
||||
tuner=82 - Philips CU1216L
|
||||
tuner=83 - NXP TDA18271
|
||||
tuner=84 - Sony BTF-Pxn01Z
|
||||
|
|
47
Documentation/video4linux/README.tlg2300
Normal file
47
Documentation/video4linux/README.tlg2300
Normal file
|
@ -0,0 +1,47 @@
|
|||
tlg2300 release notes
|
||||
====================
|
||||
|
||||
This is a v4l2/dvb device driver for the tlg2300 chip.
|
||||
|
||||
|
||||
current status
|
||||
==============
|
||||
|
||||
video
|
||||
- support mmap and read().(no overlay)
|
||||
|
||||
audio
|
||||
- The driver will register a ALSA card for the audio input.
|
||||
|
||||
vbi
|
||||
- Works for almost TV norms.
|
||||
|
||||
dvb-t
|
||||
- works for DVB-T
|
||||
|
||||
FM
|
||||
- Works for radio.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
TESTED APPLICATIONS:
|
||||
|
||||
-VLC1.0.4 test the video and dvb. The GUI is friendly to use.
|
||||
|
||||
-Mplayer test the video.
|
||||
|
||||
-Mplayer test the FM. The mplayer should be compiled with --enable-radio and
|
||||
--enable-radio-capture.
|
||||
The command runs as this(The alsa audio registers to card 1):
|
||||
#mplayer radio://103.7/capture/ -radio adevice=hw=1,0:arate=48000 \
|
||||
-rawaudio rate=48000:channels=2
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
KNOWN PROBLEMS:
|
||||
about preemphasis:
|
||||
You can set the preemphasis for radio by the following command:
|
||||
#v4l2-ctl -d /dev/radio0 --set-ctrl=pre_emphasis_settings=1
|
||||
|
||||
"pre_emphasis_settings=1" means that you select the 50us. If you want
|
||||
to select the 75us, please use "pre_emphasis_settings=2"
|
||||
|
||||
|
|
@ -42,6 +42,7 @@ ov519 041e:4064 Creative Live! VISTA VF0420
|
|||
ov519 041e:4067 Creative Live! Cam Video IM (VF0350)
|
||||
ov519 041e:4068 Creative Live! VISTA VF0470
|
||||
spca561 0458:7004 Genius VideoCAM Express V2
|
||||
sn9c2028 0458:7005 Genius Smart 300, version 2
|
||||
sunplus 0458:7006 Genius Dsc 1.3 Smart
|
||||
zc3xx 0458:7007 Genius VideoCam V2
|
||||
zc3xx 0458:700c Genius VideoCam V3
|
||||
|
@ -109,6 +110,7 @@ sunplus 04a5:3003 Benq DC 1300
|
|||
sunplus 04a5:3008 Benq DC 1500
|
||||
sunplus 04a5:300a Benq DC 3410
|
||||
spca500 04a5:300c Benq DC 1016
|
||||
benq 04a5:3035 Benq DC E300
|
||||
finepix 04cb:0104 Fujifilm FinePix 4800
|
||||
finepix 04cb:0109 Fujifilm FinePix A202
|
||||
finepix 04cb:010b Fujifilm FinePix A203
|
||||
|
@ -142,6 +144,7 @@ sunplus 04fc:5360 Sunplus Generic
|
|||
spca500 04fc:7333 PalmPixDC85
|
||||
sunplus 04fc:ffff Pure DigitalDakota
|
||||
spca501 0506:00df 3Com HomeConnect Lite
|
||||
sunplus 052b:1507 Megapixel 5 Pretec DC-1007
|
||||
sunplus 052b:1513 Megapix V4
|
||||
sunplus 052b:1803 MegaImage VI
|
||||
tv8532 0545:808b Veo Stingray
|
||||
|
@ -151,6 +154,7 @@ sunplus 0546:3191 Polaroid Ion 80
|
|||
sunplus 0546:3273 Polaroid PDC2030
|
||||
ov519 054c:0154 Sonny toy4
|
||||
ov519 054c:0155 Sonny toy5
|
||||
cpia1 0553:0002 CPIA CPiA (version1) based cameras
|
||||
zc3xx 055f:c005 Mustek Wcam300A
|
||||
spca500 055f:c200 Mustek Gsmart 300
|
||||
sunplus 055f:c211 Kowa Bs888e Microcamera
|
||||
|
@ -188,8 +192,7 @@ spca500 06bd:0404 Agfa CL20
|
|||
spca500 06be:0800 Optimedia
|
||||
sunplus 06d6:0031 Trust 610 LCD PowerC@m Zoom
|
||||
spca506 06e1:a190 ADS Instant VCD
|
||||
ov534 06f8:3002 Hercules Blog Webcam
|
||||
ov534 06f8:3003 Hercules Dualpix HD Weblog
|
||||
ov534_9 06f8:3003 Hercules Dualpix HD Weblog
|
||||
sonixj 06f8:3004 Hercules Classic Silver
|
||||
sonixj 06f8:3008 Hercules Deluxe Optical Glass
|
||||
pac7302 06f8:3009 Hercules Classic Link
|
||||
|
@ -204,6 +207,7 @@ sunplus 0733:2221 Mercury Digital Pro 3.1p
|
|||
sunplus 0733:3261 Concord 3045 spca536a
|
||||
sunplus 0733:3281 Cyberpix S550V
|
||||
spca506 0734:043b 3DeMon USB Capture aka
|
||||
cpia1 0813:0001 QX3 camera
|
||||
ov519 0813:0002 Dual Mode USB Camera Plus
|
||||
spca500 084d:0003 D-Link DSC-350
|
||||
spca500 08ca:0103 Aiptek PocketDV
|
||||
|
@ -225,7 +229,8 @@ sunplus 08ca:2050 Medion MD 41437
|
|||
sunplus 08ca:2060 Aiptek PocketDV5300
|
||||
tv8532 0923:010f ICM532 cams
|
||||
mars 093a:050f Mars-Semi Pc-Camera
|
||||
mr97310a 093a:010f Sakar Digital no. 77379
|
||||
mr97310a 093a:010e All known CIF cams with this ID
|
||||
mr97310a 093a:010f All known VGA cams with this ID
|
||||
pac207 093a:2460 Qtec Webcam 100
|
||||
pac207 093a:2461 HP Webcam
|
||||
pac207 093a:2463 Philips SPC 220 NC
|
||||
|
@ -302,6 +307,7 @@ sonixj 0c45:613b Surfer SN-206
|
|||
sonixj 0c45:613c Sonix Pccam168
|
||||
sonixj 0c45:6143 Sonix Pccam168
|
||||
sonixj 0c45:6148 Digitus DA-70811/ZSMC USB PC Camera ZS211/Microdia
|
||||
sonixj 0c45:614a Frontech E-Ccam (JIL-2225)
|
||||
sn9c20x 0c45:6240 PC Camera (SN9C201 + MT9M001)
|
||||
sn9c20x 0c45:6242 PC Camera (SN9C201 + MT9M111)
|
||||
sn9c20x 0c45:6248 PC Camera (SN9C201 + OV9655)
|
||||
|
@ -324,6 +330,10 @@ sn9c20x 0c45:62b0 PC Camera (SN9C202 + MT9V011/MT9V111/MT9V112)
|
|||
sn9c20x 0c45:62b3 PC Camera (SN9C202 + OV9655)
|
||||
sn9c20x 0c45:62bb PC Camera (SN9C202 + OV7660)
|
||||
sn9c20x 0c45:62bc PC Camera (SN9C202 + HV7131R)
|
||||
sn9c2028 0c45:8001 Wild Planet Digital Spy Camera
|
||||
sn9c2028 0c45:8003 Sakar #11199, #6637x, #67480 keychain cams
|
||||
sn9c2028 0c45:8008 Mini-Shotz ms-350
|
||||
sn9c2028 0c45:800a Vivitar Vivicam 3350B
|
||||
sunplus 0d64:0303 Sunplus FashionCam DXG
|
||||
ov519 0e96:c001 TRUST 380 USB2 SPACEC@M
|
||||
etoms 102c:6151 Qcam Sangha CIF
|
||||
|
@ -341,10 +351,11 @@ spca501 1776:501c Arowana 300K CMOS Camera
|
|||
t613 17a1:0128 TASCORP JPEG Webcam, NGS Cyclops
|
||||
vc032x 17ef:4802 Lenovo Vc0323+MI1310_SOC
|
||||
pac207 2001:f115 D-Link DSB-C120
|
||||
sq905c 2770:9050 sq905c
|
||||
sq905c 2770:905c DualCamera
|
||||
sq905 2770:9120 Argus Digital Camera DC1512
|
||||
sq905c 2770:913d sq905c
|
||||
sq905c 2770:9050 Disney pix micro (CIF)
|
||||
sq905c 2770:9052 Disney pix micro 2 (VGA)
|
||||
sq905c 2770:905c All 11 known cameras with this ID
|
||||
sq905 2770:9120 All 24 known cameras with this ID
|
||||
sq905c 2770:913d All 4 known cameras with this ID
|
||||
spca500 2899:012c Toptro Industrial
|
||||
ov519 8020:ef04 ov519
|
||||
spca508 8086:0110 Intel Easy PC Camera
|
||||
|
|
|
@ -599,99 +599,13 @@ video_device::minor fields.
|
|||
video buffer helper functions
|
||||
-----------------------------
|
||||
|
||||
The v4l2 core API provides a standard method for dealing with video
|
||||
buffers. Those methods allow a driver to implement read(), mmap() and
|
||||
overlay() on a consistent way.
|
||||
The v4l2 core API provides a set of standard methods (called "videobuf")
|
||||
for dealing with video buffers. Those methods allow a driver to implement
|
||||
read(), mmap() and overlay() in a consistent way. There are currently
|
||||
methods for using video buffers on devices that supports DMA with
|
||||
scatter/gather method (videobuf-dma-sg), DMA with linear access
|
||||
(videobuf-dma-contig), and vmalloced buffers, mostly used on USB drivers
|
||||
(videobuf-vmalloc).
|
||||
|
||||
There are currently methods for using video buffers on devices that
|
||||
supports DMA with scatter/gather method (videobuf-dma-sg), DMA with
|
||||
linear access (videobuf-dma-contig), and vmalloced buffers, mostly
|
||||
used on USB drivers (videobuf-vmalloc).
|
||||
|
||||
Any driver using videobuf should provide operations (callbacks) for
|
||||
four handlers:
|
||||
|
||||
ops->buf_setup - calculates the size of the video buffers and avoid they
|
||||
to waste more than some maximum limit of RAM;
|
||||
ops->buf_prepare - fills the video buffer structs and calls
|
||||
videobuf_iolock() to alloc and prepare mmaped memory;
|
||||
ops->buf_queue - advices the driver that another buffer were
|
||||
requested (by read() or by QBUF);
|
||||
ops->buf_release - frees any buffer that were allocated.
|
||||
|
||||
In order to use it, the driver need to have a code (generally called at
|
||||
interrupt context) that will properly handle the buffer request lists,
|
||||
announcing that a new buffer were filled.
|
||||
|
||||
The irq handling code should handle the videobuf task lists, in order
|
||||
to advice videobuf that a new frame were filled, in order to honor to a
|
||||
request. The code is generally like this one:
|
||||
if (list_empty(&dma_q->active))
|
||||
return;
|
||||
|
||||
buf = list_entry(dma_q->active.next, struct vbuffer, vb.queue);
|
||||
|
||||
if (!waitqueue_active(&buf->vb.done))
|
||||
return;
|
||||
|
||||
/* Some logic to handle the buf may be needed here */
|
||||
|
||||
list_del(&buf->vb.queue);
|
||||
do_gettimeofday(&buf->vb.ts);
|
||||
wake_up(&buf->vb.done);
|
||||
|
||||
Those are the videobuffer functions used on drivers, implemented on
|
||||
videobuf-core:
|
||||
|
||||
- Videobuf init functions
|
||||
videobuf_queue_sg_init()
|
||||
Initializes the videobuf infrastructure. This function should be
|
||||
called before any other videobuf function on drivers that uses DMA
|
||||
Scatter/Gather buffers.
|
||||
|
||||
videobuf_queue_dma_contig_init
|
||||
Initializes the videobuf infrastructure. This function should be
|
||||
called before any other videobuf function on drivers that need DMA
|
||||
contiguous buffers.
|
||||
|
||||
videobuf_queue_vmalloc_init()
|
||||
Initializes the videobuf infrastructure. This function should be
|
||||
called before any other videobuf function on USB (and other drivers)
|
||||
that need a vmalloced type of videobuf.
|
||||
|
||||
- videobuf_iolock()
|
||||
Prepares the videobuf memory for the proper method (read, mmap, overlay).
|
||||
|
||||
- videobuf_queue_is_busy()
|
||||
Checks if a videobuf is streaming.
|
||||
|
||||
- videobuf_queue_cancel()
|
||||
Stops video handling.
|
||||
|
||||
- videobuf_mmap_free()
|
||||
frees mmap buffers.
|
||||
|
||||
- videobuf_stop()
|
||||
Stops video handling, ends mmap and frees mmap and other buffers.
|
||||
|
||||
- V4L2 api functions. Those functions correspond to VIDIOC_foo ioctls:
|
||||
videobuf_reqbufs(), videobuf_querybuf(), videobuf_qbuf(),
|
||||
videobuf_dqbuf(), videobuf_streamon(), videobuf_streamoff().
|
||||
|
||||
- V4L1 api function (corresponds to VIDIOCMBUF ioctl):
|
||||
videobuf_cgmbuf()
|
||||
This function is used to provide backward compatibility with V4L1
|
||||
API.
|
||||
|
||||
- Some help functions for read()/poll() operations:
|
||||
videobuf_read_stream()
|
||||
For continuous stream read()
|
||||
videobuf_read_one()
|
||||
For snapshot read()
|
||||
videobuf_poll_stream()
|
||||
polling help function
|
||||
|
||||
The better way to understand it is to take a look at vivi driver. One
|
||||
of the main reasons for vivi is to be a videobuf usage example. the
|
||||
vivi_thread_tick() does the task that the IRQ callback would do on PCI
|
||||
drivers (or the irq callback on USB).
|
||||
Please see Documentation/video4linux/videobuf for more information on how
|
||||
to use the videobuf layer.
|
||||
|
|
360
Documentation/video4linux/videobuf
Normal file
360
Documentation/video4linux/videobuf
Normal file
|
@ -0,0 +1,360 @@
|
|||
An introduction to the videobuf layer
|
||||
Jonathan Corbet <corbet@lwn.net>
|
||||
Current as of 2.6.33
|
||||
|
||||
The videobuf layer functions as a sort of glue layer between a V4L2 driver
|
||||
and user space. It handles the allocation and management of buffers for
|
||||
the storage of video frames. There is a set of functions which can be used
|
||||
to implement many of the standard POSIX I/O system calls, including read(),
|
||||
poll(), and, happily, mmap(). Another set of functions can be used to
|
||||
implement the bulk of the V4L2 ioctl() calls related to streaming I/O,
|
||||
including buffer allocation, queueing and dequeueing, and streaming
|
||||
control. Using videobuf imposes a few design decisions on the driver
|
||||
author, but the payback comes in the form of reduced code in the driver and
|
||||
a consistent implementation of the V4L2 user-space API.
|
||||
|
||||
Buffer types
|
||||
|
||||
Not all video devices use the same kind of buffers. In fact, there are (at
|
||||
least) three common variations:
|
||||
|
||||
- Buffers which are scattered in both the physical and (kernel) virtual
|
||||
address spaces. (Almost) all user-space buffers are like this, but it
|
||||
makes great sense to allocate kernel-space buffers this way as well when
|
||||
it is possible. Unfortunately, it is not always possible; working with
|
||||
this kind of buffer normally requires hardware which can do
|
||||
scatter/gather DMA operations.
|
||||
|
||||
- Buffers which are physically scattered, but which are virtually
|
||||
contiguous; buffers allocated with vmalloc(), in other words. These
|
||||
buffers are just as hard to use for DMA operations, but they can be
|
||||
useful in situations where DMA is not available but virtually-contiguous
|
||||
buffers are convenient.
|
||||
|
||||
- Buffers which are physically contiguous. Allocation of this kind of
|
||||
buffer can be unreliable on fragmented systems, but simpler DMA
|
||||
controllers cannot deal with anything else.
|
||||
|
||||
Videobuf can work with all three types of buffers, but the driver author
|
||||
must pick one at the outset and design the driver around that decision.
|
||||
|
||||
[It's worth noting that there's a fourth kind of buffer: "overlay" buffers
|
||||
which are located within the system's video memory. The overlay
|
||||
functionality is considered to be deprecated for most use, but it still
|
||||
shows up occasionally in system-on-chip drivers where the performance
|
||||
benefits merit the use of this technique. Overlay buffers can be handled
|
||||
as a form of scattered buffer, but there are very few implementations in
|
||||
the kernel and a description of this technique is currently beyond the
|
||||
scope of this document.]
|
||||
|
||||
Data structures, callbacks, and initialization
|
||||
|
||||
Depending on which type of buffers are being used, the driver should
|
||||
include one of the following files:
|
||||
|
||||
<media/videobuf-dma-sg.h> /* Physically scattered */
|
||||
<media/videobuf-vmalloc.h> /* vmalloc() buffers */
|
||||
<media/videobuf-dma-contig.h> /* Physically contiguous */
|
||||
|
||||
The driver's data structure describing a V4L2 device should include a
|
||||
struct videobuf_queue instance for the management of the buffer queue,
|
||||
along with a list_head for the queue of available buffers. There will also
|
||||
need to be an interrupt-safe spinlock which is used to protect (at least)
|
||||
the queue.
|
||||
|
||||
The next step is to write four simple callbacks to help videobuf deal with
|
||||
the management of buffers:
|
||||
|
||||
struct videobuf_queue_ops {
|
||||
int (*buf_setup)(struct videobuf_queue *q,
|
||||
unsigned int *count, unsigned int *size);
|
||||
int (*buf_prepare)(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb,
|
||||
enum v4l2_field field);
|
||||
void (*buf_queue)(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb);
|
||||
void (*buf_release)(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb);
|
||||
};
|
||||
|
||||
buf_setup() is called early in the I/O process, when streaming is being
|
||||
initiated; its purpose is to tell videobuf about the I/O stream. The count
|
||||
parameter will be a suggested number of buffers to use; the driver should
|
||||
check it for rationality and adjust it if need be. As a practical rule, a
|
||||
minimum of two buffers are needed for proper streaming, and there is
|
||||
usually a maximum (which cannot exceed 32) which makes sense for each
|
||||
device. The size parameter should be set to the expected (maximum) size
|
||||
for each frame of data.
|
||||
|
||||
Each buffer (in the form of a struct videobuf_buffer pointer) will be
|
||||
passed to buf_prepare(), which should set the buffer's size, width, height,
|
||||
and field fields properly. If the buffer's state field is
|
||||
VIDEOBUF_NEEDS_INIT, the driver should pass it to:
|
||||
|
||||
int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
|
||||
struct v4l2_framebuffer *fbuf);
|
||||
|
||||
Among other things, this call will usually allocate memory for the buffer.
|
||||
Finally, the buf_prepare() function should set the buffer's state to
|
||||
VIDEOBUF_PREPARED.
|
||||
|
||||
When a buffer is queued for I/O, it is passed to buf_queue(), which should
|
||||
put it onto the driver's list of available buffers and set its state to
|
||||
VIDEOBUF_QUEUED. Note that this function is called with the queue spinlock
|
||||
held; if it tries to acquire it as well things will come to a screeching
|
||||
halt. Yes, this is the voice of experience. Note also that videobuf may
|
||||
wait on the first buffer in the queue; placing other buffers in front of it
|
||||
could again gum up the works. So use list_add_tail() to enqueue buffers.
|
||||
|
||||
Finally, buf_release() is called when a buffer is no longer intended to be
|
||||
used. The driver should ensure that there is no I/O active on the buffer,
|
||||
then pass it to the appropriate free routine(s):
|
||||
|
||||
/* Scatter/gather drivers */
|
||||
int videobuf_dma_unmap(struct videobuf_queue *q,
|
||||
struct videobuf_dmabuf *dma);
|
||||
int videobuf_dma_free(struct videobuf_dmabuf *dma);
|
||||
|
||||
/* vmalloc drivers */
|
||||
void videobuf_vmalloc_free (struct videobuf_buffer *buf);
|
||||
|
||||
/* Contiguous drivers */
|
||||
void videobuf_dma_contig_free(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *buf);
|
||||
|
||||
One way to ensure that a buffer is no longer under I/O is to pass it to:
|
||||
|
||||
int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr);
|
||||
|
||||
Here, vb is the buffer, non_blocking indicates whether non-blocking I/O
|
||||
should be used (it should be zero in the buf_release() case), and intr
|
||||
controls whether an interruptible wait is used.
|
||||
|
||||
File operations
|
||||
|
||||
At this point, much of the work is done; much of the rest is slipping
|
||||
videobuf calls into the implementation of the other driver callbacks. The
|
||||
first step is in the open() function, which must initialize the
|
||||
videobuf queue. The function to use depends on the type of buffer used:
|
||||
|
||||
void videobuf_queue_sg_init(struct videobuf_queue *q,
|
||||
struct videobuf_queue_ops *ops,
|
||||
struct device *dev,
|
||||
spinlock_t *irqlock,
|
||||
enum v4l2_buf_type type,
|
||||
enum v4l2_field field,
|
||||
unsigned int msize,
|
||||
void *priv);
|
||||
|
||||
void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
|
||||
struct videobuf_queue_ops *ops,
|
||||
struct device *dev,
|
||||
spinlock_t *irqlock,
|
||||
enum v4l2_buf_type type,
|
||||
enum v4l2_field field,
|
||||
unsigned int msize,
|
||||
void *priv);
|
||||
|
||||
void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
|
||||
struct videobuf_queue_ops *ops,
|
||||
struct device *dev,
|
||||
spinlock_t *irqlock,
|
||||
enum v4l2_buf_type type,
|
||||
enum v4l2_field field,
|
||||
unsigned int msize,
|
||||
void *priv);
|
||||
|
||||
In each case, the parameters are the same: q is the queue structure for the
|
||||
device, ops is the set of callbacks as described above, dev is the device
|
||||
structure for this video device, irqlock is an interrupt-safe spinlock to
|
||||
protect access to the data structures, type is the buffer type used by the
|
||||
device (cameras will use V4L2_BUF_TYPE_VIDEO_CAPTURE, for example), field
|
||||
describes which field is being captured (often V4L2_FIELD_NONE for
|
||||
progressive devices), msize is the size of any containing structure used
|
||||
around struct videobuf_buffer, and priv is a private data pointer which
|
||||
shows up in the priv_data field of struct videobuf_queue. Note that these
|
||||
are void functions which, evidently, are immune to failure.
|
||||
|
||||
V4L2 capture drivers can be written to support either of two APIs: the
|
||||
read() system call and the rather more complicated streaming mechanism. As
|
||||
a general rule, it is necessary to support both to ensure that all
|
||||
applications have a chance of working with the device. Videobuf makes it
|
||||
easy to do that with the same code. To implement read(), the driver need
|
||||
only make a call to one of:
|
||||
|
||||
ssize_t videobuf_read_one(struct videobuf_queue *q,
|
||||
char __user *data, size_t count,
|
||||
loff_t *ppos, int nonblocking);
|
||||
|
||||
ssize_t videobuf_read_stream(struct videobuf_queue *q,
|
||||
char __user *data, size_t count,
|
||||
loff_t *ppos, int vbihack, int nonblocking);
|
||||
|
||||
Either one of these functions will read frame data into data, returning the
|
||||
amount actually read; the difference is that videobuf_read_one() will only
|
||||
read a single frame, while videobuf_read_stream() will read multiple frames
|
||||
if they are needed to satisfy the count requested by the application. A
|
||||
typical driver read() implementation will start the capture engine, call
|
||||
one of the above functions, then stop the engine before returning (though a
|
||||
smarter implementation might leave the engine running for a little while in
|
||||
anticipation of another read() call happening in the near future).
|
||||
|
||||
The poll() function can usually be implemented with a direct call to:
|
||||
|
||||
unsigned int videobuf_poll_stream(struct file *file,
|
||||
struct videobuf_queue *q,
|
||||
poll_table *wait);
|
||||
|
||||
Note that the actual wait queue eventually used will be the one associated
|
||||
with the first available buffer.
|
||||
|
||||
When streaming I/O is done to kernel-space buffers, the driver must support
|
||||
the mmap() system call to enable user space to access the data. In many
|
||||
V4L2 drivers, the often-complex mmap() implementation simplifies to a
|
||||
single call to:
|
||||
|
||||
int videobuf_mmap_mapper(struct videobuf_queue *q,
|
||||
struct vm_area_struct *vma);
|
||||
|
||||
Everything else is handled by the videobuf code.
|
||||
|
||||
The release() function requires two separate videobuf calls:
|
||||
|
||||
void videobuf_stop(struct videobuf_queue *q);
|
||||
int videobuf_mmap_free(struct videobuf_queue *q);
|
||||
|
||||
The call to videobuf_stop() terminates any I/O in progress - though it is
|
||||
still up to the driver to stop the capture engine. The call to
|
||||
videobuf_mmap_free() will ensure that all buffers have been unmapped; if
|
||||
so, they will all be passed to the buf_release() callback. If buffers
|
||||
remain mapped, videobuf_mmap_free() returns an error code instead. The
|
||||
purpose is clearly to cause the closing of the file descriptor to fail if
|
||||
buffers are still mapped, but every driver in the 2.6.32 kernel cheerfully
|
||||
ignores its return value.
|
||||
|
||||
ioctl() operations
|
||||
|
||||
The V4L2 API includes a very long list of driver callbacks to respond to
|
||||
the many ioctl() commands made available to user space. A number of these
|
||||
- those associated with streaming I/O - turn almost directly into videobuf
|
||||
calls. The relevant helper functions are:
|
||||
|
||||
int videobuf_reqbufs(struct videobuf_queue *q,
|
||||
struct v4l2_requestbuffers *req);
|
||||
int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b);
|
||||
int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b);
|
||||
int videobuf_dqbuf(struct videobuf_queue *q, struct v4l2_buffer *b,
|
||||
int nonblocking);
|
||||
int videobuf_streamon(struct videobuf_queue *q);
|
||||
int videobuf_streamoff(struct videobuf_queue *q);
|
||||
int videobuf_cgmbuf(struct videobuf_queue *q, struct video_mbuf *mbuf,
|
||||
int count);
|
||||
|
||||
So, for example, a VIDIOC_REQBUFS call turns into a call to the driver's
|
||||
vidioc_reqbufs() callback which, in turn, usually only needs to locate the
|
||||
proper struct videobuf_queue pointer and pass it to videobuf_reqbufs().
|
||||
These support functions can replace a great deal of buffer management
|
||||
boilerplate in a lot of V4L2 drivers.
|
||||
|
||||
The vidioc_streamon() and vidioc_streamoff() functions will be a bit more
|
||||
complex, of course, since they will also need to deal with starting and
|
||||
stopping the capture engine. videobuf_cgmbuf(), called from the driver's
|
||||
vidiocgmbuf() function, only exists if the V4L1 compatibility module has
|
||||
been selected with CONFIG_VIDEO_V4L1_COMPAT, so its use must be surrounded
|
||||
with #ifdef directives.
|
||||
|
||||
Buffer allocation
|
||||
|
||||
Thus far, we have talked about buffers, but have not looked at how they are
|
||||
allocated. The scatter/gather case is the most complex on this front. For
|
||||
allocation, the driver can leave buffer allocation entirely up to the
|
||||
videobuf layer; in this case, buffers will be allocated as anonymous
|
||||
user-space pages and will be very scattered indeed. If the application is
|
||||
using user-space buffers, no allocation is needed; the videobuf layer will
|
||||
take care of calling get_user_pages() and filling in the scatterlist array.
|
||||
|
||||
If the driver needs to do its own memory allocation, it should be done in
|
||||
the vidioc_reqbufs() function, *after* calling videobuf_reqbufs(). The
|
||||
first step is a call to:
|
||||
|
||||
struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf);
|
||||
|
||||
The returned videobuf_dmabuf structure (defined in
|
||||
<media/videobuf-dma-sg.h>) includes a couple of relevant fields:
|
||||
|
||||
struct scatterlist *sglist;
|
||||
int sglen;
|
||||
|
||||
The driver must allocate an appropriately-sized scatterlist array and
|
||||
populate it with pointers to the pieces of the allocated buffer; sglen
|
||||
should be set to the length of the array.
|
||||
|
||||
Drivers using the vmalloc() method need not (and cannot) concern themselves
|
||||
with buffer allocation at all; videobuf will handle those details. The
|
||||
same is normally true of contiguous-DMA drivers as well; videobuf will
|
||||
allocate the buffers (with dma_alloc_coherent()) when it sees fit. That
|
||||
means that these drivers may be trying to do high-order allocations at any
|
||||
time, an operation which is not always guaranteed to work. Some drivers
|
||||
play tricks by allocating DMA space at system boot time; videobuf does not
|
||||
currently play well with those drivers.
|
||||
|
||||
As of 2.6.31, contiguous-DMA drivers can work with a user-supplied buffer,
|
||||
as long as that buffer is physically contiguous. Normal user-space
|
||||
allocations will not meet that criterion, but buffers obtained from other
|
||||
kernel drivers, or those contained within huge pages, will work with these
|
||||
drivers.
|
||||
|
||||
Filling the buffers
|
||||
|
||||
The final part of a videobuf implementation has no direct callback - it's
|
||||
the portion of the code which actually puts frame data into the buffers,
|
||||
usually in response to interrupts from the device. For all types of
|
||||
drivers, this process works approximately as follows:
|
||||
|
||||
- Obtain the next available buffer and make sure that somebody is actually
|
||||
waiting for it.
|
||||
|
||||
- Get a pointer to the memory and put video data there.
|
||||
|
||||
- Mark the buffer as done and wake up the process waiting for it.
|
||||
|
||||
Step (1) above is done by looking at the driver-managed list_head structure
|
||||
- the one which is filled in the buf_queue() callback. Because starting
|
||||
the engine and enqueueing buffers are done in separate steps, it's possible
|
||||
for the engine to be running without any buffers available - in the
|
||||
vmalloc() case especially. So the driver should be prepared for the list
|
||||
to be empty. It is equally possible that nobody is yet interested in the
|
||||
buffer; the driver should not remove it from the list or fill it until a
|
||||
process is waiting on it. That test can be done by examining the buffer's
|
||||
done field (a wait_queue_head_t structure) with waitqueue_active().
|
||||
|
||||
A buffer's state should be set to VIDEOBUF_ACTIVE before being mapped for
|
||||
DMA; that ensures that the videobuf layer will not try to do anything with
|
||||
it while the device is transferring data.
|
||||
|
||||
For scatter/gather drivers, the needed memory pointers will be found in the
|
||||
scatterlist structure described above. Drivers using the vmalloc() method
|
||||
can get a memory pointer with:
|
||||
|
||||
void *videobuf_to_vmalloc(struct videobuf_buffer *buf);
|
||||
|
||||
For contiguous DMA drivers, the function to use is:
|
||||
|
||||
dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
|
||||
|
||||
The contiguous DMA API goes out of its way to hide the kernel-space address
|
||||
of the DMA buffer from drivers.
|
||||
|
||||
The final step is to set the size field of the relevant videobuf_buffer
|
||||
structure to the actual size of the captured image, set state to
|
||||
VIDEOBUF_DONE, then call wake_up() on the done queue. At this point, the
|
||||
buffer is owned by the videobuf layer and the driver should not touch it
|
||||
again.
|
||||
|
||||
Developers who are interested in more information can go into the relevant
|
||||
header files; there are a few low-level functions declared there which have
|
||||
not been talked about here. Also worthwhile is the vivi driver
|
||||
(drivers/media/video/vivi.c), which is maintained as an example of how V4L2
|
||||
drivers should be written. Vivi only uses the vmalloc() API, but it's good
|
||||
enough to get started with. Note also that all of these calls are exported
|
||||
GPL-only, so they will not be available to non-GPL kernel modules.
|
|
@ -4693,6 +4693,13 @@ F: drivers/media/common/saa7146*
|
|||
F: drivers/media/video/*7146*
|
||||
F: include/media/*7146*
|
||||
|
||||
TLG2300 VIDEO4LINUX-2 DRIVER
|
||||
M: Huang Shijie <shijie8@gmail.com>
|
||||
M: Kang Yong <kangyong@telegent.com>
|
||||
M: Zhang Xiaobing <xbzhang@telegent.com>
|
||||
S: Supported
|
||||
F: drivers/media/video/tlg2300
|
||||
|
||||
SC1200 WDT DRIVER
|
||||
M: Zwane Mwaikambo <zwane@arm.linux.org.uk>
|
||||
S: Maintained
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#include <mach/nand.h>
|
||||
#include <mach/keyscan.h>
|
||||
|
||||
#include <media/tvp514x.h>
|
||||
|
||||
static inline int have_imager(void)
|
||||
{
|
||||
/* REVISIT when it's supported, trigger via Kconfig */
|
||||
|
@ -306,6 +308,73 @@ static void dm365evm_mmc_configure(void)
|
|||
davinci_cfg_reg(DM365_SD1_DATA0);
|
||||
}
|
||||
|
||||
static struct tvp514x_platform_data tvp5146_pdata = {
|
||||
.clk_polarity = 0,
|
||||
.hs_polarity = 1,
|
||||
.vs_polarity = 1
|
||||
};
|
||||
|
||||
#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL)
|
||||
/* Inputs available at the TVP5146 */
|
||||
static struct v4l2_input tvp5146_inputs[] = {
|
||||
{
|
||||
.index = 0,
|
||||
.name = "Composite",
|
||||
.type = V4L2_INPUT_TYPE_CAMERA,
|
||||
.std = TVP514X_STD_ALL,
|
||||
},
|
||||
{
|
||||
.index = 1,
|
||||
.name = "S-Video",
|
||||
.type = V4L2_INPUT_TYPE_CAMERA,
|
||||
.std = TVP514X_STD_ALL,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* this is the route info for connecting each input to decoder
|
||||
* ouput that goes to vpfe. There is a one to one correspondence
|
||||
* with tvp5146_inputs
|
||||
*/
|
||||
static struct vpfe_route tvp5146_routes[] = {
|
||||
{
|
||||
.input = INPUT_CVBS_VI2B,
|
||||
.output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
|
||||
},
|
||||
{
|
||||
.input = INPUT_SVIDEO_VI2C_VI1C,
|
||||
.output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
|
||||
},
|
||||
};
|
||||
|
||||
static struct vpfe_subdev_info vpfe_sub_devs[] = {
|
||||
{
|
||||
.name = "tvp5146",
|
||||
.grp_id = 0,
|
||||
.num_inputs = ARRAY_SIZE(tvp5146_inputs),
|
||||
.inputs = tvp5146_inputs,
|
||||
.routes = tvp5146_routes,
|
||||
.can_route = 1,
|
||||
.ccdc_if_params = {
|
||||
.if_type = VPFE_BT656,
|
||||
.hdpol = VPFE_PINPOL_POSITIVE,
|
||||
.vdpol = VPFE_PINPOL_POSITIVE,
|
||||
},
|
||||
.board_info = {
|
||||
I2C_BOARD_INFO("tvp5146", 0x5d),
|
||||
.platform_data = &tvp5146_pdata,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct vpfe_config vpfe_cfg = {
|
||||
.num_subdevs = ARRAY_SIZE(vpfe_sub_devs),
|
||||
.sub_devs = vpfe_sub_devs,
|
||||
.i2c_adapter_id = 1,
|
||||
.card_name = "DM365 EVM",
|
||||
.ccdc = "ISIF",
|
||||
};
|
||||
|
||||
static void __init evm_init_i2c(void)
|
||||
{
|
||||
davinci_init_i2c(&i2c_pdata);
|
||||
|
@ -497,6 +566,8 @@ static struct davinci_uart_config uart_config __initdata = {
|
|||
|
||||
static void __init dm365_evm_map_io(void)
|
||||
{
|
||||
/* setup input configuration for VPFE input devices */
|
||||
dm365_set_vpfe_config(&vpfe_cfg);
|
||||
dm365_init();
|
||||
}
|
||||
|
||||
|
|
|
@ -125,7 +125,6 @@ static struct clk vpss_slave_clk = {
|
|||
.lpsc = DAVINCI_LPSC_VPSSSLV,
|
||||
};
|
||||
|
||||
|
||||
static struct clk clkout1_clk = {
|
||||
.name = "clkout1",
|
||||
.parent = &pll1_aux_clk,
|
||||
|
@ -665,6 +664,17 @@ static struct platform_device dm355_asp1_device = {
|
|||
.resource = dm355_asp1_resources,
|
||||
};
|
||||
|
||||
static void dm355_ccdc_setup_pinmux(void)
|
||||
{
|
||||
davinci_cfg_reg(DM355_VIN_PCLK);
|
||||
davinci_cfg_reg(DM355_VIN_CAM_WEN);
|
||||
davinci_cfg_reg(DM355_VIN_CAM_VD);
|
||||
davinci_cfg_reg(DM355_VIN_CAM_HD);
|
||||
davinci_cfg_reg(DM355_VIN_YIN_EN);
|
||||
davinci_cfg_reg(DM355_VIN_CINL_EN);
|
||||
davinci_cfg_reg(DM355_VIN_CINH_EN);
|
||||
}
|
||||
|
||||
static struct resource dm355_vpss_resources[] = {
|
||||
{
|
||||
/* VPSS BL Base address */
|
||||
|
@ -701,6 +711,10 @@ static struct resource vpfe_resources[] = {
|
|||
.end = IRQ_VDINT1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32);
|
||||
static struct resource dm355_ccdc_resource[] = {
|
||||
/* CCDC Base address */
|
||||
{
|
||||
.flags = IORESOURCE_MEM,
|
||||
|
@ -708,8 +722,18 @@ static struct resource vpfe_resources[] = {
|
|||
.end = 0x01c70600 + 0x1ff,
|
||||
},
|
||||
};
|
||||
static struct platform_device dm355_ccdc_dev = {
|
||||
.name = "dm355_ccdc",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(dm355_ccdc_resource),
|
||||
.resource = dm355_ccdc_resource,
|
||||
.dev = {
|
||||
.dma_mask = &vpfe_capture_dma_mask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = dm355_ccdc_setup_pinmux,
|
||||
},
|
||||
};
|
||||
|
||||
static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32);
|
||||
static struct platform_device vpfe_capture_dev = {
|
||||
.name = CAPTURE_DRV_NAME,
|
||||
.id = -1,
|
||||
|
@ -857,20 +881,13 @@ static int __init dm355_init_devices(void)
|
|||
if (!cpu_is_davinci_dm355())
|
||||
return 0;
|
||||
|
||||
/* Add ccdc clock aliases */
|
||||
clk_add_alias("master", dm355_ccdc_dev.name, "vpss_master", NULL);
|
||||
clk_add_alias("slave", dm355_ccdc_dev.name, "vpss_master", NULL);
|
||||
davinci_cfg_reg(DM355_INT_EDMA_CC);
|
||||
platform_device_register(&dm355_edma_device);
|
||||
platform_device_register(&dm355_vpss_device);
|
||||
/*
|
||||
* setup Mux configuration for vpfe input and register
|
||||
* vpfe capture platform device
|
||||
*/
|
||||
davinci_cfg_reg(DM355_VIN_PCLK);
|
||||
davinci_cfg_reg(DM355_VIN_CAM_WEN);
|
||||
davinci_cfg_reg(DM355_VIN_CAM_VD);
|
||||
davinci_cfg_reg(DM355_VIN_CAM_HD);
|
||||
davinci_cfg_reg(DM355_VIN_YIN_EN);
|
||||
davinci_cfg_reg(DM355_VIN_CINL_EN);
|
||||
davinci_cfg_reg(DM355_VIN_CINH_EN);
|
||||
platform_device_register(&dm355_ccdc_dev);
|
||||
platform_device_register(&vpfe_capture_dev);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1008,6 +1008,97 @@ void __init dm365_init(void)
|
|||
davinci_common_init(&davinci_soc_info_dm365);
|
||||
}
|
||||
|
||||
static struct resource dm365_vpss_resources[] = {
|
||||
{
|
||||
/* VPSS ISP5 Base address */
|
||||
.name = "isp5",
|
||||
.start = 0x01c70000,
|
||||
.end = 0x01c70000 + 0xff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
/* VPSS CLK Base address */
|
||||
.name = "vpss",
|
||||
.start = 0x01c70200,
|
||||
.end = 0x01c70200 + 0xff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device dm365_vpss_device = {
|
||||
.name = "vpss",
|
||||
.id = -1,
|
||||
.dev.platform_data = "dm365_vpss",
|
||||
.num_resources = ARRAY_SIZE(dm365_vpss_resources),
|
||||
.resource = dm365_vpss_resources,
|
||||
};
|
||||
|
||||
static struct resource vpfe_resources[] = {
|
||||
{
|
||||
.start = IRQ_VDINT0,
|
||||
.end = IRQ_VDINT0,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = IRQ_VDINT1,
|
||||
.end = IRQ_VDINT1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32);
|
||||
static struct platform_device vpfe_capture_dev = {
|
||||
.name = CAPTURE_DRV_NAME,
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(vpfe_resources),
|
||||
.resource = vpfe_resources,
|
||||
.dev = {
|
||||
.dma_mask = &vpfe_capture_dma_mask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
||||
|
||||
static void dm365_isif_setup_pinmux(void)
|
||||
{
|
||||
davinci_cfg_reg(DM365_VIN_CAM_WEN);
|
||||
davinci_cfg_reg(DM365_VIN_CAM_VD);
|
||||
davinci_cfg_reg(DM365_VIN_CAM_HD);
|
||||
davinci_cfg_reg(DM365_VIN_YIN4_7_EN);
|
||||
davinci_cfg_reg(DM365_VIN_YIN0_3_EN);
|
||||
}
|
||||
|
||||
static struct resource isif_resource[] = {
|
||||
/* ISIF Base address */
|
||||
{
|
||||
.start = 0x01c71000,
|
||||
.end = 0x01c71000 + 0x1ff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
/* ISIF Linearization table 0 */
|
||||
{
|
||||
.start = 0x1C7C000,
|
||||
.end = 0x1C7C000 + 0x2ff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
/* ISIF Linearization table 1 */
|
||||
{
|
||||
.start = 0x1C7C400,
|
||||
.end = 0x1C7C400 + 0x2ff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
static struct platform_device dm365_isif_dev = {
|
||||
.name = "isif",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(isif_resource),
|
||||
.resource = isif_resource,
|
||||
.dev = {
|
||||
.dma_mask = &vpfe_capture_dma_mask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = dm365_isif_setup_pinmux,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init dm365_init_devices(void)
|
||||
{
|
||||
if (!cpu_is_davinci_dm365())
|
||||
|
@ -1016,7 +1107,16 @@ static int __init dm365_init_devices(void)
|
|||
davinci_cfg_reg(DM365_INT_EDMA_CC);
|
||||
platform_device_register(&dm365_edma_device);
|
||||
platform_device_register(&dm365_emac_device);
|
||||
|
||||
/* Add isif clock alias */
|
||||
clk_add_alias("master", dm365_isif_dev.name, "vpss_master", NULL);
|
||||
platform_device_register(&dm365_vpss_device);
|
||||
platform_device_register(&dm365_isif_dev);
|
||||
platform_device_register(&vpfe_capture_dev);
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(dm365_init_devices);
|
||||
|
||||
void dm365_set_vpfe_config(struct vpfe_config *cfg)
|
||||
{
|
||||
vpfe_capture_dev.dev.platform_data = cfg;
|
||||
}
|
||||
|
|
|
@ -612,6 +612,11 @@ static struct resource vpfe_resources[] = {
|
|||
.end = IRQ_VDINT1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32);
|
||||
static struct resource dm644x_ccdc_resource[] = {
|
||||
/* CCDC Base address */
|
||||
{
|
||||
.start = 0x01c70400,
|
||||
.end = 0x01c70400 + 0xff,
|
||||
|
@ -619,7 +624,17 @@ static struct resource vpfe_resources[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32);
|
||||
static struct platform_device dm644x_ccdc_dev = {
|
||||
.name = "dm644x_ccdc",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(dm644x_ccdc_resource),
|
||||
.resource = dm644x_ccdc_resource,
|
||||
.dev = {
|
||||
.dma_mask = &vpfe_capture_dma_mask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device vpfe_capture_dev = {
|
||||
.name = CAPTURE_DRV_NAME,
|
||||
.id = -1,
|
||||
|
@ -769,9 +784,13 @@ static int __init dm644x_init_devices(void)
|
|||
if (!cpu_is_davinci_dm644x())
|
||||
return 0;
|
||||
|
||||
/* Add ccdc clock aliases */
|
||||
clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL);
|
||||
clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL);
|
||||
platform_device_register(&dm644x_edma_device);
|
||||
platform_device_register(&dm644x_emac_device);
|
||||
platform_device_register(&dm644x_vpss_device);
|
||||
platform_device_register(&dm644x_ccdc_dev);
|
||||
platform_device_register(&vpfe_capture_dev);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <mach/emac.h>
|
||||
#include <mach/asp.h>
|
||||
#include <mach/keyscan.h>
|
||||
#include <media/davinci/vpfe_capture.h>
|
||||
|
||||
#define DM365_EMAC_BASE (0x01D07000)
|
||||
#define DM365_EMAC_CNTRL_OFFSET (0x0000)
|
||||
|
@ -36,4 +37,5 @@ void __init dm365_init_asp(struct snd_platform_data *pdata);
|
|||
void __init dm365_init_ks(struct davinci_ks_platform_data *pdata);
|
||||
void __init dm365_init_rtc(void);
|
||||
|
||||
void dm365_set_vpfe_config(struct vpfe_config *cfg);
|
||||
#endif /* __ASM_ARCH_DM365_H */
|
||||
|
|
|
@ -35,8 +35,6 @@
|
|||
#define PXA_CAMERA_VSP 0x400
|
||||
|
||||
struct pxacamera_platform_data {
|
||||
int (*init)(struct device *);
|
||||
|
||||
unsigned long flags;
|
||||
unsigned long mclk_10khz;
|
||||
};
|
||||
|
|
|
@ -471,8 +471,8 @@ static struct i2c_board_info ap325rxa_i2c_camera[] = {
|
|||
};
|
||||
|
||||
static struct ov772x_camera_info ov7725_info = {
|
||||
.buswidth = SOCAM_DATAWIDTH_8,
|
||||
.flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP,
|
||||
.flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP | \
|
||||
OV772X_FLAG_8BIT,
|
||||
.edgectrl = OV772X_AUTO_EDGECTRL(0xf, 0),
|
||||
};
|
||||
|
||||
|
|
|
@ -431,7 +431,7 @@ static struct i2c_board_info migor_i2c_camera[] = {
|
|||
};
|
||||
|
||||
static struct ov772x_camera_info ov7725_info = {
|
||||
.buswidth = SOCAM_DATAWIDTH_8,
|
||||
.flags = OV772X_FLAG_8BIT,
|
||||
};
|
||||
|
||||
static struct soc_camera_link ov7725_link = {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
ir-common-objs := ir-functions.o ir-keymaps.o
|
||||
ir-core-objs := ir-keytable.o
|
||||
ir-core-objs := ir-keytable.o ir-sysfs.o
|
||||
|
||||
obj-$(CONFIG_IR_CORE) += ir-core.o
|
||||
obj-$(CONFIG_VIDEO_IR) += ir-common.o
|
||||
|
|
|
@ -52,7 +52,7 @@ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
|
|||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
|
||||
int ir_type)
|
||||
const u64 ir_type)
|
||||
{
|
||||
ir->ir_type = ir_type;
|
||||
|
||||
|
|
|
@ -3393,3 +3393,102 @@ struct ir_scancode_table ir_codes_nec_terratec_cinergy_xs_table = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_nec_terratec_cinergy_xs_table);
|
||||
|
||||
|
||||
/* Leadtek Winfast TV USB II Deluxe remote
|
||||
Magnus Alm <magnus.alm@gmail.com>
|
||||
*/
|
||||
static struct ir_scancode ir_codes_winfast_usbii_deluxe[] = {
|
||||
{ 0x62, KEY_0},
|
||||
{ 0x75, KEY_1},
|
||||
{ 0x76, KEY_2},
|
||||
{ 0x77, KEY_3},
|
||||
{ 0x79, KEY_4},
|
||||
{ 0x7a, KEY_5},
|
||||
{ 0x7b, KEY_6},
|
||||
{ 0x7d, KEY_7},
|
||||
{ 0x7e, KEY_8},
|
||||
{ 0x7f, KEY_9},
|
||||
|
||||
{ 0x38, KEY_CAMERA}, /* SNAPSHOT */
|
||||
{ 0x37, KEY_RECORD}, /* RECORD */
|
||||
{ 0x35, KEY_TIME}, /* TIMESHIFT */
|
||||
|
||||
{ 0x74, KEY_VOLUMEUP}, /* VOLUMEUP */
|
||||
{ 0x78, KEY_VOLUMEDOWN}, /* VOLUMEDOWN */
|
||||
{ 0x64, KEY_MUTE}, /* MUTE */
|
||||
|
||||
{ 0x21, KEY_CHANNEL}, /* SURF */
|
||||
{ 0x7c, KEY_CHANNELUP}, /* CHANNELUP */
|
||||
{ 0x60, KEY_CHANNELDOWN}, /* CHANNELDOWN */
|
||||
{ 0x61, KEY_LAST}, /* LAST CHANNEL (RECALL) */
|
||||
|
||||
{ 0x72, KEY_VIDEO}, /* INPUT MODES (TV/FM) */
|
||||
|
||||
{ 0x70, KEY_POWER2}, /* TV ON/OFF */
|
||||
|
||||
{ 0x39, KEY_CYCLEWINDOWS}, /* MINIMIZE (BOSS) */
|
||||
{ 0x3a, KEY_NEW}, /* PIP */
|
||||
{ 0x73, KEY_ZOOM}, /* FULLSECREEN */
|
||||
|
||||
{ 0x66, KEY_INFO}, /* OSD (DISPLAY) */
|
||||
|
||||
{ 0x31, KEY_DOT}, /* '.' */
|
||||
{ 0x63, KEY_ENTER}, /* ENTER */
|
||||
|
||||
};
|
||||
struct ir_scancode_table ir_codes_winfast_usbii_deluxe_table = {
|
||||
.scan = ir_codes_winfast_usbii_deluxe,
|
||||
.size = ARRAY_SIZE(ir_codes_winfast_usbii_deluxe),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_winfast_usbii_deluxe_table);
|
||||
|
||||
/* Kworld 315U
|
||||
*/
|
||||
static struct ir_scancode ir_codes_kworld_315u[] = {
|
||||
{ 0x6143, KEY_POWER },
|
||||
{ 0x6101, KEY_TUNER }, /* source */
|
||||
{ 0x610b, KEY_ZOOM },
|
||||
{ 0x6103, KEY_POWER2 }, /* shutdown */
|
||||
|
||||
{ 0x6104, KEY_1 },
|
||||
{ 0x6108, KEY_2 },
|
||||
{ 0x6102, KEY_3 },
|
||||
{ 0x6109, KEY_CHANNELUP },
|
||||
|
||||
{ 0x610f, KEY_4 },
|
||||
{ 0x6105, KEY_5 },
|
||||
{ 0x6106, KEY_6 },
|
||||
{ 0x6107, KEY_CHANNELDOWN },
|
||||
|
||||
{ 0x610c, KEY_7 },
|
||||
{ 0x610d, KEY_8 },
|
||||
{ 0x610a, KEY_9 },
|
||||
{ 0x610e, KEY_VOLUMEUP },
|
||||
|
||||
{ 0x6110, KEY_LAST },
|
||||
{ 0x6111, KEY_0 },
|
||||
{ 0x6112, KEY_ENTER },
|
||||
{ 0x6113, KEY_VOLUMEDOWN },
|
||||
|
||||
{ 0x6114, KEY_RECORD },
|
||||
{ 0x6115, KEY_STOP },
|
||||
{ 0x6116, KEY_PLAY },
|
||||
{ 0x6117, KEY_MUTE },
|
||||
|
||||
{ 0x6118, KEY_UP },
|
||||
{ 0x6119, KEY_DOWN },
|
||||
{ 0x611a, KEY_LEFT },
|
||||
{ 0x611b, KEY_RIGHT },
|
||||
|
||||
{ 0x611c, KEY_RED },
|
||||
{ 0x611d, KEY_GREEN },
|
||||
{ 0x611e, KEY_YELLOW },
|
||||
{ 0x611f, KEY_BLUE },
|
||||
};
|
||||
|
||||
struct ir_scancode_table ir_codes_kworld_315u_table = {
|
||||
.scan = ir_codes_kworld_315u,
|
||||
.size = ARRAY_SIZE(ir_codes_kworld_315u),
|
||||
.ir_type = IR_TYPE_NEC,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_kworld_315u_table);
|
||||
|
|
|
@ -65,7 +65,7 @@ exit:
|
|||
* In order to reduce the quantity of table resizes, it has a minimum
|
||||
* table size of IR_TAB_MIN_SIZE.
|
||||
*/
|
||||
int ir_roundup_tablesize(int n_elems)
|
||||
static int ir_roundup_tablesize(int n_elems)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
|
@ -81,7 +81,6 @@ int ir_roundup_tablesize(int n_elems)
|
|||
|
||||
return n_elems;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_roundup_tablesize);
|
||||
|
||||
/**
|
||||
* ir_copy_table() - copies a keytable, discarding the unused entries
|
||||
|
@ -89,9 +88,11 @@ EXPORT_SYMBOL_GPL(ir_roundup_tablesize);
|
|||
* @origin: origin table
|
||||
*
|
||||
* Copies all entries where the keycode is not KEY_UNKNOWN/KEY_RESERVED
|
||||
* Also copies table size and table protocol.
|
||||
* NOTE: It shouldn't copy the lock field
|
||||
*/
|
||||
|
||||
int ir_copy_table(struct ir_scancode_table *destin,
|
||||
static int ir_copy_table(struct ir_scancode_table *destin,
|
||||
const struct ir_scancode_table *origin)
|
||||
{
|
||||
int i, j = 0;
|
||||
|
@ -105,12 +106,12 @@ int ir_copy_table(struct ir_scancode_table *destin,
|
|||
j++;
|
||||
}
|
||||
destin->size = j;
|
||||
destin->ir_type = origin->ir_type;
|
||||
|
||||
IR_dprintk(1, "Copied %d scancodes to the new keycode table\n", destin->size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_copy_table);
|
||||
|
||||
/**
|
||||
* ir_getkeycode() - get a keycode at the evdev scancode ->keycode table
|
||||
|
@ -184,18 +185,14 @@ static void ir_delete_key(struct ir_scancode_table *rc_tab, int elem)
|
|||
int newsize = rc_tab->size - 1;
|
||||
int resize = ir_is_resize_needed(rc_tab, newsize);
|
||||
struct ir_scancode *oldkeymap = rc_tab->scan;
|
||||
struct ir_scancode *newkeymap;
|
||||
struct ir_scancode *newkeymap = NULL;
|
||||
|
||||
if (resize) {
|
||||
if (resize)
|
||||
newkeymap = kzalloc(ir_roundup_tablesize(newsize) *
|
||||
sizeof(*newkeymap), GFP_ATOMIC);
|
||||
|
||||
/* There's no memory for resize. Keep the old table */
|
||||
if (!newkeymap)
|
||||
resize = 0;
|
||||
}
|
||||
|
||||
if (!resize) {
|
||||
/* There's no memory for resize. Keep the old table */
|
||||
if (!resize || !newkeymap) {
|
||||
newkeymap = oldkeymap;
|
||||
|
||||
/* We'll modify the live table. Lock it */
|
||||
|
@ -399,12 +396,14 @@ EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
|
|||
* @input_dev: the struct input_dev descriptor of the device
|
||||
* @rc_tab: the struct ir_scancode_table table of scancode/keymap
|
||||
*
|
||||
* This routine is used to initialize the input infrastructure to work with
|
||||
* an IR.
|
||||
* It should be called before registering the IR device.
|
||||
* This routine is used to initialize the input infrastructure
|
||||
* to work with an IR.
|
||||
* It will register the input/evdev interface for the device and
|
||||
* register the syfs code for IR class
|
||||
*/
|
||||
int ir_input_register(struct input_dev *input_dev,
|
||||
struct ir_scancode_table *rc_tab)
|
||||
const struct ir_scancode_table *rc_tab,
|
||||
const struct ir_dev_props *props)
|
||||
{
|
||||
struct ir_input_dev *ir_dev;
|
||||
struct ir_scancode *keymap = rc_tab->scan;
|
||||
|
@ -417,19 +416,22 @@ int ir_input_register(struct input_dev *input_dev,
|
|||
if (!ir_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&rc_tab->lock);
|
||||
spin_lock_init(&ir_dev->rc_tab.lock);
|
||||
|
||||
ir_dev->rc_tab.size = ir_roundup_tablesize(rc_tab->size);
|
||||
ir_dev->rc_tab.scan = kzalloc(ir_dev->rc_tab.size *
|
||||
sizeof(struct ir_scancode), GFP_KERNEL);
|
||||
if (!ir_dev->rc_tab.scan)
|
||||
if (!ir_dev->rc_tab.scan) {
|
||||
kfree(ir_dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n",
|
||||
ir_dev->rc_tab.size,
|
||||
ir_dev->rc_tab.size * sizeof(ir_dev->rc_tab.scan));
|
||||
|
||||
ir_copy_table(&ir_dev->rc_tab, rc_tab);
|
||||
ir_dev->props = props;
|
||||
|
||||
/* set the bits for the keys */
|
||||
IR_dprintk(1, "key map size: %d\n", rc_tab->size);
|
||||
|
@ -447,16 +449,31 @@ int ir_input_register(struct input_dev *input_dev,
|
|||
input_set_drvdata(input_dev, ir_dev);
|
||||
|
||||
rc = input_register_device(input_dev);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
|
||||
rc = ir_register_class(input_dev);
|
||||
if (rc < 0) {
|
||||
kfree(rc_tab->scan);
|
||||
kfree(ir_dev);
|
||||
input_set_drvdata(input_dev, NULL);
|
||||
input_unregister_device(input_dev);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(rc_tab->scan);
|
||||
kfree(ir_dev);
|
||||
input_set_drvdata(input_dev, NULL);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_input_register);
|
||||
|
||||
/**
|
||||
* ir_input_unregister() - unregisters IR and frees resources
|
||||
* @input_dev: the struct input_dev descriptor of the device
|
||||
|
||||
* This routine is used to free memory and de-register interfaces.
|
||||
*/
|
||||
void ir_input_unregister(struct input_dev *dev)
|
||||
{
|
||||
struct ir_input_dev *ir_dev = input_get_drvdata(dev);
|
||||
|
@ -472,6 +489,8 @@ void ir_input_unregister(struct input_dev *dev)
|
|||
kfree(rc_tab->scan);
|
||||
rc_tab->scan = NULL;
|
||||
|
||||
ir_unregister_class(dev);
|
||||
|
||||
kfree(ir_dev);
|
||||
input_unregister_device(dev);
|
||||
}
|
||||
|
|
211
drivers/media/IR/ir-sysfs.c
Normal file
211
drivers/media/IR/ir-sysfs.c
Normal file
|
@ -0,0 +1,211 @@
|
|||
/* ir-register.c - handle IR scancode->keycode tables
|
||||
*
|
||||
* Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
*
|
||||
* 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 of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/device.h>
|
||||
#include <media/ir-core.h>
|
||||
|
||||
#define IRRCV_NUM_DEVICES 256
|
||||
|
||||
/* bit array to represent IR sysfs device number */
|
||||
static unsigned long ir_core_dev_number;
|
||||
|
||||
/* class for /sys/class/irrcv */
|
||||
static struct class *ir_input_class;
|
||||
|
||||
/**
|
||||
* show_protocol() - shows the current IR protocol
|
||||
* @d: the device descriptor
|
||||
* @mattr: the device attribute struct (unused)
|
||||
* @buf: a pointer to the output buffer
|
||||
*
|
||||
* This routine is a callback routine for input read the IR protocol type.
|
||||
* it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol.
|
||||
* It returns the protocol name, as understood by the driver.
|
||||
*/
|
||||
static ssize_t show_protocol(struct device *d,
|
||||
struct device_attribute *mattr, char *buf)
|
||||
{
|
||||
char *s;
|
||||
struct ir_input_dev *ir_dev = dev_get_drvdata(d);
|
||||
u64 ir_type = ir_dev->rc_tab.ir_type;
|
||||
|
||||
IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type);
|
||||
|
||||
/* FIXME: doesn't support multiple protocols at the same time */
|
||||
if (ir_type == IR_TYPE_UNKNOWN)
|
||||
s = "Unknown";
|
||||
else if (ir_type == IR_TYPE_RC5)
|
||||
s = "RC-5";
|
||||
else if (ir_type == IR_TYPE_PD)
|
||||
s = "Pulse/distance";
|
||||
else if (ir_type == IR_TYPE_NEC)
|
||||
s = "NEC";
|
||||
else
|
||||
s = "Other";
|
||||
|
||||
return sprintf(buf, "%s\n", s);
|
||||
}
|
||||
|
||||
/**
|
||||
* store_protocol() - shows the current IR protocol
|
||||
* @d: the device descriptor
|
||||
* @mattr: the device attribute struct (unused)
|
||||
* @buf: a pointer to the input buffer
|
||||
* @len: length of the input buffer
|
||||
*
|
||||
* This routine is a callback routine for changing the IR protocol type.
|
||||
* it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol.
|
||||
* It changes the IR the protocol name, if the IR type is recognized
|
||||
* by the driver.
|
||||
* If an unknown protocol name is used, returns -EINVAL.
|
||||
*/
|
||||
static ssize_t store_protocol(struct device *d,
|
||||
struct device_attribute *mattr,
|
||||
const char *data,
|
||||
size_t len)
|
||||
{
|
||||
struct ir_input_dev *ir_dev = dev_get_drvdata(d);
|
||||
u64 ir_type = IR_TYPE_UNKNOWN;
|
||||
int rc = -EINVAL;
|
||||
unsigned long flags;
|
||||
char *buf;
|
||||
|
||||
buf = strsep((char **) &data, "\n");
|
||||
|
||||
if (!strcasecmp(buf, "rc-5"))
|
||||
ir_type = IR_TYPE_RC5;
|
||||
else if (!strcasecmp(buf, "pd"))
|
||||
ir_type = IR_TYPE_PD;
|
||||
else if (!strcasecmp(buf, "nec"))
|
||||
ir_type = IR_TYPE_NEC;
|
||||
|
||||
if (ir_type == IR_TYPE_UNKNOWN) {
|
||||
IR_dprintk(1, "Error setting protocol to %lld\n",
|
||||
(long long)ir_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ir_dev->props && ir_dev->props->change_protocol)
|
||||
rc = ir_dev->props->change_protocol(ir_dev->props->priv,
|
||||
ir_type);
|
||||
|
||||
if (rc < 0) {
|
||||
IR_dprintk(1, "Error setting protocol to %lld\n",
|
||||
(long long)ir_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
|
||||
ir_dev->rc_tab.ir_type = ir_type;
|
||||
spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
|
||||
|
||||
IR_dprintk(1, "Current protocol is %lld\n",
|
||||
(long long)ir_type);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Static device attribute struct with the sysfs attributes for IR's
|
||||
*/
|
||||
static DEVICE_ATTR(current_protocol, S_IRUGO | S_IWUSR,
|
||||
show_protocol, store_protocol);
|
||||
|
||||
static struct attribute *ir_dev_attrs[] = {
|
||||
&dev_attr_current_protocol.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/**
|
||||
* ir_register_class() - creates the sysfs for /sys/class/irrcv/irrcv?
|
||||
* @input_dev: the struct input_dev descriptor of the device
|
||||
*
|
||||
* This routine is used to register the syfs code for IR class
|
||||
*/
|
||||
int ir_register_class(struct input_dev *input_dev)
|
||||
{
|
||||
int rc;
|
||||
struct kobject *kobj;
|
||||
|
||||
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
|
||||
int devno = find_first_zero_bit(&ir_core_dev_number,
|
||||
IRRCV_NUM_DEVICES);
|
||||
|
||||
if (unlikely(devno < 0))
|
||||
return devno;
|
||||
|
||||
ir_dev->attr.attrs = ir_dev_attrs;
|
||||
ir_dev->class_dev = device_create(ir_input_class, NULL,
|
||||
input_dev->dev.devt, ir_dev,
|
||||
"irrcv%d", devno);
|
||||
kobj = &ir_dev->class_dev->kobj;
|
||||
|
||||
printk(KERN_WARNING "Creating IR device %s\n", kobject_name(kobj));
|
||||
rc = sysfs_create_group(kobj, &ir_dev->attr);
|
||||
if (unlikely(rc < 0)) {
|
||||
device_destroy(ir_input_class, input_dev->dev.devt);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ir_dev->devno = devno;
|
||||
set_bit(devno, &ir_core_dev_number);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* ir_unregister_class() - removes the sysfs for sysfs for
|
||||
* /sys/class/irrcv/irrcv?
|
||||
* @input_dev: the struct input_dev descriptor of the device
|
||||
*
|
||||
* This routine is used to unregister the syfs code for IR class
|
||||
*/
|
||||
void ir_unregister_class(struct input_dev *input_dev)
|
||||
{
|
||||
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
|
||||
struct kobject *kobj;
|
||||
|
||||
clear_bit(ir_dev->devno, &ir_core_dev_number);
|
||||
|
||||
kobj = &ir_dev->class_dev->kobj;
|
||||
|
||||
sysfs_remove_group(kobj, &ir_dev->attr);
|
||||
device_destroy(ir_input_class, input_dev->dev.devt);
|
||||
|
||||
kfree(ir_dev->attr.name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Init/exit code for the module. Basically, creates/removes /sys/class/irrcv
|
||||
*/
|
||||
|
||||
static int __init ir_core_init(void)
|
||||
{
|
||||
ir_input_class = class_create(THIS_MODULE, "irrcv");
|
||||
if (IS_ERR(ir_input_class)) {
|
||||
printk(KERN_ERR "ir_core: unable to register irrcv class\n");
|
||||
return PTR_ERR(ir_input_class);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ir_core_exit(void)
|
||||
{
|
||||
class_destroy(ir_input_class);
|
||||
}
|
||||
|
||||
module_init(ir_core_init);
|
||||
module_exit(ir_core_exit);
|
|
@ -423,14 +423,15 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
|
|||
}
|
||||
}
|
||||
|
||||
int saa7146_vv_devinit(struct saa7146_dev *dev)
|
||||
{
|
||||
return v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(saa7146_vv_devinit);
|
||||
|
||||
int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
|
||||
{
|
||||
struct saa7146_vv *vv;
|
||||
int err;
|
||||
|
||||
err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
|
||||
if (vv == NULL) {
|
||||
|
|
|
@ -1337,6 +1337,22 @@ static struct tuner_params tuner_philips_cu1216l_params[] = {
|
|||
},
|
||||
};
|
||||
|
||||
/* ---------------------- TUNER_SONY_BTF_PXN01Z ------------------------ */
|
||||
|
||||
static struct tuner_range tuner_sony_btf_pxn01z_ranges[] = {
|
||||
{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
|
||||
{ 16 * 367.25 /*MHz*/, 0x8e, 0x02, },
|
||||
{ 16 * 999.99 , 0x8e, 0x04, },
|
||||
};
|
||||
|
||||
static struct tuner_params tuner_sony_btf_pxn01z_params[] = {
|
||||
{
|
||||
.type = TUNER_PARAM_TYPE_NTSC,
|
||||
.ranges = tuner_sony_btf_pxn01z_ranges,
|
||||
.count = ARRAY_SIZE(tuner_sony_btf_pxn01z_ranges),
|
||||
},
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
struct tunertype tuners[] = {
|
||||
|
@ -1805,6 +1821,11 @@ struct tunertype tuners[] = {
|
|||
.name = "NXP TDA18271",
|
||||
/* see tda18271-fe.c for details */
|
||||
},
|
||||
[TUNER_SONY_BTF_PXN01Z] = {
|
||||
.name = "Sony BTF-Pxn01Z",
|
||||
.params = tuner_sony_btf_pxn01z_params,
|
||||
.count = ARRAY_SIZE(tuner_sony_btf_pxn01z_params),
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(tuners);
|
||||
|
||||
|
|
|
@ -917,30 +917,68 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
|
|||
* that xc2028 will be in a safe state.
|
||||
* Maybe this might also be needed for DTV.
|
||||
*/
|
||||
if (new_mode == T_ANALOG_TV)
|
||||
if (new_mode == T_ANALOG_TV) {
|
||||
rc = send_seq(priv, {0x00, 0x00});
|
||||
|
||||
/*
|
||||
* Digital modes require an offset to adjust to the
|
||||
* proper frequency.
|
||||
* Analog modes require offset = 0
|
||||
*/
|
||||
if (new_mode == T_DIGITAL_TV) {
|
||||
/* Sets the offset according with firmware */
|
||||
/* Analog modes require offset = 0 */
|
||||
} else {
|
||||
/*
|
||||
* Digital modes require an offset to adjust to the
|
||||
* proper frequency. The offset depends on what
|
||||
* firmware version is used.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adjust to the center frequency. This is calculated by the
|
||||
* formula: offset = 1.25MHz - BW/2
|
||||
* For DTV 7/8, the firmware uses BW = 8000, so it needs a
|
||||
* further adjustment to get the frequency center on VHF
|
||||
*/
|
||||
if (priv->cur_fw.type & DTV6)
|
||||
offset = 1750000;
|
||||
else if (priv->cur_fw.type & DTV7)
|
||||
offset = 2250000;
|
||||
else /* DTV8 or DTV78 */
|
||||
offset = 2750000;
|
||||
|
||||
/*
|
||||
* We must adjust the offset by 500kHz when
|
||||
* tuning a 7MHz VHF channel with DTV78 firmware
|
||||
* (used in Australia, Italy and Germany)
|
||||
*/
|
||||
if ((priv->cur_fw.type & DTV78) && freq < 470000000)
|
||||
offset -= 500000;
|
||||
|
||||
/*
|
||||
* xc3028 additional "magic"
|
||||
* Depending on the firmware version, it needs some adjustments
|
||||
* to properly centralize the frequency. This seems to be
|
||||
* needed to compensate the SCODE table adjustments made by
|
||||
* newer firmwares
|
||||
*/
|
||||
|
||||
#if 1
|
||||
/*
|
||||
* The proper adjustment would be to do it at s-code table.
|
||||
* However, this didn't work, as reported by
|
||||
* Robert Lowery <rglowery@exemail.com.au>
|
||||
*/
|
||||
|
||||
if (priv->cur_fw.type & DTV7)
|
||||
offset += 500000;
|
||||
|
||||
#else
|
||||
/*
|
||||
* Still need tests for XC3028L (firmware 3.2 or upper)
|
||||
* So, for now, let's just comment the per-firmware
|
||||
* version of this change. Reports with xc3028l working
|
||||
* with and without the lines bellow are welcome
|
||||
*/
|
||||
|
||||
if (priv->firm_version < 0x0302) {
|
||||
if (priv->cur_fw.type & DTV7)
|
||||
offset += 500000;
|
||||
} else {
|
||||
if (priv->cur_fw.type & DTV7)
|
||||
offset -= 300000;
|
||||
else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */
|
||||
offset += 200000;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
div = (freq - offset + DIV / 2) / DIV;
|
||||
|
@ -1097,17 +1135,24 @@ static int xc2028_set_params(struct dvb_frontend *fe,
|
|||
|
||||
/* All S-code tables need a 200kHz shift */
|
||||
if (priv->ctrl.demod) {
|
||||
demod = priv->ctrl.demod + 200;
|
||||
demod = priv->ctrl.demod;
|
||||
|
||||
/*
|
||||
* Newer firmwares require a 200 kHz offset only for ATSC
|
||||
*/
|
||||
if (type == ATSC || priv->firm_version < 0x0302)
|
||||
demod += 200;
|
||||
/*
|
||||
* The DTV7 S-code table needs a 700 kHz shift.
|
||||
* Thanks to Terry Wu <terrywu2009@gmail.com> for reporting this
|
||||
*
|
||||
* DTV7 is only used in Australia. Germany or Italy may also
|
||||
* use this firmware after initialization, but a tune to a UHF
|
||||
* channel should then cause DTV78 to be used.
|
||||
*
|
||||
* Unfortunately, on real-field tests, the s-code offset
|
||||
* didn't work as expected, as reported by
|
||||
* Robert Lowery <rglowery@exemail.com.au>
|
||||
*/
|
||||
if (type & DTV7)
|
||||
demod += 500;
|
||||
}
|
||||
|
||||
return generic_set_freq(fe, p->frequency,
|
||||
|
|
|
@ -76,6 +76,10 @@ comment "Supported Mantis Adapters"
|
|||
depends on DVB_CORE && PCI && I2C
|
||||
source "drivers/media/dvb/mantis/Kconfig"
|
||||
|
||||
comment "Supported nGene Adapters"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
source "drivers/media/dvb/ngene/Kconfig"
|
||||
|
||||
comment "Supported DVB Frontends"
|
||||
depends on DVB_CORE
|
||||
source "drivers/media/dvb/frontends/Kconfig"
|
||||
|
|
|
@ -14,6 +14,7 @@ obj-y := dvb-core/ \
|
|||
siano/ \
|
||||
dm1105/ \
|
||||
pt1/ \
|
||||
mantis/
|
||||
mantis/ \
|
||||
ngene/
|
||||
|
||||
obj-$(CONFIG_DVB_FIREDTV) += firewire/
|
||||
|
|
|
@ -576,43 +576,30 @@ static struct pci_driver bt878_pci_driver = {
|
|||
.remove = __devexit_p(bt878_remove),
|
||||
};
|
||||
|
||||
static int bt878_pci_driver_registered;
|
||||
|
||||
/*******************************/
|
||||
/* Module management functions */
|
||||
/*******************************/
|
||||
|
||||
static int bt878_init_module(void)
|
||||
static int __init bt878_init_module(void)
|
||||
{
|
||||
bt878_num = 0;
|
||||
bt878_pci_driver_registered = 0;
|
||||
|
||||
printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n",
|
||||
(BT878_VERSION_CODE >> 16) & 0xff,
|
||||
(BT878_VERSION_CODE >> 8) & 0xff,
|
||||
BT878_VERSION_CODE & 0xff);
|
||||
/*
|
||||
bt878_check_chipset();
|
||||
*/
|
||||
/* later we register inside of bt878_find_audio_dma()
|
||||
* because we may want to ignore certain cards */
|
||||
bt878_pci_driver_registered = 1;
|
||||
|
||||
return pci_register_driver(&bt878_pci_driver);
|
||||
}
|
||||
|
||||
static void bt878_cleanup_module(void)
|
||||
static void __exit bt878_cleanup_module(void)
|
||||
{
|
||||
if (bt878_pci_driver_registered) {
|
||||
bt878_pci_driver_registered = 0;
|
||||
pci_unregister_driver(&bt878_pci_driver);
|
||||
}
|
||||
return;
|
||||
pci_unregister_driver(&bt878_pci_driver);
|
||||
}
|
||||
|
||||
module_init(bt878_init_module);
|
||||
module_exit(bt878_cleanup_module);
|
||||
|
||||
//MODULE_AUTHOR("XXX");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
|
|
|
@ -1352,8 +1352,7 @@ static int dst_get_tuna(struct dst_state *state)
|
|||
return retval;
|
||||
}
|
||||
if ((state->type_flags & DST_TYPE_HAS_VLF) &&
|
||||
!(state->dst_type == DST_TYPE_IS_CABLE) &&
|
||||
!(state->dst_type == DST_TYPE_IS_ATSC)) {
|
||||
!(state->dst_type == DST_TYPE_IS_ATSC)) {
|
||||
|
||||
if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
|
||||
dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
|
||||
|
@ -1820,8 +1819,13 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
|
|||
.frequency_max = 858000000,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
/* . symbol_rate_tolerance = ???,*/
|
||||
.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
|
||||
.caps = FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QAM_AUTO |
|
||||
FE_CAN_QAM_16 |
|
||||
FE_CAN_QAM_32 |
|
||||
FE_CAN_QAM_64 |
|
||||
FE_CAN_QAM_128 |
|
||||
FE_CAN_QAM_256
|
||||
},
|
||||
|
||||
.release = dst_release,
|
||||
|
|
|
@ -8,6 +8,7 @@ config DVB_DM1105
|
|||
select DVB_STB6000 if !DVB_FE_CUSTOMISE
|
||||
select DVB_CX24116 if !DVB_FE_CUSTOMISE
|
||||
select DVB_SI21XX if !DVB_FE_CUSTOMISE
|
||||
select DVB_DS3000 if !DVB_FE_CUSTOMISE
|
||||
select VIDEO_IR
|
||||
help
|
||||
Support for cards based on the SDMC DM1105 PCI chip like
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "si21xx.h"
|
||||
#include "cx24116.h"
|
||||
#include "z0194a.h"
|
||||
#include "ds3000.h"
|
||||
|
||||
#define UNSET (-1U)
|
||||
|
||||
|
@ -269,7 +270,7 @@ struct infrared {
|
|||
u32 ir_command;
|
||||
};
|
||||
|
||||
struct dm1105dvb {
|
||||
struct dm1105_dev {
|
||||
/* pci */
|
||||
struct pci_dev *pdev;
|
||||
u8 __iomem *io_mem;
|
||||
|
@ -308,31 +309,47 @@ struct dm1105dvb {
|
|||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg]))
|
||||
#define dm_io_mem(reg) ((unsigned long)(&dev->io_mem[reg]))
|
||||
|
||||
#define dm_readb(reg) inb(dm_io_mem(reg))
|
||||
#define dm_writeb(reg, value) outb((value), (dm_io_mem(reg)))
|
||||
|
||||
#define dm_readw(reg) inw(dm_io_mem(reg))
|
||||
#define dm_writew(reg, value) outw((value), (dm_io_mem(reg)))
|
||||
|
||||
#define dm_readl(reg) inl(dm_io_mem(reg))
|
||||
#define dm_writel(reg, value) outl((value), (dm_io_mem(reg)))
|
||||
|
||||
#define dm_andorl(reg, mask, value) \
|
||||
outl((inl(dm_io_mem(reg)) & ~(mask)) |\
|
||||
((value) & (mask)), (dm_io_mem(reg)))
|
||||
|
||||
#define dm_setl(reg, bit) dm_andorl((reg), (bit), (bit))
|
||||
#define dm_clearl(reg, bit) dm_andorl((reg), (bit), 0)
|
||||
|
||||
static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb ;
|
||||
struct dm1105_dev *dev ;
|
||||
|
||||
int addr, rc, i, j, k, len, byte, data;
|
||||
u8 status;
|
||||
|
||||
dm1105dvb = i2c_adap->algo_data;
|
||||
dev = i2c_adap->algo_data;
|
||||
for (i = 0; i < num; i++) {
|
||||
outb(0x00, dm_io_mem(DM1105_I2CCTR));
|
||||
dm_writeb(DM1105_I2CCTR, 0x00);
|
||||
if (msgs[i].flags & I2C_M_RD) {
|
||||
/* read bytes */
|
||||
addr = msgs[i].addr << 1;
|
||||
addr |= 1;
|
||||
outb(addr, dm_io_mem(DM1105_I2CDAT));
|
||||
dm_writeb(DM1105_I2CDAT, addr);
|
||||
for (byte = 0; byte < msgs[i].len; byte++)
|
||||
outb(0, dm_io_mem(DM1105_I2CDAT + byte + 1));
|
||||
dm_writeb(DM1105_I2CDAT + byte + 1, 0);
|
||||
|
||||
outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
|
||||
dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
|
||||
for (j = 0; j < 55; j++) {
|
||||
mdelay(10);
|
||||
status = inb(dm_io_mem(DM1105_I2CSTS));
|
||||
status = dm_readb(DM1105_I2CSTS);
|
||||
if ((status & 0xc0) == 0x40)
|
||||
break;
|
||||
}
|
||||
|
@ -340,56 +357,54 @@ static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
|
|||
return -1;
|
||||
|
||||
for (byte = 0; byte < msgs[i].len; byte++) {
|
||||
rc = inb(dm_io_mem(DM1105_I2CDAT + byte + 1));
|
||||
rc = dm_readb(DM1105_I2CDAT + byte + 1);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
msgs[i].buf[byte] = rc;
|
||||
}
|
||||
} else {
|
||||
if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
|
||||
/* prepaired for cx24116 firmware */
|
||||
/* Write in small blocks */
|
||||
len = msgs[i].len - 1;
|
||||
k = 1;
|
||||
do {
|
||||
outb(msgs[i].addr << 1, dm_io_mem(DM1105_I2CDAT));
|
||||
outb(0xf7, dm_io_mem(DM1105_I2CDAT + 1));
|
||||
for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
|
||||
data = msgs[i].buf[k+byte];
|
||||
outb(data, dm_io_mem(DM1105_I2CDAT + byte + 2));
|
||||
}
|
||||
outb(0x82 + (len > 48 ? 48 : len), dm_io_mem(DM1105_I2CCTR));
|
||||
for (j = 0; j < 25; j++) {
|
||||
mdelay(10);
|
||||
status = inb(dm_io_mem(DM1105_I2CSTS));
|
||||
if ((status & 0xc0) == 0x40)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j >= 25)
|
||||
return -1;
|
||||
|
||||
k += 48;
|
||||
len -= 48;
|
||||
} while (len > 0);
|
||||
} else {
|
||||
/* write bytes */
|
||||
outb(msgs[i].addr<<1, dm_io_mem(DM1105_I2CDAT));
|
||||
for (byte = 0; byte < msgs[i].len; byte++) {
|
||||
data = msgs[i].buf[byte];
|
||||
outb(data, dm_io_mem(DM1105_I2CDAT + byte + 1));
|
||||
} else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
|
||||
/* prepaired for cx24116 firmware */
|
||||
/* Write in small blocks */
|
||||
len = msgs[i].len - 1;
|
||||
k = 1;
|
||||
do {
|
||||
dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
|
||||
dm_writeb(DM1105_I2CDAT + 1, 0xf7);
|
||||
for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
|
||||
data = msgs[i].buf[k + byte];
|
||||
dm_writeb(DM1105_I2CDAT + byte + 2, data);
|
||||
}
|
||||
outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
|
||||
dm_writeb(DM1105_I2CCTR, 0x82 + (len > 48 ? 48 : len));
|
||||
for (j = 0; j < 25; j++) {
|
||||
mdelay(10);
|
||||
status = inb(dm_io_mem(DM1105_I2CSTS));
|
||||
status = dm_readb(DM1105_I2CSTS);
|
||||
if ((status & 0xc0) == 0x40)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j >= 25)
|
||||
return -1;
|
||||
|
||||
k += 48;
|
||||
len -= 48;
|
||||
} while (len > 0);
|
||||
} else {
|
||||
/* write bytes */
|
||||
dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
|
||||
for (byte = 0; byte < msgs[i].len; byte++) {
|
||||
data = msgs[i].buf[byte];
|
||||
dm_writeb(DM1105_I2CDAT + byte + 1, data);
|
||||
}
|
||||
dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
|
||||
for (j = 0; j < 25; j++) {
|
||||
mdelay(10);
|
||||
status = dm_readb(DM1105_I2CSTS);
|
||||
if ((status & 0xc0) == 0x40)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j >= 25)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
|
@ -407,22 +422,22 @@ static struct i2c_algorithm dm1105_algo = {
|
|||
.functionality = functionality,
|
||||
};
|
||||
|
||||
static inline struct dm1105dvb *feed_to_dm1105dvb(struct dvb_demux_feed *feed)
|
||||
static inline struct dm1105_dev *feed_to_dm1105_dev(struct dvb_demux_feed *feed)
|
||||
{
|
||||
return container_of(feed->demux, struct dm1105dvb, demux);
|
||||
return container_of(feed->demux, struct dm1105_dev, demux);
|
||||
}
|
||||
|
||||
static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
|
||||
static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe)
|
||||
{
|
||||
return container_of(fe->dvb, struct dm1105dvb, dvb_adapter);
|
||||
return container_of(fe->dvb, struct dm1105_dev, dvb_adapter);
|
||||
}
|
||||
|
||||
static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||
static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
|
||||
struct dm1105_dev *dev = frontend_to_dm1105_dev(fe);
|
||||
u32 lnb_mask, lnb_13v, lnb_18v, lnb_off;
|
||||
|
||||
switch (dm1105dvb->boardnr) {
|
||||
switch (dev->boardnr) {
|
||||
case DM1105_BOARD_AXESS_DM05:
|
||||
lnb_mask = DM05_LNB_MASK;
|
||||
lnb_off = DM05_LNB_OFF;
|
||||
|
@ -438,62 +453,67 @@ static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volta
|
|||
lnb_18v = DM1105_LNB_18V;
|
||||
}
|
||||
|
||||
outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR));
|
||||
dm_writel(DM1105_GPIOCTR, lnb_mask);
|
||||
if (voltage == SEC_VOLTAGE_18)
|
||||
outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL));
|
||||
dm_writel(DM1105_GPIOVAL, lnb_18v);
|
||||
else if (voltage == SEC_VOLTAGE_13)
|
||||
outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL));
|
||||
dm_writel(DM1105_GPIOVAL, lnb_13v);
|
||||
else
|
||||
outl(lnb_off, dm_io_mem(DM1105_GPIOVAL));
|
||||
dm_writel(DM1105_GPIOVAL, lnb_off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dm1105dvb_set_dma_addr(struct dm1105dvb *dm1105dvb)
|
||||
static void dm1105_set_dma_addr(struct dm1105_dev *dev)
|
||||
{
|
||||
outl(cpu_to_le32(dm1105dvb->dma_addr), dm_io_mem(DM1105_STADR));
|
||||
dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr));
|
||||
}
|
||||
|
||||
static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb)
|
||||
static int __devinit dm1105_dma_map(struct dm1105_dev *dev)
|
||||
{
|
||||
dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr);
|
||||
dev->ts_buf = pci_alloc_consistent(dev->pdev,
|
||||
6 * DM1105_DMA_BYTES,
|
||||
&dev->dma_addr);
|
||||
|
||||
return !dm1105dvb->ts_buf;
|
||||
return !dev->ts_buf;
|
||||
}
|
||||
|
||||
static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb)
|
||||
static void dm1105_dma_unmap(struct dm1105_dev *dev)
|
||||
{
|
||||
pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr);
|
||||
pci_free_consistent(dev->pdev,
|
||||
6 * DM1105_DMA_BYTES,
|
||||
dev->ts_buf,
|
||||
dev->dma_addr);
|
||||
}
|
||||
|
||||
static void dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb)
|
||||
static void dm1105_enable_irqs(struct dm1105_dev *dev)
|
||||
{
|
||||
outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK));
|
||||
outb(1, dm_io_mem(DM1105_CR));
|
||||
dm_writeb(DM1105_INTMAK, INTMAK_ALLMASK);
|
||||
dm_writeb(DM1105_CR, 1);
|
||||
}
|
||||
|
||||
static void dm1105dvb_disable_irqs(struct dm1105dvb *dm1105dvb)
|
||||
static void dm1105_disable_irqs(struct dm1105_dev *dev)
|
||||
{
|
||||
outb(INTMAK_IRM, dm_io_mem(DM1105_INTMAK));
|
||||
outb(0, dm_io_mem(DM1105_CR));
|
||||
dm_writeb(DM1105_INTMAK, INTMAK_IRM);
|
||||
dm_writeb(DM1105_CR, 0);
|
||||
}
|
||||
|
||||
static int dm1105dvb_start_feed(struct dvb_demux_feed *f)
|
||||
static int dm1105_start_feed(struct dvb_demux_feed *f)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
|
||||
struct dm1105_dev *dev = feed_to_dm1105_dev(f);
|
||||
|
||||
if (dm1105dvb->full_ts_users++ == 0)
|
||||
dm1105dvb_enable_irqs(dm1105dvb);
|
||||
if (dev->full_ts_users++ == 0)
|
||||
dm1105_enable_irqs(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dm1105dvb_stop_feed(struct dvb_demux_feed *f)
|
||||
static int dm1105_stop_feed(struct dvb_demux_feed *f)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
|
||||
struct dm1105_dev *dev = feed_to_dm1105_dev(f);
|
||||
|
||||
if (--dm1105dvb->full_ts_users == 0)
|
||||
dm1105dvb_disable_irqs(dm1105dvb);
|
||||
if (--dev->full_ts_users == 0)
|
||||
dm1105_disable_irqs(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -517,68 +537,64 @@ static void dm1105_emit_key(struct work_struct *work)
|
|||
/* work handler */
|
||||
static void dm1105_dmx_buffer(struct work_struct *work)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb =
|
||||
container_of(work, struct dm1105dvb, work);
|
||||
struct dm1105_dev *dev = container_of(work, struct dm1105_dev, work);
|
||||
unsigned int nbpackets;
|
||||
u32 oldwrp = dm1105dvb->wrp;
|
||||
u32 nextwrp = dm1105dvb->nextwrp;
|
||||
u32 oldwrp = dev->wrp;
|
||||
u32 nextwrp = dev->nextwrp;
|
||||
|
||||
if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
|
||||
(dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
|
||||
(dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
|
||||
dm1105dvb->PacketErrorCount++;
|
||||
if (!((dev->ts_buf[oldwrp] == 0x47) &&
|
||||
(dev->ts_buf[oldwrp + 188] == 0x47) &&
|
||||
(dev->ts_buf[oldwrp + 188 * 2] == 0x47))) {
|
||||
dev->PacketErrorCount++;
|
||||
/* bad packet found */
|
||||
if ((dm1105dvb->PacketErrorCount >= 2) &&
|
||||
(dm1105dvb->dmarst == 0)) {
|
||||
outb(1, dm_io_mem(DM1105_RST));
|
||||
dm1105dvb->wrp = 0;
|
||||
dm1105dvb->PacketErrorCount = 0;
|
||||
dm1105dvb->dmarst = 0;
|
||||
if ((dev->PacketErrorCount >= 2) &&
|
||||
(dev->dmarst == 0)) {
|
||||
dm_writeb(DM1105_RST, 1);
|
||||
dev->wrp = 0;
|
||||
dev->PacketErrorCount = 0;
|
||||
dev->dmarst = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextwrp < oldwrp) {
|
||||
memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size,
|
||||
dm1105dvb->ts_buf, nextwrp);
|
||||
nbpackets = ((dm1105dvb->buffer_size - oldwrp) + nextwrp) / 188;
|
||||
memcpy(dev->ts_buf + dev->buffer_size, dev->ts_buf, nextwrp);
|
||||
nbpackets = ((dev->buffer_size - oldwrp) + nextwrp) / 188;
|
||||
} else
|
||||
nbpackets = (nextwrp - oldwrp) / 188;
|
||||
|
||||
dm1105dvb->wrp = nextwrp;
|
||||
dvb_dmx_swfilter_packets(&dm1105dvb->demux,
|
||||
&dm1105dvb->ts_buf[oldwrp], nbpackets);
|
||||
dev->wrp = nextwrp;
|
||||
dvb_dmx_swfilter_packets(&dev->demux, &dev->ts_buf[oldwrp], nbpackets);
|
||||
}
|
||||
|
||||
static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
|
||||
static irqreturn_t dm1105_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb = dev_id;
|
||||
struct dm1105_dev *dev = dev_id;
|
||||
|
||||
/* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
|
||||
unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS));
|
||||
outb(intsts, dm_io_mem(DM1105_INTSTS));
|
||||
unsigned int intsts = dm_readb(DM1105_INTSTS);
|
||||
dm_writeb(DM1105_INTSTS, intsts);
|
||||
|
||||
switch (intsts) {
|
||||
case INTSTS_TSIRQ:
|
||||
case (INTSTS_TSIRQ | INTSTS_IR):
|
||||
dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
|
||||
inl(dm_io_mem(DM1105_STADR));
|
||||
queue_work(dm1105dvb->wq, &dm1105dvb->work);
|
||||
dev->nextwrp = dm_readl(DM1105_WRP) - dm_readl(DM1105_STADR);
|
||||
queue_work(dev->wq, &dev->work);
|
||||
break;
|
||||
case INTSTS_IR:
|
||||
dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
|
||||
schedule_work(&dm1105dvb->ir.work);
|
||||
dev->ir.ir_command = dm_readl(DM1105_IRCODE);
|
||||
schedule_work(&dev->ir.work);
|
||||
break;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
|
||||
int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
|
||||
{
|
||||
struct input_dev *input_dev;
|
||||
struct ir_scancode_table *ir_codes = &ir_codes_dm1105_nec_table;
|
||||
int ir_type = IR_TYPE_OTHER;
|
||||
u64 ir_type = IR_TYPE_OTHER;
|
||||
int err = -ENOMEM;
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
|
@ -611,51 +627,51 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
|
|||
|
||||
INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
|
||||
|
||||
err = ir_input_register(input_dev, ir_codes);
|
||||
err = ir_input_register(input_dev, ir_codes, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
|
||||
void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105)
|
||||
{
|
||||
ir_input_unregister(dm1105->ir.input_dev);
|
||||
}
|
||||
|
||||
static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb)
|
||||
static int __devinit dm1105_hw_init(struct dm1105_dev *dev)
|
||||
{
|
||||
dm1105dvb_disable_irqs(dm1105dvb);
|
||||
dm1105_disable_irqs(dev);
|
||||
|
||||
outb(0, dm_io_mem(DM1105_HOST_CTR));
|
||||
dm_writeb(DM1105_HOST_CTR, 0);
|
||||
|
||||
/*DATALEN 188,*/
|
||||
outb(188, dm_io_mem(DM1105_DTALENTH));
|
||||
dm_writeb(DM1105_DTALENTH, 188);
|
||||
/*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/
|
||||
outw(0xc10a, dm_io_mem(DM1105_TSCTR));
|
||||
dm_writew(DM1105_TSCTR, 0xc10a);
|
||||
|
||||
/* map DMA and set address */
|
||||
dm1105dvb_dma_map(dm1105dvb);
|
||||
dm1105dvb_set_dma_addr(dm1105dvb);
|
||||
dm1105_dma_map(dev);
|
||||
dm1105_set_dma_addr(dev);
|
||||
/* big buffer */
|
||||
outl(5*DM1105_DMA_BYTES, dm_io_mem(DM1105_RLEN));
|
||||
outb(47, dm_io_mem(DM1105_INTCNT));
|
||||
dm_writel(DM1105_RLEN, 5 * DM1105_DMA_BYTES);
|
||||
dm_writeb(DM1105_INTCNT, 47);
|
||||
|
||||
/* IR NEC mode enable */
|
||||
outb((DM1105_IR_EN | DM1105_SYS_CHK), dm_io_mem(DM1105_IRCTR));
|
||||
outb(0, dm_io_mem(DM1105_IRMODE));
|
||||
outw(0, dm_io_mem(DM1105_SYSTEMCODE));
|
||||
dm_writeb(DM1105_IRCTR, (DM1105_IR_EN | DM1105_SYS_CHK));
|
||||
dm_writeb(DM1105_IRMODE, 0);
|
||||
dm_writew(DM1105_SYSTEMCODE, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb)
|
||||
static void dm1105_hw_exit(struct dm1105_dev *dev)
|
||||
{
|
||||
dm1105dvb_disable_irqs(dm1105dvb);
|
||||
dm1105_disable_irqs(dev);
|
||||
|
||||
/* IR disable */
|
||||
outb(0, dm_io_mem(DM1105_IRCTR));
|
||||
outb(INTMAK_NONEMASK, dm_io_mem(DM1105_INTMAK));
|
||||
dm_writeb(DM1105_IRCTR, 0);
|
||||
dm_writeb(DM1105_INTMAK, INTMAK_NONEMASK);
|
||||
|
||||
dm1105dvb_dma_unmap(dm1105dvb);
|
||||
dm1105_dma_unmap(dev);
|
||||
}
|
||||
|
||||
static struct stv0299_config sharp_z0194a_config = {
|
||||
|
@ -685,70 +701,79 @@ static struct cx24116_config serit_sp2633_config = {
|
|||
.demod_address = 0x55,
|
||||
};
|
||||
|
||||
static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
|
||||
static struct ds3000_config dvbworld_ds3000_config = {
|
||||
.demod_address = 0x68,
|
||||
};
|
||||
|
||||
static int __devinit frontend_init(struct dm1105_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (dm1105dvb->boardnr) {
|
||||
switch (dev->boardnr) {
|
||||
case DM1105_BOARD_DVBWORLD_2004:
|
||||
dm1105dvb->fe = dvb_attach(
|
||||
dev->fe = dvb_attach(
|
||||
cx24116_attach, &serit_sp2633_config,
|
||||
&dm1105dvb->i2c_adap);
|
||||
if (dm1105dvb->fe)
|
||||
dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
|
||||
&dev->i2c_adap);
|
||||
if (dev->fe) {
|
||||
dev->fe->ops.set_voltage = dm1105_set_voltage;
|
||||
break;
|
||||
}
|
||||
|
||||
dev->fe = dvb_attach(
|
||||
ds3000_attach, &dvbworld_ds3000_config,
|
||||
&dev->i2c_adap);
|
||||
if (dev->fe)
|
||||
dev->fe->ops.set_voltage = dm1105_set_voltage;
|
||||
|
||||
break;
|
||||
case DM1105_BOARD_DVBWORLD_2002:
|
||||
case DM1105_BOARD_AXESS_DM05:
|
||||
default:
|
||||
dm1105dvb->fe = dvb_attach(
|
||||
dev->fe = dvb_attach(
|
||||
stv0299_attach, &sharp_z0194a_config,
|
||||
&dm1105dvb->i2c_adap);
|
||||
if (dm1105dvb->fe) {
|
||||
dm1105dvb->fe->ops.set_voltage =
|
||||
dm1105dvb_set_voltage;
|
||||
dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
|
||||
&dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
|
||||
&dev->i2c_adap);
|
||||
if (dev->fe) {
|
||||
dev->fe->ops.set_voltage = dm1105_set_voltage;
|
||||
dvb_attach(dvb_pll_attach, dev->fe, 0x60,
|
||||
&dev->i2c_adap, DVB_PLL_OPERA1);
|
||||
break;
|
||||
}
|
||||
|
||||
dm1105dvb->fe = dvb_attach(
|
||||
dev->fe = dvb_attach(
|
||||
stv0288_attach, &earda_config,
|
||||
&dm1105dvb->i2c_adap);
|
||||
if (dm1105dvb->fe) {
|
||||
dm1105dvb->fe->ops.set_voltage =
|
||||
dm1105dvb_set_voltage;
|
||||
dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
|
||||
&dm1105dvb->i2c_adap);
|
||||
&dev->i2c_adap);
|
||||
if (dev->fe) {
|
||||
dev->fe->ops.set_voltage = dm1105_set_voltage;
|
||||
dvb_attach(stb6000_attach, dev->fe, 0x61,
|
||||
&dev->i2c_adap);
|
||||
break;
|
||||
}
|
||||
|
||||
dm1105dvb->fe = dvb_attach(
|
||||
dev->fe = dvb_attach(
|
||||
si21xx_attach, &serit_config,
|
||||
&dm1105dvb->i2c_adap);
|
||||
if (dm1105dvb->fe)
|
||||
dm1105dvb->fe->ops.set_voltage =
|
||||
dm1105dvb_set_voltage;
|
||||
&dev->i2c_adap);
|
||||
if (dev->fe)
|
||||
dev->fe->ops.set_voltage = dm1105_set_voltage;
|
||||
|
||||
}
|
||||
|
||||
if (!dm1105dvb->fe) {
|
||||
dev_err(&dm1105dvb->pdev->dev, "could not attach frontend\n");
|
||||
if (!dev->fe) {
|
||||
dev_err(&dev->pdev->dev, "could not attach frontend\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = dvb_register_frontend(&dm1105dvb->dvb_adapter, dm1105dvb->fe);
|
||||
ret = dvb_register_frontend(&dev->dvb_adapter, dev->fe);
|
||||
if (ret < 0) {
|
||||
if (dm1105dvb->fe->ops.release)
|
||||
dm1105dvb->fe->ops.release(dm1105dvb->fe);
|
||||
dm1105dvb->fe = NULL;
|
||||
if (dev->fe->ops.release)
|
||||
dev->fe->ops.release(dev->fe);
|
||||
dev->fe = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
|
||||
static void __devinit dm1105_read_mac(struct dm1105_dev *dev, u8 *mac)
|
||||
{
|
||||
static u8 command[1] = { 0x28 };
|
||||
|
||||
|
@ -766,47 +791,47 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
|
|||
},
|
||||
};
|
||||
|
||||
dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
|
||||
dev_info(&dm1105dvb->pdev->dev, "MAC %pM\n", mac);
|
||||
dm1105_i2c_xfer(&dev->i2c_adap, msg , 2);
|
||||
dev_info(&dev->pdev->dev, "MAC %pM\n", mac);
|
||||
}
|
||||
|
||||
static int __devinit dm1105_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb;
|
||||
struct dm1105_dev *dev;
|
||||
struct dvb_adapter *dvb_adapter;
|
||||
struct dvb_demux *dvbdemux;
|
||||
struct dmx_demux *dmx;
|
||||
int ret = -ENOMEM;
|
||||
int i;
|
||||
|
||||
dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
|
||||
if (!dm1105dvb)
|
||||
dev = kzalloc(sizeof(struct dm1105_dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
/* board config */
|
||||
dm1105dvb->nr = dm1105_devcount;
|
||||
dm1105dvb->boardnr = UNSET;
|
||||
if (card[dm1105dvb->nr] < ARRAY_SIZE(dm1105_boards))
|
||||
dm1105dvb->boardnr = card[dm1105dvb->nr];
|
||||
for (i = 0; UNSET == dm1105dvb->boardnr &&
|
||||
dev->nr = dm1105_devcount;
|
||||
dev->boardnr = UNSET;
|
||||
if (card[dev->nr] < ARRAY_SIZE(dm1105_boards))
|
||||
dev->boardnr = card[dev->nr];
|
||||
for (i = 0; UNSET == dev->boardnr &&
|
||||
i < ARRAY_SIZE(dm1105_subids); i++)
|
||||
if (pdev->subsystem_vendor ==
|
||||
dm1105_subids[i].subvendor &&
|
||||
pdev->subsystem_device ==
|
||||
dm1105_subids[i].subdevice)
|
||||
dm1105dvb->boardnr = dm1105_subids[i].card;
|
||||
dev->boardnr = dm1105_subids[i].card;
|
||||
|
||||
if (UNSET == dm1105dvb->boardnr) {
|
||||
dm1105dvb->boardnr = DM1105_BOARD_UNKNOWN;
|
||||
if (UNSET == dev->boardnr) {
|
||||
dev->boardnr = DM1105_BOARD_UNKNOWN;
|
||||
dm1105_card_list(pdev);
|
||||
}
|
||||
|
||||
dm1105_devcount++;
|
||||
dm1105dvb->pdev = pdev;
|
||||
dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
|
||||
dm1105dvb->PacketErrorCount = 0;
|
||||
dm1105dvb->dmarst = 0;
|
||||
dev->pdev = pdev;
|
||||
dev->buffer_size = 5 * DM1105_DMA_BYTES;
|
||||
dev->PacketErrorCount = 0;
|
||||
dev->dmarst = 0;
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret < 0)
|
||||
|
@ -822,47 +847,47 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
|
|||
if (ret < 0)
|
||||
goto err_pci_disable_device;
|
||||
|
||||
dm1105dvb->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
|
||||
if (!dm1105dvb->io_mem) {
|
||||
dev->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
|
||||
if (!dev->io_mem) {
|
||||
ret = -EIO;
|
||||
goto err_pci_release_regions;
|
||||
}
|
||||
|
||||
spin_lock_init(&dm1105dvb->lock);
|
||||
pci_set_drvdata(pdev, dm1105dvb);
|
||||
spin_lock_init(&dev->lock);
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
ret = dm1105dvb_hw_init(dm1105dvb);
|
||||
ret = dm1105_hw_init(dev);
|
||||
if (ret < 0)
|
||||
goto err_pci_iounmap;
|
||||
|
||||
/* i2c */
|
||||
i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);
|
||||
strcpy(dm1105dvb->i2c_adap.name, DRIVER_NAME);
|
||||
dm1105dvb->i2c_adap.owner = THIS_MODULE;
|
||||
dm1105dvb->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
|
||||
dm1105dvb->i2c_adap.dev.parent = &pdev->dev;
|
||||
dm1105dvb->i2c_adap.algo = &dm1105_algo;
|
||||
dm1105dvb->i2c_adap.algo_data = dm1105dvb;
|
||||
ret = i2c_add_adapter(&dm1105dvb->i2c_adap);
|
||||
i2c_set_adapdata(&dev->i2c_adap, dev);
|
||||
strcpy(dev->i2c_adap.name, DRIVER_NAME);
|
||||
dev->i2c_adap.owner = THIS_MODULE;
|
||||
dev->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
|
||||
dev->i2c_adap.dev.parent = &pdev->dev;
|
||||
dev->i2c_adap.algo = &dm1105_algo;
|
||||
dev->i2c_adap.algo_data = dev;
|
||||
ret = i2c_add_adapter(&dev->i2c_adap);
|
||||
|
||||
if (ret < 0)
|
||||
goto err_dm1105dvb_hw_exit;
|
||||
goto err_dm1105_hw_exit;
|
||||
|
||||
/* dvb */
|
||||
ret = dvb_register_adapter(&dm1105dvb->dvb_adapter, DRIVER_NAME,
|
||||
ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME,
|
||||
THIS_MODULE, &pdev->dev, adapter_nr);
|
||||
if (ret < 0)
|
||||
goto err_i2c_del_adapter;
|
||||
|
||||
dvb_adapter = &dm1105dvb->dvb_adapter;
|
||||
dvb_adapter = &dev->dvb_adapter;
|
||||
|
||||
dm1105dvb_read_mac(dm1105dvb, dvb_adapter->proposed_mac);
|
||||
dm1105_read_mac(dev, dvb_adapter->proposed_mac);
|
||||
|
||||
dvbdemux = &dm1105dvb->demux;
|
||||
dvbdemux = &dev->demux;
|
||||
dvbdemux->filternum = 256;
|
||||
dvbdemux->feednum = 256;
|
||||
dvbdemux->start_feed = dm1105dvb_start_feed;
|
||||
dvbdemux->stop_feed = dm1105dvb_stop_feed;
|
||||
dvbdemux->start_feed = dm1105_start_feed;
|
||||
dvbdemux->stop_feed = dm1105_stop_feed;
|
||||
dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
|
||||
DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
|
||||
ret = dvb_dmx_init(dvbdemux);
|
||||
|
@ -870,113 +895,113 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
|
|||
goto err_dvb_unregister_adapter;
|
||||
|
||||
dmx = &dvbdemux->dmx;
|
||||
dm1105dvb->dmxdev.filternum = 256;
|
||||
dm1105dvb->dmxdev.demux = dmx;
|
||||
dm1105dvb->dmxdev.capabilities = 0;
|
||||
dev->dmxdev.filternum = 256;
|
||||
dev->dmxdev.demux = dmx;
|
||||
dev->dmxdev.capabilities = 0;
|
||||
|
||||
ret = dvb_dmxdev_init(&dm1105dvb->dmxdev, dvb_adapter);
|
||||
ret = dvb_dmxdev_init(&dev->dmxdev, dvb_adapter);
|
||||
if (ret < 0)
|
||||
goto err_dvb_dmx_release;
|
||||
|
||||
dm1105dvb->hw_frontend.source = DMX_FRONTEND_0;
|
||||
dev->hw_frontend.source = DMX_FRONTEND_0;
|
||||
|
||||
ret = dmx->add_frontend(dmx, &dm1105dvb->hw_frontend);
|
||||
ret = dmx->add_frontend(dmx, &dev->hw_frontend);
|
||||
if (ret < 0)
|
||||
goto err_dvb_dmxdev_release;
|
||||
|
||||
dm1105dvb->mem_frontend.source = DMX_MEMORY_FE;
|
||||
dev->mem_frontend.source = DMX_MEMORY_FE;
|
||||
|
||||
ret = dmx->add_frontend(dmx, &dm1105dvb->mem_frontend);
|
||||
ret = dmx->add_frontend(dmx, &dev->mem_frontend);
|
||||
if (ret < 0)
|
||||
goto err_remove_hw_frontend;
|
||||
|
||||
ret = dmx->connect_frontend(dmx, &dm1105dvb->hw_frontend);
|
||||
ret = dmx->connect_frontend(dmx, &dev->hw_frontend);
|
||||
if (ret < 0)
|
||||
goto err_remove_mem_frontend;
|
||||
|
||||
ret = frontend_init(dm1105dvb);
|
||||
ret = frontend_init(dev);
|
||||
if (ret < 0)
|
||||
goto err_disconnect_frontend;
|
||||
|
||||
dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);
|
||||
dm1105_ir_init(dm1105dvb);
|
||||
dvb_net_init(dvb_adapter, &dev->dvbnet, dmx);
|
||||
dm1105_ir_init(dev);
|
||||
|
||||
INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
|
||||
sprintf(dm1105dvb->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
|
||||
dm1105dvb->wq = create_singlethread_workqueue(dm1105dvb->wqn);
|
||||
if (!dm1105dvb->wq)
|
||||
INIT_WORK(&dev->work, dm1105_dmx_buffer);
|
||||
sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
|
||||
dev->wq = create_singlethread_workqueue(dev->wqn);
|
||||
if (!dev->wq)
|
||||
goto err_dvb_net;
|
||||
|
||||
ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
|
||||
DRIVER_NAME, dm1105dvb);
|
||||
ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED,
|
||||
DRIVER_NAME, dev);
|
||||
if (ret < 0)
|
||||
goto err_workqueue;
|
||||
|
||||
return 0;
|
||||
|
||||
err_workqueue:
|
||||
destroy_workqueue(dm1105dvb->wq);
|
||||
destroy_workqueue(dev->wq);
|
||||
err_dvb_net:
|
||||
dvb_net_release(&dm1105dvb->dvbnet);
|
||||
dvb_net_release(&dev->dvbnet);
|
||||
err_disconnect_frontend:
|
||||
dmx->disconnect_frontend(dmx);
|
||||
err_remove_mem_frontend:
|
||||
dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
|
||||
dmx->remove_frontend(dmx, &dev->mem_frontend);
|
||||
err_remove_hw_frontend:
|
||||
dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
|
||||
dmx->remove_frontend(dmx, &dev->hw_frontend);
|
||||
err_dvb_dmxdev_release:
|
||||
dvb_dmxdev_release(&dm1105dvb->dmxdev);
|
||||
dvb_dmxdev_release(&dev->dmxdev);
|
||||
err_dvb_dmx_release:
|
||||
dvb_dmx_release(dvbdemux);
|
||||
err_dvb_unregister_adapter:
|
||||
dvb_unregister_adapter(dvb_adapter);
|
||||
err_i2c_del_adapter:
|
||||
i2c_del_adapter(&dm1105dvb->i2c_adap);
|
||||
err_dm1105dvb_hw_exit:
|
||||
dm1105dvb_hw_exit(dm1105dvb);
|
||||
i2c_del_adapter(&dev->i2c_adap);
|
||||
err_dm1105_hw_exit:
|
||||
dm1105_hw_exit(dev);
|
||||
err_pci_iounmap:
|
||||
pci_iounmap(pdev, dm1105dvb->io_mem);
|
||||
pci_iounmap(pdev, dev->io_mem);
|
||||
err_pci_release_regions:
|
||||
pci_release_regions(pdev);
|
||||
err_pci_disable_device:
|
||||
pci_disable_device(pdev);
|
||||
err_kfree:
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
kfree(dm1105dvb);
|
||||
kfree(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit dm1105_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb = pci_get_drvdata(pdev);
|
||||
struct dvb_adapter *dvb_adapter = &dm1105dvb->dvb_adapter;
|
||||
struct dvb_demux *dvbdemux = &dm1105dvb->demux;
|
||||
struct dm1105_dev *dev = pci_get_drvdata(pdev);
|
||||
struct dvb_adapter *dvb_adapter = &dev->dvb_adapter;
|
||||
struct dvb_demux *dvbdemux = &dev->demux;
|
||||
struct dmx_demux *dmx = &dvbdemux->dmx;
|
||||
|
||||
dm1105_ir_exit(dm1105dvb);
|
||||
dm1105_ir_exit(dev);
|
||||
dmx->close(dmx);
|
||||
dvb_net_release(&dm1105dvb->dvbnet);
|
||||
if (dm1105dvb->fe)
|
||||
dvb_unregister_frontend(dm1105dvb->fe);
|
||||
dvb_net_release(&dev->dvbnet);
|
||||
if (dev->fe)
|
||||
dvb_unregister_frontend(dev->fe);
|
||||
|
||||
dmx->disconnect_frontend(dmx);
|
||||
dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
|
||||
dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
|
||||
dvb_dmxdev_release(&dm1105dvb->dmxdev);
|
||||
dmx->remove_frontend(dmx, &dev->mem_frontend);
|
||||
dmx->remove_frontend(dmx, &dev->hw_frontend);
|
||||
dvb_dmxdev_release(&dev->dmxdev);
|
||||
dvb_dmx_release(dvbdemux);
|
||||
dvb_unregister_adapter(dvb_adapter);
|
||||
if (&dm1105dvb->i2c_adap)
|
||||
i2c_del_adapter(&dm1105dvb->i2c_adap);
|
||||
if (&dev->i2c_adap)
|
||||
i2c_del_adapter(&dev->i2c_adap);
|
||||
|
||||
dm1105dvb_hw_exit(dm1105dvb);
|
||||
dm1105_hw_exit(dev);
|
||||
synchronize_irq(pdev->irq);
|
||||
free_irq(pdev->irq, dm1105dvb);
|
||||
pci_iounmap(pdev, dm1105dvb->io_mem);
|
||||
free_irq(pdev->irq, dev);
|
||||
pci_iounmap(pdev, dev->io_mem);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
dm1105_devcount--;
|
||||
kfree(dm1105dvb);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static struct pci_device_id dm1105_id_table[] __devinitdata = {
|
||||
|
|
|
@ -1199,8 +1199,6 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
|
|||
{
|
||||
int r = 0;
|
||||
|
||||
dtv_property_dump(tvp);
|
||||
|
||||
/* Allow the frontend to validate incoming properties */
|
||||
if (fe->ops.get_property)
|
||||
r = fe->ops.get_property(fe, tvp);
|
||||
|
@ -1323,6 +1321,8 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
|
|||
r = -1;
|
||||
}
|
||||
|
||||
dtv_property_dump(tvp);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -1488,7 +1488,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
|
|||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
int err = -EOPNOTSUPP;
|
||||
|
||||
dprintk ("%s\n", __func__);
|
||||
dprintk("%s (%d)\n", __func__, _IOC_NR(cmd));
|
||||
|
||||
if (fepriv->exit)
|
||||
return -ENODEV;
|
||||
|
@ -1536,8 +1536,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
|
|||
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = (struct dtv_property *) kmalloc(tvps->num *
|
||||
sizeof(struct dtv_property), GFP_KERNEL);
|
||||
tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
|
||||
if (!tvp) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
|
@ -1569,8 +1568,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
|
|||
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = (struct dtv_property *) kmalloc(tvps->num *
|
||||
sizeof(struct dtv_property), GFP_KERNEL);
|
||||
tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
|
||||
if (!tvp) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
|
|
|
@ -89,6 +89,7 @@ void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
|
|||
rbuf->pread = rbuf->pwrite;
|
||||
rbuf->error = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_flush);
|
||||
|
||||
void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
|
|
|
@ -336,3 +336,11 @@ config DVB_USB_EC168
|
|||
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
|
||||
|
||||
config DVB_USB_AZ6027
|
||||
tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support"
|
||||
depends on DVB_USB
|
||||
select DVB_STB0899 if !DVB_FE_CUSTOMISE
|
||||
select DVB_STB6100 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the AZ6027 device
|
||||
|
|
|
@ -85,6 +85,9 @@ obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
|
|||
dvb-usb-ec168-objs = ec168.o
|
||||
obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
|
||||
|
||||
dvb-usb-az6027-objs = az6027.o
|
||||
obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
|
||||
# due to tuner-xc3028
|
||||
EXTRA_CFLAGS += -Idrivers/media/common/tuners
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/hash.h>
|
||||
|
||||
#include "af9015.h"
|
||||
#include "af9013.h"
|
||||
#include "mt2060.h"
|
||||
|
@ -553,26 +555,45 @@ exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* dump eeprom */
|
||||
static int af9015_eeprom_dump(struct dvb_usb_device *d)
|
||||
/* hash (and dump) eeprom */
|
||||
static int af9015_eeprom_hash(struct usb_device *udev)
|
||||
{
|
||||
u8 reg, val;
|
||||
static const unsigned int eeprom_size = 256;
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
u8 val, *eeprom;
|
||||
struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
|
||||
|
||||
for (reg = 0; ; reg++) {
|
||||
if (reg % 16 == 0) {
|
||||
if (reg)
|
||||
deb_info(KERN_CONT "\n");
|
||||
deb_info(KERN_DEBUG "%02x:", reg);
|
||||
}
|
||||
if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0)
|
||||
deb_info(KERN_CONT " %02x", val);
|
||||
else
|
||||
deb_info(KERN_CONT " --");
|
||||
if (reg == 0xff)
|
||||
break;
|
||||
eeprom = kmalloc(eeprom_size, GFP_KERNEL);
|
||||
if (eeprom == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (reg = 0; reg < eeprom_size; reg++) {
|
||||
req.addr = reg;
|
||||
ret = af9015_rw_udev(udev, &req);
|
||||
if (ret)
|
||||
goto free;
|
||||
eeprom[reg] = val;
|
||||
}
|
||||
deb_info(KERN_CONT "\n");
|
||||
return 0;
|
||||
|
||||
if (dvb_usb_af9015_debug & 0x01)
|
||||
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom,
|
||||
eeprom_size);
|
||||
|
||||
BUG_ON(eeprom_size % 4);
|
||||
|
||||
af9015_config.eeprom_sum = 0;
|
||||
for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) {
|
||||
af9015_config.eeprom_sum *= GOLDEN_RATIO_PRIME_32;
|
||||
af9015_config.eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]);
|
||||
}
|
||||
|
||||
deb_info("%s: eeprom sum=%.8x\n", __func__, af9015_config.eeprom_sum);
|
||||
|
||||
ret = 0;
|
||||
free:
|
||||
kfree(eeprom);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int af9015_download_ir_table(struct dvb_usb_device *d)
|
||||
|
@ -711,12 +732,132 @@ error:
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct af9015_setup {
|
||||
unsigned int id;
|
||||
struct dvb_usb_rc_key *rc_key_map;
|
||||
unsigned int rc_key_map_size;
|
||||
u8 *ir_table;
|
||||
unsigned int ir_table_size;
|
||||
};
|
||||
|
||||
static const struct af9015_setup *af9015_setup_match(unsigned int id,
|
||||
const struct af9015_setup *table)
|
||||
{
|
||||
for (; table->rc_key_map; table++)
|
||||
if (table->id == id)
|
||||
return table;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct af9015_setup af9015_setup_modparam[] = {
|
||||
{ AF9015_REMOTE_A_LINK_DTU_M,
|
||||
af9015_rc_keys_a_link, ARRAY_SIZE(af9015_rc_keys_a_link),
|
||||
af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
|
||||
{ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
|
||||
af9015_rc_keys_msi, ARRAY_SIZE(af9015_rc_keys_msi),
|
||||
af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
|
||||
{ AF9015_REMOTE_MYGICTV_U718,
|
||||
af9015_rc_keys_mygictv, ARRAY_SIZE(af9015_rc_keys_mygictv),
|
||||
af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
|
||||
{ AF9015_REMOTE_DIGITTRADE_DVB_T,
|
||||
af9015_rc_keys_digittrade, ARRAY_SIZE(af9015_rc_keys_digittrade),
|
||||
af9015_ir_table_digittrade, ARRAY_SIZE(af9015_ir_table_digittrade) },
|
||||
{ AF9015_REMOTE_AVERMEDIA_KS,
|
||||
af9015_rc_keys_avermedia, ARRAY_SIZE(af9015_rc_keys_avermedia),
|
||||
af9015_ir_table_avermedia_ks, ARRAY_SIZE(af9015_ir_table_avermedia_ks) },
|
||||
{ }
|
||||
};
|
||||
|
||||
/* don't add new entries here anymore, use hashes instead */
|
||||
static const struct af9015_setup af9015_setup_usbids[] = {
|
||||
{ USB_VID_LEADTEK,
|
||||
af9015_rc_keys_leadtek, ARRAY_SIZE(af9015_rc_keys_leadtek),
|
||||
af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) },
|
||||
{ USB_VID_VISIONPLUS,
|
||||
af9015_rc_keys_twinhan, ARRAY_SIZE(af9015_rc_keys_twinhan),
|
||||
af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) },
|
||||
{ USB_VID_KWORLD_2, /* TODO: use correct rc keys */
|
||||
af9015_rc_keys_twinhan, ARRAY_SIZE(af9015_rc_keys_twinhan),
|
||||
af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) },
|
||||
{ USB_VID_AVERMEDIA,
|
||||
af9015_rc_keys_avermedia, ARRAY_SIZE(af9015_rc_keys_avermedia),
|
||||
af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) },
|
||||
{ USB_VID_MSI_2,
|
||||
af9015_rc_keys_msi_digivox_iii, ARRAY_SIZE(af9015_rc_keys_msi_digivox_iii),
|
||||
af9015_ir_table_msi_digivox_iii, ARRAY_SIZE(af9015_ir_table_msi_digivox_iii) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct af9015_setup af9015_setup_hashes[] = {
|
||||
{ 0xb8feb708,
|
||||
af9015_rc_keys_msi, ARRAY_SIZE(af9015_rc_keys_msi),
|
||||
af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
|
||||
{ 0xa3703d00,
|
||||
af9015_rc_keys_a_link, ARRAY_SIZE(af9015_rc_keys_a_link),
|
||||
af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
|
||||
{ 0x9b7dc64e,
|
||||
af9015_rc_keys_mygictv, ARRAY_SIZE(af9015_rc_keys_mygictv),
|
||||
af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void af9015_set_remote_config(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props)
|
||||
{
|
||||
const struct af9015_setup *table = NULL;
|
||||
|
||||
if (dvb_usb_af9015_remote) {
|
||||
/* load remote defined as module param */
|
||||
table = af9015_setup_match(dvb_usb_af9015_remote,
|
||||
af9015_setup_modparam);
|
||||
} else {
|
||||
u16 vendor = le16_to_cpu(udev->descriptor.idVendor);
|
||||
|
||||
table = af9015_setup_match(af9015_config.eeprom_sum,
|
||||
af9015_setup_hashes);
|
||||
|
||||
if (!table && vendor == USB_VID_AFATECH) {
|
||||
/* Check USB manufacturer and product strings and try
|
||||
to determine correct remote in case of chip vendor
|
||||
reference IDs are used.
|
||||
DO NOT ADD ANYTHING NEW HERE. Use hashes instead.
|
||||
*/
|
||||
char manufacturer[10];
|
||||
memset(manufacturer, 0, sizeof(manufacturer));
|
||||
usb_string(udev, udev->descriptor.iManufacturer,
|
||||
manufacturer, sizeof(manufacturer));
|
||||
if (!strcmp("MSI", manufacturer)) {
|
||||
/* iManufacturer 1 MSI
|
||||
iProduct 2 MSI K-VOX */
|
||||
table = af9015_setup_match(
|
||||
AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
|
||||
af9015_setup_modparam);
|
||||
} else if (udev->descriptor.idProduct ==
|
||||
cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
|
||||
table = &(const struct af9015_setup){ 0,
|
||||
af9015_rc_keys_trekstor,
|
||||
ARRAY_SIZE(af9015_rc_keys_trekstor),
|
||||
af9015_ir_table_trekstor,
|
||||
ARRAY_SIZE(af9015_ir_table_trekstor)
|
||||
};
|
||||
}
|
||||
} else if (!table)
|
||||
table = af9015_setup_match(vendor, af9015_setup_usbids);
|
||||
}
|
||||
|
||||
if (table) {
|
||||
props->rc_key_map = table->rc_key_map;
|
||||
props->rc_key_map_size = table->rc_key_map_size;
|
||||
af9015_config.ir_table = table->ir_table;
|
||||
af9015_config.ir_table_size = table->ir_table_size;
|
||||
}
|
||||
}
|
||||
|
||||
static int af9015_read_config(struct usb_device *udev)
|
||||
{
|
||||
int ret;
|
||||
u8 val, i, offset = 0;
|
||||
struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
|
||||
char manufacturer[10];
|
||||
|
||||
/* IR remote controller */
|
||||
req.addr = AF9015_EEPROM_IR_MODE;
|
||||
|
@ -728,158 +869,18 @@ static int af9015_read_config(struct usb_device *udev)
|
|||
}
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = af9015_eeprom_hash(udev);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
deb_info("%s: IR mode:%d\n", __func__, val);
|
||||
for (i = 0; i < af9015_properties_count; i++) {
|
||||
if (val == AF9015_IR_MODE_DISABLED) {
|
||||
af9015_properties[i].rc_key_map = NULL;
|
||||
af9015_properties[i].rc_key_map_size = 0;
|
||||
} else if (dvb_usb_af9015_remote) {
|
||||
/* load remote defined as module param */
|
||||
switch (dvb_usb_af9015_remote) {
|
||||
case AF9015_REMOTE_A_LINK_DTU_M:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_a_link;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_a_link);
|
||||
af9015_config.ir_table = af9015_ir_table_a_link;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_a_link);
|
||||
break;
|
||||
case AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_msi;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_msi);
|
||||
af9015_config.ir_table = af9015_ir_table_msi;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_msi);
|
||||
break;
|
||||
case AF9015_REMOTE_MYGICTV_U718:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_mygictv;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_mygictv);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_mygictv;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_mygictv);
|
||||
break;
|
||||
case AF9015_REMOTE_DIGITTRADE_DVB_T:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_digittrade;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_digittrade);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_digittrade;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_digittrade);
|
||||
break;
|
||||
case AF9015_REMOTE_AVERMEDIA_KS:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_avermedia;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_avermedia);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_avermedia_ks;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_avermedia_ks);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (le16_to_cpu(udev->descriptor.idVendor)) {
|
||||
case USB_VID_LEADTEK:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_leadtek;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_leadtek);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_leadtek;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_leadtek);
|
||||
break;
|
||||
case USB_VID_VISIONPLUS:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_twinhan;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_twinhan);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_twinhan;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_twinhan);
|
||||
break;
|
||||
case USB_VID_KWORLD_2:
|
||||
/* TODO: use correct rc keys */
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_twinhan;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_twinhan);
|
||||
af9015_config.ir_table = af9015_ir_table_kworld;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_kworld);
|
||||
break;
|
||||
/* Check USB manufacturer and product strings and try
|
||||
to determine correct remote in case of chip vendor
|
||||
reference IDs are used. */
|
||||
case USB_VID_AFATECH:
|
||||
memset(manufacturer, 0, sizeof(manufacturer));
|
||||
usb_string(udev, udev->descriptor.iManufacturer,
|
||||
manufacturer, sizeof(manufacturer));
|
||||
if (!strcmp("Geniatech", manufacturer)) {
|
||||
/* iManufacturer 1 Geniatech
|
||||
iProduct 2 AF9015 */
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_mygictv;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_mygictv);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_mygictv;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_mygictv);
|
||||
} else if (!strcmp("MSI", manufacturer)) {
|
||||
/* iManufacturer 1 MSI
|
||||
iProduct 2 MSI K-VOX */
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_msi;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_msi);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_msi;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_msi);
|
||||
} else if (udev->descriptor.idProduct ==
|
||||
cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_trekstor;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_trekstor);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_trekstor;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_trekstor);
|
||||
}
|
||||
break;
|
||||
case USB_VID_AVERMEDIA:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_avermedia;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_avermedia);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_avermedia;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_avermedia);
|
||||
break;
|
||||
case USB_VID_MSI_2:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_msi_digivox_iii;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_msi_digivox_iii);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_msi_digivox_iii;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_msi_digivox_iii);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
af9015_set_remote_config(udev, &af9015_properties[i]);
|
||||
}
|
||||
|
||||
/* TS mode - one or two receivers */
|
||||
|
@ -1001,6 +1002,9 @@ static int af9015_read_config(struct usb_device *udev)
|
|||
af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
|
||||
af9015_af9013_config[i].rf_spec_inv = 1;
|
||||
break;
|
||||
case AF9013_TUNER_TDA18218:
|
||||
warn("tuner NXP TDA18218 not supported yet");
|
||||
return -ENODEV;
|
||||
default:
|
||||
warn("tuner id:%d not supported, please report!", val);
|
||||
return -ENODEV;
|
||||
|
@ -1125,11 +1129,6 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
|
|||
|
||||
deb_info("%s: init I2C\n", __func__);
|
||||
ret = af9015_i2c_init(adap->dev);
|
||||
|
||||
/* dump eeprom (debug) */
|
||||
ret = af9015_eeprom_dump(adap->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/* select I2C adapter */
|
||||
i2c_adap = &state->i2c_adap;
|
||||
|
@ -1295,6 +1294,8 @@ static struct usb_device_id af9015_usb_table[] = {
|
|||
/* 25 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
|
||||
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)},
|
||||
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)},
|
||||
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)},
|
||||
{USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
|
||||
{0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
|
||||
|
@ -1381,7 +1382,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
},
|
||||
{
|
||||
.name = "DigitalNow TinyTwin DVB-T Receiver",
|
||||
.cold_ids = {&af9015_usb_table[5], NULL},
|
||||
.cold_ids = {&af9015_usb_table[5],
|
||||
&af9015_usb_table[28], NULL},
|
||||
.warm_ids = {NULL},
|
||||
},
|
||||
{
|
||||
|
@ -1566,7 +1568,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
|
||||
.i2c_algo = &af9015_i2c_algo,
|
||||
|
||||
.num_device_descs = 6, /* max 9 */
|
||||
.num_device_descs = 7, /* max 9 */
|
||||
.devices = {
|
||||
{
|
||||
.name = "AverMedia AVerTV Volar GPS 805 (A805)",
|
||||
|
@ -1600,6 +1602,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
.cold_ids = {&af9015_usb_table[27], NULL},
|
||||
.warm_ids = {NULL},
|
||||
},
|
||||
{
|
||||
.name = "Leadtek WinFast DTV2000DS",
|
||||
.cold_ids = {&af9015_usb_table[29], NULL},
|
||||
.warm_ids = {NULL},
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -107,6 +107,7 @@ struct af9015_config {
|
|||
u16 mt2060_if1[2];
|
||||
u16 firmware_size;
|
||||
u16 firmware_checksum;
|
||||
u32 eeprom_sum;
|
||||
u8 *ir_table;
|
||||
u16 ir_table_size;
|
||||
};
|
||||
|
|
1151
drivers/media/dvb/dvb-usb/az6027.c
Normal file
1151
drivers/media/dvb/dvb-usb/az6027.c
Normal file
File diff suppressed because it is too large
Load diff
14
drivers/media/dvb/dvb-usb/az6027.h
Normal file
14
drivers/media/dvb/dvb-usb/az6027.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef _DVB_USB_VP6027_H_
|
||||
#define _DVB_USB_VP6027_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "az6027"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
|
||||
extern int dvb_usb_az6027_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_az6027_debug, 0x01, args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_az6027_debug, 0x02, args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_az6027_debug, 0x04, args)
|
||||
#define deb_fe(args...) dprintk(dvb_usb_az6027_debug, 0x08, args)
|
||||
|
||||
#endif
|
|
@ -1184,6 +1184,9 @@ static struct atbm8830_config mygica_d689_atbm8830_cfg = {
|
|||
.osc_clk_freq = 30400, /* in kHz */
|
||||
.if_freq = 0, /* zero IF */
|
||||
.zif_swap_iq = 1,
|
||||
.agc_min = 0x2E,
|
||||
.agc_max = 0x90,
|
||||
.agc_hold_loop = 0,
|
||||
};
|
||||
|
||||
static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
|
|
|
@ -42,7 +42,6 @@ struct dib0700_state {
|
|||
u16 mt2060_if1[2];
|
||||
u8 rc_toggle;
|
||||
u8 rc_counter;
|
||||
u8 rc_func_version;
|
||||
u8 is_dib7000pc;
|
||||
u8 fw_use_new_i2c_api;
|
||||
u8 disable_streaming_master_mode;
|
||||
|
|
|
@ -471,14 +471,209 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
|||
return dib0700_ctrl_wr(adap->dev, b, 4);
|
||||
}
|
||||
|
||||
/* Number of keypresses to ignore before start repeating */
|
||||
#define RC_REPEAT_DELAY_V1_20 10
|
||||
|
||||
/* This is the structure of the RC response packet starting in firmware 1.20 */
|
||||
struct dib0700_rc_response {
|
||||
u8 report_id;
|
||||
u8 data_state;
|
||||
u16 system;
|
||||
u8 data;
|
||||
u8 not_data;
|
||||
};
|
||||
#define RC_MSG_SIZE_V1_20 6
|
||||
|
||||
static void dib0700_rc_urb_completion(struct urb *purb)
|
||||
{
|
||||
struct dvb_usb_device *d = purb->context;
|
||||
struct dvb_usb_rc_key *keymap;
|
||||
struct dib0700_state *st;
|
||||
struct dib0700_rc_response poll_reply;
|
||||
u8 *buf;
|
||||
int found = 0;
|
||||
u32 event;
|
||||
int state;
|
||||
int i;
|
||||
|
||||
deb_info("%s()\n", __func__);
|
||||
if (d == NULL)
|
||||
return;
|
||||
|
||||
if (d->rc_input_dev == NULL) {
|
||||
/* This will occur if disable_rc_polling=1 */
|
||||
usb_free_urb(purb);
|
||||
return;
|
||||
}
|
||||
|
||||
keymap = d->props.rc_key_map;
|
||||
st = d->priv;
|
||||
buf = (u8 *)purb->transfer_buffer;
|
||||
|
||||
if (purb->status < 0) {
|
||||
deb_info("discontinuing polling\n");
|
||||
usb_free_urb(purb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (purb->actual_length != RC_MSG_SIZE_V1_20) {
|
||||
deb_info("malformed rc msg size=%d\n", purb->actual_length);
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
/* Set initial results in case we exit the function early */
|
||||
event = 0;
|
||||
state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
deb_data("IR raw %02X %02X %02X %02X %02X %02X (len %d)\n", buf[0],
|
||||
buf[1], buf[2], buf[3], buf[4], buf[5], purb->actual_length);
|
||||
|
||||
switch (dvb_usb_dib0700_ir_proto) {
|
||||
case 0:
|
||||
/* NEC Protocol */
|
||||
poll_reply.report_id = 0;
|
||||
poll_reply.data_state = 1;
|
||||
poll_reply.system = buf[2];
|
||||
poll_reply.data = buf[4];
|
||||
poll_reply.not_data = buf[5];
|
||||
|
||||
/* NEC protocol sends repeat code as 0 0 0 FF */
|
||||
if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
|
||||
&& (poll_reply.not_data == 0xff)) {
|
||||
poll_reply.data_state = 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* RC5 Protocol */
|
||||
poll_reply.report_id = buf[0];
|
||||
poll_reply.data_state = buf[1];
|
||||
poll_reply.system = (buf[2] << 8) | buf[3];
|
||||
poll_reply.data = buf[4];
|
||||
poll_reply.not_data = buf[5];
|
||||
break;
|
||||
}
|
||||
|
||||
if ((poll_reply.data + poll_reply.not_data) != 0xff) {
|
||||
/* Key failed integrity check */
|
||||
err("key failed integrity check: %04x %02x %02x",
|
||||
poll_reply.system,
|
||||
poll_reply.data, poll_reply.not_data);
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
deb_data("rid=%02x ds=%02x sm=%04x d=%02x nd=%02x\n",
|
||||
poll_reply.report_id, poll_reply.data_state,
|
||||
poll_reply.system, poll_reply.data, poll_reply.not_data);
|
||||
|
||||
/* Find the key in the map */
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
|
||||
rc5_data(&keymap[i]) == poll_reply.data) {
|
||||
event = keymap[i].event;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
err("Unknown remote controller key: %04x %02x %02x",
|
||||
poll_reply.system, poll_reply.data, poll_reply.not_data);
|
||||
d->last_event = 0;
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
if (poll_reply.data_state == 1) {
|
||||
/* New key hit */
|
||||
st->rc_counter = 0;
|
||||
event = keymap[i].event;
|
||||
state = REMOTE_KEY_PRESSED;
|
||||
d->last_event = keymap[i].event;
|
||||
} else if (poll_reply.data_state == 2) {
|
||||
/* Key repeated */
|
||||
st->rc_counter++;
|
||||
|
||||
/* prevents unwanted double hits */
|
||||
if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
|
||||
event = d->last_event;
|
||||
state = REMOTE_KEY_PRESSED;
|
||||
st->rc_counter = RC_REPEAT_DELAY_V1_20;
|
||||
}
|
||||
} else {
|
||||
err("Unknown data state [%d]", poll_reply.data_state);
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case REMOTE_NO_KEY_PRESSED:
|
||||
break;
|
||||
case REMOTE_KEY_PRESSED:
|
||||
deb_info("key pressed\n");
|
||||
d->last_event = event;
|
||||
case REMOTE_KEY_REPEAT:
|
||||
deb_info("key repeated\n");
|
||||
input_event(d->rc_input_dev, EV_KEY, event, 1);
|
||||
input_sync(d->rc_input_dev);
|
||||
input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
|
||||
input_sync(d->rc_input_dev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
resubmit:
|
||||
/* Clean the buffer before we requeue */
|
||||
memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20);
|
||||
|
||||
/* Requeue URB */
|
||||
usb_submit_urb(purb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
int dib0700_rc_setup(struct dvb_usb_device *d)
|
||||
{
|
||||
struct dib0700_state *st = d->priv;
|
||||
u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
|
||||
int i = dib0700_ctrl_wr(d, rc_setup, 3);
|
||||
struct urb *purb;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (d->props.rc_key_map == NULL)
|
||||
return 0;
|
||||
|
||||
/* Set the IR mode */
|
||||
i = dib0700_ctrl_wr(d, rc_setup, 3);
|
||||
if (i<0) {
|
||||
err("ir protocol setup failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (st->fw_version < 0x10200)
|
||||
return 0;
|
||||
|
||||
/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
|
||||
purb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (purb == NULL) {
|
||||
err("rc usb alloc urb failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
|
||||
if (purb->transfer_buffer == NULL) {
|
||||
err("rc kzalloc failed\n");
|
||||
usb_free_urb(purb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
purb->status = -EINPROGRESS;
|
||||
usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1),
|
||||
purb->transfer_buffer, RC_MSG_SIZE_V1_20,
|
||||
dib0700_rc_urb_completion, d);
|
||||
|
||||
ret = usb_submit_urb(purb, GFP_ATOMIC);
|
||||
if (ret != 0) {
|
||||
err("rc submit urb failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -472,20 +472,25 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
|
|||
|
||||
/* Number of keypresses to ignore before start repeating */
|
||||
#define RC_REPEAT_DELAY 6
|
||||
#define RC_REPEAT_DELAY_V1_20 10
|
||||
|
||||
|
||||
|
||||
/* Used by firmware versions < 1.20 (deprecated) */
|
||||
static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
|
||||
int *state)
|
||||
static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
u8 key[4];
|
||||
int i;
|
||||
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
|
||||
struct dib0700_state *st = d->priv;
|
||||
|
||||
*event = 0;
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
if (st->fw_version >= 0x10200) {
|
||||
/* For 1.20 firmware , We need to keep the RC polling
|
||||
callback so we can reuse the input device setup in
|
||||
dvb-usb-remote.c. However, the actual work is being done
|
||||
in the bulk URB completion handler. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
i=dib0700_ctrl_rd(d,rc_request,2,key,4);
|
||||
if (i<=0) {
|
||||
err("RC Query Failed");
|
||||
|
@ -557,149 +562,6 @@ static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* This is the structure of the RC response packet starting in firmware 1.20 */
|
||||
struct dib0700_rc_response {
|
||||
u8 report_id;
|
||||
u8 data_state;
|
||||
u16 system;
|
||||
u8 data;
|
||||
u8 not_data;
|
||||
};
|
||||
|
||||
/* This supports the new IR response format for firmware v1.20 */
|
||||
static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
|
||||
int *state)
|
||||
{
|
||||
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
|
||||
struct dib0700_state *st = d->priv;
|
||||
struct dib0700_rc_response poll_reply;
|
||||
u8 buf[6];
|
||||
int i;
|
||||
int status;
|
||||
int actlen;
|
||||
int found = 0;
|
||||
|
||||
/* Set initial results in case we exit the function early */
|
||||
*event = 0;
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
/* Firmware v1.20 provides RC data via bulk endpoint 1 */
|
||||
status = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, 1), buf,
|
||||
sizeof(buf), &actlen, 50);
|
||||
if (status < 0) {
|
||||
/* No data available (meaning no key press) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
switch (dvb_usb_dib0700_ir_proto) {
|
||||
case 0:
|
||||
poll_reply.report_id = 0;
|
||||
poll_reply.data_state = 1;
|
||||
poll_reply.system = buf[2];
|
||||
poll_reply.data = buf[4];
|
||||
poll_reply.not_data = buf[5];
|
||||
|
||||
/* NEC protocol sends repeat code as 0 0 0 FF */
|
||||
if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
|
||||
&& (poll_reply.not_data == 0xff)) {
|
||||
poll_reply.data_state = 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (actlen != sizeof(buf)) {
|
||||
/* We didn't get back the 6 byte message we expected */
|
||||
err("Unexpected RC response size [%d]", actlen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
poll_reply.report_id = buf[0];
|
||||
poll_reply.data_state = buf[1];
|
||||
poll_reply.system = (buf[2] << 8) | buf[3];
|
||||
poll_reply.data = buf[4];
|
||||
poll_reply.not_data = buf[5];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((poll_reply.data + poll_reply.not_data) != 0xff) {
|
||||
/* Key failed integrity check */
|
||||
err("key failed integrity check: %04x %02x %02x",
|
||||
poll_reply.system,
|
||||
poll_reply.data, poll_reply.not_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Find the key in the map */
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
|
||||
rc5_data(&keymap[i]) == poll_reply.data) {
|
||||
*event = keymap[i].event;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
err("Unknown remote controller key: %04x %02x %02x",
|
||||
poll_reply.system,
|
||||
poll_reply.data, poll_reply.not_data);
|
||||
d->last_event = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (poll_reply.data_state == 1) {
|
||||
/* New key hit */
|
||||
st->rc_counter = 0;
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
d->last_event = keymap[i].event;
|
||||
} else if (poll_reply.data_state == 2) {
|
||||
/* Key repeated */
|
||||
st->rc_counter++;
|
||||
|
||||
/* prevents unwanted double hits */
|
||||
if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
|
||||
*event = d->last_event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
st->rc_counter = RC_REPEAT_DELAY_V1_20;
|
||||
}
|
||||
} else {
|
||||
err("Unknown data state [%d]", poll_reply.data_state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
struct dib0700_state *st = d->priv;
|
||||
|
||||
/* Because some people may have improperly named firmware files,
|
||||
let's figure out whether to use the new firmware call or the legacy
|
||||
call based on the firmware version embedded in the file */
|
||||
if (st->rc_func_version == 0) {
|
||||
u32 hwver, romver, ramver, fwtype;
|
||||
int ret = dib0700_get_version(d, &hwver, &romver, &ramver,
|
||||
&fwtype);
|
||||
if (ret < 0) {
|
||||
err("Could not determine version info");
|
||||
return -1;
|
||||
}
|
||||
if (ramver < 0x10200)
|
||||
st->rc_func_version = 1;
|
||||
else
|
||||
st->rc_func_version = 2;
|
||||
}
|
||||
|
||||
if (st->rc_func_version == 2)
|
||||
return dib0700_rc_query_v1_20(d, event, state);
|
||||
else
|
||||
return dib0700_rc_query_legacy(d, event, state);
|
||||
}
|
||||
|
||||
static struct dvb_usb_rc_key dib0700_rc_keys[] = {
|
||||
/* Key codes for the tiny Pinnacle remote*/
|
||||
{ 0x0700, KEY_MUTE },
|
||||
|
|
|
@ -64,6 +64,8 @@
|
|||
#define USB_VID_HUMAX_COEX 0x10b9
|
||||
#define USB_VID_774 0x7a69
|
||||
#define USB_VID_EVOLUTEPC 0x1e59
|
||||
#define USB_VID_AZUREWAVE 0x13d3
|
||||
#define USB_VID_TECHNISAT 0x14f7
|
||||
|
||||
/* Product IDs */
|
||||
#define USB_PID_ADSTECH_USB2_COLD 0xa333
|
||||
|
@ -138,6 +140,7 @@
|
|||
#define USB_PID_TWINHAN_VP7021_COLD 0x3207
|
||||
#define USB_PID_TWINHAN_VP7021_WARM 0x3208
|
||||
#define USB_PID_TINYTWIN 0x3226
|
||||
#define USB_PID_TINYTWIN_2 0xe402
|
||||
#define USB_PID_DNTV_TINYUSB2_COLD 0x3223
|
||||
#define USB_PID_DNTV_TINYUSB2_WARM 0x3224
|
||||
#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
|
||||
|
@ -209,6 +212,7 @@
|
|||
#define USB_PID_PINNACLE_PCTV71E 0x022b
|
||||
#define USB_PID_PINNACLE_PCTV72E 0x0236
|
||||
#define USB_PID_PINNACLE_PCTV73E 0x0237
|
||||
#define USB_PID_PINNACLE_PCTV310E 0x3211
|
||||
#define USB_PID_PINNACLE_PCTV801E 0x023a
|
||||
#define USB_PID_PINNACLE_PCTV801E_SE 0x023b
|
||||
#define USB_PID_PINNACLE_PCTV73A 0x0243
|
||||
|
@ -248,6 +252,7 @@
|
|||
#define USB_PID_DIGIVOX_MINI_SL_WARM 0xe361
|
||||
#define USB_PID_GRANDTEC_DVBT_USB2_COLD 0x0bc6
|
||||
#define USB_PID_GRANDTEC_DVBT_USB2_WARM 0x0bc7
|
||||
#define USB_PID_WINFAST_DTV2000DS 0x6a04
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
|
||||
|
@ -290,5 +295,7 @@
|
|||
#define USB_PID_FRIIO_WHITE 0x0001
|
||||
#define USB_PID_TVWAY_PLUS 0x0002
|
||||
#define USB_PID_SVEON_STV20 0xe39d
|
||||
|
||||
#define USB_PID_AZUREWAVE_AZ6027 0x3275
|
||||
#define USB_PID_TERRATEC_DVBS2CI 0x3275
|
||||
#define USB_PID_TECHNISAT_USB2_HDCI 0x0002
|
||||
#endif
|
||||
|
|
|
@ -243,7 +243,7 @@ int dvb_usb_device_init(struct usb_interface *intf,
|
|||
d = kzalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
|
||||
if (d == NULL) {
|
||||
err("no memory for 'struct dvb_usb_device'");
|
||||
return ret;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
d->udev = udev;
|
||||
|
|
|
@ -107,6 +107,7 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
|
|||
case REMOTE_KEY_REPEAT:
|
||||
deb_rc("key repeated\n");
|
||||
input_event(d->rc_input_dev, EV_KEY, event, 1);
|
||||
input_sync(d->rc_input_dev);
|
||||
input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
|
||||
input_sync(d->rc_input_dev);
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* DVB USB framework compliant Linux driver for the
|
||||
* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
|
||||
* TeVii S600, S630, S650 Cards
|
||||
* TeVii S600, S630, S650,
|
||||
* Prof 1100, 7500 Cards
|
||||
* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -469,11 +470,13 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
|||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct usb_device *udev;
|
||||
int ret = 0;
|
||||
int len, i, j;
|
||||
|
||||
if (!d)
|
||||
return -ENODEV;
|
||||
udev = d->udev;
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
|
@ -488,8 +491,13 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
|||
}
|
||||
case (DW2102_VOLTAGE_CTRL): {
|
||||
u8 obuf[2];
|
||||
|
||||
obuf[0] = 1;
|
||||
obuf[1] = msg[j].buf[1];/* off-on */
|
||||
ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
|
||||
obuf, 2, DW210X_WRITE_MSG);
|
||||
obuf[0] = 3;
|
||||
obuf[1] = msg[j].buf[0];
|
||||
obuf[1] = msg[j].buf[0];/* 13v-18v */
|
||||
ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
|
||||
obuf, 2, DW210X_WRITE_MSG);
|
||||
break;
|
||||
|
@ -527,6 +535,17 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
|||
i += 16;
|
||||
len -= 16;
|
||||
} while (len > 0);
|
||||
} else if ((udev->descriptor.idProduct == 0x7500)
|
||||
&& (j < (num - 1))) {
|
||||
/* write register addr before read */
|
||||
u8 obuf[msg[j].len + 2];
|
||||
obuf[0] = msg[j + 1].len;
|
||||
obuf[1] = (msg[j].addr << 1);
|
||||
memcpy(obuf + 2, msg[j].buf, msg[j].len);
|
||||
ret = dw210x_op_rw(d->udev, 0x92, 0, 0,
|
||||
obuf, msg[j].len + 2,
|
||||
DW210X_WRITE_MSG);
|
||||
break;
|
||||
} else {
|
||||
/* write registers */
|
||||
u8 obuf[msg[j].len + 2];
|
||||
|
@ -651,18 +670,25 @@ static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
|
|||
|
||||
static int dw210x_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 = DW2102_VOLTAGE_CTRL, .flags = 0,
|
||||
.buf = command_13v, .len = 1},
|
||||
static u8 command_13v[] = {0x00, 0x01};
|
||||
static u8 command_18v[] = {0x01, 0x01};
|
||||
static u8 command_off[] = {0x00, 0x00};
|
||||
struct i2c_msg msg = {
|
||||
.addr = DW2102_VOLTAGE_CTRL,
|
||||
.flags = 0,
|
||||
.buf = command_off,
|
||||
.len = 2,
|
||||
};
|
||||
|
||||
struct dvb_usb_adapter *udev_adap =
|
||||
(struct dvb_usb_adapter *)(fe->dvb->priv);
|
||||
if (voltage == SEC_VOLTAGE_18)
|
||||
msg[0].buf = command_18v;
|
||||
i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
|
||||
msg.buf = command_18v;
|
||||
else if (voltage == SEC_VOLTAGE_13)
|
||||
msg.buf = command_13v;
|
||||
|
||||
i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -735,6 +761,18 @@ static struct stv6110_config dw2104_stv6110_config = {
|
|||
.clk_div = 1,
|
||||
};
|
||||
|
||||
static struct stv0900_config prof_7500_stv0900_config = {
|
||||
.demod_address = 0x6a,
|
||||
.demod_mode = 0,
|
||||
.xtal = 27000000,
|
||||
.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
|
||||
.diseqc_mode = 2,/* 2/3 PWM */
|
||||
.tun1_maddress = 0,/* 0x60 */
|
||||
.tun1_adc = 0,/* 2 Vpp */
|
||||
.path1_mode = 3,
|
||||
.tun1_type = 3,
|
||||
};
|
||||
|
||||
static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
|
||||
{
|
||||
struct dvb_tuner_ops *tuner_ops = NULL;
|
||||
|
@ -882,6 +920,19 @@ static int s6x0_frontend_attach(struct dvb_usb_adapter *d)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
|
||||
{
|
||||
d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
|
||||
&d->dev->i2c_adap, 0);
|
||||
if (d->fe == NULL)
|
||||
return -EIO;
|
||||
d->fe->ops.set_voltage = dw210x_set_voltage;
|
||||
|
||||
info("Attached STV0900+STB6100A!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
|
||||
|
@ -1073,6 +1124,7 @@ static struct usb_device_id dw2102_table[] = {
|
|||
{USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
|
||||
{USB_DEVICE(0x3011, USB_PID_PROF_1100)},
|
||||
{USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
|
||||
{USB_DEVICE(0x3034, 0x7500)},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -1387,9 +1439,30 @@ static struct dvb_usb_device_properties s6x0_properties = {
|
|||
}
|
||||
};
|
||||
|
||||
struct dvb_usb_device_properties *p7500;
|
||||
static struct dvb_usb_device_description d7500 = {
|
||||
"Prof 7500 USB DVB-S2",
|
||||
{&dw2102_table[9], NULL},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static int dw2102_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
|
||||
p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
|
||||
if (!p7500)
|
||||
return -ENOMEM;
|
||||
/* copy default structure */
|
||||
memcpy(p7500, &s6x0_properties,
|
||||
sizeof(struct dvb_usb_device_properties));
|
||||
/* fill only different fields */
|
||||
p7500->firmware = "dvb-usb-p7500.fw";
|
||||
p7500->devices[0] = d7500;
|
||||
p7500->rc_key_map = tbs_rc_keys;
|
||||
p7500->rc_key_map_size = ARRAY_SIZE(tbs_rc_keys);
|
||||
p7500->adapter->frontend_attach = prof_7500_frontend_attach;
|
||||
|
||||
if (0 == dvb_usb_device_init(intf, &dw2102_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &dw2104_properties,
|
||||
|
@ -1397,6 +1470,8 @@ static int dw2102_probe(struct usb_interface *intf,
|
|||
0 == dvb_usb_device_init(intf, &dw3101_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &s6x0_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, p7500,
|
||||
THIS_MODULE, NULL, adapter_nr))
|
||||
return 0;
|
||||
|
||||
|
@ -1431,6 +1506,6 @@ MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
|
|||
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
|
||||
" DVB-C 3101 USB2.0,"
|
||||
" TeVii S600, S630, S650, S660 USB2.0,"
|
||||
" Prof 1100 USB2.0 devices");
|
||||
" Prof 1100, 7500 USB2.0 devices");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -366,7 +366,7 @@ static u8 init_code[][2] = {
|
|||
{0x76, 0x0C},
|
||||
};
|
||||
|
||||
const static int init_code_len = sizeof(init_code) / sizeof(u8[2]);
|
||||
static const int init_code_len = sizeof(init_code) / sizeof(u8[2]);
|
||||
|
||||
static int jdvbt90502_init(struct dvb_frontend *fe)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
#include "qt1010.h"
|
||||
#include "tda1004x.h"
|
||||
#include "tda827x.h"
|
||||
|
||||
#include <media/tuner.h>
|
||||
#include "tuner-simple.h"
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/* debug */
|
||||
|
@ -158,11 +161,14 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
|
||||
case 0x93:
|
||||
case 0x92:
|
||||
case 0x83: /* pinnacle PCTV310e */
|
||||
case 0x82:
|
||||
m->rep_count = 0;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
goto unlock;
|
||||
|
||||
case 0x91:
|
||||
case 0x81: /* pinnacle PCTV310e */
|
||||
/* prevent immediate auto-repeat */
|
||||
if (++m->rep_count > 2)
|
||||
*state = REMOTE_KEY_REPEAT;
|
||||
|
@ -546,6 +552,14 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(simple_tuner_attach, adap->fe,
|
||||
&adap->dev->i2c_adap, 0x61,
|
||||
TUNER_PHILIPS_FMD1216ME_MK3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* device-specific initialization */
|
||||
static struct m920x_inits megasky_rc_init [] = {
|
||||
{ M9206_RC_INIT2, 0xa8 },
|
||||
|
@ -562,6 +576,18 @@ static struct m920x_inits tvwalkertwin_rc_init [] = {
|
|||
{ } /* terminating entry */
|
||||
};
|
||||
|
||||
static struct m920x_inits pinnacle310e_init[] = {
|
||||
/* without these the tuner don't work */
|
||||
{ 0xff20, 0x9b },
|
||||
{ 0xff22, 0x70 },
|
||||
|
||||
/* rc settings */
|
||||
{ 0xff50, 0x80 },
|
||||
{ M9206_RC_INIT1, 0x00 },
|
||||
{ M9206_RC_INIT2, 0xff },
|
||||
{ } /* terminating entry */
|
||||
};
|
||||
|
||||
/* ir keymaps */
|
||||
static struct dvb_usb_rc_key megasky_rc_keys [] = {
|
||||
{ 0x0012, KEY_POWER },
|
||||
|
@ -602,11 +628,68 @@ static struct dvb_usb_rc_key tvwalkertwin_rc_keys [] = {
|
|||
{ 0x001e, KEY_VOLUMEUP },
|
||||
};
|
||||
|
||||
static struct dvb_usb_rc_key pinnacle310e_rc_keys[] = {
|
||||
{ 0x16, KEY_POWER },
|
||||
{ 0x17, KEY_FAVORITES },
|
||||
{ 0x0f, KEY_TEXT },
|
||||
{ 0x48, KEY_MEDIA }, /* preview */
|
||||
{ 0x1c, KEY_EPG },
|
||||
{ 0x04, KEY_LIST }, /* record list */
|
||||
{ 0x03, KEY_1 },
|
||||
{ 0x01, KEY_2 },
|
||||
{ 0x06, KEY_3 },
|
||||
{ 0x09, KEY_4 },
|
||||
{ 0x1d, KEY_5 },
|
||||
{ 0x1f, KEY_6 },
|
||||
{ 0x0d, KEY_7 },
|
||||
{ 0x19, KEY_8 },
|
||||
{ 0x1b, KEY_9 },
|
||||
{ 0x15, KEY_0 },
|
||||
{ 0x0c, KEY_CANCEL },
|
||||
{ 0x4a, KEY_CLEAR },
|
||||
{ 0x13, KEY_BACK },
|
||||
{ 0x00, KEY_TAB },
|
||||
{ 0x4b, KEY_UP },
|
||||
{ 0x4e, KEY_LEFT },
|
||||
{ 0x52, KEY_RIGHT },
|
||||
{ 0x51, KEY_DOWN },
|
||||
{ 0x4f, KEY_ENTER }, /* could also be KEY_OK */
|
||||
{ 0x1e, KEY_VOLUMEUP },
|
||||
{ 0x0a, KEY_VOLUMEDOWN },
|
||||
{ 0x05, KEY_CHANNELUP },
|
||||
{ 0x02, KEY_CHANNELDOWN },
|
||||
{ 0x11, KEY_RECORD },
|
||||
{ 0x14, KEY_PLAY },
|
||||
{ 0x4c, KEY_PAUSE },
|
||||
{ 0x1a, KEY_STOP },
|
||||
{ 0x40, KEY_REWIND },
|
||||
{ 0x12, KEY_FASTFORWARD },
|
||||
{ 0x41, KEY_PREVIOUSSONG }, /* Replay */
|
||||
{ 0x42, KEY_NEXTSONG }, /* Skip */
|
||||
{ 0x54, KEY_CAMERA }, /* Capture */
|
||||
/* { 0x50, KEY_SAP }, */ /* Sap */
|
||||
{ 0x47, KEY_CYCLEWINDOWS }, /* Pip */
|
||||
{ 0x4d, KEY_SCREEN }, /* FullScreen */
|
||||
{ 0x08, KEY_SUBTITLE },
|
||||
{ 0x0e, KEY_MUTE },
|
||||
/* { 0x49, KEY_LR }, */ /* L/R */
|
||||
{ 0x07, KEY_SLEEP }, /* Hibernate */
|
||||
{ 0x08, KEY_MEDIA }, /* A/V */
|
||||
{ 0x0e, KEY_MENU }, /* Recall */
|
||||
{ 0x45, KEY_ZOOMIN },
|
||||
{ 0x46, KEY_ZOOMOUT },
|
||||
{ 0x18, KEY_TV }, /* Red */
|
||||
{ 0x53, KEY_VCR }, /* Green */
|
||||
{ 0x5e, KEY_SAT }, /* Yellow */
|
||||
{ 0x5f, KEY_PLAYER }, /* Blue */
|
||||
};
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties megasky_properties;
|
||||
static struct dvb_usb_device_properties digivox_mini_ii_properties;
|
||||
static struct dvb_usb_device_properties tvwalkertwin_properties;
|
||||
static struct dvb_usb_device_properties dposh_properties;
|
||||
static struct dvb_usb_device_properties pinnacle_pctv310e_properties;
|
||||
|
||||
static int m920x_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
|
@ -652,6 +735,13 @@ static int m920x_probe(struct usb_interface *intf,
|
|||
goto found;
|
||||
}
|
||||
|
||||
ret = dvb_usb_device_init(intf, &pinnacle_pctv310e_properties,
|
||||
THIS_MODULE, &d, adapter_nr);
|
||||
if (ret == 0) {
|
||||
rc_init_seq = pinnacle310e_init;
|
||||
goto found;
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
/* Another interface on a multi-tuner device */
|
||||
|
@ -682,6 +772,7 @@ static struct usb_device_id m920x_table [] = {
|
|||
USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM) },
|
||||
{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_COLD) },
|
||||
{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_WARM) },
|
||||
{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_PINNACLE_PCTV310E) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, m920x_table);
|
||||
|
@ -895,6 +986,56 @@ static struct dvb_usb_device_properties dposh_properties = {
|
|||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.download_firmware = NULL,
|
||||
|
||||
.rc_interval = 100,
|
||||
.rc_key_map = pinnacle310e_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(pinnacle310e_rc_keys),
|
||||
.rc_query = m920x_rc_query,
|
||||
|
||||
.size_of_priv = sizeof(struct m920x_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 = m920x_pid_filter,
|
||||
.pid_filter_ctrl = m920x_pid_filter_ctrl,
|
||||
|
||||
.frontend_attach = m920x_mt352_frontend_attach,
|
||||
.tuner_attach = m920x_fmd1216me_tuner_attach,
|
||||
|
||||
.stream = {
|
||||
.type = USB_ISOC,
|
||||
.count = 5,
|
||||
.endpoint = 0x84,
|
||||
.u = {
|
||||
.isoc = {
|
||||
.framesperurb = 128,
|
||||
.framesize = 564,
|
||||
.interval = 1,
|
||||
}
|
||||
}
|
||||
},
|
||||
} },
|
||||
.i2c_algo = &m920x_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Pinnacle PCTV 310e",
|
||||
{ &m920x_table[6], NULL },
|
||||
{ NULL },
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver m920x_driver = {
|
||||
.name = "dvb_usb_m920x",
|
||||
.probe = m920x_probe,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#define M9206_FW 0x30
|
||||
|
||||
#define M9206_MAX_FILTERS 8
|
||||
#define M9206_MAX_ADAPTERS 2
|
||||
#define M9206_MAX_ADAPTERS 4
|
||||
|
||||
/*
|
||||
sequences found in logs:
|
||||
|
|
|
@ -138,7 +138,7 @@ static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
|||
(msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0),
|
||||
msg[i].buf,
|
||||
msg[i].len
|
||||
)!= msg[i].len)) {
|
||||
)) != msg[i].len) {
|
||||
break;
|
||||
}
|
||||
if (dvb_usb_opera1_debug & 0x10)
|
||||
|
|
|
@ -90,13 +90,14 @@ static inline struct node_entry *node_of(struct firedtv *fdtv)
|
|||
return container_of(fdtv->device, struct unit_directory, device)->ne;
|
||||
}
|
||||
|
||||
static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
|
||||
static int node_lock(struct firedtv *fdtv, u64 addr, void *data)
|
||||
{
|
||||
quadlet_t *d = data;
|
||||
int ret;
|
||||
|
||||
ret = hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP,
|
||||
(__force quadlet_t *)&data[1], (__force quadlet_t)data[0]);
|
||||
data[0] = data[1];
|
||||
ret = hpsb_node_lock(node_of(fdtv), addr,
|
||||
EXTCODE_COMPARE_SWAP, &d[1], d[0]);
|
||||
d[0] = d[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -192,9 +193,13 @@ static int node_probe(struct device *dev)
|
|||
int kv_len, err;
|
||||
void *kv_str;
|
||||
|
||||
kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t);
|
||||
kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
|
||||
|
||||
if (ud->model_name_kv) {
|
||||
kv_len = (ud->model_name_kv->value.leaf.len - 2) * 4;
|
||||
kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
|
||||
} else {
|
||||
kv_len = 0;
|
||||
kv_str = NULL;
|
||||
}
|
||||
fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len);
|
||||
if (!fdtv)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -74,7 +74,6 @@
|
|||
#define EN50221_TAG_CA_INFO 0x9f8031
|
||||
|
||||
struct avc_command_frame {
|
||||
int length;
|
||||
u8 ctype;
|
||||
u8 subunit;
|
||||
u8 opcode;
|
||||
|
@ -82,13 +81,27 @@ struct avc_command_frame {
|
|||
};
|
||||
|
||||
struct avc_response_frame {
|
||||
int length;
|
||||
u8 response;
|
||||
u8 subunit;
|
||||
u8 opcode;
|
||||
u8 operand[509];
|
||||
};
|
||||
|
||||
#define LAST_OPERAND (509 - 1)
|
||||
|
||||
static inline void clear_operands(struct avc_command_frame *c, int from, int to)
|
||||
{
|
||||
memset(&c->operand[from], 0, to - from + 1);
|
||||
}
|
||||
|
||||
static void pad_operands(struct avc_command_frame *c, int from)
|
||||
{
|
||||
int to = ALIGN(from, 4);
|
||||
|
||||
if (from <= to && to <= LAST_OPERAND)
|
||||
clear_operands(c, from, to);
|
||||
}
|
||||
|
||||
#define AVC_DEBUG_READ_DESCRIPTOR 0x0001
|
||||
#define AVC_DEBUG_DSIT 0x0002
|
||||
#define AVC_DEBUG_DSD 0x0004
|
||||
|
@ -202,78 +215,65 @@ static void debug_pmt(char *msg, int length)
|
|||
16, 1, msg, length, false);
|
||||
}
|
||||
|
||||
static int __avc_write(struct firedtv *fdtv,
|
||||
const struct avc_command_frame *c, struct avc_response_frame *r)
|
||||
static int avc_write(struct firedtv *fdtv)
|
||||
{
|
||||
int err, retry;
|
||||
|
||||
if (r)
|
||||
fdtv->avc_reply_received = false;
|
||||
fdtv->avc_reply_received = false;
|
||||
|
||||
for (retry = 0; retry < 6; retry++) {
|
||||
if (unlikely(avc_debug))
|
||||
debug_fcp(&c->ctype, c->length);
|
||||
debug_fcp(fdtv->avc_data, fdtv->avc_data_length);
|
||||
|
||||
err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER,
|
||||
(void *)&c->ctype, c->length);
|
||||
fdtv->avc_data, fdtv->avc_data_length);
|
||||
if (err) {
|
||||
fdtv->avc_reply_received = true;
|
||||
dev_err(fdtv->device, "FCP command write failed\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!r)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* AV/C specs say that answers should be sent within 150 ms.
|
||||
* Time out after 200 ms.
|
||||
*/
|
||||
if (wait_event_timeout(fdtv->avc_wait,
|
||||
fdtv->avc_reply_received,
|
||||
msecs_to_jiffies(200)) != 0) {
|
||||
r->length = fdtv->response_length;
|
||||
memcpy(&r->response, fdtv->response, r->length);
|
||||
|
||||
msecs_to_jiffies(200)) != 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
dev_err(fdtv->device, "FCP response timed out\n");
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int avc_write(struct firedtv *fdtv,
|
||||
const struct avc_command_frame *c, struct avc_response_frame *r)
|
||||
static bool is_register_rc(struct avc_response_frame *r)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mutex_lock_interruptible(&fdtv->avc_mutex))
|
||||
return -EINTR;
|
||||
|
||||
ret = __avc_write(fdtv, c, r);
|
||||
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
return ret;
|
||||
return r->opcode == AVC_OPCODE_VENDOR &&
|
||||
r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
|
||||
r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
|
||||
r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
|
||||
r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
|
||||
}
|
||||
|
||||
int avc_recv(struct firedtv *fdtv, void *data, size_t length)
|
||||
{
|
||||
struct avc_response_frame *r =
|
||||
data - offsetof(struct avc_response_frame, response);
|
||||
struct avc_response_frame *r = data;
|
||||
|
||||
if (unlikely(avc_debug))
|
||||
debug_fcp(data, length);
|
||||
|
||||
if (length >= 8 &&
|
||||
r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
|
||||
r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
|
||||
r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
|
||||
r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) {
|
||||
if (r->response == AVC_RESPONSE_CHANGED) {
|
||||
fdtv_handle_rc(fdtv,
|
||||
r->operand[4] << 8 | r->operand[5]);
|
||||
if (length >= 8 && is_register_rc(r)) {
|
||||
switch (r->response) {
|
||||
case AVC_RESPONSE_CHANGED:
|
||||
fdtv_handle_rc(fdtv, r->operand[4] << 8 | r->operand[5]);
|
||||
schedule_work(&fdtv->remote_ctrl_work);
|
||||
} else if (r->response != AVC_RESPONSE_INTERIM) {
|
||||
break;
|
||||
case AVC_RESPONSE_INTERIM:
|
||||
if (is_register_rc((void *)fdtv->avc_data))
|
||||
goto wake;
|
||||
break;
|
||||
default:
|
||||
dev_info(fdtv->device,
|
||||
"remote control result = %d\n", r->response);
|
||||
}
|
||||
|
@ -285,9 +285,9 @@ int avc_recv(struct firedtv *fdtv, void *data, size_t length)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
memcpy(fdtv->response, data, length);
|
||||
fdtv->response_length = length;
|
||||
|
||||
memcpy(fdtv->avc_data, data, length);
|
||||
fdtv->avc_data_length = length;
|
||||
wake:
|
||||
fdtv->avc_reply_received = true;
|
||||
wake_up(&fdtv->avc_wait);
|
||||
|
||||
|
@ -318,10 +318,11 @@ static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
|
|||
* tuning command for setting the relative LNB frequency
|
||||
* (not supported by the AVC standard)
|
||||
*/
|
||||
static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
|
||||
struct dvb_frontend_parameters *params,
|
||||
struct avc_command_frame *c)
|
||||
static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
|
||||
c->opcode = AVC_OPCODE_VENDOR;
|
||||
|
||||
c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
|
||||
|
@ -370,16 +371,18 @@ static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
|
|||
c->operand[13] = 0x1;
|
||||
c->operand[14] = 0xff;
|
||||
c->operand[15] = 0xff;
|
||||
c->length = 20;
|
||||
|
||||
return 16;
|
||||
} else {
|
||||
c->length = 16;
|
||||
return 13;
|
||||
}
|
||||
}
|
||||
|
||||
static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
|
||||
struct dvb_frontend_parameters *params,
|
||||
struct avc_command_frame *c)
|
||||
static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
|
||||
c->opcode = AVC_OPCODE_DSD;
|
||||
|
||||
c->operand[0] = 0; /* source plug */
|
||||
|
@ -440,15 +443,14 @@ static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
|
|||
c->operand[20] = 0x00;
|
||||
c->operand[21] = 0x00;
|
||||
|
||||
/* Add PIDs to filter */
|
||||
c->length = ALIGN(22 + add_pid_filter(fdtv, &c->operand[22]) + 3, 4);
|
||||
return 22 + add_pid_filter(fdtv, &c->operand[22]);
|
||||
}
|
||||
|
||||
static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
|
||||
struct dvb_frontend_parameters *params,
|
||||
struct avc_command_frame *c)
|
||||
static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct dvb_ofdm_parameters *ofdm = ¶ms->u.ofdm;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
|
||||
c->opcode = AVC_OPCODE_DSD;
|
||||
|
||||
|
@ -543,55 +545,58 @@ static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
|
|||
c->operand[15] = 0x00; /* network_ID[0] */
|
||||
c->operand[16] = 0x00; /* network_ID[1] */
|
||||
|
||||
/* Add PIDs to filter */
|
||||
c->length = ALIGN(17 + add_pid_filter(fdtv, &c->operand[17]) + 3, 4);
|
||||
return 17 + add_pid_filter(fdtv, &c->operand[17]);
|
||||
}
|
||||
|
||||
int avc_tuner_dsd(struct firedtv *fdtv,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
int pos, ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_CONTROL;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
||||
switch (fdtv->type) {
|
||||
case FIREDTV_DVB_S:
|
||||
case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break;
|
||||
case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(fdtv, params, c); break;
|
||||
case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(fdtv, params, c); break;
|
||||
case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break;
|
||||
case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break;
|
||||
case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
pad_operands(c, pos);
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
|
||||
msleep(500);
|
||||
fdtv->avc_data_length = ALIGN(3 + pos, 4);
|
||||
ret = avc_write(fdtv);
|
||||
#if 0
|
||||
/* FIXME: */
|
||||
/* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */
|
||||
/*
|
||||
* FIXME:
|
||||
* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller.
|
||||
* Check for AVC_RESPONSE_ACCEPTED here instead?
|
||||
*/
|
||||
if (status)
|
||||
*status = r->operand[2];
|
||||
#endif
|
||||
return 0;
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
if (ret == 0)
|
||||
msleep(500);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
|
||||
int pos, k;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
int ret, pos, k;
|
||||
|
||||
if (pidc > 16 && pidc != 0xff)
|
||||
return -EINVAL;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_CONTROL;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -614,24 +619,27 @@ int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
|
|||
c->operand[pos++] = 0x00; /* tableID */
|
||||
c->operand[pos++] = 0x00; /* filter_length */
|
||||
}
|
||||
pad_operands(c, pos);
|
||||
|
||||
c->length = ALIGN(3 + pos, 4);
|
||||
fdtv->avc_data_length = ALIGN(3 + pos, 4);
|
||||
ret = avc_write(fdtv);
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
/* FIXME: check response code? */
|
||||
|
||||
msleep(50);
|
||||
return 0;
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
if (ret == 0)
|
||||
msleep(50);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avc_tuner_get_ts(struct firedtv *fdtv)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
|
||||
int sl;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
int ret, sl;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_CONTROL;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -646,26 +654,33 @@ int avc_tuner_get_ts(struct firedtv *fdtv)
|
|||
c->operand[4] = 0x00; /* antenna number */
|
||||
c->operand[5] = 0x0; /* system_specific_search_flags */
|
||||
c->operand[6] = sl; /* system_specific_multiplex selection_length */
|
||||
c->operand[7] = 0x00; /* valid_flags [0] */
|
||||
c->operand[8] = 0x00; /* valid_flags [1] */
|
||||
c->operand[7 + sl] = 0x00; /* nr_of_dsit_sel_specs (always 0) */
|
||||
/*
|
||||
* operand[7]: valid_flags[0]
|
||||
* operand[8]: valid_flags[1]
|
||||
* operand[7 + sl]: nr_of_dsit_sel_specs (always 0)
|
||||
*/
|
||||
clear_operands(c, 7, 24);
|
||||
|
||||
c->length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
|
||||
fdtv->avc_data_length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
|
||||
ret = avc_write(fdtv);
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
/* FIXME: check response code? */
|
||||
|
||||
msleep(250);
|
||||
return 0;
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
if (ret == 0)
|
||||
msleep(250);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avc_identify_subunit(struct firedtv *fdtv)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
struct avc_response_frame *r = (void *)fdtv->avc_data;
|
||||
int ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_CONTROL;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -678,31 +693,34 @@ int avc_identify_subunit(struct firedtv *fdtv)
|
|||
c->operand[4] = 0x08; /* length lowbyte */
|
||||
c->operand[5] = 0x00; /* offset highbyte */
|
||||
c->operand[6] = 0x0d; /* offset lowbyte */
|
||||
clear_operands(c, 7, 8); /* padding */
|
||||
|
||||
c->length = 12;
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
fdtv->avc_data_length = 12;
|
||||
ret = avc_write(fdtv);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if ((r->response != AVC_RESPONSE_STABLE &&
|
||||
r->response != AVC_RESPONSE_ACCEPTED) ||
|
||||
(r->operand[3] << 8) + r->operand[4] != 8) {
|
||||
dev_err(fdtv->device, "cannot read subunit identifier\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
out:
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define SIZEOF_ANTENNA_INPUT_INFO 22
|
||||
|
||||
int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer;
|
||||
int length;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
struct avc_response_frame *r = (void *)fdtv->avc_data;
|
||||
int length, ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_CONTROL;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -710,27 +728,30 @@ int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
|
|||
|
||||
c->operand[0] = DESCRIPTOR_TUNER_STATUS;
|
||||
c->operand[1] = 0xff; /* read_result_status */
|
||||
c->operand[2] = 0x00; /* reserved */
|
||||
c->operand[3] = 0; /* SIZEOF_ANTENNA_INPUT_INFO >> 8; */
|
||||
c->operand[4] = 0; /* SIZEOF_ANTENNA_INPUT_INFO & 0xff; */
|
||||
c->operand[5] = 0x00;
|
||||
c->operand[6] = 0x00;
|
||||
/*
|
||||
* operand[2]: reserved
|
||||
* operand[3]: SIZEOF_ANTENNA_INPUT_INFO >> 8
|
||||
* operand[4]: SIZEOF_ANTENNA_INPUT_INFO & 0xff
|
||||
*/
|
||||
clear_operands(c, 2, 31);
|
||||
|
||||
c->length = 12;
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
fdtv->avc_data_length = 12;
|
||||
ret = avc_write(fdtv);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (r->response != AVC_RESPONSE_STABLE &&
|
||||
r->response != AVC_RESPONSE_ACCEPTED) {
|
||||
dev_err(fdtv->device, "cannot read tuner status\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
length = r->operand[9];
|
||||
if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) {
|
||||
dev_err(fdtv->device, "got invalid tuner status\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
stat->active_system = r->operand[10];
|
||||
|
@ -766,20 +787,21 @@ int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
|
|||
stat->ca_dvb_flag = r->operand[31] >> 3 & 1;
|
||||
stat->ca_error_flag = r->operand[31] >> 2 & 1;
|
||||
stat->ca_initialization_status = r->operand[31] >> 1 & 1;
|
||||
out:
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
|
||||
char conttone, char nrdiseq,
|
||||
struct dvb_diseqc_master_cmd *diseqcmd)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer;
|
||||
int i, j, k;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
struct avc_response_frame *r = (void *)fdtv->avc_data;
|
||||
int pos, j, k, ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_CONTROL;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -789,41 +811,41 @@ int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
|
|||
c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
|
||||
c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
|
||||
c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL;
|
||||
|
||||
c->operand[4] = voltage;
|
||||
c->operand[5] = nrdiseq;
|
||||
|
||||
i = 6;
|
||||
|
||||
pos = 6;
|
||||
for (j = 0; j < nrdiseq; j++) {
|
||||
c->operand[i++] = diseqcmd[j].msg_len;
|
||||
c->operand[pos++] = diseqcmd[j].msg_len;
|
||||
|
||||
for (k = 0; k < diseqcmd[j].msg_len; k++)
|
||||
c->operand[i++] = diseqcmd[j].msg[k];
|
||||
c->operand[pos++] = diseqcmd[j].msg[k];
|
||||
}
|
||||
c->operand[pos++] = burst;
|
||||
c->operand[pos++] = conttone;
|
||||
pad_operands(c, pos);
|
||||
|
||||
c->operand[i++] = burst;
|
||||
c->operand[i++] = conttone;
|
||||
|
||||
c->length = ALIGN(3 + i, 4);
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
fdtv->avc_data_length = ALIGN(3 + pos, 4);
|
||||
ret = avc_write(fdtv);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (r->response != AVC_RESPONSE_ACCEPTED) {
|
||||
dev_err(fdtv->device, "LNB control failed\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avc_register_remote_control(struct firedtv *fdtv)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
int ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_NOTIFY;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7;
|
||||
|
@ -833,10 +855,16 @@ int avc_register_remote_control(struct firedtv *fdtv)
|
|||
c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
|
||||
c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
|
||||
c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
|
||||
c->operand[4] = 0; /* padding */
|
||||
|
||||
c->length = 8;
|
||||
fdtv->avc_data_length = 8;
|
||||
ret = avc_write(fdtv);
|
||||
|
||||
return avc_write(fdtv, c, NULL);
|
||||
/* FIXME: check response code? */
|
||||
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void avc_remote_ctrl_work(struct work_struct *work)
|
||||
|
@ -851,11 +879,10 @@ void avc_remote_ctrl_work(struct work_struct *work)
|
|||
#if 0 /* FIXME: unused */
|
||||
int avc_tuner_host2ca(struct firedtv *fdtv)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
int ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_CONTROL;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -867,15 +894,16 @@ int avc_tuner_host2ca(struct firedtv *fdtv)
|
|||
c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
|
||||
c->operand[4] = 0; /* slot */
|
||||
c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
|
||||
c->operand[6] = 0; /* more/last */
|
||||
c->operand[7] = 0; /* length */
|
||||
clear_operands(c, 6, 8);
|
||||
|
||||
c->length = 12;
|
||||
fdtv->avc_data_length = 12;
|
||||
ret = avc_write(fdtv);
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
/* FIXME: check response code? */
|
||||
|
||||
return 0;
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -906,12 +934,11 @@ static int get_ca_object_length(struct avc_response_frame *r)
|
|||
|
||||
int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer;
|
||||
int pos;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
struct avc_response_frame *r = (void *)fdtv->avc_data;
|
||||
int pos, ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_STATUS;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -923,11 +950,12 @@ int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
|
|||
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
|
||||
c->operand[4] = 0; /* slot */
|
||||
c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
|
||||
clear_operands(c, 6, LAST_OPERAND);
|
||||
|
||||
c->length = 12;
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
fdtv->avc_data_length = 12;
|
||||
ret = avc_write(fdtv);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* FIXME: check response code and validate response data */
|
||||
|
||||
|
@ -939,18 +967,19 @@ int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
|
|||
app_info[4] = 0x01;
|
||||
memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]);
|
||||
*len = app_info[3] + 4;
|
||||
out:
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer;
|
||||
int pos;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
struct avc_response_frame *r = (void *)fdtv->avc_data;
|
||||
int pos, ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_STATUS;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -962,11 +991,14 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
|
|||
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
|
||||
c->operand[4] = 0; /* slot */
|
||||
c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
|
||||
clear_operands(c, 6, LAST_OPERAND);
|
||||
|
||||
c->length = 12;
|
||||
fdtv->avc_data_length = 12;
|
||||
ret = avc_write(fdtv);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
/* FIXME: check response code and validate response data */
|
||||
|
||||
pos = get_ca_object_pos(r);
|
||||
app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
|
||||
|
@ -976,17 +1008,18 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
|
|||
app_info[4] = r->operand[pos + 0];
|
||||
app_info[5] = r->operand[pos + 1];
|
||||
*len = app_info[3] + 4;
|
||||
out:
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avc_ca_reset(struct firedtv *fdtv)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
int ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_CONTROL;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -1002,19 +1035,20 @@ int avc_ca_reset(struct firedtv *fdtv)
|
|||
c->operand[7] = 1; /* length */
|
||||
c->operand[8] = 0; /* force hardware reset */
|
||||
|
||||
c->length = 12;
|
||||
fdtv->avc_data_length = 12;
|
||||
ret = avc_write(fdtv);
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
/* FIXME: check response code? */
|
||||
|
||||
return 0;
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
struct avc_response_frame *r = (void *)fdtv->avc_data;
|
||||
int list_management;
|
||||
int program_info_length;
|
||||
int pmt_cmd_id;
|
||||
|
@ -1022,11 +1056,12 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
|
|||
int write_pos;
|
||||
int es_info_length;
|
||||
int crc32_csum;
|
||||
int ret;
|
||||
|
||||
if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT))
|
||||
debug_pmt(msg, length);
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_CONTROL;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -1058,7 +1093,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
|
|||
|
||||
c->operand[12] = 0x02; /* Table id=2 */
|
||||
c->operand[13] = 0x80; /* Section syntax + length */
|
||||
/* c->operand[14] = XXXprogram_info_length + 12; */
|
||||
|
||||
c->operand[15] = msg[1]; /* Program number */
|
||||
c->operand[16] = msg[2];
|
||||
c->operand[17] = 0x01; /* Version number=0 + current/next=1 */
|
||||
|
@ -1106,12 +1141,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
|
|||
write_pos += es_info_length;
|
||||
}
|
||||
}
|
||||
|
||||
/* CRC */
|
||||
c->operand[write_pos++] = 0x00;
|
||||
c->operand[write_pos++] = 0x00;
|
||||
c->operand[write_pos++] = 0x00;
|
||||
c->operand[write_pos++] = 0x00;
|
||||
write_pos += 4; /* CRC */
|
||||
|
||||
c->operand[7] = 0x82;
|
||||
c->operand[8] = (write_pos - 10) >> 8;
|
||||
|
@ -1123,28 +1153,31 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
|
|||
c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff;
|
||||
c->operand[write_pos - 2] = (crc32_csum >> 8) & 0xff;
|
||||
c->operand[write_pos - 1] = (crc32_csum >> 0) & 0xff;
|
||||
pad_operands(c, write_pos);
|
||||
|
||||
c->length = ALIGN(3 + write_pos, 4);
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
fdtv->avc_data_length = ALIGN(3 + write_pos, 4);
|
||||
ret = avc_write(fdtv);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (r->response != AVC_RESPONSE_ACCEPTED) {
|
||||
dev_err(fdtv->device,
|
||||
"CA PMT failed with response 0x%x\n", r->response);
|
||||
return -EFAULT;
|
||||
ret = -EFAULT;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
struct avc_response_frame *r = (void *)fdtv->avc_data;
|
||||
int ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_STATUS;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -1156,28 +1189,28 @@ int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
|
|||
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
|
||||
c->operand[4] = 0; /* slot */
|
||||
c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */
|
||||
c->operand[6] = 0; /* more/last */
|
||||
c->operand[7] = 0; /* length */
|
||||
clear_operands(c, 6, LAST_OPERAND);
|
||||
|
||||
c->length = 12;
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
fdtv->avc_data_length = 12;
|
||||
ret = avc_write(fdtv);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* FIXME: check response code and validate response data */
|
||||
|
||||
*interval = r->operand[get_ca_object_pos(r)];
|
||||
out:
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avc_ca_enter_menu(struct firedtv *fdtv)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
int ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_STATUS;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -1189,24 +1222,25 @@ int avc_ca_enter_menu(struct firedtv *fdtv)
|
|||
c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
|
||||
c->operand[4] = 0; /* slot */
|
||||
c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
|
||||
c->operand[6] = 0; /* more/last */
|
||||
c->operand[7] = 0; /* length */
|
||||
clear_operands(c, 6, 8);
|
||||
|
||||
c->length = 12;
|
||||
fdtv->avc_data_length = 12;
|
||||
ret = avc_write(fdtv);
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
/* FIXME: check response code? */
|
||||
|
||||
return 0;
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
|
||||
{
|
||||
char buffer[sizeof(struct avc_command_frame)];
|
||||
struct avc_command_frame *c = (void *)buffer;
|
||||
struct avc_response_frame *r = (void *)buffer;
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
struct avc_response_frame *r = (void *)fdtv->avc_data;
|
||||
int ret;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
c->ctype = AVC_CTYPE_STATUS;
|
||||
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
|
||||
|
@ -1218,20 +1252,21 @@ int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
|
|||
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
|
||||
c->operand[4] = 0; /* slot */
|
||||
c->operand[5] = SFE_VENDOR_TAG_CA_MMI;
|
||||
c->operand[6] = 0; /* more/last */
|
||||
c->operand[7] = 0; /* length */
|
||||
clear_operands(c, 6, LAST_OPERAND);
|
||||
|
||||
c->length = 12;
|
||||
|
||||
if (avc_write(fdtv, c, r) < 0)
|
||||
return -EIO;
|
||||
fdtv->avc_data_length = 12;
|
||||
ret = avc_write(fdtv);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* FIXME: check response code and validate response data */
|
||||
|
||||
*len = get_ca_object_length(r);
|
||||
memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len);
|
||||
out:
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL
|
||||
|
@ -1240,14 +1275,14 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (mutex_lock_interruptible(&fdtv->avc_mutex))
|
||||
return -EINTR;
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
ret = fdtv->backend->read(fdtv, addr, data);
|
||||
if (ret < 0)
|
||||
dev_err(fdtv->device, "CMP: read I/O error\n");
|
||||
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1255,14 +1290,19 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (mutex_lock_interruptible(&fdtv->avc_mutex))
|
||||
return -EINTR;
|
||||
mutex_lock(&fdtv->avc_mutex);
|
||||
|
||||
ret = fdtv->backend->lock(fdtv, addr, data);
|
||||
/* data[] is stack-allocated and should not be DMA-mapped. */
|
||||
memcpy(fdtv->avc_data, data, 8);
|
||||
|
||||
ret = fdtv->backend->lock(fdtv, addr, fdtv->avc_data);
|
||||
if (ret < 0)
|
||||
dev_err(fdtv->device, "CMP: lock I/O error\n");
|
||||
else
|
||||
memcpy(data, fdtv->avc_data, 8);
|
||||
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -277,7 +277,6 @@ struct firedtv *fdtv_alloc(struct device *dev,
|
|||
|
||||
mutex_init(&fdtv->avc_mutex);
|
||||
init_waitqueue_head(&fdtv->avc_wait);
|
||||
fdtv->avc_reply_received = true;
|
||||
mutex_init(&fdtv->demux_mutex);
|
||||
INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
|
|||
return rcode != RCODE_COMPLETE ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
|
||||
static int node_lock(struct firedtv *fdtv, u64 addr, void *data)
|
||||
{
|
||||
return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ struct input_dev;
|
|||
struct firedtv;
|
||||
|
||||
struct firedtv_backend {
|
||||
int (*lock)(struct firedtv *fdtv, u64 addr, __be32 data[]);
|
||||
int (*lock)(struct firedtv *fdtv, u64 addr, void *data);
|
||||
int (*read)(struct firedtv *fdtv, u64 addr, void *data);
|
||||
int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
|
||||
int (*start_iso)(struct firedtv *fdtv);
|
||||
|
@ -114,8 +114,8 @@ struct firedtv {
|
|||
unsigned long channel_active;
|
||||
u16 channel_pid[16];
|
||||
|
||||
size_t response_length;
|
||||
u8 response[512];
|
||||
int avc_data_length;
|
||||
u8 avc_data[512];
|
||||
};
|
||||
|
||||
/* firedtv-1394.c */
|
||||
|
|
|
@ -44,6 +44,7 @@ enum af9013_tuner {
|
|||
AF9013_TUNER_MT2060_2 = 147, /* Microtune */
|
||||
AF9013_TUNER_TDA18271 = 156, /* NXP */
|
||||
AF9013_TUNER_QT1010A = 162, /* Quantek */
|
||||
AF9013_TUNER_TDA18218 = 179, /* NXP */
|
||||
};
|
||||
|
||||
/* AF9013/5 GPIOs (mostly guessed)
|
||||
|
|
|
@ -170,6 +170,19 @@ static int is_locked(struct atbm_state *priv, u8 *locked)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int set_agc_config(struct atbm_state *priv,
|
||||
u8 min, u8 max, u8 hold_loop)
|
||||
{
|
||||
/* no effect if both min and max are zero */
|
||||
if (!min && !max)
|
||||
return 0;
|
||||
|
||||
atbm8830_write_reg(priv, REG_AGC_MIN, min);
|
||||
atbm8830_write_reg(priv, REG_AGC_MAX, max);
|
||||
atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_static_channel_mode(struct atbm_state *priv)
|
||||
{
|
||||
|
@ -227,6 +240,9 @@ static int atbm8830_init(struct dvb_frontend *fe)
|
|||
/*Set IF frequency*/
|
||||
set_if_freq(priv, cfg->if_freq);
|
||||
|
||||
/*Set AGC Config*/
|
||||
set_agc_config(priv, cfg->agc_min, cfg->agc_max,
|
||||
cfg->agc_hold_loop);
|
||||
|
||||
/*Set static channel mode*/
|
||||
set_static_channel_mode(priv);
|
||||
|
|
|
@ -283,7 +283,7 @@ static int dib0090_sleep(struct dvb_frontend *fe)
|
|||
return 0;
|
||||
}
|
||||
|
||||
extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
|
||||
void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
|
||||
{
|
||||
struct dib0090_state *state = fe->tuner_priv;
|
||||
if (fast)
|
||||
|
|
|
@ -1999,6 +1999,8 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
|
|||
struct dib8000_state *state = fe->demodulator_priv;
|
||||
int time, ret;
|
||||
|
||||
fe->dtv_property_cache.delivery_system = SYS_ISDBT;
|
||||
|
||||
dib8000_set_output_mode(state, OUTMODE_HIGH_Z);
|
||||
|
||||
if (fe->ops.tuner_ops.set_params)
|
||||
|
|
|
@ -174,7 +174,7 @@ void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
|
|||
EXPORT_SYMBOL(dibx000_exit_i2c_master);
|
||||
|
||||
|
||||
u32 systime()
|
||||
u32 systime(void)
|
||||
{
|
||||
struct timespec t;
|
||||
|
||||
|
|
|
@ -158,7 +158,8 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
|
|||
/* override frontend ops */
|
||||
fe->ops.set_voltage = lnbp21_set_voltage;
|
||||
fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
|
||||
fe->ops.set_tone = lnbp21_set_tone;
|
||||
if (!(override_clear & LNBH24_TEN)) /*22kHz logic controlled by demod*/
|
||||
fe->ops.set_tone = lnbp21_set_tone;
|
||||
printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
|
||||
|
||||
return fe;
|
||||
|
|
|
@ -97,8 +97,6 @@
|
|||
#define LNB_SUPPLY_CTRL_REG_4 0xce
|
||||
#define LNB_SUPPLY_STATUS_REG 0xcf
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#define FAIL -1
|
||||
#define PASS 0
|
||||
|
||||
|
@ -718,7 +716,7 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
|
|||
int fine_tune_freq;
|
||||
unsigned char sample_rate = 0;
|
||||
/* boolean */
|
||||
unsigned int inband_interferer_ind;
|
||||
bool inband_interferer_ind;
|
||||
|
||||
/* INTERMEDIATE VALUES */
|
||||
int icoarse_tune_freq; /* MHz */
|
||||
|
@ -728,15 +726,8 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
|
|||
unsigned int x1;
|
||||
unsigned int x2;
|
||||
int i;
|
||||
unsigned int inband_interferer_div2[ALLOWABLE_FS_COUNT] = {
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE,
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE
|
||||
};
|
||||
unsigned int inband_interferer_div4[ALLOWABLE_FS_COUNT] = {
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE,
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE
|
||||
};
|
||||
|
||||
bool inband_interferer_div2[ALLOWABLE_FS_COUNT];
|
||||
bool inband_interferer_div4[ALLOWABLE_FS_COUNT];
|
||||
int status;
|
||||
|
||||
/* allowable sample rates for ADC in MHz */
|
||||
|
@ -762,7 +753,7 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
|
|||
}
|
||||
|
||||
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
|
||||
inband_interferer_div2[i] = inband_interferer_div4[i] = FALSE;
|
||||
inband_interferer_div2[i] = inband_interferer_div4[i] = false;
|
||||
|
||||
if_limit_high = -700000;
|
||||
if_limit_low = -100000;
|
||||
|
@ -798,7 +789,7 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
|
|||
|
||||
if (((band_low < x1) && (x1 < band_high)) ||
|
||||
((band_low < x2) && (x2 < band_high)))
|
||||
inband_interferer_div4[i] = TRUE;
|
||||
inband_interferer_div4[i] = true;
|
||||
|
||||
}
|
||||
|
||||
|
@ -811,25 +802,28 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
|
|||
|
||||
if (((band_low < x1) && (x1 < band_high)) ||
|
||||
((band_low < x2) && (x2 < band_high)))
|
||||
inband_interferer_div2[i] = TRUE;
|
||||
inband_interferer_div2[i] = true;
|
||||
}
|
||||
|
||||
inband_interferer_ind = TRUE;
|
||||
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
|
||||
inband_interferer_ind &= inband_interferer_div2[i] |
|
||||
inband_interferer_div4[i];
|
||||
inband_interferer_ind = true;
|
||||
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
|
||||
if (inband_interferer_div2[i] || inband_interferer_div4[i]) {
|
||||
inband_interferer_ind = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (inband_interferer_ind) {
|
||||
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
|
||||
if (inband_interferer_div2[i] == FALSE) {
|
||||
if (!inband_interferer_div2[i]) {
|
||||
sample_rate = (u8) afs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
|
||||
if ((inband_interferer_div2[i] |
|
||||
inband_interferer_div4[i]) == FALSE) {
|
||||
if ((inband_interferer_div2[i] ||
|
||||
!inband_interferer_div4[i])) {
|
||||
sample_rate = (u8) afs[i];
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ struct stv0900_config {
|
|||
u8 tun2_maddress;
|
||||
u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
|
||||
u8 tun2_adc;
|
||||
u8 tun1_type;/* for now 3 for stb6100 auto, else - software */
|
||||
u8 tun2_type;
|
||||
/* Set device param to start dma */
|
||||
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
|
||||
};
|
||||
|
|
|
@ -177,7 +177,7 @@ u8 stv0900_read_reg(struct stv0900_internal *intp, u16 reg)
|
|||
return buf;
|
||||
}
|
||||
|
||||
void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
|
||||
static void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
|
||||
{
|
||||
u8 position = 0, i = 0;
|
||||
|
||||
|
@ -218,7 +218,7 @@ u8 stv0900_get_bits(struct stv0900_internal *intp, u32 label)
|
|||
return val;
|
||||
}
|
||||
|
||||
enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
|
||||
static enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
|
||||
{
|
||||
s32 i;
|
||||
|
||||
|
@ -282,7 +282,7 @@ enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
|
|||
return STV0900_NO_ERROR;
|
||||
}
|
||||
|
||||
u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk)
|
||||
static u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk)
|
||||
{
|
||||
u32 mclk = 90000000, div = 0, ad_div = 0;
|
||||
|
||||
|
@ -296,7 +296,7 @@ u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk)
|
|||
return mclk;
|
||||
}
|
||||
|
||||
enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk)
|
||||
static enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk)
|
||||
{
|
||||
u32 m_div, clk_sel;
|
||||
|
||||
|
@ -334,7 +334,7 @@ enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk)
|
|||
return STV0900_NO_ERROR;
|
||||
}
|
||||
|
||||
u32 stv0900_get_err_count(struct stv0900_internal *intp, int cntr,
|
||||
static u32 stv0900_get_err_count(struct stv0900_internal *intp, int cntr,
|
||||
enum fe_stv0900_demod_num demod)
|
||||
{
|
||||
u32 lsb, msb, hsb, err_val;
|
||||
|
@ -567,6 +567,46 @@ void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
|
|||
}
|
||||
}
|
||||
|
||||
u32 stv0900_get_freq_auto(struct stv0900_internal *intp, int demod)
|
||||
{
|
||||
u32 freq, round;
|
||||
/* Formulat :
|
||||
Tuner_Frequency(MHz) = Regs / 64
|
||||
Tuner_granularity(MHz) = Regs / 2048
|
||||
real_Tuner_Frequency = Tuner_Frequency(MHz) - Tuner_granularity(MHz)
|
||||
*/
|
||||
freq = (stv0900_get_bits(intp, TUN_RFFREQ2) << 10) +
|
||||
(stv0900_get_bits(intp, TUN_RFFREQ1) << 2) +
|
||||
stv0900_get_bits(intp, TUN_RFFREQ0);
|
||||
|
||||
freq = (freq * 1000) / 64;
|
||||
|
||||
round = (stv0900_get_bits(intp, TUN_RFRESTE1) >> 2) +
|
||||
stv0900_get_bits(intp, TUN_RFRESTE0);
|
||||
|
||||
round = (round * 1000) / 2048;
|
||||
|
||||
return freq + round;
|
||||
}
|
||||
|
||||
void stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
|
||||
u32 Bandwidth, int demod)
|
||||
{
|
||||
u32 tunerFrequency;
|
||||
/* Formulat:
|
||||
Tuner_frequency_reg= Frequency(MHz)*64
|
||||
*/
|
||||
tunerFrequency = (Frequency * 64) / 1000;
|
||||
|
||||
stv0900_write_bits(intp, TUN_RFFREQ2, (tunerFrequency >> 10));
|
||||
stv0900_write_bits(intp, TUN_RFFREQ1, (tunerFrequency >> 2) & 0xff);
|
||||
stv0900_write_bits(intp, TUN_RFFREQ0, (tunerFrequency & 0x03));
|
||||
/* Low Pass Filter = BW /2 (MHz)*/
|
||||
stv0900_write_bits(intp, TUN_BW, Bandwidth / 2000000);
|
||||
/* Tuner Write trig */
|
||||
stv0900_write_reg(intp, TNRLD, 1);
|
||||
}
|
||||
|
||||
static s32 stv0900_get_rf_level(struct stv0900_internal *intp,
|
||||
const struct stv0900_table *lookup,
|
||||
enum fe_stv0900_demod_num demod)
|
||||
|
@ -1329,7 +1369,6 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
|
|||
enum fe_stv0900_error error = STV0900_NO_ERROR;
|
||||
enum fe_stv0900_error demodError = STV0900_NO_ERROR;
|
||||
struct stv0900_internal *intp = NULL;
|
||||
|
||||
int selosci, i;
|
||||
|
||||
struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
|
||||
|
@ -1345,7 +1384,14 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
|
|||
} else {
|
||||
state->internal = kmalloc(sizeof(struct stv0900_internal),
|
||||
GFP_KERNEL);
|
||||
if (state->internal == NULL)
|
||||
return STV0900_INVALID_HANDLE;
|
||||
temp_int = append_internal(state->internal);
|
||||
if (temp_int == NULL) {
|
||||
kfree(state->internal);
|
||||
state->internal = NULL;
|
||||
return STV0900_INVALID_HANDLE;
|
||||
}
|
||||
state->internal->dmds_used = 1;
|
||||
state->internal->i2c_adap = state->i2c_adap;
|
||||
state->internal->i2c_addr = state->config->demod_address;
|
||||
|
@ -1371,11 +1417,6 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
|
|||
return error;
|
||||
}
|
||||
|
||||
if (state->internal == NULL) {
|
||||
error = STV0900_INVALID_HANDLE;
|
||||
return error;
|
||||
}
|
||||
|
||||
intp = state->internal;
|
||||
|
||||
intp->demod_mode = p_init->demod_mode;
|
||||
|
@ -1404,6 +1445,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
|
|||
stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
|
||||
}
|
||||
|
||||
intp->tuner_type[0] = p_init->tuner1_type;
|
||||
intp->tuner_type[1] = p_init->tuner2_type;
|
||||
/* tuner init */
|
||||
switch (p_init->tuner1_type) {
|
||||
case 3: /*FE_AUTO_STB6100:*/
|
||||
stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x3c);
|
||||
stv0900_write_reg(intp, R0900_P1_TNRCFG2, 0x86);
|
||||
stv0900_write_reg(intp, R0900_P1_TNRCFG3, 0x18);
|
||||
stv0900_write_reg(intp, R0900_P1_TNRXTAL, 27); /* 27MHz */
|
||||
stv0900_write_reg(intp, R0900_P1_TNRSTEPS, 0x05);
|
||||
stv0900_write_reg(intp, R0900_P1_TNRGAIN, 0x17);
|
||||
stv0900_write_reg(intp, R0900_P1_TNRADJ, 0x1f);
|
||||
stv0900_write_reg(intp, R0900_P1_TNRCTL2, 0x0);
|
||||
stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 3);
|
||||
break;
|
||||
/* case FE_SW_TUNER: */
|
||||
default:
|
||||
stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 6);
|
||||
break;
|
||||
}
|
||||
|
||||
stv0900_write_bits(intp, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
|
||||
switch (p_init->tuner1_adc) {
|
||||
case 1:
|
||||
|
@ -1413,6 +1475,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
|
|||
break;
|
||||
}
|
||||
|
||||
stv0900_write_reg(intp, R0900_P1_TNRLD, 1); /* hw tuner */
|
||||
|
||||
/* tuner init */
|
||||
switch (p_init->tuner2_type) {
|
||||
case 3: /*FE_AUTO_STB6100:*/
|
||||
stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x3c);
|
||||
stv0900_write_reg(intp, R0900_P2_TNRCFG2, 0x86);
|
||||
stv0900_write_reg(intp, R0900_P2_TNRCFG3, 0x18);
|
||||
stv0900_write_reg(intp, R0900_P2_TNRXTAL, 27); /* 27MHz */
|
||||
stv0900_write_reg(intp, R0900_P2_TNRSTEPS, 0x05);
|
||||
stv0900_write_reg(intp, R0900_P2_TNRGAIN, 0x17);
|
||||
stv0900_write_reg(intp, R0900_P2_TNRADJ, 0x1f);
|
||||
stv0900_write_reg(intp, R0900_P2_TNRCTL2, 0x0);
|
||||
stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 3);
|
||||
break;
|
||||
/* case FE_SW_TUNER: */
|
||||
default:
|
||||
stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 6);
|
||||
break;
|
||||
}
|
||||
|
||||
stv0900_write_bits(intp, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress);
|
||||
switch (p_init->tuner2_adc) {
|
||||
case 1:
|
||||
|
@ -1422,6 +1505,8 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
|
|||
break;
|
||||
}
|
||||
|
||||
stv0900_write_reg(intp, R0900_P2_TNRLD, 1); /* hw tuner */
|
||||
|
||||
stv0900_write_bits(intp, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inv);
|
||||
stv0900_write_bits(intp, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inv);
|
||||
stv0900_set_mclk(intp, 135000000);
|
||||
|
@ -1824,10 +1909,12 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
|
|||
init_params.tun1_maddress = config->tun1_maddress;
|
||||
init_params.tun1_iq_inv = STV0900_IQ_NORMAL;
|
||||
init_params.tuner1_adc = config->tun1_adc;
|
||||
init_params.tuner1_type = config->tun1_type;
|
||||
init_params.path2_ts_clock = config->path2_mode;
|
||||
init_params.ts_config = config->ts_config_regs;
|
||||
init_params.tun2_maddress = config->tun2_maddress;
|
||||
init_params.tuner2_adc = config->tun2_adc;
|
||||
init_params.tuner2_type = config->tun2_type;
|
||||
init_params.tun2_iq_inv = STV0900_IQ_SWAPPED;
|
||||
|
||||
err_stv0900 = stv0900_init_internal(&state->frontend,
|
||||
|
|
|
@ -247,6 +247,7 @@ struct stv0900_init_params{
|
|||
|
||||
u8 tun1_maddress;
|
||||
int tuner1_adc;
|
||||
int tuner1_type;
|
||||
|
||||
/* IQ from the tuner1 to the demod */
|
||||
enum stv0900_iq_inversion tun1_iq_inv;
|
||||
|
@ -254,6 +255,7 @@ struct stv0900_init_params{
|
|||
|
||||
u8 tun2_maddress;
|
||||
int tuner2_adc;
|
||||
int tuner2_type;
|
||||
|
||||
/* IQ from the tuner2 to the demod */
|
||||
enum stv0900_iq_inversion tun2_iq_inv;
|
||||
|
@ -309,6 +311,8 @@ struct stv0900_internal{
|
|||
s32 bw[2];
|
||||
s32 symbol_rate[2];
|
||||
s32 srch_range[2];
|
||||
/* for software/auto tuner */
|
||||
int tuner_type[2];
|
||||
|
||||
/* algorithm for search Blind, Cold or Warm*/
|
||||
enum fe_stv0900_search_algo srch_algo[2];
|
||||
|
@ -394,4 +398,11 @@ extern enum
|
|||
fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
|
||||
enum fe_stv0900_demod_num demod);
|
||||
|
||||
extern u32
|
||||
stv0900_get_freq_auto(struct stv0900_internal *intp, int demod);
|
||||
|
||||
extern void
|
||||
stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
|
||||
u32 Bandwidth, int demod);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3174,17 +3174,21 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
|
|||
#define R0900_P1_TNRRF1 0xf4e9
|
||||
#define TNRRF1 REGx(R0900_P1_TNRRF1)
|
||||
#define F0900_P1_TUN_RFFREQ2 0xf4e900ff
|
||||
#define TUN_RFFREQ2 FLDx(F0900_P1_TUN_RFFREQ2)
|
||||
|
||||
/*P1_TNRRF0*/
|
||||
#define R0900_P1_TNRRF0 0xf4ea
|
||||
#define TNRRF0 REGx(R0900_P1_TNRRF0)
|
||||
#define F0900_P1_TUN_RFFREQ1 0xf4ea00ff
|
||||
#define TUN_RFFREQ1 FLDx(F0900_P1_TUN_RFFREQ1)
|
||||
|
||||
/*P1_TNRBW*/
|
||||
#define R0900_P1_TNRBW 0xf4eb
|
||||
#define TNRBW REGx(R0900_P1_TNRBW)
|
||||
#define F0900_P1_TUN_RFFREQ0 0xf4eb00c0
|
||||
#define TUN_RFFREQ0 FLDx(F0900_P1_TUN_RFFREQ0)
|
||||
#define F0900_P1_TUN_BW 0xf4eb003f
|
||||
#define TUN_BW FLDx(F0900_P1_TUN_BW)
|
||||
|
||||
/*P1_TNRADJ*/
|
||||
#define R0900_P1_TNRADJ 0xf4ec
|
||||
|
@ -3234,11 +3238,13 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
|
|||
#define F0900_P1_TUN_I2CLOCKED 0xf4f60010
|
||||
#define F0900_P1_TUN_PROGDONE 0xf4f6000c
|
||||
#define F0900_P1_TUN_RFRESTE1 0xf4f60003
|
||||
#define TUN_RFRESTE1 FLDx(F0900_P1_TUN_RFRESTE1)
|
||||
|
||||
/*P1_TNRRESTE*/
|
||||
#define R0900_P1_TNRRESTE 0xf4f7
|
||||
#define TNRRESTE REGx(R0900_P1_TNRRESTE)
|
||||
#define F0900_P1_TUN_RFRESTE0 0xf4f700ff
|
||||
#define TUN_RFRESTE0 FLDx(F0900_P1_TUN_RFRESTE0)
|
||||
|
||||
/*P1_SMAPCOEF7*/
|
||||
#define R0900_P1_SMAPCOEF7 0xf500
|
||||
|
|
|
@ -193,7 +193,7 @@ static int stv0900_search_carr_sw_loop(struct stv0900_internal *intp,
|
|||
return lock;
|
||||
}
|
||||
|
||||
int stv0900_sw_algo(struct stv0900_internal *intp,
|
||||
static int stv0900_sw_algo(struct stv0900_internal *intp,
|
||||
enum fe_stv0900_demod_num demod)
|
||||
{
|
||||
int lock = FALSE,
|
||||
|
@ -606,7 +606,12 @@ static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe,
|
|||
tuner_freq -= (current_step * currier_step);
|
||||
|
||||
if (intp->chip_id <= 0x20) {
|
||||
stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
|
||||
if (intp->tuner_type[d] == 3)
|
||||
stv0900_set_tuner_auto(intp, tuner_freq,
|
||||
intp->bw[d], demod);
|
||||
else
|
||||
stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
|
||||
|
||||
stv0900_write_reg(intp, DMDISTATE, 0x1c);
|
||||
stv0900_write_reg(intp, CFRINIT1, 0);
|
||||
stv0900_write_reg(intp, CFRINIT0, 0);
|
||||
|
@ -790,7 +795,7 @@ static enum fe_stv0900_fec stv0900_get_vit_fec(struct stv0900_internal *intp,
|
|||
return prate;
|
||||
}
|
||||
|
||||
void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp,
|
||||
static void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp,
|
||||
enum fe_stv0900_demod_num demod,
|
||||
u32 srate)
|
||||
{
|
||||
|
@ -976,8 +981,16 @@ static void stv0900_track_optimization(struct dvb_frontend *fe)
|
|||
intp->rolloff) + 10000000;
|
||||
|
||||
if ((intp->chip_id >= 0x20) || (blind_tun_sw == 1)) {
|
||||
if (intp->srch_algo[demod] != STV0900_WARM_START)
|
||||
stv0900_set_bandwidth(fe, intp->bw[demod]);
|
||||
if (intp->srch_algo[demod] != STV0900_WARM_START) {
|
||||
if (intp->tuner_type[demod] == 3)
|
||||
stv0900_set_tuner_auto(intp,
|
||||
intp->freq[demod],
|
||||
intp->bw[demod],
|
||||
demod);
|
||||
else
|
||||
stv0900_set_bandwidth(fe,
|
||||
intp->bw[demod]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((intp->srch_algo[demod] == STV0900_BLIND_SEARCH) ||
|
||||
|
@ -1202,7 +1215,11 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
|
|||
}
|
||||
|
||||
result->standard = stv0900_get_standard(fe, d);
|
||||
result->frequency = stv0900_get_tuner_freq(fe);
|
||||
if (intp->tuner_type[demod] == 3)
|
||||
result->frequency = stv0900_get_freq_auto(intp, d);
|
||||
else
|
||||
result->frequency = stv0900_get_tuner_freq(fe);
|
||||
|
||||
offsetFreq = stv0900_get_carr_freq(intp, intp->mclk, d) / 1000;
|
||||
result->frequency += offsetFreq;
|
||||
result->symbol_rate = stv0900_get_symbol_rate(intp, intp->mclk, d);
|
||||
|
@ -1213,6 +1230,9 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
|
|||
result->pilot = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01;
|
||||
result->frame_len = ((u32)stv0900_get_bits(intp, DEMOD_TYPE)) >> 1;
|
||||
result->rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS);
|
||||
|
||||
dprintk("%s: modcode=0x%x \n", __func__, result->modcode);
|
||||
|
||||
switch (result->standard) {
|
||||
case STV0900_DVBS2_STANDARD:
|
||||
result->spectrum = stv0900_get_bits(intp, SPECINV_DEMOD);
|
||||
|
@ -1239,7 +1259,11 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
|
|||
if ((intp->srch_algo[d] == STV0900_BLIND_SEARCH) ||
|
||||
(intp->symbol_rate[d] < 10000000)) {
|
||||
offsetFreq = result->frequency - intp->freq[d];
|
||||
intp->freq[d] = stv0900_get_tuner_freq(fe);
|
||||
if (intp->tuner_type[demod] == 3)
|
||||
intp->freq[d] = stv0900_get_freq_auto(intp, d);
|
||||
else
|
||||
intp->freq[d] = stv0900_get_tuner_freq(fe);
|
||||
|
||||
if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
|
||||
range = STV0900_RANGEOK;
|
||||
else if (ABS(offsetFreq) <=
|
||||
|
@ -1481,7 +1505,12 @@ static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe)
|
|||
else
|
||||
tuner_freq -= (current_step * currier_step);
|
||||
|
||||
stv0900_set_tuner(fe, tuner_freq, intp->bw[demod]);
|
||||
if (intp->tuner_type[demod] == 3)
|
||||
stv0900_set_tuner_auto(intp, tuner_freq,
|
||||
intp->bw[demod], demod);
|
||||
else
|
||||
stv0900_set_tuner(fe, tuner_freq,
|
||||
intp->bw[demod]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1608,7 +1637,8 @@ static int stv0900_blind_search_algo(struct dvb_frontend *fe)
|
|||
|
||||
agc2_int = stv0900_blind_check_agc2_min_level(intp, demod);
|
||||
|
||||
if (agc2_int > STV0900_BLIND_SEARCH_AGC2_TH)
|
||||
dprintk("%s agc2_int=%d agc2_th=%d \n", __func__, agc2_int, agc2_th);
|
||||
if (agc2_int > agc2_th)
|
||||
return FALSE;
|
||||
|
||||
if (intp->chip_id == 0x10)
|
||||
|
@ -1875,7 +1905,11 @@ enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe)
|
|||
|
||||
}
|
||||
|
||||
stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
|
||||
if (intp->tuner_type[demod] == 3)
|
||||
stv0900_set_tuner_auto(intp, intp->freq[demod],
|
||||
intp->bw[demod], demod);
|
||||
else
|
||||
stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
|
||||
|
||||
agc1_power = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1),
|
||||
stv0900_get_bits(intp, AGCIQ_VALUE0));
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -60,6 +60,11 @@ enum stv090x_i2crpt {
|
|||
STV090x_RPTLEVEL_2 = 7,
|
||||
};
|
||||
|
||||
enum stv090x_adc_range {
|
||||
STV090x_ADC_2Vpp = 0,
|
||||
STV090x_ADC_1Vpp = 1
|
||||
};
|
||||
|
||||
struct stv090x_config {
|
||||
enum stv090x_device device;
|
||||
enum stv090x_mode demod_mode;
|
||||
|
@ -68,13 +73,17 @@ struct stv090x_config {
|
|||
u32 xtal; /* default: 8000000 */
|
||||
u8 address; /* default: 0x68 */
|
||||
|
||||
u32 ref_clk; /* default: 16000000 FIXME to tuner config */
|
||||
|
||||
u8 ts1_mode;
|
||||
u8 ts2_mode;
|
||||
u32 ts1_clk;
|
||||
u32 ts2_clk;
|
||||
|
||||
enum stv090x_i2crpt repeater_level;
|
||||
|
||||
u8 tuner_bbgain; /* default: 10db */
|
||||
enum stv090x_adc_range adc1_range; /* default: 2Vpp */
|
||||
enum stv090x_adc_range adc2_range; /* default: 2Vpp */
|
||||
|
||||
bool diseqc_envelope_mode;
|
||||
|
||||
int (*tuner_init) (struct dvb_frontend *fe);
|
||||
|
|
|
@ -230,11 +230,23 @@ struct stv090x_tab {
|
|||
s32 read;
|
||||
};
|
||||
|
||||
struct stv090x_internal {
|
||||
struct i2c_adapter *i2c_adap;
|
||||
u8 i2c_addr;
|
||||
|
||||
struct mutex demod_lock; /* Lock access to shared register */
|
||||
struct mutex tuner_lock; /* Lock access to tuners */
|
||||
s32 mclk; /* Masterclock Divider factor */
|
||||
u32 dev_ver;
|
||||
|
||||
int num_used;
|
||||
};
|
||||
|
||||
struct stv090x_state {
|
||||
enum stv090x_device device;
|
||||
enum stv090x_demodulator demod;
|
||||
enum stv090x_mode demod_mode;
|
||||
u32 dev_ver;
|
||||
struct stv090x_internal *internal;
|
||||
|
||||
struct i2c_adapter *i2c;
|
||||
const struct stv090x_config *config;
|
||||
|
@ -256,11 +268,8 @@ struct stv090x_state {
|
|||
u32 frequency;
|
||||
u32 srate;
|
||||
|
||||
s32 mclk; /* Masterclock Divider factor */
|
||||
s32 tuner_bw;
|
||||
|
||||
u32 tuner_refclk;
|
||||
|
||||
s32 search_range;
|
||||
|
||||
s32 DemodTimeout;
|
||||
|
|
|
@ -35,8 +35,6 @@ static unsigned int verbose;
|
|||
module_param(verbose, int, 0644);
|
||||
MODULE_PARM_DESC(verbose, "Set Verbosity level");
|
||||
|
||||
static u8 stv6110x_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
|
||||
|
||||
static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
|
||||
{
|
||||
int ret;
|
||||
|
@ -58,12 +56,23 @@ static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
|
||||
static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 data[], int len)
|
||||
{
|
||||
int ret;
|
||||
const struct stv6110x_config *config = stv6110x->config;
|
||||
u8 buf[] = { reg, data };
|
||||
struct i2c_msg msg = { .addr = config->addr, .flags = 0, . buf = buf, .len = 2 };
|
||||
u8 buf[len + 1];
|
||||
struct i2c_msg msg = {
|
||||
.addr = config->addr,
|
||||
.flags = 0,
|
||||
.buf = buf,
|
||||
.len = len + 1
|
||||
};
|
||||
|
||||
if (start + len > 8)
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = start;
|
||||
memcpy(&buf[1], data, len);
|
||||
|
||||
ret = i2c_transfer(stv6110x->i2c, &msg, 1);
|
||||
if (ret != 1) {
|
||||
|
@ -74,18 +83,21 @@ static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
|
||||
{
|
||||
return stv6110x_write_regs(stv6110x, reg, &data, 1);
|
||||
}
|
||||
|
||||
static int stv6110x_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct stv6110x_state *stv6110x = fe->tuner_priv;
|
||||
int ret;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(stv6110x_regs); i++) {
|
||||
ret = stv6110x_write_reg(stv6110x, i, stv6110x_regs[i]);
|
||||
if (ret < 0) {
|
||||
dprintk(FE_ERROR, 1, "Initialization failed");
|
||||
return -1;
|
||||
}
|
||||
ret = stv6110x_write_regs(stv6110x, 0, stv6110x->regs,
|
||||
ARRAY_SIZE(stv6110x->regs));
|
||||
if (ret < 0) {
|
||||
dprintk(FE_ERROR, 1, "Initialization failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -98,23 +110,23 @@ static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
|||
s32 pVal, pCalc, rDivOpt = 0, pCalcOpt = 1000;
|
||||
u8 i;
|
||||
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
|
||||
|
||||
if (frequency <= 1023000) {
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
|
||||
pVal = 40;
|
||||
} else if (frequency <= 1300000) {
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
|
||||
pVal = 40;
|
||||
} else if (frequency <= 2046000) {
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
|
||||
pVal = 20;
|
||||
} else {
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
|
||||
pVal = 20;
|
||||
}
|
||||
|
||||
|
@ -130,21 +142,21 @@ static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
|||
divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz;
|
||||
divider = (divider + 5) / 10;
|
||||
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
|
||||
|
||||
/* VCO Auto calibration */
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
|
||||
|
||||
stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x_regs[STV6110x_TNG1]);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x_regs[STV6110x_TNG0]);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x->regs[STV6110x_TNG1]);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x->regs[STV6110x_TNG0]);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]);
|
||||
|
||||
for (i = 0; i < TRIALS; i++) {
|
||||
stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
|
||||
if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x_regs[STV6110x_STAT1]))
|
||||
stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
|
||||
if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x->regs[STV6110x_STAT1]))
|
||||
break;
|
||||
msleep(1);
|
||||
}
|
||||
|
@ -156,14 +168,14 @@ static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
|||
{
|
||||
struct stv6110x_state *stv6110x = fe->tuner_priv;
|
||||
|
||||
stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x_regs[STV6110x_TNG1]);
|
||||
stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x_regs[STV6110x_TNG0]);
|
||||
stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x->regs[STV6110x_TNG1]);
|
||||
stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x->regs[STV6110x_TNG0]);
|
||||
|
||||
*frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x_regs[STV6110x_TNG1]),
|
||||
STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x_regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
|
||||
*frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x->regs[STV6110x_TNG1]),
|
||||
STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x->regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
|
||||
|
||||
*frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x_regs[STV6110x_TNG1]) +
|
||||
STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x_regs[STV6110x_TNG1])));
|
||||
*frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x->regs[STV6110x_TNG1]) +
|
||||
STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x->regs[STV6110x_TNG1])));
|
||||
|
||||
*frequency >>= 2;
|
||||
|
||||
|
@ -179,27 +191,27 @@ static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
|
|||
halfbw = bandwidth >> 1;
|
||||
|
||||
if (halfbw > 36000000)
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
|
||||
else if (halfbw < 5000000)
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
|
||||
else
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
|
||||
|
||||
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
|
||||
|
||||
stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]);
|
||||
|
||||
for (i = 0; i < TRIALS; i++) {
|
||||
stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
|
||||
if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x_regs[STV6110x_STAT1]))
|
||||
stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
|
||||
if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x->regs[STV6110x_STAT1]))
|
||||
break;
|
||||
msleep(1);
|
||||
}
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
|
||||
stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
|
||||
stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -208,8 +220,8 @@ static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
|
|||
{
|
||||
struct stv6110x_state *stv6110x = fe->tuner_priv;
|
||||
|
||||
stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x_regs[STV6110x_CTRL3]);
|
||||
*bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x_regs[STV6110x_CTRL3]) + 5) * 2000000;
|
||||
stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x->regs[STV6110x_CTRL3]);
|
||||
*bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x->regs[STV6110x_CTRL3]) + 5) * 2000000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -222,20 +234,20 @@ static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock)
|
|||
switch (refclock) {
|
||||
default:
|
||||
case 1:
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
|
||||
break;
|
||||
case 2:
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
|
||||
break;
|
||||
case 4:
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
|
||||
break;
|
||||
case 8:
|
||||
case 0:
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
|
||||
break;
|
||||
}
|
||||
stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -244,8 +256,8 @@ static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain)
|
|||
{
|
||||
struct stv6110x_state *stv6110x = fe->tuner_priv;
|
||||
|
||||
stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x_regs[STV6110x_CTRL2]);
|
||||
*gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x_regs[STV6110x_CTRL2]);
|
||||
stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x->regs[STV6110x_CTRL2]);
|
||||
*gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x->regs[STV6110x_CTRL2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -254,8 +266,8 @@ static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain)
|
|||
{
|
||||
struct stv6110x_state *stv6110x = fe->tuner_priv;
|
||||
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
|
||||
stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -267,19 +279,19 @@ static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
|
|||
|
||||
switch (mode) {
|
||||
case TUNER_SLEEP:
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 0);
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 0);
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 0);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 0);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 0);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 0);
|
||||
break;
|
||||
|
||||
case TUNER_WAKE:
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 1);
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 1);
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 1);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 1);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 1);
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
|
||||
ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]);
|
||||
if (ret < 0) {
|
||||
dprintk(FE_ERROR, 1, "I/O Error");
|
||||
return -EIO;
|
||||
|
@ -297,9 +309,9 @@ static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
|
|||
{
|
||||
struct stv6110x_state *stv6110x = fe->tuner_priv;
|
||||
|
||||
stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
|
||||
stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
|
||||
|
||||
if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x_regs[STV6110x_STAT1]))
|
||||
if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x->regs[STV6110x_STAT1]))
|
||||
*status = TUNER_PHASELOCKED;
|
||||
else
|
||||
*status = 0;
|
||||
|
@ -349,6 +361,8 @@ struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
|
|||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct stv6110x_state *stv6110x;
|
||||
u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
|
||||
int ret;
|
||||
|
||||
stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL);
|
||||
if (stv6110x == NULL)
|
||||
|
@ -357,6 +371,44 @@ struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
|
|||
stv6110x->i2c = i2c;
|
||||
stv6110x->config = config;
|
||||
stv6110x->devctl = &stv6110x_ctl;
|
||||
memcpy(stv6110x->regs, default_regs, 8);
|
||||
|
||||
/* setup divider */
|
||||
switch (stv6110x->config->clk_div) {
|
||||
default:
|
||||
case 1:
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
|
||||
break;
|
||||
case 2:
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
|
||||
break;
|
||||
case 4:
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
|
||||
break;
|
||||
case 8:
|
||||
case 0:
|
||||
STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
|
||||
break;
|
||||
}
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl) {
|
||||
ret = fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = stv6110x_write_regs(stv6110x, 0, stv6110x->regs,
|
||||
ARRAY_SIZE(stv6110x->regs));
|
||||
if (ret < 0) {
|
||||
dprintk(FE_ERROR, 1, "Initialization failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl) {
|
||||
ret = fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
fe->tuner_priv = stv6110x;
|
||||
fe->ops.tuner_ops = stv6110x_ops;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
struct stv6110x_config {
|
||||
u8 addr;
|
||||
u32 refclk;
|
||||
u8 clk_div; /* divisor value for the output clock */
|
||||
};
|
||||
|
||||
enum tuner_mode {
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
struct stv6110x_state {
|
||||
struct i2c_adapter *i2c;
|
||||
const struct stv6110x_config *config;
|
||||
u8 regs[8];
|
||||
|
||||
struct stv6110x_devctl *devctl;
|
||||
};
|
||||
|
|
|
@ -133,7 +133,7 @@ static int tda665x_set_state(struct dvb_frontend *fe,
|
|||
frequency += config->ref_divider >> 1;
|
||||
frequency /= config->ref_divider;
|
||||
|
||||
buf[0] = (u8) (frequency & 0x7f00) >> 8;
|
||||
buf[0] = (u8) ((frequency & 0x7f00) >> 8);
|
||||
buf[1] = (u8) (frequency & 0x00ff) >> 0;
|
||||
buf[2] = 0x80 | 0x40 | 0x02;
|
||||
buf[3] = 0x00;
|
||||
|
|
|
@ -39,7 +39,7 @@ static int tda8261_read(struct tda8261_state *state, u8 *buf)
|
|||
{
|
||||
const struct tda8261_config *config = state->config;
|
||||
int err = 0;
|
||||
struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD,.buf = buf, .len = 2 };
|
||||
struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD,.buf = buf, .len = 1 };
|
||||
|
||||
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
|
||||
printk("%s: read error, err=%d\n", __func__, err);
|
||||
|
|
|
@ -411,7 +411,7 @@ static int zl10036_init_regs(struct zl10036_state *state)
|
|||
state->bf = 0xff;
|
||||
|
||||
if (!state->config->rf_loop_enable)
|
||||
zl10036_init_tab[1][2] |= 0x01;
|
||||
zl10036_init_tab[1][0] |= 0x01;
|
||||
|
||||
deb_info("%s\n", __func__);
|
||||
|
||||
|
|
|
@ -287,7 +287,6 @@ struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
|
|||
break;
|
||||
default:
|
||||
dprintk("Chip ID=%x does not match a known type\n", state->id);
|
||||
break;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,6 @@
|
|||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
|
|
|
@ -126,7 +126,7 @@ int mantis_input_init(struct mantis_pci *mantis)
|
|||
rc->id.version = 1;
|
||||
rc->dev = mantis->pdev->dev;
|
||||
|
||||
err = ir_input_register(rc, &ir_mantis);
|
||||
err = ir_input_register(rc, &ir_mantis, NULL);
|
||||
if (err) {
|
||||
dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err);
|
||||
input_free_device(rc);
|
||||
|
|
|
@ -41,11 +41,6 @@
|
|||
#include "dvb_frontend.h"
|
||||
#include "dvb_net.h"
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "mantis_common.h"
|
||||
#include "mantis_reg.h"
|
||||
#include "mantis_pci.h"
|
||||
|
|
9
drivers/media/dvb/ngene/Kconfig
Normal file
9
drivers/media/dvb/ngene/Kconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
config DVB_NGENE
|
||||
tristate "Micronas nGene support"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
|
||||
select DVB_STV6110x if !DVB_FE_CUSTOMISE
|
||||
select DVB_STV090x if !DVB_FE_CUSTOMISE
|
||||
---help---
|
||||
Support for Micronas PCI express cards with nGene bridge.
|
||||
|
11
drivers/media/dvb/ngene/Makefile
Normal file
11
drivers/media/dvb/ngene/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# Makefile for the nGene device driver
|
||||
#
|
||||
|
||||
ngene-objs := ngene-core.o
|
||||
|
||||
obj-$(CONFIG_DVB_NGENE) += ngene.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
|
||||
|
2024
drivers/media/dvb/ngene/ngene-core.c
Normal file
2024
drivers/media/dvb/ngene/ngene-core.c
Normal file
File diff suppressed because it is too large
Load diff
859
drivers/media/dvb/ngene/ngene.h
Normal file
859
drivers/media/dvb/ngene/ngene.h
Normal file
|
@ -0,0 +1,859 @@
|
|||
/*
|
||||
* ngene.h: nGene PCIe bridge driver
|
||||
*
|
||||
* Copyright (C) 2005-2007 Micronas
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#ifndef _NGENE_H_
|
||||
#define _NGENE_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <asm/dma.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb_ringbuffer.h"
|
||||
|
||||
#define NGENE_VID 0x18c3
|
||||
#define NGENE_PID 0x0720
|
||||
|
||||
#ifndef VIDEO_CAP_VC1
|
||||
#define VIDEO_CAP_AVC 128
|
||||
#define VIDEO_CAP_H264 128
|
||||
#define VIDEO_CAP_VC1 256
|
||||
#define VIDEO_CAP_WMV9 256
|
||||
#define VIDEO_CAP_MPEG4 512
|
||||
#endif
|
||||
|
||||
enum STREAM {
|
||||
STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */
|
||||
STREAM_VIDEOIN2,
|
||||
STREAM_AUDIOIN1, /* I2S or SPI Input */
|
||||
STREAM_AUDIOIN2,
|
||||
STREAM_AUDIOOUT,
|
||||
MAX_STREAM
|
||||
};
|
||||
|
||||
enum SMODE_BITS {
|
||||
SMODE_AUDIO_SPDIF = 0x20,
|
||||
SMODE_AVSYNC = 0x10,
|
||||
SMODE_TRANSPORT_STREAM = 0x08,
|
||||
SMODE_AUDIO_CAPTURE = 0x04,
|
||||
SMODE_VBI_CAPTURE = 0x02,
|
||||
SMODE_VIDEO_CAPTURE = 0x01
|
||||
};
|
||||
|
||||
enum STREAM_FLAG_BITS {
|
||||
SFLAG_CHROMA_FORMAT_2COMP = 0x01, /* Chroma Format : 2's complement */
|
||||
SFLAG_CHROMA_FORMAT_OFFSET = 0x00, /* Chroma Format : Binary offset */
|
||||
SFLAG_ORDER_LUMA_CHROMA = 0x02, /* Byte order: Y,Cb,Y,Cr */
|
||||
SFLAG_ORDER_CHROMA_LUMA = 0x00, /* Byte order: Cb,Y,Cr,Y */
|
||||
SFLAG_COLORBAR = 0x04, /* Select colorbar */
|
||||
};
|
||||
|
||||
#define PROGRAM_ROM 0x0000
|
||||
#define PROGRAM_SRAM 0x1000
|
||||
#define PERIPHERALS0 0x8000
|
||||
#define PERIPHERALS1 0x9000
|
||||
#define SHARED_BUFFER 0xC000
|
||||
|
||||
#define HOST_TO_NGENE (SHARED_BUFFER+0x0000)
|
||||
#define NGENE_TO_HOST (SHARED_BUFFER+0x0100)
|
||||
#define NGENE_COMMAND (SHARED_BUFFER+0x0200)
|
||||
#define NGENE_COMMAND_HI (SHARED_BUFFER+0x0204)
|
||||
#define NGENE_STATUS (SHARED_BUFFER+0x0208)
|
||||
#define NGENE_STATUS_HI (SHARED_BUFFER+0x020C)
|
||||
#define NGENE_EVENT (SHARED_BUFFER+0x0210)
|
||||
#define NGENE_EVENT_HI (SHARED_BUFFER+0x0214)
|
||||
#define VARIABLES (SHARED_BUFFER+0x0210)
|
||||
|
||||
#define NGENE_INT_COUNTS (SHARED_BUFFER+0x0260)
|
||||
#define NGENE_INT_ENABLE (SHARED_BUFFER+0x0264)
|
||||
#define NGENE_VBI_LINE_COUNT (SHARED_BUFFER+0x0268)
|
||||
|
||||
#define BUFFER_GP_XMIT (SHARED_BUFFER+0x0800)
|
||||
#define BUFFER_GP_RECV (SHARED_BUFFER+0x0900)
|
||||
#define EEPROM_AREA (SHARED_BUFFER+0x0A00)
|
||||
|
||||
#define SG_V_IN_1 (SHARED_BUFFER+0x0A80)
|
||||
#define SG_VBI_1 (SHARED_BUFFER+0x0B00)
|
||||
#define SG_A_IN_1 (SHARED_BUFFER+0x0B80)
|
||||
#define SG_V_IN_2 (SHARED_BUFFER+0x0C00)
|
||||
#define SG_VBI_2 (SHARED_BUFFER+0x0C80)
|
||||
#define SG_A_IN_2 (SHARED_BUFFER+0x0D00)
|
||||
#define SG_V_OUT (SHARED_BUFFER+0x0D80)
|
||||
#define SG_A_OUT2 (SHARED_BUFFER+0x0E00)
|
||||
|
||||
#define DATA_A_IN_1 (SHARED_BUFFER+0x0E80)
|
||||
#define DATA_A_IN_2 (SHARED_BUFFER+0x0F00)
|
||||
#define DATA_A_OUT (SHARED_BUFFER+0x0F80)
|
||||
#define DATA_V_IN_1 (SHARED_BUFFER+0x1000)
|
||||
#define DATA_V_IN_2 (SHARED_BUFFER+0x2000)
|
||||
#define DATA_V_OUT (SHARED_BUFFER+0x3000)
|
||||
|
||||
#define DATA_FIFO_AREA (SHARED_BUFFER+0x1000)
|
||||
|
||||
#define TIMESTAMPS 0xA000
|
||||
#define SCRATCHPAD 0xA080
|
||||
#define FORCE_INT 0xA088
|
||||
#define FORCE_NMI 0xA090
|
||||
#define INT_STATUS 0xA0A0
|
||||
|
||||
#define DEV_VER 0x9004
|
||||
|
||||
#define FW_DEBUG_DEFAULT (PROGRAM_SRAM+0x00FF)
|
||||
|
||||
struct SG_ADDR {
|
||||
u64 start;
|
||||
u64 curr;
|
||||
u16 curr_ptr;
|
||||
u16 elements;
|
||||
u32 pad[3];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct SHARED_MEMORY {
|
||||
/* C000 */
|
||||
u32 HostToNgene[64];
|
||||
|
||||
/* C100 */
|
||||
u32 NgeneToHost[64];
|
||||
|
||||
/* C200 */
|
||||
u64 NgeneCommand;
|
||||
u64 NgeneStatus;
|
||||
u64 NgeneEvent;
|
||||
|
||||
/* C210 */
|
||||
u8 pad1[0xc260 - 0xc218];
|
||||
|
||||
/* C260 */
|
||||
u32 IntCounts;
|
||||
u32 IntEnable;
|
||||
|
||||
/* C268 */
|
||||
u8 pad2[0xd000 - 0xc268];
|
||||
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct BUFFER_STREAM_RESULTS {
|
||||
u32 Clock; /* Stream time in 100ns units */
|
||||
u16 RemainingLines; /* Remaining lines in this field.
|
||||
0 for complete field */
|
||||
u8 FieldCount; /* Video field number */
|
||||
u8 Flags; /* Bit 7 = Done, Bit 6 = seen, Bit 5 = overflow,
|
||||
Bit 0 = FieldID */
|
||||
u16 BlockCount; /* Audio block count (unused) */
|
||||
u8 Reserved[2];
|
||||
u32 DTOUpdate;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct HW_SCATTER_GATHER_ELEMENT {
|
||||
u64 Address;
|
||||
u32 Length;
|
||||
u32 Reserved;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct BUFFER_HEADER {
|
||||
u64 Next;
|
||||
struct BUFFER_STREAM_RESULTS SR;
|
||||
|
||||
u32 Number_of_entries_1;
|
||||
u32 Reserved5;
|
||||
u64 Address_of_first_entry_1;
|
||||
|
||||
u32 Number_of_entries_2;
|
||||
u32 Reserved7;
|
||||
u64 Address_of_first_entry_2;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct EVENT_BUFFER {
|
||||
u32 TimeStamp;
|
||||
u8 GPIOStatus;
|
||||
u8 UARTStatus;
|
||||
u8 RXCharacter;
|
||||
u8 EventStatus;
|
||||
u32 Reserved[2];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/* Firmware commands. */
|
||||
|
||||
enum OPCODES {
|
||||
CMD_NOP = 0,
|
||||
CMD_FWLOAD_PREPARE = 0x01,
|
||||
CMD_FWLOAD_FINISH = 0x02,
|
||||
CMD_I2C_READ = 0x03,
|
||||
CMD_I2C_WRITE = 0x04,
|
||||
|
||||
CMD_I2C_WRITE_NOSTOP = 0x05,
|
||||
CMD_I2C_CONTINUE_WRITE = 0x06,
|
||||
CMD_I2C_CONTINUE_WRITE_NOSTOP = 0x07,
|
||||
|
||||
CMD_DEBUG_OUTPUT = 0x09,
|
||||
|
||||
CMD_CONTROL = 0x10,
|
||||
CMD_CONFIGURE_BUFFER = 0x11,
|
||||
CMD_CONFIGURE_FREE_BUFFER = 0x12,
|
||||
|
||||
CMD_SPI_READ = 0x13,
|
||||
CMD_SPI_WRITE = 0x14,
|
||||
|
||||
CMD_MEM_READ = 0x20,
|
||||
CMD_MEM_WRITE = 0x21,
|
||||
CMD_SFR_READ = 0x22,
|
||||
CMD_SFR_WRITE = 0x23,
|
||||
CMD_IRAM_READ = 0x24,
|
||||
CMD_IRAM_WRITE = 0x25,
|
||||
CMD_SET_GPIO_PIN = 0x26,
|
||||
CMD_SET_GPIO_INT = 0x27,
|
||||
CMD_CONFIGURE_UART = 0x28,
|
||||
CMD_WRITE_UART = 0x29,
|
||||
MAX_CMD
|
||||
};
|
||||
|
||||
enum RESPONSES {
|
||||
OK = 0,
|
||||
ERROR = 1
|
||||
};
|
||||
|
||||
struct FW_HEADER {
|
||||
u8 Opcode;
|
||||
u8 Length;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_I2C_WRITE {
|
||||
struct FW_HEADER hdr;
|
||||
u8 Device;
|
||||
u8 Data[250];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_I2C_CONTINUE_WRITE {
|
||||
struct FW_HEADER hdr;
|
||||
u8 Data[250];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_I2C_READ {
|
||||
struct FW_HEADER hdr;
|
||||
u8 Device;
|
||||
u8 Data[252]; /* followed by two bytes of read data count */
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_SPI_WRITE {
|
||||
struct FW_HEADER hdr;
|
||||
u8 ModeSelect;
|
||||
u8 Data[250];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_SPI_READ {
|
||||
struct FW_HEADER hdr;
|
||||
u8 ModeSelect;
|
||||
u8 Data[252]; /* followed by two bytes of read data count */
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_FWLOAD_PREPARE {
|
||||
struct FW_HEADER hdr;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_FWLOAD_FINISH {
|
||||
struct FW_HEADER hdr;
|
||||
u16 Address; /* address of final block */
|
||||
u16 Length;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/*
|
||||
* Meaning of FW_STREAM_CONTROL::Mode bits:
|
||||
* Bit 7: Loopback PEXin to PEXout using TVOut channel
|
||||
* Bit 6: AVLOOP
|
||||
* Bit 5: Audio select; 0=I2S, 1=SPDIF
|
||||
* Bit 4: AVSYNC
|
||||
* Bit 3: Enable transport stream
|
||||
* Bit 2: Enable audio capture
|
||||
* Bit 1: Enable ITU-Video VBI capture
|
||||
* Bit 0: Enable ITU-Video capture
|
||||
*
|
||||
* Meaning of FW_STREAM_CONTROL::Control bits (see UVI1_CTL)
|
||||
* Bit 7: continuous capture
|
||||
* Bit 6: capture one field
|
||||
* Bit 5: capture one frame
|
||||
* Bit 4: unused
|
||||
* Bit 3: starting field; 0=odd, 1=even
|
||||
* Bit 2: sample size; 0=8-bit, 1=10-bit
|
||||
* Bit 1: data format; 0=UYVY, 1=YUY2
|
||||
* Bit 0: resets buffer pointers
|
||||
*/
|
||||
|
||||
enum FSC_MODE_BITS {
|
||||
SMODE_LOOPBACK = 0x80,
|
||||
SMODE_AVLOOP = 0x40,
|
||||
_SMODE_AUDIO_SPDIF = 0x20,
|
||||
_SMODE_AVSYNC = 0x10,
|
||||
_SMODE_TRANSPORT_STREAM = 0x08,
|
||||
_SMODE_AUDIO_CAPTURE = 0x04,
|
||||
_SMODE_VBI_CAPTURE = 0x02,
|
||||
_SMODE_VIDEO_CAPTURE = 0x01
|
||||
};
|
||||
|
||||
|
||||
/* Meaning of FW_STREAM_CONTROL::Stream bits:
|
||||
* Bit 3: Audio sample count: 0 = relative, 1 = absolute
|
||||
* Bit 2: color bar select; 1=color bars, 0=CV3 decoder
|
||||
* Bits 1-0: stream select, UVI1, UVI2, TVOUT
|
||||
*/
|
||||
|
||||
struct FW_STREAM_CONTROL {
|
||||
struct FW_HEADER hdr;
|
||||
u8 Stream; /* Stream number (UVI1, UVI2, TVOUT) */
|
||||
u8 Control; /* Value written to UVI1_CTL */
|
||||
u8 Mode; /* Controls clock source */
|
||||
u8 SetupDataLen; /* Length of setup data, MSB=1 write
|
||||
backwards */
|
||||
u16 CaptureBlockCount; /* Blocks (a 256 Bytes) to capture per buffer
|
||||
for TS and Audio */
|
||||
u64 Buffer_Address; /* Address of first buffer header */
|
||||
u16 BytesPerVideoLine;
|
||||
u16 MaxLinesPerField;
|
||||
u16 MinLinesPerField;
|
||||
u16 Reserved_1;
|
||||
u16 BytesPerVBILine;
|
||||
u16 MaxVBILinesPerField;
|
||||
u16 MinVBILinesPerField;
|
||||
u16 SetupDataAddr; /* ngene relative address of setup data */
|
||||
u8 SetupData[32]; /* setup data */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define AUDIO_BLOCK_SIZE 256
|
||||
#define TS_BLOCK_SIZE 256
|
||||
|
||||
struct FW_MEM_READ {
|
||||
struct FW_HEADER hdr;
|
||||
u16 address;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_MEM_WRITE {
|
||||
struct FW_HEADER hdr;
|
||||
u16 address;
|
||||
u8 data;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_SFR_IRAM_READ {
|
||||
struct FW_HEADER hdr;
|
||||
u8 address;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_SFR_IRAM_WRITE {
|
||||
struct FW_HEADER hdr;
|
||||
u8 address;
|
||||
u8 data;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_SET_GPIO_PIN {
|
||||
struct FW_HEADER hdr;
|
||||
u8 select;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_SET_GPIO_INT {
|
||||
struct FW_HEADER hdr;
|
||||
u8 select;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_SET_DEBUGMODE {
|
||||
struct FW_HEADER hdr;
|
||||
u8 debug_flags;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_CONFIGURE_BUFFERS {
|
||||
struct FW_HEADER hdr;
|
||||
u8 config;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
enum _BUFFER_CONFIGS {
|
||||
/* 4k UVI1, 4k UVI2, 2k AUD1, 2k AUD2 (standard usage) */
|
||||
BUFFER_CONFIG_4422 = 0,
|
||||
/* 3k UVI1, 3k UVI2, 3k AUD1, 3k AUD2 (4x TS input usage) */
|
||||
BUFFER_CONFIG_3333 = 1,
|
||||
/* 8k UVI1, 0k UVI2, 2k AUD1, 2k I2SOut (HDTV decoder usage) */
|
||||
BUFFER_CONFIG_8022 = 2,
|
||||
BUFFER_CONFIG_FW17 = 255, /* Use new FW 17 command */
|
||||
};
|
||||
|
||||
struct FW_CONFIGURE_FREE_BUFFERS {
|
||||
struct FW_HEADER hdr;
|
||||
u8 UVI1_BufferLength;
|
||||
u8 UVI2_BufferLength;
|
||||
u8 TVO_BufferLength;
|
||||
u8 AUD1_BufferLength;
|
||||
u8 AUD2_BufferLength;
|
||||
u8 TVA_BufferLength;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct FW_CONFIGURE_UART {
|
||||
struct FW_HEADER hdr;
|
||||
u8 UartControl;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
enum _UART_CONFIG {
|
||||
_UART_BAUDRATE_19200 = 0,
|
||||
_UART_BAUDRATE_9600 = 1,
|
||||
_UART_BAUDRATE_4800 = 2,
|
||||
_UART_BAUDRATE_2400 = 3,
|
||||
_UART_RX_ENABLE = 0x40,
|
||||
_UART_TX_ENABLE = 0x80,
|
||||
};
|
||||
|
||||
struct FW_WRITE_UART {
|
||||
struct FW_HEADER hdr;
|
||||
u8 Data[252];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
|
||||
struct ngene_command {
|
||||
u32 in_len;
|
||||
u32 out_len;
|
||||
union {
|
||||
u32 raw[64];
|
||||
u8 raw8[256];
|
||||
struct FW_HEADER hdr;
|
||||
struct FW_I2C_WRITE I2CWrite;
|
||||
struct FW_I2C_CONTINUE_WRITE I2CContinueWrite;
|
||||
struct FW_I2C_READ I2CRead;
|
||||
struct FW_STREAM_CONTROL StreamControl;
|
||||
struct FW_FWLOAD_PREPARE FWLoadPrepare;
|
||||
struct FW_FWLOAD_FINISH FWLoadFinish;
|
||||
struct FW_MEM_READ MemoryRead;
|
||||
struct FW_MEM_WRITE MemoryWrite;
|
||||
struct FW_SFR_IRAM_READ SfrIramRead;
|
||||
struct FW_SFR_IRAM_WRITE SfrIramWrite;
|
||||
struct FW_SPI_WRITE SPIWrite;
|
||||
struct FW_SPI_READ SPIRead;
|
||||
struct FW_SET_GPIO_PIN SetGpioPin;
|
||||
struct FW_SET_GPIO_INT SetGpioInt;
|
||||
struct FW_SET_DEBUGMODE SetDebugMode;
|
||||
struct FW_CONFIGURE_BUFFERS ConfigureBuffers;
|
||||
struct FW_CONFIGURE_FREE_BUFFERS ConfigureFreeBuffers;
|
||||
struct FW_CONFIGURE_UART ConfigureUart;
|
||||
struct FW_WRITE_UART WriteUart;
|
||||
} cmd;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
#define NGENE_INTERFACE_VERSION 0x103
|
||||
#define MAX_VIDEO_BUFFER_SIZE (417792) /* 288*1440 rounded up to next page */
|
||||
#define MAX_AUDIO_BUFFER_SIZE (8192) /* Gives room for about 23msec@48KHz */
|
||||
#define MAX_VBI_BUFFER_SIZE (28672) /* 1144*18 rounded up to next page */
|
||||
#define MAX_TS_BUFFER_SIZE (98304) /* 512*188 rounded up to next page */
|
||||
#define MAX_HDTV_BUFFER_SIZE (2080768) /* 541*1920*2 rounded up to next page
|
||||
Max: (1920x1080i60) */
|
||||
|
||||
#define OVERFLOW_BUFFER_SIZE (8192)
|
||||
|
||||
#define RING_SIZE_VIDEO 4
|
||||
#define RING_SIZE_AUDIO 8
|
||||
#define RING_SIZE_TS 8
|
||||
|
||||
#define NUM_SCATTER_GATHER_ENTRIES 8
|
||||
|
||||
#define MAX_DMA_LENGTH (((MAX_VIDEO_BUFFER_SIZE + MAX_VBI_BUFFER_SIZE) * \
|
||||
RING_SIZE_VIDEO * 2) + \
|
||||
(MAX_AUDIO_BUFFER_SIZE * RING_SIZE_AUDIO * 2) + \
|
||||
(MAX_TS_BUFFER_SIZE * RING_SIZE_TS * 4) + \
|
||||
(RING_SIZE_VIDEO * PAGE_SIZE * 2) + \
|
||||
(RING_SIZE_AUDIO * PAGE_SIZE * 2) + \
|
||||
(RING_SIZE_TS * PAGE_SIZE * 4) + \
|
||||
8 * PAGE_SIZE + OVERFLOW_BUFFER_SIZE + PAGE_SIZE)
|
||||
|
||||
#define EVENT_QUEUE_SIZE 16
|
||||
|
||||
/* Gathers the current state of a single channel. */
|
||||
|
||||
struct SBufferHeader {
|
||||
struct BUFFER_HEADER ngeneBuffer; /* Physical descriptor */
|
||||
struct SBufferHeader *Next;
|
||||
void *Buffer1;
|
||||
struct HW_SCATTER_GATHER_ELEMENT *scList1;
|
||||
void *Buffer2;
|
||||
struct HW_SCATTER_GATHER_ELEMENT *scList2;
|
||||
};
|
||||
|
||||
/* Sizeof SBufferHeader aligned to next 64 Bit boundary (hw restriction) */
|
||||
#define SIZEOF_SBufferHeader ((sizeof(struct SBufferHeader) + 63) & ~63)
|
||||
|
||||
enum HWSTATE {
|
||||
HWSTATE_STOP,
|
||||
HWSTATE_STARTUP,
|
||||
HWSTATE_RUN,
|
||||
HWSTATE_PAUSE,
|
||||
};
|
||||
|
||||
enum KSSTATE {
|
||||
KSSTATE_STOP,
|
||||
KSSTATE_ACQUIRE,
|
||||
KSSTATE_PAUSE,
|
||||
KSSTATE_RUN,
|
||||
};
|
||||
|
||||
struct SRingBufferDescriptor {
|
||||
struct SBufferHeader *Head; /* Points to first buffer in ring buffer
|
||||
structure*/
|
||||
u64 PAHead; /* Physical address of first buffer */
|
||||
u32 MemSize; /* Memory size of allocated ring buffers
|
||||
(needed for freeing) */
|
||||
u32 NumBuffers; /* Number of buffers in the ring */
|
||||
u32 Buffer1Length; /* Allocated length of Buffer 1 */
|
||||
u32 Buffer2Length; /* Allocated length of Buffer 2 */
|
||||
void *SCListMem; /* Memory to hold scatter gather lists for this
|
||||
ring */
|
||||
u64 PASCListMem; /* Physical address .. */
|
||||
u32 SCListMemSize; /* Size of this memory */
|
||||
};
|
||||
|
||||
enum STREAMMODEFLAGS {
|
||||
StreamMode_NONE = 0, /* Stream not used */
|
||||
StreamMode_ANALOG = 1, /* Analog: Stream 0,1 = Video, 2,3 = Audio */
|
||||
StreamMode_TSIN = 2, /* Transport stream input (all) */
|
||||
StreamMode_HDTV = 4, /* HDTV: Maximum 1920x1080p30,1920x1080i60
|
||||
(only stream 0) */
|
||||
StreamMode_TSOUT = 8, /* Transport stream output (only stream 3) */
|
||||
};
|
||||
|
||||
|
||||
enum BufferExchangeFlags {
|
||||
BEF_EVEN_FIELD = 0x00000001,
|
||||
BEF_CONTINUATION = 0x00000002,
|
||||
BEF_MORE_DATA = 0x00000004,
|
||||
BEF_OVERFLOW = 0x00000008,
|
||||
DF_SWAP32 = 0x00010000,
|
||||
};
|
||||
|
||||
typedef void *(IBufferExchange)(void *, void *, u32, u32, u32);
|
||||
|
||||
struct MICI_STREAMINFO {
|
||||
IBufferExchange *pExchange;
|
||||
IBufferExchange *pExchangeVBI; /* Secondary (VBI, ancillary) */
|
||||
u8 Stream;
|
||||
u8 Flags;
|
||||
u8 Mode;
|
||||
u8 Reserved;
|
||||
u16 nLinesVideo;
|
||||
u16 nBytesPerLineVideo;
|
||||
u16 nLinesVBI;
|
||||
u16 nBytesPerLineVBI;
|
||||
u32 CaptureLength; /* Used for audio and transport stream */
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
/* STRUCTS ******************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
/* sound hardware definition */
|
||||
#define MIXER_ADDR_TVTUNER 0
|
||||
#define MIXER_ADDR_LAST 0
|
||||
|
||||
struct ngene_channel;
|
||||
|
||||
/*struct sound chip*/
|
||||
|
||||
struct mychip {
|
||||
struct ngene_channel *chan;
|
||||
struct snd_card *card;
|
||||
struct pci_dev *pci;
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_pcm *pcm;
|
||||
unsigned long port;
|
||||
int irq;
|
||||
spinlock_t mixer_lock;
|
||||
spinlock_t lock;
|
||||
int mixer_volume[MIXER_ADDR_LAST + 1][2];
|
||||
int capture_source[MIXER_ADDR_LAST + 1][2];
|
||||
};
|
||||
|
||||
#ifdef NGENE_V4L
|
||||
struct ngene_overlay {
|
||||
int tvnorm;
|
||||
struct v4l2_rect w;
|
||||
enum v4l2_field field;
|
||||
struct v4l2_clip *clips;
|
||||
int nclips;
|
||||
int setup_ok;
|
||||
};
|
||||
|
||||
struct ngene_tvnorm {
|
||||
int v4l2_id;
|
||||
char *name;
|
||||
u16 swidth, sheight; /* scaled standard width, height */
|
||||
int tuner_norm;
|
||||
int soundstd;
|
||||
};
|
||||
|
||||
struct ngene_vopen {
|
||||
struct ngene_channel *ch;
|
||||
enum v4l2_priority prio;
|
||||
int width;
|
||||
int height;
|
||||
int depth;
|
||||
struct videobuf_queue vbuf_q;
|
||||
struct videobuf_queue vbi;
|
||||
int fourcc;
|
||||
int picxcount;
|
||||
int resources;
|
||||
enum v4l2_buf_type type;
|
||||
const struct ngene_format *fmt;
|
||||
|
||||
const struct ngene_format *ovfmt;
|
||||
struct ngene_overlay ov;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct ngene_channel {
|
||||
struct device device;
|
||||
struct i2c_adapter i2c_adapter;
|
||||
|
||||
struct ngene *dev;
|
||||
int number;
|
||||
int type;
|
||||
int mode;
|
||||
|
||||
struct dvb_frontend *fe;
|
||||
struct dmxdev dmxdev;
|
||||
struct dvb_demux demux;
|
||||
struct dmx_frontend hw_frontend;
|
||||
struct dmx_frontend mem_frontend;
|
||||
int users;
|
||||
struct video_device *v4l_dev;
|
||||
struct tasklet_struct demux_tasklet;
|
||||
|
||||
struct SBufferHeader *nextBuffer;
|
||||
enum KSSTATE State;
|
||||
enum HWSTATE HWState;
|
||||
u8 Stream;
|
||||
u8 Flags;
|
||||
u8 Mode;
|
||||
IBufferExchange *pBufferExchange;
|
||||
IBufferExchange *pBufferExchange2;
|
||||
|
||||
spinlock_t state_lock;
|
||||
u16 nLines;
|
||||
u16 nBytesPerLine;
|
||||
u16 nVBILines;
|
||||
u16 nBytesPerVBILine;
|
||||
u16 itumode;
|
||||
u32 Capture1Length;
|
||||
u32 Capture2Length;
|
||||
struct SRingBufferDescriptor RingBuffer;
|
||||
struct SRingBufferDescriptor TSRingBuffer;
|
||||
struct SRingBufferDescriptor TSIdleBuffer;
|
||||
|
||||
u32 DataFormatFlags;
|
||||
|
||||
int AudioDTOUpdated;
|
||||
u32 AudioDTOValue;
|
||||
|
||||
int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t);
|
||||
u8 lnbh;
|
||||
|
||||
/* stuff from analog driver */
|
||||
|
||||
int minor;
|
||||
struct mychip *mychip;
|
||||
struct snd_card *soundcard;
|
||||
u8 *evenbuffer;
|
||||
u8 dma_on;
|
||||
int soundstreamon;
|
||||
int audiomute;
|
||||
int soundbuffisallocated;
|
||||
int sndbuffflag;
|
||||
int tun_rdy;
|
||||
int dec_rdy;
|
||||
int tun_dec_rdy;
|
||||
int lastbufferflag;
|
||||
|
||||
struct ngene_tvnorm *tvnorms;
|
||||
int tvnorm_num;
|
||||
int tvnorm;
|
||||
|
||||
#ifdef NGENE_V4L
|
||||
int videousers;
|
||||
struct v4l2_prio_state prio;
|
||||
struct ngene_vopen init;
|
||||
int resources;
|
||||
struct v4l2_framebuffer fbuf;
|
||||
struct ngene_buffer *screen; /* overlay */
|
||||
struct list_head capture; /* video capture queue */
|
||||
spinlock_t s_lock;
|
||||
struct semaphore reslock;
|
||||
#endif
|
||||
|
||||
int running;
|
||||
};
|
||||
|
||||
struct ngene;
|
||||
|
||||
typedef void (rx_cb_t)(struct ngene *, u32, u8);
|
||||
typedef void (tx_cb_t)(struct ngene *, u32);
|
||||
|
||||
struct ngene {
|
||||
int nr;
|
||||
struct pci_dev *pci_dev;
|
||||
unsigned char *iomem;
|
||||
|
||||
/*struct i2c_adapter i2c_adapter;*/
|
||||
|
||||
u32 device_version;
|
||||
u32 fw_interface_version;
|
||||
u32 icounts;
|
||||
|
||||
u8 *CmdDoneByte;
|
||||
int BootFirmware;
|
||||
void *OverflowBuffer;
|
||||
dma_addr_t PAOverflowBuffer;
|
||||
void *FWInterfaceBuffer;
|
||||
dma_addr_t PAFWInterfaceBuffer;
|
||||
u8 *ngenetohost;
|
||||
u8 *hosttongene;
|
||||
|
||||
struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE];
|
||||
int EventQueueOverflowCount;
|
||||
int EventQueueOverflowFlag;
|
||||
struct tasklet_struct event_tasklet;
|
||||
struct EVENT_BUFFER *EventBuffer;
|
||||
int EventQueueWriteIndex;
|
||||
int EventQueueReadIndex;
|
||||
|
||||
wait_queue_head_t cmd_wq;
|
||||
int cmd_done;
|
||||
struct semaphore cmd_mutex;
|
||||
struct semaphore stream_mutex;
|
||||
struct semaphore pll_mutex;
|
||||
struct semaphore i2c_switch_mutex;
|
||||
int i2c_current_channel;
|
||||
int i2c_current_bus;
|
||||
spinlock_t cmd_lock;
|
||||
|
||||
struct dvb_adapter adapter[MAX_STREAM];
|
||||
struct ngene_channel channel[MAX_STREAM];
|
||||
|
||||
struct ngene_info *card_info;
|
||||
|
||||
tx_cb_t *TxEventNotify;
|
||||
rx_cb_t *RxEventNotify;
|
||||
int tx_busy;
|
||||
wait_queue_head_t tx_wq;
|
||||
wait_queue_head_t rx_wq;
|
||||
#define UART_RBUF_LEN 4096
|
||||
u8 uart_rbuf[UART_RBUF_LEN];
|
||||
int uart_rp, uart_wp;
|
||||
|
||||
u8 *tsout_buf;
|
||||
#define TSOUT_BUF_SIZE (512*188*8)
|
||||
struct dvb_ringbuffer tsout_rbuf;
|
||||
|
||||
u8 *ain_buf;
|
||||
#define AIN_BUF_SIZE (128*1024)
|
||||
struct dvb_ringbuffer ain_rbuf;
|
||||
|
||||
|
||||
u8 *vin_buf;
|
||||
#define VIN_BUF_SIZE (4*1920*1080)
|
||||
struct dvb_ringbuffer vin_rbuf;
|
||||
|
||||
unsigned long exp_val;
|
||||
int prev_cmd;
|
||||
};
|
||||
|
||||
struct ngene_info {
|
||||
int type;
|
||||
#define NGENE_APP 0
|
||||
#define NGENE_TERRATEC 1
|
||||
#define NGENE_SIDEWINDER 2
|
||||
#define NGENE_RACER 3
|
||||
#define NGENE_VIPER 4
|
||||
#define NGENE_PYTHON 5
|
||||
#define NGENE_VBOX_V1 6
|
||||
#define NGENE_VBOX_V2 7
|
||||
|
||||
int fw_version;
|
||||
char *name;
|
||||
|
||||
int io_type[MAX_STREAM];
|
||||
#define NGENE_IO_NONE 0
|
||||
#define NGENE_IO_TV 1
|
||||
#define NGENE_IO_HDTV 2
|
||||
#define NGENE_IO_TSIN 4
|
||||
#define NGENE_IO_TSOUT 8
|
||||
#define NGENE_IO_AIN 16
|
||||
|
||||
void *fe_config[4];
|
||||
void *tuner_config[4];
|
||||
|
||||
int (*demod_attach[4])(struct ngene_channel *);
|
||||
int (*tuner_attach[4])(struct ngene_channel *);
|
||||
|
||||
u8 avf[4];
|
||||
u8 msp[4];
|
||||
u8 demoda[4];
|
||||
u8 lnb[4];
|
||||
int i2c_access;
|
||||
u8 ntsc;
|
||||
u8 tsf[4];
|
||||
u8 i2s[4];
|
||||
|
||||
int (*gate_ctrl)(struct dvb_frontend *, int);
|
||||
int (*switch_ctrl)(struct ngene_channel *, int, int);
|
||||
};
|
||||
|
||||
#ifdef NGENE_V4L
|
||||
struct ngene_format{
|
||||
char *name;
|
||||
int fourcc; /* video4linux 2 */
|
||||
int btformat; /* BT848_COLOR_FMT_* */
|
||||
int format;
|
||||
int btswap; /* BT848_COLOR_CTL_* */
|
||||
int depth; /* bit/pixel */
|
||||
int flags;
|
||||
int hshift, vshift; /* for planar modes */
|
||||
int palette;
|
||||
};
|
||||
|
||||
#define RESOURCE_OVERLAY 1
|
||||
#define RESOURCE_VIDEO 2
|
||||
#define RESOURCE_VBI 4
|
||||
|
||||
struct ngene_buffer {
|
||||
/* common v4l buffer stuff -- must be first */
|
||||
struct videobuf_buffer vb;
|
||||
|
||||
/* ngene specific */
|
||||
const struct ngene_format *fmt;
|
||||
int tvnorm;
|
||||
int btformat;
|
||||
int btswap;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* LocalWords: Endif
|
||||
*/
|
|
@ -62,6 +62,7 @@ static struct sms_board sms_boards[] = {
|
|||
[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
|
||||
.name = "Hauppauge WinTV MiniStick",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
|
||||
.board_cfg.leds_power = 26,
|
||||
.board_cfg.led0 = 27,
|
||||
|
|
|
@ -1459,8 +1459,10 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
|
|||
if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
|
||||
pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
|
||||
if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
|
||||
&groupCfg) != 0)
|
||||
return -EINVAL;
|
||||
&groupCfg) != 0) {
|
||||
rc = -EINVAL;
|
||||
goto free;
|
||||
}
|
||||
|
||||
pMsg->msgData[1] = TranslatedPinNum;
|
||||
pMsg->msgData[2] = GroupNum;
|
||||
|
@ -1490,6 +1492,7 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
|
|||
else
|
||||
sms_err("smscore_gpio_configure error");
|
||||
}
|
||||
free:
|
||||
kfree(buffer);
|
||||
|
||||
return rc;
|
||||
|
|
|
@ -212,6 +212,8 @@ struct smscore_device_t {
|
|||
#define MSG_SMS_DAB_CHANNEL 607
|
||||
#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608
|
||||
#define MSG_SMS_GET_PID_FILTER_LIST_RES 609
|
||||
#define MSG_SMS_GET_STATISTICS_RES 616
|
||||
#define MSG_SMS_GET_STATISTICS_REQ 615
|
||||
#define MSG_SMS_HO_PER_SLICES_IND 630
|
||||
#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651
|
||||
#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652
|
||||
|
@ -339,7 +341,7 @@ struct SmsFirmware_ST {
|
|||
|
||||
/* Statistics information returned as response for
|
||||
* SmsHostApiGetStatistics_Req */
|
||||
struct SMSHOSTLIB_STATISTICS_S {
|
||||
struct SMSHOSTLIB_STATISTICS_ST {
|
||||
u32 Reserved; /* Reserved */
|
||||
|
||||
/* Common parameters */
|
||||
|
@ -424,6 +426,79 @@ struct SMSHOSTLIB_STATISTICS_S {
|
|||
u32 ReservedFields[10]; /* Reserved */
|
||||
};
|
||||
|
||||
struct SmsMsgStatisticsInfo_ST {
|
||||
u32 RequestResult;
|
||||
|
||||
struct SMSHOSTLIB_STATISTICS_ST Stat;
|
||||
|
||||
/* Split the calc of the SNR in DAB */
|
||||
u32 Signal; /* dB */
|
||||
u32 Noise; /* dB */
|
||||
|
||||
};
|
||||
|
||||
struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST {
|
||||
/* Per-layer information */
|
||||
u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
|
||||
* 255 means layer does not exist */
|
||||
u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET,
|
||||
* 255 means layer does not exist */
|
||||
u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
|
||||
u32 BERErrorCount; /* Post Viterbi Error Bits Count */
|
||||
u32 BERBitCount; /* Post Viterbi Total Bits Count */
|
||||
u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
|
||||
u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */
|
||||
u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
|
||||
u32 TotalTSPackets; /* Total number of transport-stream packets */
|
||||
u32 TILdepthI; /* Time interleaver depth I parameter,
|
||||
* 255 means layer does not exist */
|
||||
u32 NumberOfSegments; /* Number of segments in layer A,
|
||||
* 255 means layer does not exist */
|
||||
u32 TMCCErrors; /* TMCC errors */
|
||||
};
|
||||
|
||||
struct SMSHOSTLIB_STATISTICS_ISDBT_ST {
|
||||
u32 StatisticsType; /* Enumerator identifying the type of the
|
||||
* structure. Values are the same as
|
||||
* SMSHOSTLIB_DEVICE_MODES_E
|
||||
*
|
||||
* This field MUST always be first in any
|
||||
* statistics structure */
|
||||
|
||||
u32 FullSize; /* Total size of the structure returned by the modem.
|
||||
* If the size requested by the host is smaller than
|
||||
* FullSize, the struct will be truncated */
|
||||
|
||||
/* Common parameters */
|
||||
u32 IsRfLocked; /* 0 - not locked, 1 - locked */
|
||||
u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
|
||||
u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
|
||||
|
||||
/* Reception quality */
|
||||
s32 SNR; /* dB */
|
||||
s32 RSSI; /* dBm */
|
||||
s32 InBandPwr; /* In band power in dBM */
|
||||
s32 CarrierOffset; /* Carrier Offset in Hz */
|
||||
|
||||
/* Transmission parameters */
|
||||
u32 Frequency; /* Frequency in Hz */
|
||||
u32 Bandwidth; /* Bandwidth in MHz */
|
||||
u32 TransmissionMode; /* ISDB-T transmission mode */
|
||||
u32 ModemState; /* 0 - Acquisition, 1 - Locked */
|
||||
u32 GuardInterval; /* Guard Interval, 1 divided by value */
|
||||
u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
|
||||
u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */
|
||||
u32 NumOfLayers; /* Number of ISDB-T layers in the network */
|
||||
|
||||
/* Per-layer information */
|
||||
/* Layers A, B and C */
|
||||
struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3];
|
||||
/* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */
|
||||
|
||||
/* Interface information */
|
||||
u32 SmsToHostTxErrors; /* Total number of transmission errors. */
|
||||
};
|
||||
|
||||
struct PID_STATISTICS_DATA_S {
|
||||
struct PID_BURST_S {
|
||||
u32 size;
|
||||
|
|
|
@ -116,6 +116,118 @@ static void sms_board_dvb3_event(struct smsdvb_client_t *client,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
|
||||
struct SMSHOSTLIB_STATISTICS_ST *p)
|
||||
{
|
||||
if (sms_dbg & 2) {
|
||||
printk(KERN_DEBUG "Reserved = %d", p->Reserved);
|
||||
printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
|
||||
printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
|
||||
printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
|
||||
printk(KERN_DEBUG "SNR = %d", p->SNR);
|
||||
printk(KERN_DEBUG "BER = %d", p->BER);
|
||||
printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
|
||||
printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
|
||||
printk(KERN_DEBUG "MFER = %d", p->MFER);
|
||||
printk(KERN_DEBUG "RSSI = %d", p->RSSI);
|
||||
printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
|
||||
printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
|
||||
printk(KERN_DEBUG "Frequency = %d", p->Frequency);
|
||||
printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
|
||||
printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
|
||||
printk(KERN_DEBUG "ModemState = %d", p->ModemState);
|
||||
printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
|
||||
printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
|
||||
printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
|
||||
printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
|
||||
printk(KERN_DEBUG "Constellation = %d", p->Constellation);
|
||||
printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
|
||||
printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
|
||||
printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
|
||||
printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
|
||||
printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
|
||||
printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
|
||||
printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
|
||||
printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
|
||||
printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
|
||||
printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
|
||||
printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
|
||||
printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
|
||||
printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
|
||||
printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
|
||||
printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
|
||||
printk(KERN_DEBUG "PreBER = %d", p->PreBER);
|
||||
printk(KERN_DEBUG "CellId = %d", p->CellId);
|
||||
printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
|
||||
printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
|
||||
printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
|
||||
}
|
||||
|
||||
pReceptionData->IsDemodLocked = p->IsDemodLocked;
|
||||
|
||||
pReceptionData->SNR = p->SNR;
|
||||
pReceptionData->BER = p->BER;
|
||||
pReceptionData->BERErrorCount = p->BERErrorCount;
|
||||
pReceptionData->InBandPwr = p->InBandPwr;
|
||||
pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
|
||||
};
|
||||
|
||||
|
||||
static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
|
||||
struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (sms_dbg & 2) {
|
||||
printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
|
||||
printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
|
||||
printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
|
||||
printk(KERN_DEBUG "SNR = %d", p->SNR);
|
||||
printk(KERN_DEBUG "RSSI = %d", p->RSSI);
|
||||
printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
|
||||
printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
|
||||
printk(KERN_DEBUG "Frequency = %d", p->Frequency);
|
||||
printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
|
||||
printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
|
||||
printk(KERN_DEBUG "ModemState = %d", p->ModemState);
|
||||
printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
|
||||
printk(KERN_DEBUG "SystemType = %d", p->SystemType);
|
||||
printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
|
||||
printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
|
||||
printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
|
||||
printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
|
||||
printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
|
||||
printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
|
||||
printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
|
||||
printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
|
||||
printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
|
||||
printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
|
||||
printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
|
||||
printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
|
||||
printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
|
||||
printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
|
||||
}
|
||||
}
|
||||
|
||||
pReceptionData->IsDemodLocked = p->IsDemodLocked;
|
||||
|
||||
pReceptionData->SNR = p->SNR;
|
||||
pReceptionData->InBandPwr = p->InBandPwr;
|
||||
|
||||
pReceptionData->ErrorTSPackets = 0;
|
||||
pReceptionData->BER = 0;
|
||||
pReceptionData->BERErrorCount = 0;
|
||||
for (i = 0; i < 3; i++) {
|
||||
pReceptionData->BER += p->LayerInfo[i].BER;
|
||||
pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
|
||||
pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
|
||||
}
|
||||
}
|
||||
|
||||
static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
|
||||
{
|
||||
struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
|
||||
|
@ -134,6 +246,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
|
|||
break;
|
||||
|
||||
case MSG_SMS_RF_TUNE_RES:
|
||||
case MSG_SMS_ISDBT_TUNE_RES:
|
||||
complete(&client->tune_done);
|
||||
break;
|
||||
|
||||
|
@ -217,6 +330,40 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
|
|||
is_status_update = true;
|
||||
break;
|
||||
}
|
||||
case MSG_SMS_GET_STATISTICS_RES: {
|
||||
union {
|
||||
struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt;
|
||||
struct SmsMsgStatisticsInfo_ST dvb;
|
||||
} *p = (void *) (phdr + 1);
|
||||
struct RECEPTION_STATISTICS_S *pReceptionData =
|
||||
&client->sms_stat_dvb.ReceptionData;
|
||||
|
||||
sms_info("MSG_SMS_GET_STATISTICS_RES");
|
||||
|
||||
is_status_update = true;
|
||||
|
||||
switch (smscore_get_device_mode(client->coredev)) {
|
||||
case DEVICE_MODE_ISDBT:
|
||||
case DEVICE_MODE_ISDBT_BDA:
|
||||
smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
|
||||
break;
|
||||
default:
|
||||
smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
|
||||
}
|
||||
if (!pReceptionData->IsDemodLocked) {
|
||||
pReceptionData->SNR = 0;
|
||||
pReceptionData->BER = 0;
|
||||
pReceptionData->BERErrorCount = 0;
|
||||
pReceptionData->InBandPwr = 0;
|
||||
pReceptionData->ErrorTSPackets = 0;
|
||||
}
|
||||
|
||||
complete(&client->tune_done);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sms_info("Unhandled message %d", phdr->msgType);
|
||||
|
||||
}
|
||||
smscore_putbuffer(client->coredev, cb);
|
||||
|
||||
|
@ -233,10 +380,10 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
|
|||
DVB3_EVENT_UNC_ERR);
|
||||
|
||||
} else {
|
||||
/*client->fe_status =
|
||||
(phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ?
|
||||
0 : FE_HAS_SIGNAL;*/
|
||||
client->fe_status = 0;
|
||||
if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
|
||||
client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
|
||||
else
|
||||
client->fe_status = 0;
|
||||
sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
|
||||
}
|
||||
}
|
||||
|
@ -325,6 +472,20 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
|
|||
0 : -ETIME;
|
||||
}
|
||||
|
||||
static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
|
||||
{
|
||||
int rc;
|
||||
struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
|
||||
DVBT_BDA_CONTROL_MSG_ID,
|
||||
HIF_TASK,
|
||||
sizeof(struct SmsMsgHdr_ST), 0 };
|
||||
|
||||
rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
|
||||
&client->tune_done);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int led_feedback(struct smsdvb_client_t *client)
|
||||
{
|
||||
if (client->fe_status & FE_HAS_LOCK)
|
||||
|
@ -337,33 +498,43 @@ static inline int led_feedback(struct smsdvb_client_t *client)
|
|||
|
||||
static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
|
||||
{
|
||||
int rc;
|
||||
struct smsdvb_client_t *client;
|
||||
client = container_of(fe, struct smsdvb_client_t, frontend);
|
||||
|
||||
rc = smsdvb_send_statistics_request(client);
|
||||
|
||||
*stat = client->fe_status;
|
||||
|
||||
led_feedback(client);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
int rc;
|
||||
struct smsdvb_client_t *client;
|
||||
client = container_of(fe, struct smsdvb_client_t, frontend);
|
||||
|
||||
rc = smsdvb_send_statistics_request(client);
|
||||
|
||||
*ber = client->sms_stat_dvb.ReceptionData.BER;
|
||||
|
||||
led_feedback(client);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
{
|
||||
int rc;
|
||||
|
||||
struct smsdvb_client_t *client;
|
||||
client = container_of(fe, struct smsdvb_client_t, frontend);
|
||||
|
||||
rc = smsdvb_send_statistics_request(client);
|
||||
|
||||
if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
|
||||
*strength = 0;
|
||||
else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
|
||||
|
@ -375,31 +546,37 @@ static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
|||
|
||||
led_feedback(client);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
int rc;
|
||||
struct smsdvb_client_t *client;
|
||||
client = container_of(fe, struct smsdvb_client_t, frontend);
|
||||
|
||||
rc = smsdvb_send_statistics_request(client);
|
||||
|
||||
*snr = client->sms_stat_dvb.ReceptionData.SNR;
|
||||
|
||||
led_feedback(client);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
int rc;
|
||||
struct smsdvb_client_t *client;
|
||||
client = container_of(fe, struct smsdvb_client_t, frontend);
|
||||
|
||||
rc = smsdvb_send_statistics_request(client);
|
||||
|
||||
*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
|
||||
|
||||
led_feedback(client);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
|
||||
|
@ -413,9 +590,10 @@ static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int smsdvb_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
|
||||
|
@ -429,24 +607,33 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
|
|||
client->fe_status = FE_HAS_SIGNAL;
|
||||
client->event_fe_state = -1;
|
||||
client->event_unc_state = -1;
|
||||
fe->dtv_property_cache.delivery_system = SYS_DVBT;
|
||||
|
||||
Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
|
||||
Msg.Msg.msgDstId = HIF_TASK;
|
||||
Msg.Msg.msgFlags = 0;
|
||||
Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
|
||||
Msg.Msg.msgLength = sizeof(Msg);
|
||||
Msg.Data[0] = fep->frequency;
|
||||
Msg.Data[0] = c->frequency;
|
||||
Msg.Data[2] = 12000000;
|
||||
|
||||
sms_debug("freq %d band %d",
|
||||
fep->frequency, fep->u.ofdm.bandwidth);
|
||||
sms_info("%s: freq %d band %d", __func__, c->frequency,
|
||||
c->bandwidth_hz);
|
||||
|
||||
switch (fep->u.ofdm.bandwidth) {
|
||||
case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break;
|
||||
case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break;
|
||||
case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break;
|
||||
case BANDWIDTH_AUTO: return -EOPNOTSUPP;
|
||||
default: return -EINVAL;
|
||||
switch (c->bandwidth_hz / 1000000) {
|
||||
case 8:
|
||||
Msg.Data[1] = BW_8_MHZ;
|
||||
break;
|
||||
case 7:
|
||||
Msg.Data[1] = BW_7_MHZ;
|
||||
break;
|
||||
case 6:
|
||||
Msg.Data[1] = BW_6_MHZ;
|
||||
break;
|
||||
case 0:
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Disable LNA, if any. An error is returned if no LNA is present */
|
||||
ret = sms_board_lna_control(client->coredev, 0);
|
||||
|
@ -470,6 +657,90 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
|
|||
&client->tune_done);
|
||||
}
|
||||
|
||||
static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
|
||||
struct {
|
||||
struct SmsMsgHdr_ST Msg;
|
||||
u32 Data[4];
|
||||
} Msg;
|
||||
|
||||
fe->dtv_property_cache.delivery_system = SYS_ISDBT;
|
||||
|
||||
Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
|
||||
Msg.Msg.msgDstId = HIF_TASK;
|
||||
Msg.Msg.msgFlags = 0;
|
||||
Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
|
||||
Msg.Msg.msgLength = sizeof(Msg);
|
||||
|
||||
if (c->isdbt_sb_segment_idx == -1)
|
||||
c->isdbt_sb_segment_idx = 0;
|
||||
|
||||
switch (c->isdbt_sb_segment_count) {
|
||||
case 3:
|
||||
Msg.Data[1] = BW_ISDBT_3SEG;
|
||||
break;
|
||||
case 1:
|
||||
Msg.Data[1] = BW_ISDBT_1SEG;
|
||||
break;
|
||||
case 0: /* AUTO */
|
||||
switch (c->bandwidth_hz / 1000000) {
|
||||
case 8:
|
||||
case 7:
|
||||
c->isdbt_sb_segment_count = 3;
|
||||
Msg.Data[1] = BW_ISDBT_3SEG;
|
||||
break;
|
||||
case 6:
|
||||
c->isdbt_sb_segment_count = 1;
|
||||
Msg.Data[1] = BW_ISDBT_1SEG;
|
||||
break;
|
||||
default: /* Assumes 6 MHZ bw */
|
||||
c->isdbt_sb_segment_count = 1;
|
||||
c->bandwidth_hz = 6000;
|
||||
Msg.Data[1] = BW_ISDBT_1SEG;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
Msg.Data[0] = c->frequency;
|
||||
Msg.Data[2] = 12000000;
|
||||
Msg.Data[3] = c->isdbt_sb_segment_idx;
|
||||
|
||||
sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
|
||||
c->frequency, c->isdbt_sb_segment_count,
|
||||
c->isdbt_sb_segment_idx);
|
||||
|
||||
return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
|
||||
&client->tune_done);
|
||||
}
|
||||
|
||||
static int smsdvb_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
struct smscore_device_t *coredev = client->coredev;
|
||||
|
||||
switch (smscore_get_device_mode(coredev)) {
|
||||
case DEVICE_MODE_DVBT:
|
||||
case DEVICE_MODE_DVBT_BDA:
|
||||
return smsdvb_dvbt_set_frontend(fe, fep);
|
||||
case DEVICE_MODE_ISDBT:
|
||||
case DEVICE_MODE_ISDBT_BDA:
|
||||
return smsdvb_isdbt_set_frontend(fe, fep);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int smsdvb_get_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
|
@ -557,13 +828,6 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
|
|||
/* device removal handled by onremove callback */
|
||||
if (!arrival)
|
||||
return 0;
|
||||
|
||||
if (smscore_get_device_mode(coredev) != DEVICE_MODE_DVBT_BDA) {
|
||||
sms_err("SMS Device mode is not set for "
|
||||
"DVB operation.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
|
||||
if (!client) {
|
||||
sms_err("kmalloc() failed");
|
||||
|
|
|
@ -85,9 +85,9 @@ static struct keyboard_layout_map_t keyboard_layout_maps[] = {
|
|||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
u32 ir_pos;
|
||||
u32 ir_word;
|
||||
u32 ir_toggle;
|
||||
static u32 ir_pos;
|
||||
static u32 ir_word;
|
||||
static u32 ir_toggle;
|
||||
|
||||
#define RC5_PUSH_BIT(dst, bit, pos) \
|
||||
{ dst <<= 1; dst |= bit; pos++; }
|
||||
|
|
|
@ -268,8 +268,8 @@ int av7110_check_ir_config(struct av7110 *av7110, int force)
|
|||
|
||||
|
||||
/* /proc/av7110_ir interface */
|
||||
static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer,
|
||||
size_t count, loff_t *pos)
|
||||
{
|
||||
char *page;
|
||||
u32 ir_config;
|
||||
|
@ -309,6 +309,10 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
|
|||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations av7110_ir_proc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.write = av7110_ir_proc_write,
|
||||
};
|
||||
|
||||
/* interrupt handler */
|
||||
static void ir_handler(struct av7110 *av7110, u32 ircom)
|
||||
|
@ -368,11 +372,9 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
|
|||
input_dev->timer.data = (unsigned long) &av7110->ir;
|
||||
|
||||
if (av_cnt == 1) {
|
||||
e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL);
|
||||
if (e) {
|
||||
e->write_proc = av7110_ir_write_proc;
|
||||
e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops);
|
||||
if (e)
|
||||
e->size = 4 + 256 * sizeof(u16);
|
||||
}
|
||||
}
|
||||
|
||||
tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir);
|
||||
|
|
|
@ -254,7 +254,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
|||
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 = ir_input_register(input_dev, ir_codes);
|
||||
error = ir_input_register(input_dev, ir_codes, NULL);
|
||||
if (error) {
|
||||
printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
|
||||
return error;
|
||||
|
|
|
@ -433,9 +433,8 @@ static struct stv090x_config tt1600_stv090x_config = {
|
|||
.demod_mode = STV090x_SINGLE,
|
||||
.clk_mode = STV090x_CLK_EXT,
|
||||
|
||||
.xtal = 27000000,
|
||||
.xtal = 13500000,
|
||||
.address = 0x68,
|
||||
.ref_clk = 27000000,
|
||||
|
||||
.ts1_mode = STV090x_TSMODE_DVBCI,
|
||||
.ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS,
|
||||
|
@ -457,6 +456,7 @@ static struct stv090x_config tt1600_stv090x_config = {
|
|||
static struct stv6110x_config tt1600_stv6110x_config = {
|
||||
.addr = 0x60,
|
||||
.refclk = 27000000,
|
||||
.clk_div = 2,
|
||||
};
|
||||
|
||||
static struct isl6423_config tt1600_isl6423_config = {
|
||||
|
|
|
@ -417,6 +417,18 @@ config RADIO_TEA5764_XTAL
|
|||
Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N
|
||||
here if TEA5764 reference frequency is connected in FREQIN.
|
||||
|
||||
config RADIO_SAA7706H
|
||||
tristate "SAA7706H Car Radio DSP"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
---help---
|
||||
Say Y here if you want to use the SAA7706H Car radio Digital
|
||||
Signal Processor, found for instance on the Russellville development
|
||||
board. On the russellville the device is connected to internal
|
||||
timberdale I2C bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called SAA7706H.
|
||||
|
||||
config RADIO_TEF6862
|
||||
tristate "TEF6862 Car Radio Enhanced Selectivity Tuner"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
|
@ -429,4 +441,15 @@ config RADIO_TEF6862
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called TEF6862.
|
||||
|
||||
config RADIO_TIMBERDALE
|
||||
tristate "Enable the Timberdale radio driver"
|
||||
depends on MFD_TIMBERDALE && VIDEO_V4L2
|
||||
depends on I2C # for RADIO_SAA7706H
|
||||
select RADIO_TEF6862
|
||||
select RADIO_SAA7706H
|
||||
---help---
|
||||
This is a kind of umbrella driver for the Radio Tuner and DSP
|
||||
found behind the Timberdale FPGA on the Russellville board.
|
||||
Enabling this driver will automatically select the DSP and tuner.
|
||||
|
||||
endif # RADIO_ADAPTERS
|
||||
|
|
|
@ -23,6 +23,8 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o
|
|||
obj-$(CONFIG_RADIO_SI470X) += si470x/
|
||||
obj-$(CONFIG_USB_MR800) += radio-mr800.o
|
||||
obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
|
||||
obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
|
||||
obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
|
||||
obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
|
||||
|
||||
EXTRA_CFLAGS += -Isound
|
||||
|
|
244
drivers/media/radio/radio-timb.c
Normal file
244
drivers/media/radio/radio-timb.c
Normal file
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* radio-timb.c Timberdale FPGA Radio driver
|
||||
* Copyright (c) 2009 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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/version.h>
|
||||
#include <linux/io.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <media/timb_radio.h>
|
||||
|
||||
#define DRIVER_NAME "timb-radio"
|
||||
|
||||
struct timbradio {
|
||||
struct timb_radio_platform_data pdata;
|
||||
struct v4l2_subdev *sd_tuner;
|
||||
struct v4l2_subdev *sd_dsp;
|
||||
struct video_device video_dev;
|
||||
struct v4l2_device v4l2_dev;
|
||||
};
|
||||
|
||||
|
||||
static int timbradio_vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver));
|
||||
strlcpy(v->card, "Timberdale Radio", sizeof(v->card));
|
||||
snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME);
|
||||
v->version = KERNEL_VERSION(0, 0, 1);
|
||||
v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int timbradio_vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct timbradio *tr = video_drvdata(file);
|
||||
return v4l2_subdev_call(tr->sd_tuner, tuner, g_tuner, v);
|
||||
}
|
||||
|
||||
static int timbradio_vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct timbradio *tr = video_drvdata(file);
|
||||
return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v);
|
||||
}
|
||||
|
||||
static int timbradio_vidioc_g_input(struct file *filp, void *priv,
|
||||
unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int timbradio_vidioc_s_input(struct file *filp, void *priv,
|
||||
unsigned int i)
|
||||
{
|
||||
return i ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static int timbradio_vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
a->index = 0;
|
||||
strlcpy(a->name, "Radio", sizeof(a->name));
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int timbradio_vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
return a->index ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static int timbradio_vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct timbradio *tr = video_drvdata(file);
|
||||
return v4l2_subdev_call(tr->sd_tuner, tuner, s_frequency, f);
|
||||
}
|
||||
|
||||
static int timbradio_vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct timbradio *tr = video_drvdata(file);
|
||||
return v4l2_subdev_call(tr->sd_tuner, tuner, g_frequency, f);
|
||||
}
|
||||
|
||||
static int timbradio_vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
struct timbradio *tr = video_drvdata(file);
|
||||
return v4l2_subdev_call(tr->sd_dsp, core, queryctrl, qc);
|
||||
}
|
||||
|
||||
static int timbradio_vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct timbradio *tr = video_drvdata(file);
|
||||
return v4l2_subdev_call(tr->sd_dsp, core, g_ctrl, ctrl);
|
||||
}
|
||||
|
||||
static int timbradio_vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct timbradio *tr = video_drvdata(file);
|
||||
return v4l2_subdev_call(tr->sd_dsp, core, s_ctrl, ctrl);
|
||||
}
|
||||
|
||||
static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {
|
||||
.vidioc_querycap = timbradio_vidioc_querycap,
|
||||
.vidioc_g_tuner = timbradio_vidioc_g_tuner,
|
||||
.vidioc_s_tuner = timbradio_vidioc_s_tuner,
|
||||
.vidioc_g_frequency = timbradio_vidioc_g_frequency,
|
||||
.vidioc_s_frequency = timbradio_vidioc_s_frequency,
|
||||
.vidioc_g_input = timbradio_vidioc_g_input,
|
||||
.vidioc_s_input = timbradio_vidioc_s_input,
|
||||
.vidioc_g_audio = timbradio_vidioc_g_audio,
|
||||
.vidioc_s_audio = timbradio_vidioc_s_audio,
|
||||
.vidioc_queryctrl = timbradio_vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = timbradio_vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = timbradio_vidioc_s_ctrl
|
||||
};
|
||||
|
||||
static const struct v4l2_file_operations timbradio_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.ioctl = video_ioctl2,
|
||||
};
|
||||
|
||||
static int __devinit timbradio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct timb_radio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct timbradio *tr;
|
||||
int err;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "Platform data missing\n");
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
tr = kzalloc(sizeof(*tr), GFP_KERNEL);
|
||||
if (!tr) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
tr->pdata = *pdata;
|
||||
|
||||
strlcpy(tr->video_dev.name, "Timberdale Radio",
|
||||
sizeof(tr->video_dev.name));
|
||||
tr->video_dev.fops = &timbradio_fops;
|
||||
tr->video_dev.ioctl_ops = &timbradio_ioctl_ops;
|
||||
tr->video_dev.release = video_device_release_empty;
|
||||
tr->video_dev.minor = -1;
|
||||
|
||||
strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
|
||||
err = v4l2_device_register(NULL, &tr->v4l2_dev);
|
||||
if (err)
|
||||
goto err_v4l2_dev;
|
||||
|
||||
tr->video_dev.v4l2_dev = &tr->v4l2_dev;
|
||||
|
||||
err = video_register_device(&tr->video_dev, VFL_TYPE_RADIO, -1);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Error reg video\n");
|
||||
goto err_video_req;
|
||||
}
|
||||
|
||||
video_set_drvdata(&tr->video_dev, tr);
|
||||
|
||||
platform_set_drvdata(pdev, tr);
|
||||
return 0;
|
||||
|
||||
err_video_req:
|
||||
video_device_release_empty(&tr->video_dev);
|
||||
v4l2_device_unregister(&tr->v4l2_dev);
|
||||
err_v4l2_dev:
|
||||
kfree(tr);
|
||||
err:
|
||||
dev_err(&pdev->dev, "Failed to register: %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit timbradio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct timbradio *tr = platform_get_drvdata(pdev);
|
||||
|
||||
video_unregister_device(&tr->video_dev);
|
||||
video_device_release_empty(&tr->video_dev);
|
||||
|
||||
v4l2_device_unregister(&tr->v4l2_dev);
|
||||
|
||||
kfree(tr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver timbradio_platform_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = timbradio_probe,
|
||||
.remove = timbradio_remove,
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
static int __init timbradio_init(void)
|
||||
{
|
||||
return platform_driver_register(&timbradio_platform_driver);
|
||||
}
|
||||
|
||||
static void __exit timbradio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&timbradio_platform_driver);
|
||||
}
|
||||
|
||||
module_init(timbradio_init);
|
||||
module_exit(timbradio_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Timberdale Radio driver");
|
||||
MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:"DRIVER_NAME);
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue