提交 6df419e4 编写于 作者: L Linus Torvalds

Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab:
 "This is the first part of the media patches for v3.6.

  This patch series contain:
   - new DVB frontend: rtl2832
   - new video drivers: adv7393
   - some unused files got removed
   - a selection API cleanup between V4L2 and V4L2 subdev API's
   - a major redesign at v4l-ioctl2, in order to clean it up
   - several driver fixes and improvements."

* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (174 commits)
  v4l: Export v4l2-common.h in include/linux/Kbuild
  media: Revert "[media] Terratec Cinergy S2 USB HD Rev.2"
  [media] media: Use pr_info not homegrown pr_reg macro
  [media] Terratec Cinergy S2 USB HD Rev.2
  [media] v4l: Correct conflicting V4L2 subdev selection API documentation
  [media] Feature removal: V4L2 selections API target and flag definitions
  [media] v4l: Unify selection flags documentation
  [media] v4l: Unify selection flags
  [media] v4l: Common documentation for selection targets
  [media] v4l: Unify selection targets across V4L2 and V4L2 subdev interfaces
  [media] v4l: Remove "_ACTUAL" from subdev selection API target definition names
  [media] V4L: Remove "_ACTIVE" from the selection target name definitions
  [media] media: dvb-usb: print mac address via native %pM
  [media] s5p-tv: Use module_i2c_driver in sii9234_drv.c file
  [media] media: gpio-ir-recv: add allowed_protos for platform data
  [media] s5p-jpeg: Use module_platform_driver in jpeg-core.c file
  [media] saa7134: fix spelling of detach in label
  [media] cx88-blackbird: replace ioctl by unlocked_ioctl
  [media] cx88: don't use current_norm
  [media] cx88: fix a number of v4l2-compliance violations
  ...
......@@ -194,7 +194,7 @@ in the frequency range from 87,5 to 108,0 MHz</title>
<corpauthor>National Radio Systems Committee
(<ulink url="http://www.nrscstandards.org">http://www.nrscstandards.org</ulink>)</corpauthor>
</authorgroup>
<title>NTSC-4: United States RBDS Standard</title>
<title>NRSC-4: United States RBDS Standard</title>
</biblioentry>
<biblioentry id="iso12232">
......
......@@ -464,14 +464,14 @@ The <structfield>type</structfield> field of the respective
<structfield>tuner</structfield> field contains the index number of
the tuner.</para>
<para>Radio devices have exactly one tuner with index zero, no
<para>Radio input devices have exactly one tuner with index zero, no
video inputs.</para>
<para>To query and change tuner properties applications use the
&VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; ioctl, respectively. The
&v4l2-tuner; returned by <constant>VIDIOC_G_TUNER</constant> also
contains signal status information applicable when the tuner of the
current video input, or a radio tuner is queried. Note that
current video or radio input is queried. Note that
<constant>VIDIOC_S_TUNER</constant> does not switch the current tuner,
when there is more than one at all. The tuner is solely determined by
the current video input. Drivers must support both ioctls and set the
......@@ -491,8 +491,17 @@ the modulator. The <structfield>type</structfield> field of the
respective &v4l2-output; returned by the &VIDIOC-ENUMOUTPUT; ioctl is
set to <constant>V4L2_OUTPUT_TYPE_MODULATOR</constant> and its
<structfield>modulator</structfield> field contains the index number
of the modulator. This specification does not define radio output
devices.</para>
of the modulator.</para>
<para>Radio output devices have exactly one modulator with index
zero, no video outputs.</para>
<para>A video or radio device cannot support both a tuner and a
modulator. Two separate device nodes will have to be used for such
hardware, one that supports the tuner functionality and one that supports
the modulator functionality. The reason is a limitation with the
&VIDIOC-S-FREQUENCY; ioctl where you cannot specify whether the frequency
is for a tuner or a modulator.</para>
<para>To query and change modulator properties applications use
the &VIDIOC-G-MODULATOR; and &VIDIOC-S-MODULATOR; ioctl. Note that
......
......@@ -2377,10 +2377,11 @@ that used it. It was originally scheduled for removal in 2.6.35.
<para>V4L2_CTRL_FLAG_VOLATILE was added to signal volatile controls to userspace.</para>
</listitem>
<listitem>
<para>Add selection API for extended control over cropping and
composing. Does not affect the compatibility of current drivers and
applications. See <link linkend="selection-api"> selection API </link> for
details.</para>
<para>Add selection API for extended control over cropping
and composing. Does not affect the compatibility of current
drivers and applications. See <link
linkend="selection-api"> selection API </link> for
details.</para>
</listitem>
</orderedlist>
</section>
......@@ -2458,6 +2459,18 @@ details.</para>
</orderedlist>
</section>
<section>
<title>V4L2 in Linux 3.5</title>
<orderedlist>
<listitem>
<para>Replaced <structfield>input</structfield> in
<structname>v4l2_buffer</structname> by
<structfield>reserved2</structfield> and removed
<constant>V4L2_BUF_FLAG_INPUT</constant>.</para>
</listitem>
</orderedlist>
</section>
<section id="other">
<title>Relation of V4L2 to other Linux multimedia APIs</title>
......
......@@ -276,7 +276,7 @@
</para>
</section>
<section>
<section id="v4l2-subdev-selections">
<title>Selections: cropping, scaling and composition</title>
<para>Many sub-devices support cropping frames on their input or output
......@@ -290,8 +290,8 @@
size. Both the coordinates and sizes are expressed in pixels.</para>
<para>As for pad formats, drivers store try and active
rectangles for the selection targets of ACTUAL type <xref
linkend="v4l2-subdev-selection-targets">.</xref></para>
rectangles for the selection targets <xref
linkend="v4l2-selections-common" />.</para>
<para>On sink pads, cropping is applied relative to the
current pad format. The pad format represents the image size as
......@@ -308,7 +308,7 @@
<para>Scaling support is optional. When supported by a subdev,
the crop rectangle on the subdev's sink pad is scaled to the
size configured using the &VIDIOC-SUBDEV-S-SELECTION; IOCTL
using <constant>V4L2_SUBDEV_SEL_COMPOSE_ACTUAL</constant>
using <constant>V4L2_SEL_TGT_COMPOSE</constant>
selection target on the same pad. If the subdev supports scaling
but not composing, the top and left values are not used and must
always be set to zero.</para>
......@@ -323,32 +323,32 @@
<para>The drivers should always use the closest possible
rectangle the user requests on all selection targets, unless
specifically told otherwise.
<constant>V4L2_SUBDEV_SEL_FLAG_SIZE_GE</constant> and
<constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant> flags may be
<constant>V4L2_SEL_FLAG_GE</constant> and
<constant>V4L2_SEL_FLAG_LE</constant> flags may be
used to round the image size either up or down. <xref
linkend="v4l2-subdev-selection-flags"></xref></para>
linkend="v4l2-selection-flags" /></para>
</section>
<section>
<title>Types of selection targets</title>
<section>
<title>ACTUAL targets</title>
<title>Actual targets</title>
<para>ACTUAL targets reflect the actual hardware configuration
at any point of time. There is a BOUNDS target
corresponding to every ACTUAL.</para>
<para>Actual targets (without a postfix) reflect the actual
hardware configuration at any point of time. There is a BOUNDS
target corresponding to every actual target.</para>
</section>
<section>
<title>BOUNDS targets</title>
<para>BOUNDS targets is the smallest rectangle that contains
all valid ACTUAL rectangles. It may not be possible to set the
ACTUAL rectangle as large as the BOUNDS rectangle, however.
This may be because e.g. a sensor's pixel array is not
rectangular but cross-shaped or round. The maximum size may
also be smaller than the BOUNDS rectangle.</para>
<para>BOUNDS targets is the smallest rectangle that contains all
valid actual rectangles. It may not be possible to set the actual
rectangle as large as the BOUNDS rectangle, however. This may be
because e.g. a sensor's pixel array is not rectangular but
cross-shaped or round. The maximum size may also be smaller than the
BOUNDS rectangle.</para>
</section>
</section>
......@@ -362,7 +362,7 @@
performed by the user: the changes made will be propagated to
any subsequent stages. If this behaviour is not desired, the
user must set
<constant>V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG</constant> flag. This
<constant>V4L2_SEL_FLAG_KEEP_CONFIG</constant> flag. This
flag causes no propagation of the changes are allowed in any
circumstances. This may also cause the accessed rectangle to be
adjusted by the driver, depending on the properties of the
......
......@@ -683,14 +683,12 @@ memory, set by the application. See <xref linkend="userp" /> for details.
</row>
<row>
<entry>__u32</entry>
<entry><structfield>input</structfield></entry>
<entry><structfield>reserved2</structfield></entry>
<entry></entry>
<entry>Some video capture drivers support rapid and
synchronous video input changes, a function useful for example in
video surveillance applications. For this purpose applications set the
<constant>V4L2_BUF_FLAG_INPUT</constant> flag, and this field to the
number of a video input as in &v4l2-input; field
<structfield>index</structfield>.</entry>
<entry>A place holder for future extensions and custom
(driver defined) buffer types
<constant>V4L2_BUF_TYPE_PRIVATE</constant> and higher. Applications
should set this to 0.</entry>
</row>
<row>
<entry>__u32</entry>
......@@ -921,13 +919,6 @@ previous key frame.</entry>
<entry>The <structfield>timecode</structfield> field is valid.
Drivers set or clear this flag when the <constant>VIDIOC_DQBUF</constant>
ioctl is called.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_INPUT</constant></entry>
<entry>0x0200</entry>
<entry>The <structfield>input</structfield> field is valid.
Applications set or clear this flag before calling the
<constant>VIDIOC_QBUF</constant> ioctl.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_PREPARED</constant></entry>
......
......@@ -53,11 +53,11 @@ cropping and composing rectangles have the same size.</para>
</mediaobject>
</figure>
For complete list of the available selection targets see table <xref
linkend="v4l2-sel-target"/>
</section>
See <xref linkend="v4l2-selection-targets" /> for more
information.
<section>
<title>Configuration</title>
......@@ -74,7 +74,7 @@ cropping/composing rectangles may have to be aligned, and both the source and
the sink may have arbitrary upper and lower size limits. Therefore, as usual,
drivers are expected to adjust the requested parameters and return the actual
values selected. An application can control the rounding behaviour using <link
linkend="v4l2-sel-flags"> constraint flags </link>.</para>
linkend="v4l2-selection-flags"> constraint flags </link>.</para>
<section>
......@@ -91,7 +91,7 @@ top/left corner at position <constant> (0,0) </constant>. The rectangle's
coordinates are expressed in pixels.</para>
<para>The top left corner, width and height of the source rectangle, that is
the area actually sampled, is given by the <constant> V4L2_SEL_TGT_CROP_ACTIVE
the area actually sampled, is given by the <constant> V4L2_SEL_TGT_CROP
</constant> target. It uses the same coordinate system as <constant>
V4L2_SEL_TGT_CROP_BOUNDS </constant>. The active cropping area must lie
completely inside the capture boundaries. The driver may further adjust the
......@@ -111,13 +111,13 @@ height are equal to the image size set by <constant> VIDIOC_S_FMT </constant>.
</para>
<para>The part of a buffer into which the image is inserted by the hardware is
controlled by the <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.
controlled by the <constant> V4L2_SEL_TGT_COMPOSE </constant> target.
The rectangle's coordinates are also expressed in the same coordinate system as
the bounds rectangle. The composing rectangle must lie completely inside bounds
rectangle. The driver must adjust the composing rectangle to fit to the
bounding limits. Moreover, the driver can perform other adjustments according
to hardware limitations. The application can control rounding behaviour using
<link linkend="v4l2-sel-flags"> constraint flags </link>.</para>
<link linkend="v4l2-selection-flags"> constraint flags </link>.</para>
<para>For capture devices the default composing rectangle is queried using
<constant> V4L2_SEL_TGT_COMPOSE_DEFAULT </constant>. It is usually equal to the
......@@ -125,7 +125,7 @@ bounding rectangle.</para>
<para>The part of a buffer that is modified by the hardware is given by
<constant> V4L2_SEL_TGT_COMPOSE_PADDED </constant>. It contains all pixels
defined using <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> plus all
defined using <constant> V4L2_SEL_TGT_COMPOSE </constant> plus all
padding data modified by hardware during insertion process. All pixels outside
this rectangle <emphasis>must not</emphasis> be changed by the hardware. The
content of pixels that lie inside the padded area but outside active area is
......@@ -153,7 +153,7 @@ specified using <constant> VIDIOC_S_FMT </constant> ioctl.</para>
<para>The top left corner, width and height of the source rectangle, that is
the area from which image date are processed by the hardware, is given by the
<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant>. Its coordinates are expressed
<constant> V4L2_SEL_TGT_CROP </constant>. Its coordinates are expressed
in in the same coordinate system as the bounds rectangle. The active cropping
area must lie completely inside the crop boundaries and the driver may further
adjust the requested size and/or position according to hardware
......@@ -165,7 +165,7 @@ bounding rectangle.</para>
<para>The part of a video signal or graphics display where the image is
inserted by the hardware is controlled by <constant>
V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target. The rectangle's coordinates
V4L2_SEL_TGT_COMPOSE </constant> target. The rectangle's coordinates
are expressed in pixels. The composing rectangle must lie completely inside the
bounds rectangle. The driver must adjust the area to fit to the bounding
limits. Moreover, the driver can perform other adjustments according to
......@@ -184,7 +184,7 @@ such a padded area is driver-dependent feature not covered by this document.
Driver developers are encouraged to keep padded rectangle equal to active one.
The padded target is accessed by the <constant> V4L2_SEL_TGT_COMPOSE_PADDED
</constant> identifier. It must contain all pixels from the <constant>
V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.</para>
V4L2_SEL_TGT_COMPOSE </constant> target.</para>
</section>
......@@ -193,8 +193,8 @@ V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.</para>
<title>Scaling control</title>
<para>An application can detect if scaling is performed by comparing the width
and the height of rectangles obtained using <constant> V4L2_SEL_TGT_CROP_ACTIVE
</constant> and <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> targets. If
and the height of rectangles obtained using <constant> V4L2_SEL_TGT_CROP
</constant> and <constant> V4L2_SEL_TGT_COMPOSE </constant> targets. If
these are not equal then the scaling is applied. The application can compute
the scaling ratios using these values.</para>
......@@ -252,7 +252,7 @@ area)</para>
ret = ioctl(fd, &VIDIOC-G-SELECTION;, &amp;sel);
if (ret)
exit(-1);
sel.target = V4L2_SEL_TGT_CROP_ACTIVE;
sel.target = V4L2_SEL_TGT_CROP;
ret = ioctl(fd, &VIDIOC-S-SELECTION;, &amp;sel);
if (ret)
exit(-1);
......@@ -281,7 +281,7 @@ area)</para>
r.left = sel.r.width / 4;
r.top = sel.r.height / 4;
sel.r = r;
sel.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
sel.target = V4L2_SEL_TGT_COMPOSE;
sel.flags = V4L2_SEL_FLAG_LE;
ret = ioctl(fd, &VIDIOC-S-SELECTION;, &amp;sel);
if (ret)
......@@ -298,11 +298,11 @@ V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> for other devices</para>
&v4l2-selection; compose = {
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
.target = V4L2_SEL_TGT_COMPOSE_ACTIVE,
.target = V4L2_SEL_TGT_COMPOSE,
};
&v4l2-selection; crop = {
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
.target = V4L2_SEL_TGT_CROP_ACTIVE,
.target = V4L2_SEL_TGT_CROP,
};
double hscale, vscale;
......
<section id="v4l2-selections-common">
<title>Common selection definitions</title>
<para>While the <link linkend="selection-api">V4L2 selection
API</link> and <link linkend="v4l2-subdev-selections">V4L2 subdev
selection APIs</link> are very similar, there's one fundamental
difference between the two. On sub-device API, the selection
rectangle refers to the media bus format, and is bound to a
sub-device's pad. On the V4L2 interface the selection rectangles
refer to the in-memory pixel format.</para>
<para>This section defines the common definitions of the
selection interfaces on the two APIs.</para>
<section id="v4l2-selection-targets">
<title>Selection targets</title>
<para>The precise meaning of the selection targets may be
dependent on which of the two interfaces they are used.</para>
<table pgwide="1" frame="none" id="v4l2-selection-targets-table">
<title>Selection target definitions</title>
<tgroup cols="5">
<colspec colname="c1" />
<colspec colname="c2" />
<colspec colname="c3" />
<colspec colname="c4" />
<colspec colname="c5" />
&cs-def;
<thead>
<row rowsep="1">
<entry align="left">Target name</entry>
<entry align="left">id</entry>
<entry align="left">Definition</entry>
<entry align="left">Valid for V4L2</entry>
<entry align="left">Valid for V4L2 subdev</entry>
</row>
</thead>
<tbody valign="top">
<row>
<entry><constant>V4L2_SEL_TGT_CROP</constant></entry>
<entry>0x0000</entry>
<entry>Crop rectangle. Defines the cropped area.</entry>
<entry>Yes</entry>
<entry>Yes</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_CROP_DEFAULT</constant></entry>
<entry>0x0001</entry>
<entry>Suggested cropping rectangle that covers the "whole picture".</entry>
<entry>Yes</entry>
<entry>No</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_CROP_BOUNDS</constant></entry>
<entry>0x0002</entry>
<entry>Bounds of the crop rectangle. All valid crop
rectangles fit inside the crop bounds rectangle.
</entry>
<entry>Yes</entry>
<entry>Yes</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_COMPOSE</constant></entry>
<entry>0x0100</entry>
<entry>Compose rectangle. Used to configure scaling
and composition.</entry>
<entry>Yes</entry>
<entry>Yes</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant></entry>
<entry>0x0101</entry>
<entry>Suggested composition rectangle that covers the "whole picture".</entry>
<entry>Yes</entry>
<entry>No</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
<entry>0x0102</entry>
<entry>Bounds of the compose rectangle. All valid compose
rectangles fit inside the compose bounds rectangle.</entry>
<entry>Yes</entry>
<entry>Yes</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant></entry>
<entry>0x0103</entry>
<entry>The active area and all padding pixels that are inserted or
modified by hardware.</entry>
<entry>Yes</entry>
<entry>No</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section id="v4l2-selection-flags">
<title>Selection flags</title>
<table pgwide="1" frame="none" id="v4l2-selection-flags-table">
<title>Selection flag definitions</title>
<tgroup cols="5">
<colspec colname="c1" />
<colspec colname="c2" />
<colspec colname="c3" />
<colspec colname="c4" />
<colspec colname="c5" />
&cs-def;
<thead>
<row rowsep="1">
<entry align="left">Flag name</entry>
<entry align="left">id</entry>
<entry align="left">Definition</entry>
<entry align="left">Valid for V4L2</entry>
<entry align="left">Valid for V4L2 subdev</entry>
</row>
</thead>
<tbody valign="top">
<row>
<entry><constant>V4L2_SEL_FLAG_GE</constant></entry>
<entry>(1 &lt;&lt; 0)</entry>
<entry>Suggest the driver it should choose greater or
equal rectangle (in size) than was requested. Albeit the
driver may choose a lesser size, it will only do so due to
hardware limitations. Without this flag (and
<constant>V4L2_SEL_FLAG_LE</constant>) the
behaviour is to choose the closest possible
rectangle.</entry>
<entry>Yes</entry>
<entry>Yes</entry>
</row>
<row>
<entry><constant>V4L2_SEL_FLAG_LE</constant></entry>
<entry>(1 &lt;&lt; 1)</entry>
<entry>Suggest the driver it
should choose lesser or equal rectangle (in size) than was
requested. Albeit the driver may choose a greater size, it
will only do so due to hardware limitations.</entry>
<entry>Yes</entry>
<entry>Yes</entry>
</row>
<row>
<entry><constant>V4L2_SEL_FLAG_KEEP_CONFIG</constant></entry>
<entry>(1 &lt;&lt; 2)</entry>
<entry>The configuration must not be propagated to any
further processing steps. If this flag is not given, the
configuration is propagated inside the subdevice to all
further processing steps.</entry>
<entry>No</entry>
<entry>Yes</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
</section>
......@@ -589,6 +589,11 @@ and discussions on the V4L mailing list.</revremark>
&sub-write;
</appendix>
<appendix>
<title>Common definitions for V4L2 and V4L2 subdev interfaces</title>
&sub-selections-common;
</appendix>
<appendix id="videodev">
<title>Video For Linux Two Header File</title>
&sub-videodev2-h;
......
......@@ -97,7 +97,13 @@ information.</para>
<row>
<entry>__u32</entry>
<entry><structfield>count</structfield></entry>
<entry>The number of buffers requested or granted.</entry>
<entry>The number of buffers requested or granted. If count == 0, then
<constant>VIDIOC_CREATE_BUFS</constant> will set <structfield>index</structfield>
to the current number of created buffers, and it will check the validity of
<structfield>memory</structfield> and <structfield>format.type</structfield>.
If those are invalid -1 is returned and errno is set to &EINVAL;,
otherwise <constant>VIDIOC_CREATE_BUFS</constant> returns 0. It will
never set errno to &EBUSY; in this particular case.</entry>
</row>
<row>
<entry>__u32</entry>
......
......@@ -135,6 +135,12 @@ bounds or the value in the <structfield>type</structfield> field is
wrong.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>EBUSY</errorcode></term>
<listitem>
<para>A hardware seek is in progress.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
</refentry>
......@@ -65,9 +65,9 @@ Do not use multiplanar buffers. Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
</constant>. Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
<constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>. The next step is
setting the value of &v4l2-selection; <structfield>target</structfield> field
to <constant> V4L2_SEL_TGT_CROP_ACTIVE </constant> (<constant>
V4L2_SEL_TGT_COMPOSE_ACTIVE </constant>). Please refer to table <xref
linkend="v4l2-sel-target" /> or <xref linkend="selection-api" /> for additional
to <constant> V4L2_SEL_TGT_CROP </constant> (<constant>
V4L2_SEL_TGT_COMPOSE </constant>). Please refer to table <xref
linkend="v4l2-selections-common" /> or <xref linkend="selection-api" /> for additional
targets. The <structfield>flags</structfield> and <structfield>reserved
</structfield> fields of &v4l2-selection; are ignored and they must be filled
with zeros. The driver fills the rest of the structure or
......@@ -86,9 +86,9 @@ use multiplanar buffers. Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
</constant>. Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
<constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>. The next step is
setting the value of &v4l2-selection; <structfield>target</structfield> to
<constant>V4L2_SEL_TGT_CROP_ACTIVE</constant> (<constant>
V4L2_SEL_TGT_COMPOSE_ACTIVE </constant>). Please refer to table <xref
linkend="v4l2-sel-target" /> or <xref linkend="selection-api" /> for additional
<constant>V4L2_SEL_TGT_CROP</constant> (<constant>
V4L2_SEL_TGT_COMPOSE </constant>). Please refer to table <xref
linkend="v4l2-selections-common" /> or <xref linkend="selection-api" /> for additional
targets. The &v4l2-rect; <structfield>r</structfield> rectangle need to be
set to the desired active area. Field &v4l2-selection; <structfield> reserved
</structfield> is ignored and must be filled with zeros. The driver may adjust
......@@ -154,74 +154,8 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
</refsect1>
<refsect1>
<table frame="none" pgwide="1" id="v4l2-sel-target">
<title>Selection targets.</title>
<tgroup cols="3">
&cs-def;
<tbody valign="top">
<row>
<entry><constant>V4L2_SEL_TGT_CROP_ACTIVE</constant></entry>
<entry>0x0000</entry>
<entry>The area that is currently cropped by hardware.</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_CROP_DEFAULT</constant></entry>
<entry>0x0001</entry>
<entry>Suggested cropping rectangle that covers the "whole picture".</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_CROP_BOUNDS</constant></entry>
<entry>0x0002</entry>
<entry>Limits for the cropping rectangle.</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_COMPOSE_ACTIVE</constant></entry>
<entry>0x0100</entry>
<entry>The area to which data is composed by hardware.</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant></entry>
<entry>0x0101</entry>
<entry>Suggested composing rectangle that covers the "whole picture".</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
<entry>0x0102</entry>
<entry>Limits for the composing rectangle.</entry>
</row>
<row>
<entry><constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant></entry>
<entry>0x0103</entry>
<entry>The active area and all padding pixels that are inserted or modified by hardware.</entry>
</row>
</tbody>
</tgroup>
</table>
</refsect1>
<refsect1>
<table frame="none" pgwide="1" id="v4l2-sel-flags">
<title>Selection constraint flags</title>
<tgroup cols="3">
&cs-def;
<tbody valign="top">
<row>
<entry><constant>V4L2_SEL_FLAG_GE</constant></entry>
<entry>0x00000001</entry>
<entry>Indicates that the adjusted rectangle must contain the original
&v4l2-selection; <structfield>r</structfield> rectangle.</entry>
</row>
<row>
<entry><constant>V4L2_SEL_FLAG_LE</constant></entry>
<entry>0x00000002</entry>
<entry>Indicates that the adjusted rectangle must be inside the original
&v4l2-rect; <structfield>r</structfield> rectangle.</entry>
</row>
</tbody>
</tgroup>
</table>
</refsect1>
<para>Selection targets and flags are documented in <xref
linkend="v4l2-selections-common"/>.</para>
<section>
<figure id="sel-const-adjust">
......@@ -252,14 +186,14 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
<row>
<entry>__u32</entry>
<entry><structfield>target</structfield></entry>
<entry>Used to select between <link linkend="v4l2-sel-target"> cropping
<entry>Used to select between <link linkend="v4l2-selections-common"> cropping
and composing rectangles</link>.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>flags</structfield></entry>
<entry>Flags controlling the selection rectangle adjustments, refer to
<link linkend="v4l2-sel-flags">selection flags</link>.</entry>
<link linkend="v4l2-selection-flags">selection flags</link>.</entry>
</row>
<row>
<entry>&v4l2-rect;</entry>
......
......@@ -275,6 +275,18 @@ can or must be switched. (B/G PAL tuners for example are typically not
see the description of ioctl &VIDIOC-ENUMINPUT; for details. Only
<constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
</row>
<row>
<entry><constant>V4L2_TUNER_CAP_HWSEEK_BOUNDED</constant></entry>
<entry>0x0004</entry>
<entry>If set, then this tuner supports the hardware seek functionality
where the seek stops when it reaches the end of the frequency range.</entry>
</row>
<row>
<entry><constant>V4L2_TUNER_CAP_HWSEEK_WRAP</constant></entry>
<entry>0x0008</entry>
<entry>If set, then this tuner supports the hardware seek functionality
where the seek wraps around when it reaches the end of the frequency range.</entry>
</row>
<row>
<entry><constant>V4L2_TUNER_CAP_STEREO</constant></entry>
<entry>0x0010</entry>
......
......@@ -71,12 +71,9 @@ initialize the <structfield>bytesused</structfield>,
<structfield>field</structfield> and
<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. When using
Applications must also set <structfield>flags</structfield> to 0.
The <structfield>reserved2</structfield> and
<structfield>reserved</structfield> fields must be set to 0. When using
the <link linkend="planar-apis">multi-planar API</link>, the
<structfield>m.planes</structfield> field must contain a userspace pointer
to a filled-in array of &v4l2-plane; and the <structfield>length</structfield>
......
......@@ -58,6 +58,9 @@ To do this applications initialize the <structfield>tuner</structfield>,
call the <constant>VIDIOC_S_HW_FREQ_SEEK</constant> ioctl with a pointer
to this structure.</para>
<para>If an error is returned, then the original frequency will
be restored.</para>
<para>This ioctl is supported if the <constant>V4L2_CAP_HW_FREQ_SEEK</constant> capability is set.</para>
<table pgwide="1" frame="none" id="v4l2-hw-freq-seek">
......@@ -87,7 +90,10 @@ field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
<row>
<entry>__u32</entry>
<entry><structfield>wrap_around</structfield></entry>
<entry>If non-zero, wrap around when at the end of the frequency range, else stop seeking.</entry>
<entry>If non-zero, wrap around when at the end of the frequency range, else stop seeking.
The &v4l2-tuner; <structfield>capability</structfield> field will tell you what the
hardware supports.
</entry>
</row>
<row>
<entry>__u32</entry>
......@@ -118,9 +124,15 @@ wrong.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>EAGAIN</errorcode></term>
<term><errorcode>ENODATA</errorcode></term>
<listitem>
<para>The hardware seek found no channels.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>EBUSY</errorcode></term>
<listitem>
<para>The ioctl timed-out. Try again.</para>
<para>Another hardware seek is already in progress.</para>
</listitem>
</varlistentry>
</variablelist>
......
......@@ -72,10 +72,10 @@
<section>
<title>Types of selection targets</title>
<para>There are two types of selection targets: actual and bounds.
The ACTUAL targets are the targets which configure the hardware.
The BOUNDS target will return a rectangle that contain all
possible ACTUAL rectangles.</para>
<para>There are two types of selection targets: actual and bounds. The
actual targets are the targets which configure the hardware. The BOUNDS
target will return a rectangle that contain all possible actual
rectangles.</para>
</section>
<section>
......@@ -87,71 +87,8 @@
<constant>EINVAL</constant>.</para>
</section>
<table pgwide="1" frame="none" id="v4l2-subdev-selection-targets">
<title>V4L2 subdev selection targets</title>
<tgroup cols="3">
&cs-def;
<tbody valign="top">
<row>
<entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL</constant></entry>
<entry>0x0000</entry>
<entry>Actual crop. Defines the cropping
performed by the processing step.</entry>
</row>
<row>
<entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS</constant></entry>
<entry>0x0002</entry>
<entry>Bounds of the crop rectangle.</entry>
</row>
<row>
<entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL</constant></entry>
<entry>0x0100</entry>
<entry>Actual compose rectangle. Used to configure scaling
on sink pads and composition on source pads.</entry>
</row>
<row>
<entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
<entry>0x0102</entry>
<entry>Bounds of the compose rectangle.</entry>
</row>
</tbody>
</tgroup>
</table>
<table pgwide="1" frame="none" id="v4l2-subdev-selection-flags">
<title>V4L2 subdev selection flags</title>
<tgroup cols="3">
&cs-def;
<tbody valign="top">
<row>
<entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_GE</constant></entry>
<entry>(1 &lt;&lt; 0)</entry> <entry>Suggest the driver it
should choose greater or equal rectangle (in size) than
was requested. Albeit the driver may choose a lesser size,
it will only do so due to hardware limitations. Without
this flag (and
<constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant>) the
behaviour is to choose the closest possible
rectangle.</entry>
</row>
<row>
<entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant></entry>
<entry>(1 &lt;&lt; 1)</entry> <entry>Suggest the driver it
should choose lesser or equal rectangle (in size) than was
requested. Albeit the driver may choose a greater size, it
will only do so due to hardware limitations.</entry>
</row>
<row>
<entry><constant>V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG</constant></entry>
<entry>(1 &lt;&lt; 2)</entry>
<entry>The configuration should not be propagated to any
further processing steps. If this flag is not given, the
configuration is propagated inside the subdevice to all
further processing steps.</entry>
</row>
</tbody>
</tgroup>
</table>
<para>Selection targets and flags are documented in <xref
linkend="v4l2-selections-common"/>.</para>
<table pgwide="1" frame="none" id="v4l2-subdev-selection">
<title>struct <structname>v4l2_subdev_selection</structname></title>
......@@ -173,13 +110,13 @@
<entry>__u32</entry>
<entry><structfield>target</structfield></entry>
<entry>Target selection rectangle. See
<xref linkend="v4l2-subdev-selection-targets">.</xref>.</entry>
<xref linkend="v4l2-selections-common" />.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>flags</structfield></entry>
<entry>Flags. See
<xref linkend="v4l2-subdev-selection-flags">.</xref></entry>
<xref linkend="v4l2-selection-flags" />.</entry>
</row>
<row>
<entry>&v4l2-rect;</entry>
......
......@@ -29,7 +29,7 @@ use IO::Handle;
"af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
"lme2510c_s7395_old", "drxk", "drxk_terratec_h5",
"drxk_hauppauge_hvr930c", "tda10071", "it9135", "it9137",
"drxk_pctv");
"drxk_pctv", "drxk_terratec_htc_stick", "sms1xxx_hcw");
# Check args
syntax() if (scalar(@ARGV) != 1);
......@@ -676,6 +676,24 @@ sub drxk_terratec_h5 {
"$fwfile"
}
sub drxk_terratec_htc_stick {
my $url = "http://ftp.terratec.de/Receiver/Cinergy_HTC_Stick/Updates/";
my $zipfile = "Cinergy_HTC_Stick_Drv_5.09.1202.00_XP_Vista_7.exe";
my $hash = "6722a2442a05423b781721fbc069ed5e";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
my $drvfile = "Cinergy HTC Stick/BDA Driver 5.09.1202.00/Windows 32 Bit/emOEM.sys";
my $fwfile = "dvb-usb-terratec-htc-stick-drxk.fw";
checkstandard();
wgetfile($zipfile, $url . $zipfile);
verify($zipfile, $hash);
unzip($zipfile, $tmpdir);
extract("$tmpdir/$drvfile", 0x4e5c0, 42692, "$fwfile");
"$fwfile"
}
sub it9135 {
my $sourcefile = "dvb-usb-it9135.zip";
my $url = "http://www.ite.com.tw/uploads/firmware/v3.6.0.0/$sourcefile";
......@@ -748,6 +766,28 @@ sub drxk_pctv {
"$fwfile";
}
sub sms1xxx_hcw {
my $url = "http://steventoth.net/linux/sms1xxx/";
my %files = (
'sms1xxx-hcw-55xxx-dvbt-01.fw' => "afb6f9fb9a71d64392e8564ef9577e5a",
'sms1xxx-hcw-55xxx-dvbt-02.fw' => "b44807098ba26e52cbedeadc052ba58f",
'sms1xxx-hcw-55xxx-isdbt-02.fw' => "dae934eeea85225acbd63ce6cfe1c9e4",
);
checkstandard();
my $allfiles;
foreach my $fwfile (keys %files) {
wgetfile($fwfile, "$url/$fwfile");
verify($fwfile, $files{$fwfile});
$allfiles .= " $fwfile";
}
$allfiles =~ s/^\s//;
$allfiles;
}
# ---------------------------------------------------------------
# Utilities
......
......@@ -600,3 +600,21 @@ When: June 2013
Why: Unsupported/unmaintained/unused since 2.6
----------------------------
What: V4L2 selections API target rectangle and flags unification, the
following definitions will be removed: V4L2_SEL_TGT_CROP_ACTIVE,
V4L2_SEL_TGT_COMPOSE_ACTIVE, V4L2_SUBDEV_SEL_*, V4L2_SUBDEV_SEL_FLAG_*
in favor of common V4L2_SEL_TGT_* and V4L2_SEL_FLAG_* definitions.
For more details see include/linux/v4l2-common.h.
When: 3.8
Why: The regular V4L2 selections and the subdev selection API originally
defined distinct names for the target rectangles and flags - V4L2_SEL_*
and V4L2_SUBDEV_SEL_*. Although, it turned out that the meaning of these
target rectangles is virtually identical and the APIs were consolidated
to use single set of names - V4L2_SEL_*. This didn't involve any ABI
changes. Alias definitions were created for the original ones to avoid
any instabilities in the user space interface. After few cycles these
backward compatibility definitions will be removed.
Who: Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
----------------------------
......@@ -594,6 +594,15 @@ You should also set these fields:
unlocked_ioctl file operation is called this lock will be taken by the
core and released afterwards. See the next section for more details.
- queue: a pointer to the struct vb2_queue associated with this device node.
If queue is non-NULL, and queue->lock is non-NULL, then queue->lock is
used for the queuing ioctls (VIDIOC_REQBUFS, CREATE_BUFS, QBUF, DQBUF,
QUERYBUF, PREPARE_BUF, STREAMON and STREAMOFF) instead of the lock above.
That way the vb2 queuing framework does not have to wait for other ioctls.
This queue pointer is also used by the vb2 helper functions to check for
queuing ownership (i.e. is the filehandle calling it allowed to do the
operation).
- prio: keeps track of the priorities. Used to implement VIDIOC_G/S_PRIORITY.
If left to NULL, then it will use the struct v4l2_prio_state in v4l2_device.
If you want to have a separate priority state per (group of) device node(s),
......@@ -647,47 +656,43 @@ manually set the struct media_entity type and name fields.
A reference to the entity will be automatically acquired/released when the
video device is opened/closed.
v4l2_file_operations and locking
--------------------------------
You can set a pointer to a mutex_lock in struct video_device. Usually this
will be either a top-level mutex or a mutex per device node. By default this
lock will be used for unlocked_ioctl, but you can disable locking for
selected ioctls by calling:
void v4l2_disable_ioctl_locking(struct video_device *vdev, unsigned int cmd);
E.g.: v4l2_disable_ioctl_locking(vdev, VIDIOC_DQBUF);
ioctls and locking
------------------
You have to call this before you register the video_device.
The V4L core provides optional locking services. The main service is the
lock field in struct video_device, which is a pointer to a mutex. If you set
this pointer, then that will be used by unlocked_ioctl to serialize all ioctls.
Particularly with USB drivers where certain commands such as setting controls
can take a long time you may want to do your own locking for the buffer queuing
ioctls.
If you are using the videobuf2 framework, then there is a second lock that you
can set: video_device->queue->lock. If set, then this lock will be used instead
of video_device->lock to serialize all queuing ioctls (see the previous section
for the full list of those ioctls).
If you want still finer-grained locking then you have to set mutex_lock to NULL
and do you own locking completely.
The advantage of using a different lock for the queuing ioctls is that for some
drivers (particularly USB drivers) certain commands such as setting controls
can take a long time, so you want to use a separate lock for the buffer queuing
ioctls. That way your VIDIOC_DQBUF doesn't stall because the driver is busy
changing the e.g. exposure of the webcam.
It is up to the driver developer to decide which method to use. However, if
your driver has high-latency operations (for example, changing the exposure
of a USB webcam might take a long time), then you might be better off with
doing your own locking if you want to allow the user to do other things with
the device while waiting for the high-latency command to finish.
Of course, you can always do all the locking yourself by leaving both lock
pointers at NULL.
If a lock is specified then all ioctl commands will be serialized on that
lock. If you use videobuf then you must pass the same lock to the videobuf
queue initialize function: if videobuf has to wait for a frame to arrive, then
it will temporarily unlock the lock and relock it afterwards. If your driver
also waits in the code, then you should do the same to allow other processes
to access the device node while the first process is waiting for something.
If you use the old videobuf then you must pass the video_device lock to the
videobuf queue initialize function: if videobuf has to wait for a frame to
arrive, then it will temporarily unlock the lock and relock it afterwards. If
your driver also waits in the code, then you should do the same to allow other
processes to access the device node while the first process is waiting for
something.
In the case of videobuf2 you will need to implement the wait_prepare and
wait_finish callbacks to unlock/lock if applicable. In particular, if you use
the lock in struct video_device then you must unlock/lock this mutex in
wait_prepare and wait_finish.
The implementation of a hotplug disconnect should also take the lock before
calling v4l2_device_disconnect.
wait_finish callbacks to unlock/lock if applicable. If you use the queue->lock
pointer, then you can use the helper functions vb2_ops_wait_prepare/finish.
The implementation of a hotplug disconnect should also take the lock from
video_device before calling v4l2_device_disconnect. If you are also using
video_device->queue->lock, then you have to first lock video_device->queue->lock
followed by video_device->lock. That way you can be sure no ioctl is running
when you call v4l2_device_disconnect.
video_device registration
-------------------------
......
......@@ -3156,8 +3156,7 @@ S: Maintained
F: drivers/media/video/gspca/t613.c
GSPCA USB WEBCAM DRIVER
M: Jean-Francois Moine <moinejf@free.fr>
W: http://moinejf.free.fr
M: Hans de Goede <hdegoede@redhat.com>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
S: Maintained
......
......@@ -1311,6 +1311,37 @@ module_exit(i2c_exit);
* ----------------------------------------------------
*/
/**
* __i2c_transfer - unlocked flavor of i2c_transfer
* @adap: Handle to I2C bus
* @msgs: One or more messages to execute before STOP is issued to
* terminate the operation; each message begins with a START.
* @num: Number of messages to be executed.
*
* Returns negative errno, else the number of messages executed.
*
* Adapter lock must be held when calling this function. No debug logging
* takes place. adap->algo->master_xfer existence isn't checked.
*/
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
unsigned long orig_jiffies;
int ret, try;
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}
return ret;
}
EXPORT_SYMBOL(__i2c_transfer);
/**
* i2c_transfer - execute a single or combined I2C message
* @adap: Handle to I2C bus
......@@ -1325,8 +1356,7 @@ module_exit(i2c_exit);
*/
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
unsigned long orig_jiffies;
int ret, try;
int ret;
/* REVISIT the fault reporting model here is weak:
*
......@@ -1364,15 +1394,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
i2c_lock_adapter(adap);
}
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}
ret = __i2c_transfer(adap, msgs, num);
i2c_unlock_adapter(adap);
return ret;
......
......@@ -6,20 +6,82 @@ menuconfig MEDIA_SUPPORT
tristate "Multimedia support"
depends on HAS_IOMEM
help
If you want to use Video for Linux, DVB for Linux, or DAB adapters,
If you want to use Webcams, Video grabber devices and/or TV devices
enable this option and other options below.
Additional info and docs are available on the web at
<http://linuxtv.org>
if MEDIA_SUPPORT
comment "Multimedia core support"
#
# Multimedia support - automatically enable V4L2 and DVB core
#
config MEDIA_CAMERA_SUPPORT
bool "Cameras/video grabbers support"
---help---
Enable support for webcams and video grabbers.
Say Y when you have a webcam or a video capture grabber board.
config MEDIA_ANALOG_TV_SUPPORT
bool "Analog TV support"
---help---
Enable analog TV support.
Say Y when you have a TV board with analog support or with a
hybrid analog/digital TV chipset.
Note: There are several DVB cards that are based on chips that
support both analog and digital TV. Disabling this option
will disable support for them.
config MEDIA_DIGITAL_TV_SUPPORT
bool "Digital TV support"
---help---
Enable digital TV support.
Say Y when you have a board with digital support or a board with
hybrid digital TV and analog TV.
config MEDIA_RADIO_SUPPORT
bool "AM/FM radio receivers/transmitters support"
---help---
Enable AM/FM radio support.
Additional info and docs are available on the web at
<http://linuxtv.org>
Say Y when you have a board with radio support.
Note: There are several TV cards that are based on chips that
support radio reception. Disabling this option will
disable support for them.
config MEDIA_RC_SUPPORT
bool "Remote Controller support"
depends on INPUT
---help---
Enable support for Remote Controllers on Linux. This is
needed in order to support several video capture adapters,
standalone IR receivers/transmitters, and RF receivers.
Enable this option if you have a video capture board even
if you don't need IR, as otherwise, you may not be able to
compile the driver for your adapter.
Say Y when you have a TV or an IR device.
#
# Media controller
# Selectable only for webcam/grabbers, as other drivers don't use it
#
config MEDIA_CONTROLLER
bool "Media Controller API (EXPERIMENTAL)"
depends on EXPERIMENTAL
depends on MEDIA_CAMERA_SUPPORT
---help---
Enable the media controller API used to query media devices internal
topology and configure it dynamically.
......@@ -27,26 +89,15 @@ config MEDIA_CONTROLLER
This API is mostly used by camera interfaces in embedded platforms.
#
# V4L core and enabled API's
# Video4Linux support
# Only enables if one of the V4L2 types (ATV, webcam, radio) is selected
#
config VIDEO_DEV
tristate "Video For Linux"
---help---
V4L core support for video capture and overlay devices, webcams and
AM/FM radio cards.
This kernel includes support for the new Video for Linux Two API,
(V4L2).
Additional info and docs are available on the web at
<http://linuxtv.org>
Documentation for V4L2 is also available on the web at
<http://bytesex.org/v4l/>.
To compile this driver as a module, choose M here: the
module will be called videodev.
tristate
depends on MEDIA_SUPPORT
depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT
default y
config VIDEO_V4L2_COMMON
tristate
......@@ -64,25 +115,15 @@ config VIDEO_V4L2_SUBDEV_API
#
# DVB Core
# Only enables if one of DTV is selected
#
config DVB_CORE
tristate "DVB for Linux"
tristate
depends on MEDIA_SUPPORT
depends on MEDIA_DIGITAL_TV_SUPPORT
default y
select CRC32
help
DVB core utility functions for device handling, software fallbacks etc.
Enable this if you own a DVB/ATSC adapter and want to use it or if
you compile Linux for a digital SetTopBox.
Say Y when you have a DVB or an ATSC card and want to use it.
API specs and user tools are available from <http://www.linuxtv.org/>.
Please report problems regarding this support to the LinuxDVB
mailing list.
If unsure say N.
config DVB_NET
bool "DVB Network Support"
......@@ -97,12 +138,7 @@ config DVB_NET
You may want to disable the network support on embedded devices. If
unsure say Y.
config VIDEO_MEDIA
tristate
default (DVB_CORE && (VIDEO_DEV = n)) || (VIDEO_DEV && (DVB_CORE = n)) || (DVB_CORE && VIDEO_DEV)
comment "Multimedia drivers"
comment "Media drivers"
source "drivers/media/common/Kconfig"
source "drivers/media/rc/Kconfig"
......
config MEDIA_ATTACH
bool "Load and attach frontend and tuner driver modules as needed"
depends on VIDEO_MEDIA
depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
depends on MODULES
default y if !EXPERT
help
Remove the static dependency of DVB card drivers on all
frontend modules for all possible card variants. Instead,
......@@ -19,15 +20,15 @@ config MEDIA_ATTACH
config MEDIA_TUNER
tristate
default VIDEO_MEDIA && I2C
depends on VIDEO_MEDIA && I2C
depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C
default y
select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && EXPERIMENTAL
select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT && EXPERIMENTAL
select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT
select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
......@@ -47,10 +48,11 @@ config MEDIA_TUNER_CUSTOMISE
menu "Customize TV tuners"
visible if MEDIA_TUNER_CUSTOMISE
depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
config MEDIA_TUNER_SIMPLE
tristate "Simple tuner support"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
select MEDIA_TUNER_TDA9887
default m if MEDIA_TUNER_CUSTOMISE
help
......@@ -58,7 +60,7 @@ config MEDIA_TUNER_SIMPLE
config MEDIA_TUNER_TDA8290
tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
select MEDIA_TUNER_TDA827X
select MEDIA_TUNER_TDA18271
default m if MEDIA_TUNER_CUSTOMISE
......@@ -67,21 +69,21 @@ config MEDIA_TUNER_TDA8290
config MEDIA_TUNER_TDA827X
tristate "Philips TDA827X silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A DVB-T silicon tuner module. Say Y when you want to support this tuner.
config MEDIA_TUNER_TDA18271
tristate "NXP TDA18271 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A silicon tuner module. Say Y when you want to support this tuner.
config MEDIA_TUNER_TDA9887
tristate "TDA 9885/6/7 analog IF demodulator"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
Say Y here to include support for Philips TDA9885/6/7
......@@ -89,7 +91,7 @@ config MEDIA_TUNER_TDA9887
config MEDIA_TUNER_TEA5761
tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
depends on EXPERIMENTAL
default m if MEDIA_TUNER_CUSTOMISE
help
......@@ -97,63 +99,63 @@ config MEDIA_TUNER_TEA5761
config MEDIA_TUNER_TEA5767
tristate "TEA 5767 radio tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
Say Y here to include support for the Philips TEA5767 radio tuner.
config MEDIA_TUNER_MT20XX
tristate "Microtune 2032 / 2050 tuners"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
Say Y here to include support for the MT2032 / MT2050 tuner.
config MEDIA_TUNER_MT2060
tristate "Microtune MT2060 silicon IF tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A driver for the silicon IF tuner MT2060 from Microtune.
config MEDIA_TUNER_MT2063
tristate "Microtune MT2063 silicon IF tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A driver for the silicon IF tuner MT2063 from Microtune.
config MEDIA_TUNER_MT2266
tristate "Microtune MT2266 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A driver for the silicon baseband tuner MT2266 from Microtune.
config MEDIA_TUNER_MT2131
tristate "Microtune MT2131 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A driver for the silicon baseband tuner MT2131 from Microtune.
config MEDIA_TUNER_QT1010
tristate "Quantek QT1010 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A driver for the silicon tuner QT1010 from Quantek.
config MEDIA_TUNER_XC2028
tristate "XCeive xc2028/xc3028 tuners"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
Say Y here to include support for the xc2028/xc3028 tuners.
config MEDIA_TUNER_XC5000
tristate "Xceive XC5000 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A driver for the silicon tuner XC5000 from Xceive.
......@@ -162,7 +164,7 @@ config MEDIA_TUNER_XC5000
config MEDIA_TUNER_XC4000
tristate "Xceive XC4000 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A driver for the silicon tuner XC4000 from Xceive.
......@@ -171,70 +173,70 @@ config MEDIA_TUNER_XC4000
config MEDIA_TUNER_MXL5005S
tristate "MaxLinear MSL5005S silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A driver for the silicon tuner MXL5005S from MaxLinear.
config MEDIA_TUNER_MXL5007T
tristate "MaxLinear MxL5007T silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A driver for the silicon tuner MxL5007T from MaxLinear.
config MEDIA_TUNER_MC44S803
tristate "Freescale MC44S803 Low Power CMOS Broadband tuners"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the Freescale MC44S803 based tuners
config MEDIA_TUNER_MAX2165
tristate "Maxim MAX2165 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
A driver for the silicon tuner MAX2165 from Maxim.
config MEDIA_TUNER_TDA18218
tristate "NXP TDA18218 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
NXP TDA18218 silicon tuner driver.
config MEDIA_TUNER_FC0011
tristate "Fitipower FC0011 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
Fitipower FC0011 silicon tuner driver.
config MEDIA_TUNER_FC0012
tristate "Fitipower FC0012 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
Fitipower FC0012 silicon tuner driver.
config MEDIA_TUNER_FC0013
tristate "Fitipower FC0013 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
Fitipower FC0013 silicon tuner driver.
config MEDIA_TUNER_TDA18212
tristate "NXP TDA18212 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
NXP TDA18212 silicon tuner driver.
config MEDIA_TUNER_TUA9001
tristate "Infineon TUA 9001 silicon tuner"
depends on VIDEO_MEDIA && I2C
depends on MEDIA_SUPPORT && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
Infineon TUA 9001 silicon tuner driver.
......
......@@ -90,11 +90,22 @@ struct firmware_properties {
int scode_nr;
};
enum xc2028_state {
XC2028_NO_FIRMWARE = 0,
XC2028_WAITING_FIRMWARE,
XC2028_ACTIVE,
XC2028_SLEEP,
XC2028_NODEV,
};
struct xc2028_data {
struct list_head hybrid_tuner_instance_list;
struct tuner_i2c_props i2c_props;
__u32 frequency;
enum xc2028_state state;
const char *fname;
struct firmware_description *firm;
int firm_size;
__u16 firm_version;
......@@ -255,6 +266,21 @@ static v4l2_std_id parse_audio_std_option(void)
return 0;
}
static int check_device_status(struct xc2028_data *priv)
{
switch (priv->state) {
case XC2028_NO_FIRMWARE:
case XC2028_WAITING_FIRMWARE:
return -EAGAIN;
case XC2028_ACTIVE:
case XC2028_SLEEP:
return 0;
case XC2028_NODEV:
return -ENODEV;
}
return 0;
}
static void free_firmware(struct xc2028_data *priv)
{
int i;
......@@ -270,45 +296,28 @@ static void free_firmware(struct xc2028_data *priv)
priv->firm = NULL;
priv->firm_size = 0;
priv->state = XC2028_NO_FIRMWARE;
memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
}
static int load_all_firmwares(struct dvb_frontend *fe)
static int load_all_firmwares(struct dvb_frontend *fe,
const struct firmware *fw)
{
struct xc2028_data *priv = fe->tuner_priv;
const struct firmware *fw = NULL;
const unsigned char *p, *endp;
int rc = 0;
int n, n_array;
char name[33];
char *fname;
tuner_dbg("%s called\n", __func__);
if (!firmware_name[0])
fname = priv->ctrl.fname;
else
fname = firmware_name;
tuner_dbg("Reading firmware %s\n", fname);
rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
if (rc < 0) {
if (rc == -ENOENT)
tuner_err("Error: firmware %s not found.\n",
fname);
else
tuner_err("Error %d while requesting firmware %s \n",
rc, fname);
return rc;
}
p = fw->data;
endp = p + fw->size;
if (fw->size < sizeof(name) - 1 + 2 + 2) {
tuner_err("Error: firmware file %s has invalid size!\n",
fname);
priv->fname);
goto corrupt;
}
......@@ -323,7 +332,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
p += 2;
tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
n_array, fname, name,
n_array, priv->fname, name,
priv->firm_version >> 8, priv->firm_version & 0xff);
priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
......@@ -417,9 +426,10 @@ static int load_all_firmwares(struct dvb_frontend *fe)
free_firmware(priv);
done:
release_firmware(fw);
if (rc == 0)
tuner_dbg("Firmware files loaded.\n");
else
priv->state = XC2028_NODEV;
return rc;
}
......@@ -707,22 +717,15 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
{
struct xc2028_data *priv = fe->tuner_priv;
struct firmware_properties new_fw;
int rc = 0, retry_count = 0;
int rc, retry_count = 0;
u16 version, hwmodel;
v4l2_std_id std0;
tuner_dbg("%s called\n", __func__);
if (!priv->firm) {
if (!priv->ctrl.fname) {
tuner_info("xc2028/3028 firmware name not set!\n");
return -EINVAL;
}
rc = load_all_firmwares(fe);
if (rc < 0)
return rc;
}
rc = check_device_status(priv);
if (rc < 0)
return rc;
if (priv->ctrl.mts && !(type & FM))
type |= MTS;
......@@ -749,9 +752,13 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
printk("scode_nr %d\n", new_fw.scode_nr);
}
/* No need to reload base firmware if it matches */
if (((BASE | new_fw.type) & BASE_TYPES) ==
(priv->cur_fw.type & BASE_TYPES)) {
/*
* No need to reload base firmware if it matches and if the tuner
* is not at sleep mode
*/
if ((priv->state = XC2028_ACTIVE) &&
(((BASE | new_fw.type) & BASE_TYPES) ==
(priv->cur_fw.type & BASE_TYPES))) {
tuner_dbg("BASE firmware not changed.\n");
goto skip_base;
}
......@@ -872,10 +879,13 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
* 2. Tell whether BASE firmware was just changed the next time through.
*/
priv->cur_fw.type |= BASE;
priv->state = XC2028_ACTIVE;
return 0;
fail:
priv->state = XC2028_SLEEP;
memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
if (retry_count < 8) {
msleep(50);
......@@ -893,28 +903,39 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
{
struct xc2028_data *priv = fe->tuner_priv;
u16 frq_lock, signal = 0;
int rc;
int rc, i;
tuner_dbg("%s called\n", __func__);
rc = check_device_status(priv);
if (rc < 0)
return rc;
mutex_lock(&priv->lock);
/* Sync Lock Indicator */
rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
if (rc < 0)
goto ret;
for (i = 0; i < 3; i++) {
rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
if (rc < 0)
goto ret;
/* Frequency is locked */
if (frq_lock == 1)
signal = 1 << 11;
if (frq_lock)
break;
msleep(6);
}
/* Frequency didn't lock */
if (frq_lock == 2)
goto ret;
/* Get SNR of the video signal */
rc = xc2028_get_reg(priv, XREG_SNR, &signal);
if (rc < 0)
goto ret;
/* Use both frq_lock and signal to generate the result */
signal = signal || ((signal & 0x07) << 12);
/* Signal level is 3 bits only */
signal = ((1 << 12) - 1) | ((signal & 0x07) << 12);
ret:
mutex_unlock(&priv->lock);
......@@ -926,6 +947,49 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
return rc;
}
static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc)
{
struct xc2028_data *priv = fe->tuner_priv;
int i, rc;
u16 frq_lock = 0;
s16 afc_reg = 0;
rc = check_device_status(priv);
if (rc < 0)
return rc;
mutex_lock(&priv->lock);
/* Sync Lock Indicator */
for (i = 0; i < 3; i++) {
rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
if (rc < 0)
goto ret;
if (frq_lock)
break;
msleep(6);
}
/* Frequency didn't lock */
if (frq_lock == 2)
goto ret;
/* Get AFC */
rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg);
if (rc < 0)
return rc;
*afc = afc_reg * 15625; /* Hz */
tuner_dbg("AFC is %d Hz\n", *afc);
ret:
mutex_unlock(&priv->lock);
return rc;
}
#define DIV 15625
static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
......@@ -1111,11 +1175,16 @@ static int xc2028_set_params(struct dvb_frontend *fe)
u32 delsys = c->delivery_system;
u32 bw = c->bandwidth_hz;
struct xc2028_data *priv = fe->tuner_priv;
unsigned int type=0;
int rc;
unsigned int type = 0;
u16 demod = 0;
tuner_dbg("%s called\n", __func__);
rc = check_device_status(priv);
if (rc < 0)
return rc;
switch (delsys) {
case SYS_DVBT:
case SYS_DVBT2:
......@@ -1201,7 +1270,11 @@ static int xc2028_set_params(struct dvb_frontend *fe)
static int xc2028_sleep(struct dvb_frontend *fe)
{
struct xc2028_data *priv = fe->tuner_priv;
int rc = 0;
int rc;
rc = check_device_status(priv);
if (rc < 0)
return rc;
/* Avoid firmware reload on slow devices or if PM disabled */
if (no_poweroff || priv->ctrl.disable_power_mgmt)
......@@ -1220,7 +1293,7 @@ static int xc2028_sleep(struct dvb_frontend *fe)
else
rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00});
priv->cur_fw.type = 0; /* need firmware reload */
priv->state = XC2028_SLEEP;
mutex_unlock(&priv->lock);
......@@ -1237,8 +1310,9 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)
/* only perform final cleanup if this is the last instance */
if (hybrid_tuner_report_instance_count(priv) == 1) {
kfree(priv->ctrl.fname);
free_firmware(priv);
kfree(priv->ctrl.fname);
priv->ctrl.fname = NULL;
}
if (priv)
......@@ -1254,14 +1328,42 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)
static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct xc2028_data *priv = fe->tuner_priv;
int rc;
tuner_dbg("%s called\n", __func__);
rc = check_device_status(priv);
if (rc < 0)
return rc;
*frequency = priv->frequency;
return 0;
}
static void load_firmware_cb(const struct firmware *fw,
void *context)
{
struct dvb_frontend *fe = context;
struct xc2028_data *priv = fe->tuner_priv;
int rc;
tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error");
if (!fw) {
tuner_err("Could not load firmware %s.\n", priv->fname);
priv->state = XC2028_NODEV;
return;
}
rc = load_all_firmwares(fe, fw);
release_firmware(fw);
if (rc < 0)
return;
priv->state = XC2028_SLEEP;
}
static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
{
struct xc2028_data *priv = fe->tuner_priv;
......@@ -1272,21 +1374,49 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
mutex_lock(&priv->lock);
/*
* Copy the config data.
* For the firmware name, keep a local copy of the string,
* in order to avoid troubles during device release.
*/
if (priv->ctrl.fname)
kfree(priv->ctrl.fname);
memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
if (priv->ctrl.max_len < 9)
priv->ctrl.max_len = 13;
if (p->fname) {
if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) {
kfree(priv->ctrl.fname);
free_firmware(priv);
}
priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
if (priv->ctrl.fname == NULL)
rc = -ENOMEM;
}
/*
* If firmware name changed, frees firmware. As free_firmware will
* reset the status to NO_FIRMWARE, this forces a new request_firmware
*/
if (!firmware_name[0] && p->fname &&
priv->fname && strcmp(p->fname, priv->fname))
free_firmware(priv);
if (priv->ctrl.max_len < 9)
priv->ctrl.max_len = 13;
if (priv->state == XC2028_NO_FIRMWARE) {
if (!firmware_name[0])
priv->fname = priv->ctrl.fname;
else
priv->fname = firmware_name;
rc = request_firmware_nowait(THIS_MODULE, 1,
priv->fname,
priv->i2c_props.adap->dev.parent,
GFP_KERNEL,
fe, load_firmware_cb);
if (rc < 0) {
tuner_err("Failed to request firmware %s\n",
priv->fname);
priv->state = XC2028_NODEV;
}
priv->state = XC2028_WAITING_FIRMWARE;
}
mutex_unlock(&priv->lock);
return rc;
......@@ -1305,6 +1435,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
.release = xc2028_dvb_release,
.get_frequency = xc2028_get_frequency,
.get_rf_strength = xc2028_signal,
.get_afc = xc2028_get_afc,
.set_params = xc2028_set_params,
.sleep = xc2028_sleep,
};
......@@ -1375,3 +1506,5 @@ MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE);
MODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE);
......@@ -717,6 +717,12 @@ static int xc5000_set_params(struct dvb_frontend *fe)
priv->freq_hz = freq - 1750000;
priv->video_standard = DTV6;
break;
case SYS_ISDBT:
/* All ISDB-T are currently for 6 MHz bw */
if (!bw)
bw = 6000000;
/* fall to OFDM handling */
case SYS_DMBTH:
case SYS_DVBT:
case SYS_DVBT2:
dprintk(1, "%s() OFDM\n", __func__);
......
......@@ -578,6 +578,7 @@ static int demod_attach_drxk(struct ddb_input *input)
memset(&config, 0, sizeof(config));
config.microcode_name = "drxk_a3.mc";
config.qam_demod_parameter_count = 4;
config.adr = 0x29 + (input->nr & 1);
fe = input->fe = dvb_attach(drxk_attach, &config, i2c);
......
......@@ -220,6 +220,7 @@ struct dvb_tuner_ops {
#define TUNER_STATUS_STEREO 2
int (*get_status)(struct dvb_frontend *fe, u32 *status);
int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
/** These are provided separately from set_params in order to facilitate silicon
* tuners which require sophisticated tuning loops, controlling each parameter separately. */
......
......@@ -418,9 +418,12 @@ config DVB_USB_RTL28XXU
tristate "Realtek RTL28xxU DVB USB support"
depends on DVB_USB && EXPERIMENTAL
select DVB_RTL2830
select DVB_RTL2832
select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_FC0013 if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the Realtek RTL28xxU DVB USB receiver.
......
......@@ -593,9 +593,7 @@ static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
memcpy(mac, st->data, sizeof(mac));
if (ret > 0)
deb_info("%s: mac is %02x:%02x:%02x:%02x:%02x:%02x\n",
__func__, mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
deb_info("%s: mac is %pM\n", __func__, mac);
return ret;
}
......
......@@ -100,6 +100,7 @@
#define USB_PID_CONCEPTRONIC_CTVDIGRCU 0xe397
#define USB_PID_CONEXANT_D680_DMB 0x86d6
#define USB_PID_CREATIX_CTX1921 0x1921
#define USB_PID_DELOCK_USB2_DVBT 0xb803
#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
......@@ -160,6 +161,7 @@
#define USB_PID_TERRATEC_CINERGY_T_STICK 0x0093
#define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097
#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099
#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1 0x00a9
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
#define USB_PID_TWINHAN_VP7020_COLD 0x3203
......@@ -245,6 +247,7 @@
#define USB_PID_TERRATEC_H7_2 0x10a3
#define USB_PID_TERRATEC_T3 0x10a0
#define USB_PID_TERRATEC_T5 0x10a1
#define USB_PID_NOXON_DAB_STICK 0x00b3
#define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e
#define USB_PID_PINNACLE_PCTV2000E 0x022c
#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228
......
config DVB_FE_CUSTOMISE
bool "Customise the frontend modules to build"
depends on DVB_CORE
depends on EXPERT
default y if EXPERT
help
This allows the user to select/deselect frontend drivers for their
......@@ -432,6 +433,13 @@ config DVB_RTL2830
help
Say Y when you want to support this frontend.
config DVB_RTL2832
tristate "Realtek RTL2832 DVB-T"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
Say Y when you want to support this frontend.
comment "DVB-C (cable) frontends"
depends on DVB_CORE
......
......@@ -99,6 +99,7 @@ obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
obj-$(CONFIG_DVB_A8293) += a8293.o
obj-$(CONFIG_DVB_TDA10071) += tda10071.o
obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
obj-$(CONFIG_DVB_AF9033) += af9033.o
......@@ -21,24 +21,6 @@
#include "dvb_frontend.h"
#include "a8293.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
#define LOG_PREFIX "a8293"
#undef dbg
#define dbg(f, arg...) \
if (debug) \
printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
#undef err
#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
#undef info
#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
#undef warn
#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
struct a8293_priv {
struct i2c_adapter *i2c;
const struct a8293_config *cfg;
......@@ -65,7 +47,8 @@ static int a8293_i2c(struct a8293_priv *priv, u8 *val, int len, bool rd)
if (ret == 1) {
ret = 0;
} else {
warn("i2c failed=%d rd=%d", ret, rd);
dev_warn(&priv->i2c->dev, "%s: i2c failed=%d rd=%d\n",
KBUILD_MODNAME, ret, rd);
ret = -EREMOTEIO;
}
......@@ -88,7 +71,8 @@ static int a8293_set_voltage(struct dvb_frontend *fe,
struct a8293_priv *priv = fe->sec_priv;
int ret;
dbg("%s: fe_sec_voltage=%d", __func__, fe_sec_voltage);
dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__,
fe_sec_voltage);
switch (fe_sec_voltage) {
case SEC_VOLTAGE_OFF:
......@@ -114,14 +98,12 @@ static int a8293_set_voltage(struct dvb_frontend *fe,
return ret;
err:
dbg("%s: failed=%d", __func__, ret);
dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static void a8293_release_sec(struct dvb_frontend *fe)
{
dbg("%s:", __func__);
a8293_set_voltage(fe, SEC_VOLTAGE_OFF);
kfree(fe->sec_priv);
......@@ -154,7 +136,7 @@ struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
/* ENB=0 */
priv->reg[0] = 0x10;
ret = a8293_wr(priv, &priv->reg[1], 1);
ret = a8293_wr(priv, &priv->reg[0], 1);
if (ret)
goto err;
......@@ -164,16 +146,17 @@ struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
if (ret)
goto err;
info("Allegro A8293 SEC attached.");
fe->ops.release_sec = a8293_release_sec;
/* override frontend ops */
fe->ops.set_voltage = a8293_set_voltage;
dev_info(&priv->i2c->dev, "%s: Allegro A8293 SEC attached\n",
KBUILD_MODNAME);
return fe;
err:
dbg("%s: failed=%d", __func__, ret);
dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
kfree(priv);
return NULL;
}
......
......@@ -20,6 +20,14 @@
* means that 1=DVBC, 0 = DVBT. Zero means the opposite.
* @mpeg_out_clk_strength: DRXK Mpeg output clock drive strength.
* @microcode_name: Name of the firmware file with the microcode
* @qam_demod_parameter_count: The number of parameters used for the command
* to set the demodulator parameters. All
* firmwares are using the 2-parameter commmand.
* An exception is the "drxk_a3.mc" firmware,
* which uses the 4-parameter command.
* A value of 0 (default) or lower indicates that
* the correct number of parameters will be
* automatically detected.
*
* On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is
* UIO-3.
......@@ -38,7 +46,8 @@ struct drxk_config {
u8 mpeg_out_clk_strength;
int chunk_size;
const char *microcode_name;
const char *microcode_name;
int qam_demod_parameter_count;
};
#if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \
......
......@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/hardirq.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
......@@ -308,16 +309,42 @@ static u32 Log10Times100(u32 x)
/* I2C **********************************************************************/
/****************************************************************************/
static int i2c_read1(struct i2c_adapter *adapter, u8 adr, u8 *val)
static int drxk_i2c_lock(struct drxk_state *state)
{
i2c_lock_adapter(state->i2c);
state->drxk_i2c_exclusive_lock = true;
return 0;
}
static void drxk_i2c_unlock(struct drxk_state *state)
{
if (!state->drxk_i2c_exclusive_lock)
return;
i2c_unlock_adapter(state->i2c);
state->drxk_i2c_exclusive_lock = false;
}
static int drxk_i2c_transfer(struct drxk_state *state, struct i2c_msg *msgs,
unsigned len)
{
if (state->drxk_i2c_exclusive_lock)
return __i2c_transfer(state->i2c, msgs, len);
else
return i2c_transfer(state->i2c, msgs, len);
}
static int i2c_read1(struct drxk_state *state, u8 adr, u8 *val)
{
struct i2c_msg msgs[1] = { {.addr = adr, .flags = I2C_M_RD,
.buf = val, .len = 1}
};
return i2c_transfer(adapter, msgs, 1);
return drxk_i2c_transfer(state, msgs, 1);
}
static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
static int i2c_write(struct drxk_state *state, u8 adr, u8 *data, int len)
{
int status;
struct i2c_msg msg = {
......@@ -330,7 +357,7 @@ static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
printk(KERN_CONT " %02x", data[i]);
printk(KERN_CONT "\n");
}
status = i2c_transfer(adap, &msg, 1);
status = drxk_i2c_transfer(state, &msg, 1);
if (status >= 0 && status != 1)
status = -EIO;
......@@ -340,7 +367,7 @@ static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
return status;
}
static int i2c_read(struct i2c_adapter *adap,
static int i2c_read(struct drxk_state *state,
u8 adr, u8 *msg, int len, u8 *answ, int alen)
{
int status;
......@@ -351,7 +378,7 @@ static int i2c_read(struct i2c_adapter *adap,
.buf = answ, .len = alen}
};
status = i2c_transfer(adap, msgs, 2);
status = drxk_i2c_transfer(state, msgs, 2);
if (status != 2) {
if (debug > 2)
printk(KERN_CONT ": ERROR!\n");
......@@ -394,7 +421,7 @@ static int read16_flags(struct drxk_state *state, u32 reg, u16 *data, u8 flags)
len = 2;
}
dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
status = i2c_read(state->i2c, adr, mm1, len, mm2, 2);
status = i2c_read(state, adr, mm1, len, mm2, 2);
if (status < 0)
return status;
if (data)
......@@ -428,7 +455,7 @@ static int read32_flags(struct drxk_state *state, u32 reg, u32 *data, u8 flags)
len = 2;
}
dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
status = i2c_read(state->i2c, adr, mm1, len, mm2, 4);
status = i2c_read(state, adr, mm1, len, mm2, 4);
if (status < 0)
return status;
if (data)
......@@ -464,7 +491,7 @@ static int write16_flags(struct drxk_state *state, u32 reg, u16 data, u8 flags)
mm[len + 1] = (data >> 8) & 0xff;
dprintk(2, "(0x%08x, 0x%04x, 0x%02x)\n", reg, data, flags);
return i2c_write(state->i2c, adr, mm, len + 2);
return i2c_write(state, adr, mm, len + 2);
}
static int write16(struct drxk_state *state, u32 reg, u16 data)
......@@ -495,7 +522,7 @@ static int write32_flags(struct drxk_state *state, u32 reg, u32 data, u8 flags)
mm[len + 3] = (data >> 24) & 0xff;
dprintk(2, "(0x%08x, 0x%08x, 0x%02x)\n", reg, data, flags);
return i2c_write(state->i2c, adr, mm, len + 4);
return i2c_write(state, adr, mm, len + 4);
}
static int write32(struct drxk_state *state, u32 reg, u32 data)
......@@ -542,7 +569,7 @@ static int write_block(struct drxk_state *state, u32 Address,
printk(KERN_CONT " %02x", pBlock[i]);
printk(KERN_CONT "\n");
}
status = i2c_write(state->i2c, state->demod_address,
status = i2c_write(state, state->demod_address,
&state->Chunk[0], Chunk + AdrLength);
if (status < 0) {
printk(KERN_ERR "drxk: %s: i2c write error at addr 0x%02x\n",
......@@ -568,17 +595,17 @@ int PowerUpDevice(struct drxk_state *state)
dprintk(1, "\n");
status = i2c_read1(state->i2c, state->demod_address, &data);
status = i2c_read1(state, state->demod_address, &data);
if (status < 0) {
do {
data = 0;
status = i2c_write(state->i2c, state->demod_address,
status = i2c_write(state, state->demod_address,
&data, 1);
msleep(10);
retryCount++;
if (status < 0)
continue;
status = i2c_read1(state->i2c, state->demod_address,
status = i2c_read1(state, state->demod_address,
&data);
} while (status < 0 &&
(retryCount < DRXK_MAX_RETRIES_POWERUP));
......@@ -932,7 +959,7 @@ static int GetDeviceCapabilities(struct drxk_state *state)
if (status < 0)
goto error;
printk(KERN_ERR "drxk: status = 0x%08x\n", sioTopJtagidLo);
printk(KERN_INFO "drxk: status = 0x%08x\n", sioTopJtagidLo);
/* driver 0.9.0 */
switch ((sioTopJtagidLo >> 29) & 0xF) {
......@@ -2824,7 +2851,7 @@ static int ConfigureI2CBridge(struct drxk_state *state, bool bEnableBridge)
dprintk(1, "\n");
if (state->m_DrxkState == DRXK_UNINITIALIZED)
goto error;
return 0;
if (state->m_DrxkState == DRXK_POWERED_DOWN)
goto error;
......@@ -2977,7 +3004,7 @@ static int ADCSynchronization(struct drxk_state *state)
status = read16(state, IQM_AF_CLKNEG__A, &clkNeg);
if (status < 0)
goto error;
if ((clkNeg | IQM_AF_CLKNEG_CLKNEGDATA__M) ==
if ((clkNeg & IQM_AF_CLKNEG_CLKNEGDATA__M) ==
IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS) {
clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
clkNeg |=
......@@ -5361,7 +5388,7 @@ static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK, 0, NULL, 2,
Result);
if (status < 0)
printk(KERN_ERR "drxk: %s status = %08x\n", __func__, status);
printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) {
/* 0x0000 NOT LOCKED */
......@@ -5388,12 +5415,67 @@ static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
#define QAM_LOCKRANGE__M 0x10
#define QAM_LOCKRANGE_NORMAL 0x10
static int QAMDemodulatorCommand(struct drxk_state *state,
int numberOfParameters)
{
int status;
u16 cmdResult;
u16 setParamParameters[4] = { 0, 0, 0, 0 };
setParamParameters[0] = state->m_Constellation; /* modulation */
setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */
if (numberOfParameters == 2) {
u16 setEnvParameters[1] = { 0 };
if (state->m_OperationMode == OM_QAM_ITU_C)
setEnvParameters[0] = QAM_TOP_ANNEX_C;
else
setEnvParameters[0] = QAM_TOP_ANNEX_A;
status = scu_command(state,
SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV,
1, setEnvParameters, 1, &cmdResult);
if (status < 0)
goto error;
status = scu_command(state,
SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
numberOfParameters, setParamParameters,
1, &cmdResult);
} else if (numberOfParameters == 4) {
if (state->m_OperationMode == OM_QAM_ITU_C)
setParamParameters[2] = QAM_TOP_ANNEX_C;
else
setParamParameters[2] = QAM_TOP_ANNEX_A;
setParamParameters[3] |= (QAM_MIRROR_AUTO_ON);
/* Env parameters */
/* check for LOCKRANGE Extented */
/* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */
status = scu_command(state,
SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
numberOfParameters, setParamParameters,
1, &cmdResult);
} else {
printk(KERN_WARNING "drxk: Unknown QAM demodulator parameter "
"count %d\n", numberOfParameters);
}
error:
if (status < 0)
printk(KERN_WARNING "drxk: Warning %d on %s\n",
status, __func__);
return status;
}
static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
s32 tunerFreqOffset)
{
int status;
u16 setParamParameters[4] = { 0, 0, 0, 0 };
u16 cmdResult;
int qamDemodParamCount = state->qam_demod_parameter_count;
dprintk(1, "\n");
/*
......@@ -5445,34 +5527,42 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
}
if (status < 0)
goto error;
setParamParameters[0] = state->m_Constellation; /* modulation */
setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */
if (state->m_OperationMode == OM_QAM_ITU_C)
setParamParameters[2] = QAM_TOP_ANNEX_C;
else
setParamParameters[2] = QAM_TOP_ANNEX_A;
setParamParameters[3] |= (QAM_MIRROR_AUTO_ON);
/* Env parameters */
/* check for LOCKRANGE Extented */
/* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */
status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 4, setParamParameters, 1, &cmdResult);
if (status < 0) {
/* Fall-back to the simpler call */
if (state->m_OperationMode == OM_QAM_ITU_C)
setParamParameters[0] = QAM_TOP_ANNEX_C;
else
setParamParameters[0] = QAM_TOP_ANNEX_A;
status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 1, setParamParameters, 1, &cmdResult);
if (status < 0)
goto error;
/* Use the 4-parameter if it's requested or we're probing for
* the correct command. */
if (state->qam_demod_parameter_count == 4
|| !state->qam_demod_parameter_count) {
qamDemodParamCount = 4;
status = QAMDemodulatorCommand(state, qamDemodParamCount);
}
setParamParameters[0] = state->m_Constellation; /* modulation */
setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */
status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 2, setParamParameters, 1, &cmdResult);
/* Use the 2-parameter command if it was requested or if we're
* probing for the correct command and the 4-parameter command
* failed. */
if (state->qam_demod_parameter_count == 2
|| (!state->qam_demod_parameter_count && status < 0)) {
qamDemodParamCount = 2;
status = QAMDemodulatorCommand(state, qamDemodParamCount);
}
if (status < 0)
if (status < 0) {
dprintk(1, "Could not set demodulator parameters. Make "
"sure qam_demod_parameter_count (%d) is correct for "
"your firmware (%s).\n",
state->qam_demod_parameter_count,
state->microcode_name);
goto error;
} else if (!state->qam_demod_parameter_count) {
dprintk(1, "Auto-probing the correct QAM demodulator command "
"parameters was successful - using %d parameters.\n",
qamDemodParamCount);
/*
* One of our commands was successful. We don't need to
* auto-probe anymore, now that we got the correct command.
*/
state->qam_demod_parameter_count = qamDemodParamCount;
}
/*
* STEP 3: enable the system in a mode where the ADC provides valid
......@@ -5968,34 +6058,15 @@ static int PowerDownDevice(struct drxk_state *state)
return status;
}
static int load_microcode(struct drxk_state *state, const char *mc_name)
{
const struct firmware *fw = NULL;
int err = 0;
dprintk(1, "\n");
err = request_firmware(&fw, mc_name, state->i2c->dev.parent);
if (err < 0) {
printk(KERN_ERR
"drxk: Could not load firmware file %s.\n", mc_name);
printk(KERN_INFO
"drxk: Copy %s to your hotplug directory!\n", mc_name);
return err;
}
err = DownloadMicrocode(state, fw->data, fw->size);
release_firmware(fw);
return err;
}
static int init_drxk(struct drxk_state *state)
{
int status = 0;
int status = 0, n = 0;
enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
u16 driverVersion;
dprintk(1, "\n");
if ((state->m_DrxkState == DRXK_UNINITIALIZED)) {
drxk_i2c_lock(state);
status = PowerUpDevice(state);
if (status < 0)
goto error;
......@@ -6073,8 +6144,12 @@ static int init_drxk(struct drxk_state *state)
if (status < 0)
goto error;
if (state->microcode_name)
load_microcode(state, state->microcode_name);
if (state->fw) {
status = DownloadMicrocode(state, state->fw->data,
state->fw->size);
if (status < 0)
goto error;
}
/* disable token-ring bus through OFDM block for possible ucode upload */
status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF);
......@@ -6167,19 +6242,71 @@ static int init_drxk(struct drxk_state *state)
state->m_DrxkState = DRXK_POWERED_DOWN;
} else
state->m_DrxkState = DRXK_STOPPED;
/* Initialize the supported delivery systems */
n = 0;
if (state->m_hasDVBC) {
state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C;
strlcat(state->frontend.ops.info.name, " DVB-C",
sizeof(state->frontend.ops.info.name));
}
if (state->m_hasDVBT) {
state->frontend.ops.delsys[n++] = SYS_DVBT;
strlcat(state->frontend.ops.info.name, " DVB-T",
sizeof(state->frontend.ops.info.name));
}
drxk_i2c_unlock(state);
}
error:
if (status < 0)
if (status < 0) {
state->m_DrxkState = DRXK_NO_DEV;
drxk_i2c_unlock(state);
printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
}
return status;
}
static void load_firmware_cb(const struct firmware *fw,
void *context)
{
struct drxk_state *state = context;
dprintk(1, ": %s\n", fw ? "firmware loaded" : "firmware not loaded");
if (!fw) {
printk(KERN_ERR
"drxk: Could not load firmware file %s.\n",
state->microcode_name);
printk(KERN_INFO
"drxk: Copy %s to your hotplug directory!\n",
state->microcode_name);
state->microcode_name = NULL;
/*
* As firmware is now load asynchronous, it is not possible
* anymore to fail at frontend attach. We might silently
* return here, and hope that the driver won't crash.
* We might also change all DVB callbacks to return -ENODEV
* if the device is not initialized.
* As the DRX-K devices have their own internal firmware,
* let's just hope that it will match a firmware revision
* compatible with this driver and proceed.
*/
}
state->fw = fw;
init_drxk(state);
}
static void drxk_release(struct dvb_frontend *fe)
{
struct drxk_state *state = fe->demodulator_priv;
dprintk(1, "\n");
if (state->fw)
release_firmware(state->fw);
kfree(state);
}
......@@ -6188,6 +6315,12 @@ static int drxk_sleep(struct dvb_frontend *fe)
struct drxk_state *state = fe->demodulator_priv;
dprintk(1, "\n");
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return 0;
ShutDown(state);
return 0;
}
......@@ -6196,7 +6329,11 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct drxk_state *state = fe->demodulator_priv;
dprintk(1, "%s\n", enable ? "enable" : "disable");
dprintk(1, ": %s\n", enable ? "enable" : "disable");
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
return ConfigureI2CBridge(state, enable ? true : false);
}
......@@ -6209,6 +6346,12 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
dprintk(1, "\n");
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
if (!fe->ops.tuner_ops.get_if_frequency) {
printk(KERN_ERR
"drxk: Error: get_if_frequency() not defined at tuner. Can't work without it!\n");
......@@ -6262,6 +6405,12 @@ static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
u32 stat;
dprintk(1, "\n");
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
*status = 0;
GetLockStatus(state, &stat, 0);
if (stat == MPEG_LOCK)
......@@ -6275,8 +6424,15 @@ static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
static int drxk_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct drxk_state *state = fe->demodulator_priv;
dprintk(1, "\n");
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
*ber = 0;
return 0;
}
......@@ -6288,6 +6444,12 @@ static int drxk_read_signal_strength(struct dvb_frontend *fe,
u32 val = 0;
dprintk(1, "\n");
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
ReadIFAgc(state, &val);
*strength = val & 0xffff;
return 0;
......@@ -6299,6 +6461,12 @@ static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
s32 snr2;
dprintk(1, "\n");
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
GetSignalToNoise(state, &snr2);
*snr = snr2 & 0xffff;
return 0;
......@@ -6310,6 +6478,12 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
u16 err;
dprintk(1, "\n");
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
DVBTQAMGetAccPktErr(state, &err);
*ucblocks = (u32) err;
return 0;
......@@ -6318,9 +6492,16 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
*sets)
{
struct drxk_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
dprintk(1, "\n");
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
switch (p->delivery_system) {
case SYS_DVBC_ANNEX_A:
case SYS_DVBC_ANNEX_C:
......@@ -6371,10 +6552,9 @@ static struct dvb_frontend_ops drxk_ops = {
struct dvb_frontend *drxk_attach(const struct drxk_config *config,
struct i2c_adapter *i2c)
{
int n;
struct drxk_state *state = NULL;
u8 adr = config->adr;
int status;
dprintk(1, "\n");
state = kzalloc(sizeof(struct drxk_state), GFP_KERNEL);
......@@ -6385,6 +6565,7 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
state->demod_address = adr;
state->single_master = config->single_master;
state->microcode_name = config->microcode_name;
state->qam_demod_parameter_count = config->qam_demod_parameter_count;
state->no_i2c_bridge = config->no_i2c_bridge;
state->antenna_gpio = config->antenna_gpio;
state->antenna_dvbt = config->antenna_dvbt;
......@@ -6425,22 +6606,21 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
state->frontend.demodulator_priv = state;
init_state(state);
if (init_drxk(state) < 0)
goto error;
/* Initialize the supported delivery systems */
n = 0;
if (state->m_hasDVBC) {
state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C;
strlcat(state->frontend.ops.info.name, " DVB-C",
sizeof(state->frontend.ops.info.name));
}
if (state->m_hasDVBT) {
state->frontend.ops.delsys[n++] = SYS_DVBT;
strlcat(state->frontend.ops.info.name, " DVB-T",
sizeof(state->frontend.ops.info.name));
}
/* Load firmware and initialize DRX-K */
if (state->microcode_name) {
status = request_firmware_nowait(THIS_MODULE, 1,
state->microcode_name,
state->i2c->dev.parent,
GFP_KERNEL,
state, load_firmware_cb);
if (status < 0) {
printk(KERN_ERR
"drxk: failed to request a firmware\n");
return NULL;
}
} else if (init_drxk(state) < 0)
goto error;
printk(KERN_INFO "drxk: frontend initialized.\n");
return &state->frontend;
......
......@@ -94,7 +94,15 @@ enum DRXPowerMode {
enum AGC_CTRL_MODE { DRXK_AGC_CTRL_AUTO = 0, DRXK_AGC_CTRL_USER, DRXK_AGC_CTRL_OFF };
enum EDrxkState { DRXK_UNINITIALIZED = 0, DRXK_STOPPED, DRXK_DTV_STARTED, DRXK_ATV_STARTED, DRXK_POWERED_DOWN };
enum EDrxkState {
DRXK_UNINITIALIZED = 0,
DRXK_STOPPED,
DRXK_DTV_STARTED,
DRXK_ATV_STARTED,
DRXK_POWERED_DOWN,
DRXK_NO_DEV /* If drxk init failed */
};
enum EDrxkCoefArrayIndex {
DRXK_COEF_IDX_MN = 0,
DRXK_COEF_IDX_FM ,
......@@ -325,6 +333,9 @@ struct drxk_state {
enum DRXPowerMode m_currentPowerMode;
/* when true, avoids other devices to use the I2C bus */
bool drxk_i2c_exclusive_lock;
/*
* Configurable parameters at the driver. They stores the values found
* at struct drxk_config.
......@@ -338,7 +349,11 @@ struct drxk_state {
bool antenna_dvbt;
u16 antenna_gpio;
/* Firmware */
const char *microcode_name;
struct completion fw_wait_load;
const struct firmware *fw;
int qam_demod_parameter_count;
};
#define NEVER_LOCK 0
......
/*
* Realtek RTL2832 DVB-T demodulator driver
*
* Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "rtl2832_priv.h"
#include <linux/bitops.h>
int rtl2832_debug;
module_param_named(debug, rtl2832_debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
#define REG_MASK(b) (BIT(b + 1) - 1)
static const struct rtl2832_reg_entry registers[] = {
[DVBT_SOFT_RST] = {0x1, 0x1, 2, 2},
[DVBT_IIC_REPEAT] = {0x1, 0x1, 3, 3},
[DVBT_TR_WAIT_MIN_8K] = {0x1, 0x88, 11, 2},
[DVBT_RSD_BER_FAIL_VAL] = {0x1, 0x8f, 15, 0},
[DVBT_EN_BK_TRK] = {0x1, 0xa6, 7, 7},
[DVBT_AD_EN_REG] = {0x0, 0x8, 7, 7},
[DVBT_AD_EN_REG1] = {0x0, 0x8, 6, 6},
[DVBT_EN_BBIN] = {0x1, 0xb1, 0, 0},
[DVBT_MGD_THD0] = {0x1, 0x95, 7, 0},
[DVBT_MGD_THD1] = {0x1, 0x96, 7, 0},
[DVBT_MGD_THD2] = {0x1, 0x97, 7, 0},
[DVBT_MGD_THD3] = {0x1, 0x98, 7, 0},
[DVBT_MGD_THD4] = {0x1, 0x99, 7, 0},
[DVBT_MGD_THD5] = {0x1, 0x9a, 7, 0},
[DVBT_MGD_THD6] = {0x1, 0x9b, 7, 0},
[DVBT_MGD_THD7] = {0x1, 0x9c, 7, 0},
[DVBT_EN_CACQ_NOTCH] = {0x1, 0x61, 4, 4},
[DVBT_AD_AV_REF] = {0x0, 0x9, 6, 0},
[DVBT_REG_PI] = {0x0, 0xa, 2, 0},
[DVBT_PIP_ON] = {0x0, 0x21, 3, 3},
[DVBT_SCALE1_B92] = {0x2, 0x92, 7, 0},
[DVBT_SCALE1_B93] = {0x2, 0x93, 7, 0},
[DVBT_SCALE1_BA7] = {0x2, 0xa7, 7, 0},
[DVBT_SCALE1_BA9] = {0x2, 0xa9, 7, 0},
[DVBT_SCALE1_BAA] = {0x2, 0xaa, 7, 0},
[DVBT_SCALE1_BAB] = {0x2, 0xab, 7, 0},
[DVBT_SCALE1_BAC] = {0x2, 0xac, 7, 0},
[DVBT_SCALE1_BB0] = {0x2, 0xb0, 7, 0},
[DVBT_SCALE1_BB1] = {0x2, 0xb1, 7, 0},
[DVBT_KB_P1] = {0x1, 0x64, 3, 1},
[DVBT_KB_P2] = {0x1, 0x64, 6, 4},
[DVBT_KB_P3] = {0x1, 0x65, 2, 0},
[DVBT_OPT_ADC_IQ] = {0x0, 0x6, 5, 4},
[DVBT_AD_AVI] = {0x0, 0x9, 1, 0},
[DVBT_AD_AVQ] = {0x0, 0x9, 3, 2},
[DVBT_K1_CR_STEP12] = {0x2, 0xad, 9, 4},
[DVBT_TRK_KS_P2] = {0x1, 0x6f, 2, 0},
[DVBT_TRK_KS_I2] = {0x1, 0x70, 5, 3},
[DVBT_TR_THD_SET2] = {0x1, 0x72, 3, 0},
[DVBT_TRK_KC_P2] = {0x1, 0x73, 5, 3},
[DVBT_TRK_KC_I2] = {0x1, 0x75, 2, 0},
[DVBT_CR_THD_SET2] = {0x1, 0x76, 7, 6},
[DVBT_PSET_IFFREQ] = {0x1, 0x19, 21, 0},
[DVBT_SPEC_INV] = {0x1, 0x15, 0, 0},
[DVBT_RSAMP_RATIO] = {0x1, 0x9f, 27, 2},
[DVBT_CFREQ_OFF_RATIO] = {0x1, 0x9d, 23, 4},
[DVBT_FSM_STAGE] = {0x3, 0x51, 6, 3},
[DVBT_RX_CONSTEL] = {0x3, 0x3c, 3, 2},
[DVBT_RX_HIER] = {0x3, 0x3c, 6, 4},
[DVBT_RX_C_RATE_LP] = {0x3, 0x3d, 2, 0},
[DVBT_RX_C_RATE_HP] = {0x3, 0x3d, 5, 3},
[DVBT_GI_IDX] = {0x3, 0x51, 1, 0},
[DVBT_FFT_MODE_IDX] = {0x3, 0x51, 2, 2},
[DVBT_RSD_BER_EST] = {0x3, 0x4e, 15, 0},
[DVBT_CE_EST_EVM] = {0x4, 0xc, 15, 0},
[DVBT_RF_AGC_VAL] = {0x3, 0x5b, 13, 0},
[DVBT_IF_AGC_VAL] = {0x3, 0x59, 13, 0},
[DVBT_DAGC_VAL] = {0x3, 0x5, 7, 0},
[DVBT_SFREQ_OFF] = {0x3, 0x18, 13, 0},
[DVBT_CFREQ_OFF] = {0x3, 0x5f, 17, 0},
[DVBT_POLAR_RF_AGC] = {0x0, 0xe, 1, 1},
[DVBT_POLAR_IF_AGC] = {0x0, 0xe, 0, 0},
[DVBT_AAGC_HOLD] = {0x1, 0x4, 5, 5},
[DVBT_EN_RF_AGC] = {0x1, 0x4, 6, 6},
[DVBT_EN_IF_AGC] = {0x1, 0x4, 7, 7},
[DVBT_IF_AGC_MIN] = {0x1, 0x8, 7, 0},
[DVBT_IF_AGC_MAX] = {0x1, 0x9, 7, 0},
[DVBT_RF_AGC_MIN] = {0x1, 0xa, 7, 0},
[DVBT_RF_AGC_MAX] = {0x1, 0xb, 7, 0},
[DVBT_IF_AGC_MAN] = {0x1, 0xc, 6, 6},
[DVBT_IF_AGC_MAN_VAL] = {0x1, 0xc, 13, 0},
[DVBT_RF_AGC_MAN] = {0x1, 0xe, 6, 6},
[DVBT_RF_AGC_MAN_VAL] = {0x1, 0xe, 13, 0},
[DVBT_DAGC_TRG_VAL] = {0x1, 0x12, 7, 0},
[DVBT_AGC_TARG_VAL_0] = {0x1, 0x2, 0, 0},
[DVBT_AGC_TARG_VAL_8_1] = {0x1, 0x3, 7, 0},
[DVBT_AAGC_LOOP_GAIN] = {0x1, 0xc7, 5, 1},
[DVBT_LOOP_GAIN2_3_0] = {0x1, 0x4, 4, 1},
[DVBT_LOOP_GAIN2_4] = {0x1, 0x5, 7, 7},
[DVBT_LOOP_GAIN3] = {0x1, 0xc8, 4, 0},
[DVBT_VTOP1] = {0x1, 0x6, 5, 0},
[DVBT_VTOP2] = {0x1, 0xc9, 5, 0},
[DVBT_VTOP3] = {0x1, 0xca, 5, 0},
[DVBT_KRF1] = {0x1, 0xcb, 7, 0},
[DVBT_KRF2] = {0x1, 0x7, 7, 0},
[DVBT_KRF3] = {0x1, 0xcd, 7, 0},
[DVBT_KRF4] = {0x1, 0xce, 7, 0},
[DVBT_EN_GI_PGA] = {0x1, 0xe5, 0, 0},
[DVBT_THD_LOCK_UP] = {0x1, 0xd9, 8, 0},
[DVBT_THD_LOCK_DW] = {0x1, 0xdb, 8, 0},
[DVBT_THD_UP1] = {0x1, 0xdd, 7, 0},
[DVBT_THD_DW1] = {0x1, 0xde, 7, 0},
[DVBT_INTER_CNT_LEN] = {0x1, 0xd8, 3, 0},
[DVBT_GI_PGA_STATE] = {0x1, 0xe6, 3, 3},
[DVBT_EN_AGC_PGA] = {0x1, 0xd7, 0, 0},
[DVBT_CKOUTPAR] = {0x1, 0x7b, 5, 5},
[DVBT_CKOUT_PWR] = {0x1, 0x7b, 6, 6},
[DVBT_SYNC_DUR] = {0x1, 0x7b, 7, 7},
[DVBT_ERR_DUR] = {0x1, 0x7c, 0, 0},
[DVBT_SYNC_LVL] = {0x1, 0x7c, 1, 1},
[DVBT_ERR_LVL] = {0x1, 0x7c, 2, 2},
[DVBT_VAL_LVL] = {0x1, 0x7c, 3, 3},
[DVBT_SERIAL] = {0x1, 0x7c, 4, 4},
[DVBT_SER_LSB] = {0x1, 0x7c, 5, 5},
[DVBT_CDIV_PH0] = {0x1, 0x7d, 3, 0},
[DVBT_CDIV_PH1] = {0x1, 0x7d, 7, 4},
[DVBT_MPEG_IO_OPT_2_2] = {0x0, 0x6, 7, 7},
[DVBT_MPEG_IO_OPT_1_0] = {0x0, 0x7, 7, 6},
[DVBT_CKOUTPAR_PIP] = {0x0, 0xb7, 4, 4},
[DVBT_CKOUT_PWR_PIP] = {0x0, 0xb7, 3, 3},
[DVBT_SYNC_LVL_PIP] = {0x0, 0xb7, 2, 2},
[DVBT_ERR_LVL_PIP] = {0x0, 0xb7, 1, 1},
[DVBT_VAL_LVL_PIP] = {0x0, 0xb7, 0, 0},
[DVBT_CKOUTPAR_PID] = {0x0, 0xb9, 4, 4},
[DVBT_CKOUT_PWR_PID] = {0x0, 0xb9, 3, 3},
[DVBT_SYNC_LVL_PID] = {0x0, 0xb9, 2, 2},
[DVBT_ERR_LVL_PID] = {0x0, 0xb9, 1, 1},
[DVBT_VAL_LVL_PID] = {0x0, 0xb9, 0, 0},
[DVBT_SM_PASS] = {0x1, 0x93, 11, 0},
[DVBT_AD7_SETTING] = {0x0, 0x11, 15, 0},
[DVBT_RSSI_R] = {0x3, 0x1, 6, 0},
[DVBT_ACI_DET_IND] = {0x3, 0x12, 0, 0},
[DVBT_REG_MON] = {0x0, 0xd, 1, 0},
[DVBT_REG_MONSEL] = {0x0, 0xd, 2, 2},
[DVBT_REG_GPE] = {0x0, 0xd, 7, 7},
[DVBT_REG_GPO] = {0x0, 0x10, 0, 0},
[DVBT_REG_4MSEL] = {0x0, 0x13, 0, 0},
};
/* write multiple hardware registers */
static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
{
int ret;
u8 buf[1+len];
struct i2c_msg msg[1] = {
{
.addr = priv->cfg.i2c_addr,
.flags = 0,
.len = 1+len,
.buf = buf,
}
};
buf[0] = reg;
memcpy(&buf[1], val, len);
ret = i2c_transfer(priv->i2c, msg, 1);
if (ret == 1) {
ret = 0;
} else {
warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
/* read multiple hardware registers */
static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
{
int ret;
struct i2c_msg msg[2] = {
{
.addr = priv->cfg.i2c_addr,
.flags = 0,
.len = 1,
.buf = &reg,
}, {
.addr = priv->cfg.i2c_addr,
.flags = I2C_M_RD,
.len = len,
.buf = val,
}
};
ret = i2c_transfer(priv->i2c, msg, 2);
if (ret == 2) {
ret = 0;
} else {
warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
/* write multiple registers */
static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
int len)
{
int ret;
/* switch bank if needed */
if (page != priv->page) {
ret = rtl2832_wr(priv, 0x00, &page, 1);
if (ret)
return ret;
priv->page = page;
}
return rtl2832_wr(priv, reg, val, len);
}
/* read multiple registers */
static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
int len)
{
int ret;
/* switch bank if needed */
if (page != priv->page) {
ret = rtl2832_wr(priv, 0x00, &page, 1);
if (ret)
return ret;
priv->page = page;
}
return rtl2832_rd(priv, reg, val, len);
}
#if 0 /* currently not used */
/* write single register */
static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val)
{
return rtl2832_wr_regs(priv, reg, page, &val, 1);
}
#endif
/* read single register */
static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
{
return rtl2832_rd_regs(priv, reg, page, val, 1);
}
int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val)
{
int ret;
u8 reg_start_addr;
u8 msb, lsb;
u8 page;
u8 reading[4];
u32 reading_tmp;
int i;
u8 len;
u32 mask;
reg_start_addr = registers[reg].start_address;
msb = registers[reg].msb;
lsb = registers[reg].lsb;
page = registers[reg].page;
len = (msb >> 3) + 1;
mask = REG_MASK(msb - lsb);
ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
if (ret)
goto err;
reading_tmp = 0;
for (i = 0; i < len; i++)
reading_tmp |= reading[i] << ((len - 1 - i) * 8);
*val = (reading_tmp >> lsb) & mask;
return ret;
err:
dbg("%s: failed=%d", __func__, ret);
return ret;
}
int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
{
int ret, i;
u8 len;
u8 reg_start_addr;
u8 msb, lsb;
u8 page;
u32 mask;
u8 reading[4];
u8 writing[4];
u32 reading_tmp;
u32 writing_tmp;
reg_start_addr = registers[reg].start_address;
msb = registers[reg].msb;
lsb = registers[reg].lsb;
page = registers[reg].page;
len = (msb >> 3) + 1;
mask = REG_MASK(msb - lsb);
ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
if (ret)
goto err;
reading_tmp = 0;
for (i = 0; i < len; i++)
reading_tmp |= reading[i] << ((len - 1 - i) * 8);
writing_tmp = reading_tmp & ~(mask << lsb);
writing_tmp |= ((val & mask) << lsb);
for (i = 0; i < len; i++)
writing[i] = (writing_tmp >> ((len - 1 - i) * 8)) & 0xff;
ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len);
if (ret)
goto err;
return ret;
err:
dbg("%s: failed=%d", __func__, ret);
return ret;
}
static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
int ret;
struct rtl2832_priv *priv = fe->demodulator_priv;
dbg("%s: enable=%d", __func__, enable);
/* gate already open or close */
if (priv->i2c_gate_state == enable)
return 0;
ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable ? 0x1 : 0x0));
if (ret)
goto err;
priv->i2c_gate_state = enable;
return ret;
err:
dbg("%s: failed=%d", __func__, ret);
return ret;
}
static int rtl2832_init(struct dvb_frontend *fe)
{
struct rtl2832_priv *priv = fe->demodulator_priv;
int i, ret;
u8 en_bbin;
u64 pset_iffreq;
/* initialization values for the demodulator registers */
struct rtl2832_reg_value rtl2832_initial_regs[] = {
{DVBT_AD_EN_REG, 0x1},
{DVBT_AD_EN_REG1, 0x1},
{DVBT_RSD_BER_FAIL_VAL, 0x2800},
{DVBT_MGD_THD0, 0x10},
{DVBT_MGD_THD1, 0x20},
{DVBT_MGD_THD2, 0x20},
{DVBT_MGD_THD3, 0x40},
{DVBT_MGD_THD4, 0x22},
{DVBT_MGD_THD5, 0x32},
{DVBT_MGD_THD6, 0x37},
{DVBT_MGD_THD7, 0x39},
{DVBT_EN_BK_TRK, 0x0},
{DVBT_EN_CACQ_NOTCH, 0x0},
{DVBT_AD_AV_REF, 0x2a},
{DVBT_REG_PI, 0x6},
{DVBT_PIP_ON, 0x0},
{DVBT_CDIV_PH0, 0x8},
{DVBT_CDIV_PH1, 0x8},
{DVBT_SCALE1_B92, 0x4},
{DVBT_SCALE1_B93, 0xb0},
{DVBT_SCALE1_BA7, 0x78},
{DVBT_SCALE1_BA9, 0x28},
{DVBT_SCALE1_BAA, 0x59},
{DVBT_SCALE1_BAB, 0x83},
{DVBT_SCALE1_BAC, 0xd4},
{DVBT_SCALE1_BB0, 0x65},
{DVBT_SCALE1_BB1, 0x43},
{DVBT_KB_P1, 0x1},
{DVBT_KB_P2, 0x4},
{DVBT_KB_P3, 0x7},
{DVBT_K1_CR_STEP12, 0xa},
{DVBT_REG_GPE, 0x1},
{DVBT_SERIAL, 0x0},
{DVBT_CDIV_PH0, 0x9},
{DVBT_CDIV_PH1, 0x9},
{DVBT_MPEG_IO_OPT_2_2, 0x0},
{DVBT_MPEG_IO_OPT_1_0, 0x0},
{DVBT_TRK_KS_P2, 0x4},
{DVBT_TRK_KS_I2, 0x7},
{DVBT_TR_THD_SET2, 0x6},
{DVBT_TRK_KC_I2, 0x5},
{DVBT_CR_THD_SET2, 0x1},
{DVBT_SPEC_INV, 0x0},
{DVBT_DAGC_TRG_VAL, 0x5a},
{DVBT_AGC_TARG_VAL_0, 0x0},
{DVBT_AGC_TARG_VAL_8_1, 0x5a},
{DVBT_AAGC_LOOP_GAIN, 0x16},
{DVBT_LOOP_GAIN2_3_0, 0x6},
{DVBT_LOOP_GAIN2_4, 0x1},
{DVBT_LOOP_GAIN3, 0x16},
{DVBT_VTOP1, 0x35},
{DVBT_VTOP2, 0x21},
{DVBT_VTOP3, 0x21},
{DVBT_KRF1, 0x0},
{DVBT_KRF2, 0x40},
{DVBT_KRF3, 0x10},
{DVBT_KRF4, 0x10},
{DVBT_IF_AGC_MIN, 0x80},
{DVBT_IF_AGC_MAX, 0x7f},
{DVBT_RF_AGC_MIN, 0x80},
{DVBT_RF_AGC_MAX, 0x7f},
{DVBT_POLAR_RF_AGC, 0x0},
{DVBT_POLAR_IF_AGC, 0x0},
{DVBT_AD7_SETTING, 0xe9bf},
{DVBT_EN_GI_PGA, 0x0},
{DVBT_THD_LOCK_UP, 0x0},
{DVBT_THD_LOCK_DW, 0x0},
{DVBT_THD_UP1, 0x11},
{DVBT_THD_DW1, 0xef},
{DVBT_INTER_CNT_LEN, 0xc},
{DVBT_GI_PGA_STATE, 0x0},
{DVBT_EN_AGC_PGA, 0x1},
{DVBT_IF_AGC_MAN, 0x0},
};
dbg("%s", __func__);
en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0);
/*
* PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22)
* / CrystalFreqHz)
*/
pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal;
pset_iffreq *= 0x400000;
pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
pset_iffreq = pset_iffreq & 0x3fffff;
for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) {
ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg,
rtl2832_initial_regs[i].value);
if (ret)
goto err;
}
/* if frequency settings */
ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
if (ret)
goto err;
ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
if (ret)
goto err;
priv->sleeping = false;
return ret;
err:
dbg("%s: failed=%d", __func__, ret);
return ret;
}
static int rtl2832_sleep(struct dvb_frontend *fe)
{
struct rtl2832_priv *priv = fe->demodulator_priv;
dbg("%s", __func__);
priv->sleeping = true;
return 0;
}
int rtl2832_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s)
{
dbg("%s", __func__);
s->min_delay_ms = 1000;
s->step_size = fe->ops.info.frequency_stepsize * 2;
s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
return 0;
}
static int rtl2832_set_frontend(struct dvb_frontend *fe)
{
struct rtl2832_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i, j;
u64 bw_mode, num, num2;
u32 resamp_ratio, cfreq_off_ratio;
static u8 bw_params[3][32] = {
/* 6 MHz bandwidth */
{
0xf5, 0xff, 0x15, 0x38, 0x5d, 0x6d, 0x52, 0x07, 0xfa, 0x2f,
0x53, 0xf5, 0x3f, 0xca, 0x0b, 0x91, 0xea, 0x30, 0x63, 0xb2,
0x13, 0xda, 0x0b, 0xc4, 0x18, 0x7e, 0x16, 0x66, 0x08, 0x67,
0x19, 0xe0,
},
/* 7 MHz bandwidth */
{
0xe7, 0xcc, 0xb5, 0xba, 0xe8, 0x2f, 0x67, 0x61, 0x00, 0xaf,
0x86, 0xf2, 0xbf, 0x59, 0x04, 0x11, 0xb6, 0x33, 0xa4, 0x30,
0x15, 0x10, 0x0a, 0x42, 0x18, 0xf8, 0x17, 0xd9, 0x07, 0x22,
0x19, 0x10,
},
/* 8 MHz bandwidth */
{
0x09, 0xf6, 0xd2, 0xa7, 0x9a, 0xc9, 0x27, 0x77, 0x06, 0xbf,
0xec, 0xf4, 0x4f, 0x0b, 0xfc, 0x01, 0x63, 0x35, 0x54, 0xa7,
0x16, 0x66, 0x08, 0xb4, 0x19, 0x6e, 0x19, 0x65, 0x05, 0xc8,
0x19, 0xe0,
},
};
dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
c->frequency, c->bandwidth_hz, c->inversion);
/* program tuner */
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe);
switch (c->bandwidth_hz) {
case 6000000:
i = 0;
bw_mode = 48000000;
break;
case 7000000:
i = 1;
bw_mode = 56000000;
break;
case 8000000:
i = 2;
bw_mode = 64000000;
break;
default:
dbg("invalid bandwidth");
return -EINVAL;
}
for (j = 0; j < sizeof(bw_params[j]); j++) {
ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1);
if (ret)
goto err;
}
/* calculate and set resample ratio
* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22)
* / ConstWithBandwidthMode)
*/
num = priv->cfg.xtal * 7;
num *= 0x400000;
num = div_u64(num, bw_mode);
resamp_ratio = num & 0x3ffffff;
ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio);
if (ret)
goto err;
/* calculate and set cfreq off ratio
* CFREQ_OFF_RATIO = - floor(ConstWithBandwidthMode * pow(2, 20)
* / (CrystalFreqHz * 7))
*/
num = bw_mode << 20;
num2 = priv->cfg.xtal * 7;
num = div_u64(num, num2);
num = -num;
cfreq_off_ratio = num & 0xfffff;
ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
if (ret)
goto err;
/* soft reset */
ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
if (ret)
goto err;
ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
if (ret)
goto err;
return ret;
err:
info("%s: failed=%d", __func__, ret);
return ret;
}
static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct rtl2832_priv *priv = fe->demodulator_priv;
int ret;
u32 tmp;
*status = 0;
dbg("%s", __func__);
if (priv->sleeping)
return 0;
ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp);
if (ret)
goto err;
if (tmp == 11) {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
}
/* TODO find out if this is also true for rtl2832? */
/*else if (tmp == 10) {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI;
}*/
return ret;
err:
info("%s: failed=%d", __func__, ret);
return ret;
}
static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
{
*snr = 0;
return 0;
}
static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
{
*ber = 0;
return 0;
}
static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
*ucblocks = 0;
return 0;
}
static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
*strength = 0;
return 0;
}
static struct dvb_frontend_ops rtl2832_ops;
static void rtl2832_release(struct dvb_frontend *fe)
{
struct rtl2832_priv *priv = fe->demodulator_priv;
dbg("%s", __func__);
kfree(priv);
}
struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
struct i2c_adapter *i2c)
{
struct rtl2832_priv *priv = NULL;
int ret = 0;
u8 tmp;
dbg("%s", __func__);
/* allocate memory for the internal state */
priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
if (priv == NULL)
goto err;
/* setup the priv */
priv->i2c = i2c;
priv->tuner = cfg->tuner;
memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
/* check if the demod is there */
ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
if (ret)
goto err;
/* create dvb_frontend */
memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
priv->fe.demodulator_priv = priv;
/* TODO implement sleep mode */
priv->sleeping = true;
return &priv->fe;
err:
dbg("%s: failed=%d", __func__, ret);
kfree(priv);
return NULL;
}
EXPORT_SYMBOL(rtl2832_attach);
static struct dvb_frontend_ops rtl2832_ops = {
.delsys = { SYS_DVBT },
.info = {
.name = "Realtek RTL2832 (DVB-T)",
.frequency_min = 174000000,
.frequency_max = 862000000,
.frequency_stepsize = 166667,
.caps = FE_CAN_FEC_1_2 |
FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 |
FE_CAN_FEC_7_8 |
FE_CAN_FEC_AUTO |
FE_CAN_QPSK |
FE_CAN_QAM_16 |
FE_CAN_QAM_64 |
FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO |
FE_CAN_RECOVER |
FE_CAN_MUTE_TS
},
.release = rtl2832_release,
.init = rtl2832_init,
.sleep = rtl2832_sleep,
.get_tune_settings = rtl2832_get_tune_settings,
.set_frontend = rtl2832_set_frontend,
.read_status = rtl2832_read_status,
.read_snr = rtl2832_read_snr,
.read_ber = rtl2832_read_ber,
.read_ucblocks = rtl2832_read_ucblocks,
.read_signal_strength = rtl2832_read_signal_strength,
.i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
};
MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.5");
/*
* Realtek RTL2832 DVB-T demodulator driver
*
* Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef RTL2832_H
#define RTL2832_H
#include <linux/dvb/frontend.h>
struct rtl2832_config {
/*
* Demodulator I2C address.
*/
u8 i2c_addr;
/*
* Xtal frequency.
* Hz
* 4000000, 16000000, 25000000, 28800000
*/
u32 xtal;
/*
* IFs for all used modes.
* Hz
* 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
*/
u32 if_dvbt;
/*
*/
u8 tuner;
};
#if defined(CONFIG_DVB_RTL2832) || \
(defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE))
extern struct dvb_frontend *rtl2832_attach(
const struct rtl2832_config *cfg,
struct i2c_adapter *i2c
);
extern struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
struct dvb_frontend *fe
);
#else
static inline struct dvb_frontend *rtl2832_attach(
const struct rtl2832_config *config,
struct i2c_adapter *i2c
)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
#endif /* RTL2832_H */
/*
* Realtek RTL2832 DVB-T demodulator driver
*
* Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef RTL2832_PRIV_H
#define RTL2832_PRIV_H
#include "dvb_frontend.h"
#include "rtl2832.h"
#define LOG_PREFIX "rtl2832"
#undef dbg
#define dbg(f, arg...) \
do { \
if (rtl2832_debug) \
printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg); \
} while (0)
#undef err
#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
#undef info
#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
#undef warn
#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
struct rtl2832_priv {
struct i2c_adapter *i2c;
struct dvb_frontend fe;
struct rtl2832_config cfg;
bool i2c_gate_state;
bool sleeping;
u8 tuner;
u8 page; /* active register page */
};
struct rtl2832_reg_entry {
u8 page;
u8 start_address;
u8 msb;
u8 lsb;
};
struct rtl2832_reg_value {
int reg;
u32 value;
};
/* Demod register bit names */
enum DVBT_REG_BIT_NAME {
DVBT_SOFT_RST,
DVBT_IIC_REPEAT,
DVBT_TR_WAIT_MIN_8K,
DVBT_RSD_BER_FAIL_VAL,
DVBT_EN_BK_TRK,
DVBT_REG_PI,
DVBT_REG_PFREQ_1_0,
DVBT_PD_DA8,
DVBT_LOCK_TH,
DVBT_BER_PASS_SCAL,
DVBT_CE_FFSM_BYPASS,
DVBT_ALPHAIIR_N,
DVBT_ALPHAIIR_DIF,
DVBT_EN_TRK_SPAN,
DVBT_LOCK_TH_LEN,
DVBT_CCI_THRE,
DVBT_CCI_MON_SCAL,
DVBT_CCI_M0,
DVBT_CCI_M1,
DVBT_CCI_M2,
DVBT_CCI_M3,
DVBT_SPEC_INIT_0,
DVBT_SPEC_INIT_1,
DVBT_SPEC_INIT_2,
DVBT_AD_EN_REG,
DVBT_AD_EN_REG1,
DVBT_EN_BBIN,
DVBT_MGD_THD0,
DVBT_MGD_THD1,
DVBT_MGD_THD2,
DVBT_MGD_THD3,
DVBT_MGD_THD4,
DVBT_MGD_THD5,
DVBT_MGD_THD6,
DVBT_MGD_THD7,
DVBT_EN_CACQ_NOTCH,
DVBT_AD_AV_REF,
DVBT_PIP_ON,
DVBT_SCALE1_B92,
DVBT_SCALE1_B93,
DVBT_SCALE1_BA7,
DVBT_SCALE1_BA9,
DVBT_SCALE1_BAA,
DVBT_SCALE1_BAB,
DVBT_SCALE1_BAC,
DVBT_SCALE1_BB0,
DVBT_SCALE1_BB1,
DVBT_KB_P1,
DVBT_KB_P2,
DVBT_KB_P3,
DVBT_OPT_ADC_IQ,
DVBT_AD_AVI,
DVBT_AD_AVQ,
DVBT_K1_CR_STEP12,
DVBT_TRK_KS_P2,
DVBT_TRK_KS_I2,
DVBT_TR_THD_SET2,
DVBT_TRK_KC_P2,
DVBT_TRK_KC_I2,
DVBT_CR_THD_SET2,
DVBT_PSET_IFFREQ,
DVBT_SPEC_INV,
DVBT_BW_INDEX,
DVBT_RSAMP_RATIO,
DVBT_CFREQ_OFF_RATIO,
DVBT_FSM_STAGE,
DVBT_RX_CONSTEL,
DVBT_RX_HIER,
DVBT_RX_C_RATE_LP,
DVBT_RX_C_RATE_HP,
DVBT_GI_IDX,
DVBT_FFT_MODE_IDX,
DVBT_RSD_BER_EST,
DVBT_CE_EST_EVM,
DVBT_RF_AGC_VAL,
DVBT_IF_AGC_VAL,
DVBT_DAGC_VAL,
DVBT_SFREQ_OFF,
DVBT_CFREQ_OFF,
DVBT_POLAR_RF_AGC,
DVBT_POLAR_IF_AGC,
DVBT_AAGC_HOLD,
DVBT_EN_RF_AGC,
DVBT_EN_IF_AGC,
DVBT_IF_AGC_MIN,
DVBT_IF_AGC_MAX,
DVBT_RF_AGC_MIN,
DVBT_RF_AGC_MAX,
DVBT_IF_AGC_MAN,
DVBT_IF_AGC_MAN_VAL,
DVBT_RF_AGC_MAN,
DVBT_RF_AGC_MAN_VAL,
DVBT_DAGC_TRG_VAL,
DVBT_AGC_TARG_VAL,
DVBT_LOOP_GAIN_3_0,
DVBT_LOOP_GAIN_4,
DVBT_VTOP,
DVBT_KRF,
DVBT_AGC_TARG_VAL_0,
DVBT_AGC_TARG_VAL_8_1,
DVBT_AAGC_LOOP_GAIN,
DVBT_LOOP_GAIN2_3_0,
DVBT_LOOP_GAIN2_4,
DVBT_LOOP_GAIN3,
DVBT_VTOP1,
DVBT_VTOP2,
DVBT_VTOP3,
DVBT_KRF1,
DVBT_KRF2,
DVBT_KRF3,
DVBT_KRF4,
DVBT_EN_GI_PGA,
DVBT_THD_LOCK_UP,
DVBT_THD_LOCK_DW,
DVBT_THD_UP1,
DVBT_THD_DW1,
DVBT_INTER_CNT_LEN,
DVBT_GI_PGA_STATE,
DVBT_EN_AGC_PGA,
DVBT_CKOUTPAR,
DVBT_CKOUT_PWR,
DVBT_SYNC_DUR,
DVBT_ERR_DUR,
DVBT_SYNC_LVL,
DVBT_ERR_LVL,
DVBT_VAL_LVL,
DVBT_SERIAL,
DVBT_SER_LSB,
DVBT_CDIV_PH0,
DVBT_CDIV_PH1,
DVBT_MPEG_IO_OPT_2_2,
DVBT_MPEG_IO_OPT_1_0,
DVBT_CKOUTPAR_PIP,
DVBT_CKOUT_PWR_PIP,
DVBT_SYNC_LVL_PIP,
DVBT_ERR_LVL_PIP,
DVBT_VAL_LVL_PIP,
DVBT_CKOUTPAR_PID,
DVBT_CKOUT_PWR_PID,
DVBT_SYNC_LVL_PID,
DVBT_ERR_LVL_PID,
DVBT_VAL_LVL_PID,
DVBT_SM_PASS,
DVBT_UPDATE_REG_2,
DVBT_BTHD_P3,
DVBT_BTHD_D3,
DVBT_FUNC4_REG0,
DVBT_FUNC4_REG1,
DVBT_FUNC4_REG2,
DVBT_FUNC4_REG3,
DVBT_FUNC4_REG4,
DVBT_FUNC4_REG5,
DVBT_FUNC4_REG6,
DVBT_FUNC4_REG7,
DVBT_FUNC4_REG8,
DVBT_FUNC4_REG9,
DVBT_FUNC4_REG10,
DVBT_FUNC5_REG0,
DVBT_FUNC5_REG1,
DVBT_FUNC5_REG2,
DVBT_FUNC5_REG3,
DVBT_FUNC5_REG4,
DVBT_FUNC5_REG5,
DVBT_FUNC5_REG6,
DVBT_FUNC5_REG7,
DVBT_FUNC5_REG8,
DVBT_FUNC5_REG9,
DVBT_FUNC5_REG10,
DVBT_FUNC5_REG11,
DVBT_FUNC5_REG12,
DVBT_FUNC5_REG13,
DVBT_FUNC5_REG14,
DVBT_FUNC5_REG15,
DVBT_FUNC5_REG16,
DVBT_FUNC5_REG17,
DVBT_FUNC5_REG18,
DVBT_AD7_SETTING,
DVBT_RSSI_R,
DVBT_ACI_DET_IND,
DVBT_REG_MON,
DVBT_REG_MONSEL,
DVBT_REG_GPE,
DVBT_REG_GPO,
DVBT_REG_4MSEL,
DVBT_TEST_REG_1,
DVBT_TEST_REG_2,
DVBT_TEST_REG_3,
DVBT_TEST_REG_4,
DVBT_REG_BIT_NAME_ITEM_TERMINATOR,
};
#endif /* RTL2832_PRIV_H */
......@@ -634,7 +634,6 @@ static int s5h1420_set_frontend(struct dvb_frontend *fe)
struct s5h1420_state* state = fe->demodulator_priv;
int frequency_delta;
struct dvb_frontend_tune_settings fesettings;
uint8_t clock_setting;
dprintk("enter %s\n", __func__);
......@@ -679,25 +678,6 @@ static int s5h1420_set_frontend(struct dvb_frontend *fe)
else
state->fclk = 44000000;
/* Clock */
switch (state->fclk) {
default:
case 88000000:
clock_setting = 80;
break;
case 86000000:
clock_setting = 78;
break;
case 80000000:
clock_setting = 72;
break;
case 59000000:
clock_setting = 51;
break;
case 44000000:
clock_setting = 36;
break;
}
dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8);
s5h1420_writereg(state, PLL02, 0x40);
......
......@@ -1129,7 +1129,6 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
struct stb0899_internal *internal = &state->internal;
u8 lsb, msb;
u32 i;
*ber = 0;
......@@ -1137,14 +1136,9 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
case SYS_DVBS:
case SYS_DSS:
if (internal->lock) {
/* average 5 BER values */
for (i = 0; i < 5; i++) {
msleep(100);
lsb = stb0899_read_reg(state, STB0899_ECNT1L);
msb = stb0899_read_reg(state, STB0899_ECNT1M);
*ber += MAKEWORD16(msb, lsb);
}
*ber /= 5;
lsb = stb0899_read_reg(state, STB0899_ECNT1L);
msb = stb0899_read_reg(state, STB0899_ECNT1M);
*ber = MAKEWORD16(msb, lsb);
/* Viterbi Check */
if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) {
/* Error Rate */
......@@ -1157,13 +1151,9 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
break;
case SYS_DVBS2:
if (internal->lock) {
/* Average 5 PER values */
for (i = 0; i < 5; i++) {
msleep(100);
lsb = stb0899_read_reg(state, STB0899_ECNT1L);
msb = stb0899_read_reg(state, STB0899_ECNT1M);
*ber += MAKEWORD16(msb, lsb);
}
lsb = stb0899_read_reg(state, STB0899_ECNT1L);
msb = stb0899_read_reg(state, STB0899_ECNT1M);
*ber = MAKEWORD16(msb, lsb);
/* ber = ber * 10 ^ 7 */
*ber *= 10000000;
*ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl))));
......
......@@ -1584,7 +1584,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe)
struct stv0367ter_state *ter_state = state->ter_state;
int offset = 0, tempo = 0;
u8 u_var;
u8 /*constell,*/ counter, tps_rcvd[2];
u8 /*constell,*/ counter;
s8 step;
s32 timing_offset = 0;
u32 trl_nomrate = 0, InternalFreq = 0, temp = 0;
......@@ -1709,9 +1709,6 @@ static int stv0367ter_algo(struct dvb_frontend *fe)
return 0;
ter_state->state = FE_TER_LOCKOK;
/* update results */
tps_rcvd[0] = stv0367_readreg(state, R367TER_TPS_RCVD2);
tps_rcvd[1] = stv0367_readreg(state, R367TER_TPS_RCVD3);
ter_state->mode = stv0367_readbits(state, F367TER_SYR_MODE);
ter_state->guard = stv0367_readbits(state, F367TER_SYR_GUARD);
......
......@@ -3172,7 +3172,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
enum stv090x_signal_state signal_state = STV090x_NOCARRIER;
u32 reg;
s32 agc1_power, power_iq = 0, i;
int lock = 0, low_sr = 0, no_signal = 0;
int lock = 0, low_sr = 0;
reg = STV090x_READ_DEMOD(state, TSCFGH);
STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */
......@@ -3413,7 +3413,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
goto err;
} else {
signal_state = STV090x_NODATA;
no_signal = stv090x_chk_signal(state);
stv090x_chk_signal(state);
}
}
return signal_state;
......
......@@ -25,19 +25,6 @@
#include "tda10071.h"
#include <linux/firmware.h>
#define LOG_PREFIX "tda10071"
#undef dbg
#define dbg(f, arg...) \
if (tda10071_debug) \
printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
#undef err
#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
#undef info
#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
#undef warn
#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
struct tda10071_priv {
struct i2c_adapter *i2c;
struct dvb_frontend fe;
......@@ -112,7 +99,7 @@ struct tda10071_reg_val_mask {
#define CMD_BER_UPDATE_COUNTERS 0x3f
/* firmare command struct */
#define TDA10071_ARGLEN 0x1e
#define TDA10071_ARGLEN 30
struct tda10071_cmd {
u8 args[TDA10071_ARGLEN];
u8 len;
......
......@@ -217,6 +217,7 @@ static int demod_attach_drxk(struct ngene_channel *chan,
memset(&config, 0, sizeof(config));
config.microcode_name = "drxk_a3.mc";
config.qam_demod_parameter_count = 4;
config.adr = 0x29 + (chan->number ^ 2);
chan->fe = dvb_attach(drxk_attach, &config, i2c);
......
......@@ -5,6 +5,7 @@
menuconfig RADIO_ADAPTERS
bool "Radio Adapters"
depends on VIDEO_V4L2
depends on MEDIA_RADIO_SUPPORT
default y
---help---
Say Y here to enable selecting AM/FM radio adapters.
......
#ifndef __LM7000_H
#define __LM7000_H
/* Sanyo LM7000 tuner chip control
*
* Copyright 2012 Ondrej Zary <linux@rainbow-software.org>
* based on radio-aimslab.c by M. Kirkwood
* and radio-sf16fmi.c by M. Kirkwood and Petr Vandrovec
*/
#define LM7000_DATA (1 << 0)
#define LM7000_CLK (1 << 1)
#define LM7000_CE (1 << 2)
#define LM7000_FM_100 (0 << 20)
#define LM7000_FM_50 (1 << 20)
#define LM7000_FM_25 (2 << 20)
#define LM7000_BIT_FM (1 << 23)
static inline void lm7000_set_freq(u32 freq, void *handle,
void (*set_pins)(void *handle, u8 pins))
{
int i;
u8 data;
u32 val;
freq += 171200; /* Add 10.7 MHz IF */
freq /= 400; /* Convert to 25 kHz units */
val = freq | LM7000_FM_25 | LM7000_BIT_FM;
/* write the 24-bit register, starting with LSB */
for (i = 0; i < 24; i++) {
data = val & (1 << i) ? LM7000_DATA : 0;
set_pins(handle, data | LM7000_CE);
udelay(2);
set_pins(handle, data | LM7000_CE | LM7000_CLK);
udelay(2);
set_pins(handle, data | LM7000_CE);
udelay(2);
}
set_pins(handle, 0);
}
#endif /* __LM7000_H */
......@@ -37,6 +37,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include "radio-isa.h"
#include "lm7000.h"
MODULE_AUTHOR("M. Kirkwood");
MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
......@@ -72,55 +73,38 @@ static struct radio_isa_card *rtrack_alloc(void)
return rt ? &rt->isa : NULL;
}
/* The 128+64 on these outb's is to keep the volume stable while tuning.
* Without them, the volume _will_ creep up with each frequency change
* and bit 4 (+16) is to keep the signal strength meter enabled.
*/
#define AIMS_BIT_TUN_CE (1 << 0)
#define AIMS_BIT_TUN_CLK (1 << 1)
#define AIMS_BIT_TUN_DATA (1 << 2)
#define AIMS_BIT_VOL_CE (1 << 3)
#define AIMS_BIT_TUN_STRQ (1 << 4)
/* bit 5 is not connected */
#define AIMS_BIT_VOL_UP (1 << 6) /* active low */
#define AIMS_BIT_VOL_DN (1 << 7) /* active low */
static void send_0_byte(struct radio_isa_card *isa, int on)
void rtrack_set_pins(void *handle, u8 pins)
{
outb_p(128+64+16+on+1, isa->io); /* wr-enable + data low */
outb_p(128+64+16+on+2+1, isa->io); /* clock */
msleep(1);
}
struct radio_isa_card *isa = handle;
struct rtrack *rt = container_of(isa, struct rtrack, isa);
u8 bits = AIMS_BIT_VOL_DN | AIMS_BIT_VOL_UP | AIMS_BIT_TUN_STRQ;
static void send_1_byte(struct radio_isa_card *isa, int on)
{
outb_p(128+64+16+on+4+1, isa->io); /* wr-enable+data high */
outb_p(128+64+16+on+4+2+1, isa->io); /* clock */
msleep(1);
if (!v4l2_ctrl_g_ctrl(rt->isa.mute))
bits |= AIMS_BIT_VOL_CE;
if (pins & LM7000_DATA)
bits |= AIMS_BIT_TUN_DATA;
if (pins & LM7000_CLK)
bits |= AIMS_BIT_TUN_CLK;
if (pins & LM7000_CE)
bits |= AIMS_BIT_TUN_CE;
outb_p(bits, rt->isa.io);
}
static int rtrack_s_frequency(struct radio_isa_card *isa, u32 freq)
{
int on = v4l2_ctrl_g_ctrl(isa->mute) ? 0 : 8;
int i;
freq += 171200; /* Add 10.7 MHz IF */
freq /= 800; /* Convert to 50 kHz units */
send_0_byte(isa, on); /* 0: LSB of frequency */
for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
if (freq & (1 << i))
send_1_byte(isa, on);
else
send_0_byte(isa, on);
send_0_byte(isa, on); /* 14: test bit - always 0 */
send_0_byte(isa, on); /* 15: test bit - always 0 */
send_0_byte(isa, on); /* 16: band data 0 - always 0 */
send_0_byte(isa, on); /* 17: band data 1 - always 0 */
send_0_byte(isa, on); /* 18: band data 2 - always 0 */
send_0_byte(isa, on); /* 19: time base - always 0 */
send_0_byte(isa, on); /* 20: spacing (0 = 25 kHz) */
send_1_byte(isa, on); /* 21: spacing (1 = 25 kHz) */
send_0_byte(isa, on); /* 22: spacing (0 = 25 kHz) */
send_1_byte(isa, on); /* 23: AM/FM (FM = 1, always) */
lm7000_set_freq(freq, isa, rtrack_set_pins);
outb(0xd0 + on, isa->io); /* volume steady + sigstr */
return 0;
}
......
......@@ -295,7 +295,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
v->type = V4L2_TUNER_RADIO;
v->rangelow = FREQ_MIN * FREQ_MUL;
v->rangehigh = FREQ_MAX * FREQ_MUL;
v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_HWSEEK_WRAP;
v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
v->audmode = radio->stereo ?
V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
......@@ -372,7 +373,7 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *priv,
timeout = jiffies + msecs_to_jiffies(30000);
for (;;) {
if (time_after(jiffies, timeout)) {
retval = -EAGAIN;
retval = -ENODATA;
break;
}
if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
......
......@@ -27,6 +27,7 @@
#include <linux/io.h> /* outb, outb_p */
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include "lm7000.h"
MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
MODULE_DESCRIPTION("A driver for the SF16-FMI, SF16-FMP and SF16-FMD radio.");
......@@ -54,31 +55,33 @@ static struct fmi fmi_card;
static struct pnp_dev *dev;
bool pnp_attached;
/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
/* It is only useful to give freq in interval of 800 (=0.05Mhz),
* other bits will be truncated, e.g 92.7400016 -> 92.7, but
* 92.7400017 -> 92.75
*/
#define RSF16_ENCODE(x) ((x) / 800 + 214)
#define RSF16_MINFREQ (87 * 16000)
#define RSF16_MAXFREQ (108 * 16000)
static void outbits(int bits, unsigned int data, int io)
#define FMI_BIT_TUN_CE (1 << 0)
#define FMI_BIT_TUN_CLK (1 << 1)
#define FMI_BIT_TUN_DATA (1 << 2)
#define FMI_BIT_VOL_SW (1 << 3)
#define FMI_BIT_TUN_STRQ (1 << 4)
void fmi_set_pins(void *handle, u8 pins)
{
while (bits--) {
if (data & 1) {
outb(5, io);
udelay(6);
outb(7, io);
udelay(6);
} else {
outb(1, io);
udelay(6);
outb(3, io);
udelay(6);
}
data >>= 1;
}
struct fmi *fmi = handle;
u8 bits = FMI_BIT_TUN_STRQ;
if (!fmi->mute)
bits |= FMI_BIT_VOL_SW;
if (pins & LM7000_DATA)
bits |= FMI_BIT_TUN_DATA;
if (pins & LM7000_CLK)
bits |= FMI_BIT_TUN_CLK;
if (pins & LM7000_CE)
bits |= FMI_BIT_TUN_CE;
mutex_lock(&fmi->lock);
outb_p(bits, fmi->io);
mutex_unlock(&fmi->lock);
}
static inline void fmi_mute(struct fmi *fmi)
......@@ -95,20 +98,6 @@ static inline void fmi_unmute(struct fmi *fmi)
mutex_unlock(&fmi->lock);
}
static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq)
{
mutex_lock(&fmi->lock);
fmi->curfreq = freq;
outbits(16, RSF16_ENCODE(freq), fmi->io);
outbits(8, 0xC0, fmi->io);
msleep(143); /* was schedule_timeout(HZ/7) */
mutex_unlock(&fmi->lock);
if (!fmi->mute)
fmi_unmute(fmi);
return 0;
}
static inline int fmi_getsigstr(struct fmi *fmi)
{
int val;
......@@ -173,7 +162,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
return -EINVAL;
/* rounding in steps of 800 to match the freq
that will be used */
fmi_setfreq(fmi, (f->frequency / 800) * 800);
lm7000_set_freq((f->frequency / 800) * 800, fmi, fmi_set_pins);
return 0;
}
......
......@@ -1514,7 +1514,8 @@ static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv,
tuner->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH);
tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS |
V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO;
V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO |
V4L2_TUNER_CAP_HWSEEK_BOUNDED | V4L2_TUNER_CAP_HWSEEK_WRAP;
if (radio->stereo)
tuner->audmode = V4L2_TUNER_MODE_STEREO;
......
......@@ -363,7 +363,7 @@ static int si470x_set_seek(struct si470x_device *radio,
/* try again, if timed out */
if (retval == 0 && timed_out)
return -EAGAIN;
return -ENODATA;
return retval;
}
......@@ -596,7 +596,9 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
strcpy(tuner->name, "FM");
tuner->type = V4L2_TUNER_RADIO;
tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
V4L2_TUNER_CAP_HWSEEK_BOUNDED |
V4L2_TUNER_CAP_HWSEEK_WRAP;
/* range limits */
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册