1
0
Fork 0

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
  ...
hifive-unleashed-5.1
Linus Torvalds 2010-02-26 17:16:20 -08:00
commit 2b8c70b217
293 changed files with 27858 additions and 4784 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -35,8 +35,6 @@
#define PXA_CAMERA_VSP 0x400
struct pxacamera_platform_data {
int (*init)(struct device *);
unsigned long flags;
unsigned long mclk_10khz;
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,6 +14,7 @@ obj-y := dvb-core/ \
siano/ \
dm1105/ \
pt1/ \
mantis/
mantis/ \
ngene/
obj-$(CONFIG_DVB_FIREDTV) += firewire/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 = &params->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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,6 +26,7 @@
struct stv6110x_config {
u8 addr;
u32 refclk;
u8 clk_div; /* divisor value for the output clock */
};
enum tuner_mode {

View File

@ -68,6 +68,7 @@
struct stv6110x_state {
struct i2c_adapter *i2c;
const struct stv6110x_config *config;
u8 regs[8];
struct stv6110x_devctl *devctl;
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

File diff suppressed because it is too large Load Diff

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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