dect
/
linux-2.6
Archived
13
0
Fork 0

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

* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (348 commits)
  [media] pctv452e: Remove bogus code
  [media] adv7175: Make use of media bus pixel codes
  [media] media: vb2: fix incorrect return value
  [media] em28xx: implement VIDIOC_ENUM_FRAMESIZES
  [media] cx23885: Stop the risc video fifo before reconfiguring it
  [media] cx23885: Avoid incorrect error handling and reporting
  [media] cx23885: Avoid stopping the risc engine during buffer timeout
  [media] cx23885: Removed a spurious function cx23885_set_scale()
  [media] cx23885: v4l2 api compliance, set the audioset field correctly
  [media] cx23885: hook the audio selection functions into the main driver
  [media] cx23885: add generic functions for dealing with audio input selection
  [media] cx23885: fixes related to maximum number of inputs and range checking
  [media] cx23885: Initial support for the MPX-885 mini-card
  [media] cx25840: Ensure AUDIO6 and AUDIO7 trigger line-in baseband use
  [media] cx23885: Enable audio line in support from the back panel
  [media] cx23885: Allow the audio mux config to be specified on a per input basis
  [media] cx25840: Enable support for non-tuner LR1/LR2 audio inputs
  [media] cx23885: Name an internal i2c part and declare a bitfield by name
  [media] cx23885: Ensure VBI buffers timeout quickly - bugfix for vbi hangs during streaming
  [media] cx23885: remove channel dump diagnostics when a vbi buffer times out
  ...

Fix up trivial conflicts in drivers/misc/altera-stapl/altera.c (header
file rename vs add)
This commit is contained in:
Linus Torvalds 2011-10-31 15:42:54 -07:00
commit 1eb6337835
422 changed files with 28016 additions and 6711 deletions

View File

@ -352,6 +352,7 @@ typedef enum fe_delivery_system {
SYS_CMMB,
SYS_DAB,
SYS_DVBT2,
SYS_TURBO,
} fe_delivery_system_t;
</programlisting>
</section>
@ -809,6 +810,8 @@ typedef enum fe_hierarchy {
<listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
<listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
<listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
<listitem><para><link linkend="DTV-VOLTAGE"><constant>DTV_VOLTAGE</constant></link></para></listitem>
<listitem><para><link linkend="DTV-TONE"><constant>DTV_TONE</constant></link></para></listitem>
</itemizedlist>
<para>Future implementations might add those two missing parameters:</para>
<itemizedlist mark='opencircle'>
@ -818,25 +821,18 @@ typedef enum fe_hierarchy {
</section>
<section id="dvbs2-params">
<title>DVB-S2 delivery system</title>
<para>The following parameters are valid for DVB-S2:</para>
<para>In addition to all parameters valid for DVB-S, DVB-S2 supports the following parameters:</para>
<itemizedlist mark='opencircle'>
<listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
<listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
<listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
<listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
<listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
<listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
<listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
<listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
<listitem><para><link linkend="DTV-VOLTAGE"><constant>DTV_VOLTAGE</constant></link></para></listitem>
<listitem><para><link linkend="DTV-TONE"><constant>DTV_TONE</constant></link></para></listitem>
<listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
<listitem><para><link linkend="DTV-PILOT"><constant>DTV_PILOT</constant></link></para></listitem>
<listitem><para><link linkend="DTV-ROLLOFF"><constant>DTV_ROLLOFF</constant></link></para></listitem>
</itemizedlist>
<para>Future implementations might add those two missing parameters:</para>
</section>
<section id="turbo-params">
<title>Turbo code delivery system</title>
<para>In addition to all parameters valid for DVB-S, turbo code supports the following parameters:</para>
<itemizedlist mark='opencircle'>
<listitem><para><link linkend="DTV-DISEQC-MASTER"><constant>DTV_DISEQC_MASTER</constant></link></para></listitem>
<listitem><para><link linkend="DTV-DISEQC-SLAVE-REPLY"><constant>DTV_DISEQC_SLAVE_REPLY</constant></link></para></listitem>
<listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
</itemizedlist>
</section>
<section id="isdbs-params">

View File

@ -205,7 +205,7 @@ a partial path like:</para>
additional include file <emphasis
role="tt">linux/dvb/version.h</emphasis> exists, which defines the
constant <emphasis role="tt">DVB_API_VERSION</emphasis>. This document
describes <emphasis role="tt">DVB_API_VERSION&#x00A0;3</emphasis>.
describes <emphasis role="tt">DVB_API_VERSION 5.4</emphasis>.
</para>
</section>

View File

@ -2370,6 +2370,14 @@ that used it. It was originally scheduled for removal in 2.6.35.
</listitem>
</orderedlist>
</section>
<section>
<title>V4L2 in Linux 3.2</title>
<orderedlist>
<listitem>
<para>V4L2_CTRL_FLAG_VOLATILE was added to signal volatile controls to userspace.</para>
</listitem>
</orderedlist>
</section>
<section id="other">
<title>Relation of V4L2 to other Linux multimedia APIs</title>

View File

@ -266,7 +266,7 @@
<para>When satisfied with the try results, applications can set the active
formats by setting the <structfield>which</structfield> argument to
<constant>V4L2_SUBDEV_FORMAT_TRY</constant>. Active formats are changed
<constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. Active formats are changed
exactly as try formats by drivers. To avoid modifying the hardware state
during format negotiation, applications should negotiate try formats first
and then modify the active settings using the try formats returned during

View File

@ -127,6 +127,13 @@ structs, ioctls) must be noted in more detail in the history chapter
(compat.xml), along with the possible impact on existing drivers and
applications. -->
<revision>
<revnumber>3.2</revnumber>
<date>2011-08-26</date>
<authorinitials>hv</authorinitials>
<revremark>Added V4L2_CTRL_FLAG_VOLATILE.</revremark>
</revision>
<revision>
<revnumber>3.1</revnumber>
<date>2011-06-27</date>
@ -410,7 +417,7 @@ and discussions on the V4L mailing list.</revremark>
</partinfo>
<title>Video for Linux Two API Specification</title>
<subtitle>Revision 3.1</subtitle>
<subtitle>Revision 3.2</subtitle>
<chapter id="common">
&sub-common;

View File

@ -86,6 +86,12 @@
<entry>Event data for event V4L2_EVENT_CTRL.
</entry>
</row>
<row>
<entry></entry>
<entry>&v4l2-event-frame-sync;</entry>
<entry><structfield>frame</structfield></entry>
<entry>Event data for event V4L2_EVENT_FRAME_SYNC.</entry>
</row>
<row>
<entry></entry>
<entry>__u8</entry>
@ -135,6 +141,129 @@
</tgroup>
</table>
<table frame="none" pgwide="1" id="v4l2-event-vsync">
<title>struct <structname>v4l2_event_vsync</structname></title>
<tgroup cols="3">
&cs-str;
<tbody valign="top">
<row>
<entry>__u8</entry>
<entry><structfield>field</structfield></entry>
<entry>The upcoming field. See &v4l2-field;.</entry>
</row>
</tbody>
</tgroup>
</table>
<table frame="none" pgwide="1" id="v4l2-event-ctrl">
<title>struct <structname>v4l2_event_ctrl</structname></title>
<tgroup cols="4">
&cs-str;
<tbody valign="top">
<row>
<entry>__u32</entry>
<entry><structfield>changes</structfield></entry>
<entry></entry>
<entry>A bitmask that tells what has changed. See <xref linkend="changes-flags" />.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry></entry>
<entry>The type of the control. See &v4l2-ctrl-type;.</entry>
</row>
<row>
<entry>union (anonymous)</entry>
<entry></entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry></entry>
<entry>__s32</entry>
<entry><structfield>value</structfield></entry>
<entry>The 32-bit value of the control for 32-bit control types.
This is 0 for string controls since the value of a string
cannot be passed using &VIDIOC-DQEVENT;.</entry>
</row>
<row>
<entry></entry>
<entry>__s64</entry>
<entry><structfield>value64</structfield></entry>
<entry>The 64-bit value of the control for 64-bit control types.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>flags</structfield></entry>
<entry></entry>
<entry>The control flags. See <xref linkend="control-flags" />.</entry>
</row>
<row>
<entry>__s32</entry>
<entry><structfield>minimum</structfield></entry>
<entry></entry>
<entry>The minimum value of the control. See &v4l2-queryctrl;.</entry>
</row>
<row>
<entry>__s32</entry>
<entry><structfield>maximum</structfield></entry>
<entry></entry>
<entry>The maximum value of the control. See &v4l2-queryctrl;.</entry>
</row>
<row>
<entry>__s32</entry>
<entry><structfield>step</structfield></entry>
<entry></entry>
<entry>The step value of the control. See &v4l2-queryctrl;.</entry>
</row>
<row>
<entry>__s32</entry>
<entry><structfield>default_value</structfield></entry>
<entry></entry>
<entry>The default value value of the control. See &v4l2-queryctrl;.</entry>
</row>
</tbody>
</tgroup>
</table>
<table frame="none" pgwide="1" id="v4l2-event-frame-sync">
<title>struct <structname>v4l2_event_frame_sync</structname></title>
<tgroup cols="3">
&cs-str;
<tbody valign="top">
<row>
<entry>__u32</entry>
<entry><structfield>frame_sequence</structfield></entry>
<entry>
The sequence number of the frame being received.
</entry>
</row>
</tbody>
</tgroup>
</table>
<table pgwide="1" frame="none" id="changes-flags">
<title>Changes</title>
<tgroup cols="3">
&cs-def;
<tbody valign="top">
<row>
<entry><constant>V4L2_EVENT_CTRL_CH_VALUE</constant></entry>
<entry>0x0001</entry>
<entry>This control event was triggered because the value of the control
changed. Special case: if a button control is pressed, then this
event is sent as well, even though there is not explicit value
associated with a button control.</entry>
</row>
<row>
<entry><constant>V4L2_EVENT_CTRL_CH_FLAGS</constant></entry>
<entry>0x0002</entry>
<entry>This control event was triggered because the control flags
changed.</entry>
</row>
</tbody>
</tgroup>
</table>
</refsect1>
<refsect1>
&return-value;

View File

@ -406,6 +406,15 @@ flag is typically present for relative controls or action controls where
writing a value will cause the device to carry out a given action
(&eg; motor control) but no meaningful value can be returned.</entry>
</row>
<row>
<entry><constant>V4L2_CTRL_FLAG_VOLATILE</constant></entry>
<entry>0x0080</entry>
<entry>This control is volatile, which means that the value of the control
changes continuously. A typical example would be the current gain value if the device
is in auto-gain mode. In such a case the hardware calculates the gain value based on
the lighting conditions which can change over time. Note that setting a new value for
a volatile control will have no effect. The new value will just be ignored.</entry>
</row>
</tbody>
</tgroup>
</table>

View File

@ -138,6 +138,22 @@
field of the oldest event.</para>
</entry>
</row>
<row>
<entry><constant>V4L2_EVENT_FRAME_SYNC</constant></entry>
<entry>4</entry>
<entry>
<para>Triggered immediately when the reception of a
frame has begun. This event has a
&v4l2-event-frame-sync; associated with it.</para>
<para>If the hardware needs to be stopped in the case of a
buffer underrun it might not be able to generate this event.
In such cases the <structfield>frame_sequence</structfield>
field in &v4l2-event-frame-sync; will not be incremented. This
causes two consecutive frame sequence numbers to have n times
frame interval in between them.</para>
</entry>
</row>
<row>
<entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry>
<entry>0x08000000</entry>
@ -183,113 +199,6 @@
</tgroup>
</table>
<table frame="none" pgwide="1" id="v4l2-event-vsync">
<title>struct <structname>v4l2_event_vsync</structname></title>
<tgroup cols="3">
&cs-str;
<tbody valign="top">
<row>
<entry>__u8</entry>
<entry><structfield>field</structfield></entry>
<entry>The upcoming field. See &v4l2-field;.</entry>
</row>
</tbody>
</tgroup>
</table>
<table frame="none" pgwide="1" id="v4l2-event-ctrl">
<title>struct <structname>v4l2_event_ctrl</structname></title>
<tgroup cols="4">
&cs-str;
<tbody valign="top">
<row>
<entry>__u32</entry>
<entry><structfield>changes</structfield></entry>
<entry></entry>
<entry>A bitmask that tells what has changed. See <xref linkend="changes-flags" />.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry></entry>
<entry>The type of the control. See &v4l2-ctrl-type;.</entry>
</row>
<row>
<entry>union (anonymous)</entry>
<entry></entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry></entry>
<entry>__s32</entry>
<entry><structfield>value</structfield></entry>
<entry>The 32-bit value of the control for 32-bit control types.
This is 0 for string controls since the value of a string
cannot be passed using &VIDIOC-DQEVENT;.</entry>
</row>
<row>
<entry></entry>
<entry>__s64</entry>
<entry><structfield>value64</structfield></entry>
<entry>The 64-bit value of the control for 64-bit control types.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>flags</structfield></entry>
<entry></entry>
<entry>The control flags. See <xref linkend="control-flags" />.</entry>
</row>
<row>
<entry>__s32</entry>
<entry><structfield>minimum</structfield></entry>
<entry></entry>
<entry>The minimum value of the control. See &v4l2-queryctrl;.</entry>
</row>
<row>
<entry>__s32</entry>
<entry><structfield>maximum</structfield></entry>
<entry></entry>
<entry>The maximum value of the control. See &v4l2-queryctrl;.</entry>
</row>
<row>
<entry>__s32</entry>
<entry><structfield>step</structfield></entry>
<entry></entry>
<entry>The step value of the control. See &v4l2-queryctrl;.</entry>
</row>
<row>
<entry>__s32</entry>
<entry><structfield>default_value</structfield></entry>
<entry></entry>
<entry>The default value value of the control. See &v4l2-queryctrl;.</entry>
</row>
</tbody>
</tgroup>
</table>
<table pgwide="1" frame="none" id="changes-flags">
<title>Changes</title>
<tgroup cols="3">
&cs-def;
<tbody valign="top">
<row>
<entry><constant>V4L2_EVENT_CTRL_CH_VALUE</constant></entry>
<entry>0x0001</entry>
<entry>This control event was triggered because the value of the control
changed. Special case: if a button control is pressed, then this
event is sent as well, even though there is not explicit value
associated with a button control.</entry>
</row>
<row>
<entry><constant>V4L2_EVENT_CTRL_CH_FLAGS</constant></entry>
<entry>0x0002</entry>
<entry>This control event was triggered because the control flags
changed.</entry>
</row>
</tbody>
</tgroup>
</table>
</refsect1>
<refsect1>
&return-value;

View File

@ -27,7 +27,8 @@ use IO::Handle;
"or51211", "or51132_qam", "or51132_vsb", "bluebird",
"opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
"af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
"lme2510c_s7395_old", "drxk", "drxk_terratec_h5");
"lme2510c_s7395_old", "drxk", "drxk_terratec_h5", "tda10071",
"it9135" );
# Check args
syntax() if (scalar(@ARGV) != 1);
@ -575,19 +576,10 @@ sub ngene {
}
sub az6027{
my $file = "AZ6027_Linux_Driver.tar.gz";
my $url = "http://linux.terratec.de/files/$file";
my $firmware = "dvb-usb-az6027-03.fw";
my $url = "http://linux.terratec.de/files/TERRATEC_S7/$firmware";
wgetfile($file, $url);
#untar
if( system("tar xzvf $file $firmware")){
die "failed to untar firmware";
}
if( system("rm $file")){
die ("unable to remove unnecessary files");
}
wgetfile($firmware, $url);
$firmware;
}
@ -665,6 +657,41 @@ sub drxk_terratec_h5 {
"$fwfile"
}
sub it9135 {
my $url = "http://kworld.server261.com/kworld/CD/ITE_TiVme/V1.00/";
my $zipfile = "Driver_V10.323.1.0412.100412.zip";
my $hash = "79b597dc648698ed6820845c0c9d0d37";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
my $drvfile = "Driver_V10.323.1.0412.100412/Data/x86/IT9135BDA.sys";
my $fwfile = "dvb-usb-it9137-01.fw";
checkstandard();
wgetfile($zipfile, $url . $zipfile);
verify($zipfile, $hash);
unzip($zipfile, $tmpdir);
extract("$tmpdir/$drvfile", 69632, 5731, "$fwfile");
"$fwfile"
}
sub tda10071 {
my $sourcefile = "PCTV_460e_reference.zip";
my $url = "ftp://ftp.pctvsystems.com/TV/driver/PCTV%2070e%2080e%20100e%20320e%20330e%20800e/";
my $hash = "4403de903bf2593464c8d74bbc200a57";
my $fwfile = "dvb-fe-tda10071.fw";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
checkstandard();
wgetfile($sourcefile, $url . $sourcefile);
verify($sourcefile, $hash);
unzip($sourcefile, $tmpdir);
extract("$tmpdir/PCTV\ 70e\ 80e\ 100e\ 320e\ 330e\ 800e/32\ bit/emOEM.sys", 0x67d38, 40504, $fwfile);
"$fwfile";
}
# ---------------------------------------------------------------
# Utilities

View File

@ -0,0 +1,9 @@
To extract firmware for Kworld UB499-2T (id 1b80:e409) you need to copy the
following file(s) to this directory.
IT9135BDA.sys Dated Mon 22 Mar 2010 02:20:08 GMT
extract using dd
dd if=IT9135BDA.sys ibs=1 skip=69632 count=5731 of=dvb-usb-it9137-01.fw
copy to default firmware location.

View File

@ -495,29 +495,6 @@ Who: Jean Delvare <khali@linux-fr.org>
----------------------------
What: Support for UVCIOC_CTRL_ADD in the uvcvideo driver
When: 3.2
Why: The information passed to the driver by this ioctl is now queried
dynamically from the device.
Who: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
----------------------------
What: Support for UVCIOC_CTRL_MAP_OLD in the uvcvideo driver
When: 3.2
Why: Used only by applications compiled against older driver versions.
Superseded by UVCIOC_CTRL_MAP which supports V4L2 menu controls.
Who: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
----------------------------
What: Support for UVCIOC_CTRL_GET and UVCIOC_CTRL_SET in the uvcvideo driver
When: 3.2
Why: Superseded by the UVCIOC_CTRL_QUERY ioctl.
Who: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
----------------------------
What: Support for driver specific ioctls in the pwc driver (everything
defined in media/pwc-ioctl.h)
When: 3.3

View File

@ -8,6 +8,7 @@ xxxx vend:prod
----
spca501 0000:0000 MystFromOri Unknown Camera
spca508 0130:0130 Clone Digital Webcam 11043
zc3xx 03f0:1b07 HP Premium Starter Cam
m5602 0402:5602 ALi Video Camera Controller
spca501 040a:0002 Kodak DVC-325
spca500 040a:0300 Kodak EZ200
@ -190,6 +191,7 @@ ov519 05a9:0519 OV519 Microphone
ov519 05a9:0530 OmniVision
ov519 05a9:2800 OmniVision SuperCAM
ov519 05a9:4519 Webcam Classic
ov534_9 05a9:8065 OmniVision test kit ov538+ov9712
ov519 05a9:8519 OmniVision
ov519 05a9:a511 D-Link USB Digital Video Camera
ov519 05a9:a518 D-Link DSB-C310 Webcam
@ -199,6 +201,8 @@ gl860 05e3:0503 Genesys Logic PC Camera
gl860 05e3:f191 Genesys Logic PC Camera
spca561 060b:a001 Maxell Compact Pc PM3
zc3xx 0698:2003 CTX M730V built in
topro 06a2:0003 TP6800 PC Camera, CmoX CX0342 webcam
topro 06a2:6810 Creative Qmax
nw80x 06a5:0000 Typhoon Webcam 100 USB
nw80x 06a5:d001 Divio based webcams
nw80x 06a5:d800 Divio Chicony TwinkleCam, Trust SpaceCam

View File

@ -70,10 +70,11 @@ Events
The OMAP 3 ISP driver does support the V4L2 event interface on CCDC and
statistics (AEWB, AF and histogram) subdevs.
The CCDC subdev produces V4L2_EVENT_OMAP3ISP_HS_VS type event on HS_VS
interrupt which is used to signal frame start. The event is triggered exactly
when the reception of the first line of the frame starts in the CCDC module.
The event can be subscribed on the CCDC subdev.
The CCDC subdev produces V4L2_EVENT_FRAME_SYNC type event on HS_VS
interrupt which is used to signal frame start. Earlier version of this
driver used V4L2_EVENT_OMAP3ISP_HS_VS for this purpose. The event is
triggered exactly when the reception of the first line of the frame starts
in the CCDC module. The event can be subscribed on the CCDC subdev.
(When using parallel interface one must pay account to correct configuration
of the VS signal polarity. This is automatically correct when using the serial

View File

@ -285,11 +285,11 @@ implement g_volatile_ctrl like this:
Note that you use the 'new value' union as well in g_volatile_ctrl. In general
controls that need to implement g_volatile_ctrl are read-only controls.
To mark a control as volatile you have to set the is_volatile flag:
To mark a control as volatile you have to set V4L2_CTRL_FLAG_VOLATILE:
ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...);
if (ctrl)
ctrl->is_volatile = 1;
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
For try/s_ctrl the new values (i.e. as passed by the user) are filled in and
you can modify them in try_ctrl or set them in s_ctrl. The 'cur' union
@ -367,8 +367,7 @@ Driver specific controls can be created using v4l2_ctrl_new_custom():
The last argument is the priv pointer which can be set to driver-specific
private data.
The v4l2_ctrl_config struct also has fields to set the is_private and is_volatile
flags.
The v4l2_ctrl_config struct also has a field to set the is_private flag.
If the name field is not set, then the framework will assume this is a standard
control and will fill in the name, type and flags fields accordingly.
@ -496,18 +495,20 @@ Handling autogain/gain-type Controls with Auto Clusters
A common type of control cluster is one that handles 'auto-foo/foo'-type
controls. Typical examples are autogain/gain, autoexposure/exposure,
autowhitebalance/red balance/blue balance. In all cases you have one controls
autowhitebalance/red balance/blue balance. In all cases you have one control
that determines whether another control is handled automatically by the hardware,
or whether it is under manual control from the user.
If the cluster is in automatic mode, then the manual controls should be
marked inactive. When the volatile controls are read the g_volatile_ctrl
operation should return the value that the hardware's automatic mode set up
automatically.
marked inactive and volatile. When the volatile controls are read the
g_volatile_ctrl operation should return the value that the hardware's automatic
mode set up automatically.
If the cluster is put in manual mode, then the manual controls should become
active again and the is_volatile flag should be ignored (so g_volatile_ctrl is
no longer called while in manual mode).
active again and the volatile flag is cleared (so g_volatile_ctrl is no longer
called while in manual mode). In addition just before switching to manual mode
the current values as determined by the auto mode are copied as the new manual
values.
Finally the V4L2_CTRL_FLAG_UPDATE should be set for the auto control since
changing that control affects the control flags of the manual controls.
@ -520,7 +521,11 @@ void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
The first two arguments are identical to v4l2_ctrl_cluster. The third argument
tells the framework which value switches the cluster into manual mode. The
last argument will optionally set the is_volatile flag for the non-auto controls.
last argument will optionally set V4L2_CTRL_FLAG_VOLATILE for the non-auto controls.
If it is false, then the manual controls are never volatile. You would typically
use that if the hardware does not give you the option to read back to values as
determined by the auto mode (e.g. if autogain is on, the hardware doesn't allow
you to obtain the current gain value).
The first control of the cluster is assumed to be the 'auto' control.
@ -681,16 +686,6 @@ if there are no controls at all.
count if nothing was done yet. If it is less than count then only the controls
up to error_idx-1 were successfully applied.
3) When attempting to read a button control the framework will return -EACCES
instead of -EINVAL as stated in the spec. It seems to make more sense since
button controls are write-only controls.
4) Attempting to write to a read-only control will return -EACCES instead of
-EINVAL as the spec says.
5) The spec does not mention what should happen when you try to set/get a
control class controls. The framework will return -EACCES.
Proposals for Extensions
========================
@ -703,9 +698,3 @@ decimal. Useful for e.g. video_mute_yuv.
2) It is possible to mark in the controls array which controls have been
successfully written and which failed by for example adding a bit to the
control ID. Not sure if it is worth the effort, though.
3) Trying to set volatile inactive controls should result in -EACCESS.
4) Add a new flag to mark volatile controls. Any application that wants
to store the state of the controls can then skip volatile inactive controls.
Currently it is not possible to detect such controls.

View File

@ -1085,6 +1085,24 @@ F: arch/arm/plat-s5p/dev-fimc*
F: arch/arm/plat-samsung/include/plat/*fimc*
F: drivers/media/video/s5p-fimc/
ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT
M: Kyungmin Park <kyungmin.park@samsung.com>
M: Kamil Debski <k.debski@samsung.com>
L: linux-arm-kernel@lists.infradead.org
L: linux-media@vger.kernel.org
S: Maintained
F: arch/arm/plat-s5p/dev-mfc.c
F: drivers/media/video/s5p-mfc/
ARM/SAMSUNG S5P SERIES TV SUBSYSTEM SUPPORT
M: Kyungmin Park <kyungmin.park@samsung.com>
M: Tomasz Stanislawski <t.stanislaws@samsung.com>
L: linux-arm-kernel@lists.infradead.org
L: linux-media@vger.kernel.org
S: Maintained
F: arch/arm/plat-s5p/dev-tv.c
F: drivers/media/video/s5p-tv/
ARM/SHMOBILE ARM ARCHITECTURE
M: Paul Mundt <lethal@linux-sh.org>
M: Magnus Damm <magnus.damm@gmail.com>

View File

@ -217,22 +217,6 @@ config INPUT_ATLAS_BTNS
To compile this driver as a module, choose M here: the module will
be called atlas_btns.
config INPUT_ATI_REMOTE
tristate "ATI / X10 USB RF remote control"
depends on USB_ARCH_HAS_HCD
select USB
help
Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
These are RF remotes with USB receivers.
The ATI remote comes with many of ATI's All-In-Wonder video cards.
The X10 "Lola" remote is available at:
<http://www.x10.com/products/lola_sg1.htm>
This driver provides mouse pointer, left and right mouse buttons,
and maps all the other remote buttons to keypress events.
To compile this driver as a module, choose M here: the module will be
called ati_remote.
config INPUT_ATI_REMOTE2
tristate "ATI / Philips USB RF remote control"
depends on USB_ARCH_HAS_HCD

View File

@ -13,7 +13,6 @@ obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o
obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o
obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o
obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o

View File

@ -18,6 +18,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <media/saa7146.h>
LIST_HEAD(saa7146_devices);
@ -35,10 +37,9 @@ static void dump_registers(struct saa7146_dev* dev)
{
int i = 0;
INFO((" @ %li jiffies:\n",jiffies));
for(i = 0; i <= 0x148; i+=4) {
printk("0x%03x: 0x%08x\n",i,saa7146_read(dev,i));
}
pr_info(" @ %li jiffies:\n", jiffies);
for (i = 0; i <= 0x148; i += 4)
pr_info("0x%03x: 0x%08x\n", i, saa7146_read(dev, i));
}
#endif
@ -72,9 +73,8 @@ static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
if (saa7146_read(dev, MC2) & 2)
break;
if (err) {
printk(KERN_ERR "%s: %s timed out while waiting for "
"registers getting programmed\n",
dev->name, __func__);
pr_err("%s: %s timed out while waiting for registers getting programmed\n",
dev->name, __func__);
return -ETIMEDOUT;
}
msleep(1);
@ -88,8 +88,8 @@ static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
break;
saa7146_read(dev, MC2);
if (err) {
DEB_S(("%s: %s timed out while waiting for transfer "
"completion\n", dev->name, __func__));
DEB_S("%s: %s timed out while waiting for transfer completion\n",
dev->name, __func__);
return -ETIMEDOUT;
}
msleep(1);
@ -109,9 +109,8 @@ static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
if (saa7146_read(dev, MC2) & 2)
break;
if (!loops--) {
printk(KERN_ERR "%s: %s timed out while waiting for "
"registers getting programmed\n",
dev->name, __func__);
pr_err("%s: %s timed out while waiting for registers getting programmed\n",
dev->name, __func__);
return -ETIMEDOUT;
}
udelay(1);
@ -124,8 +123,8 @@ static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
break;
saa7146_read(dev, MC2);
if (!loops--) {
DEB_S(("%s: %s timed out while waiting for transfer "
"completion\n", dev->name, __func__));
DEB_S("%s: %s timed out while waiting for transfer completion\n",
dev->name, __func__);
return -ETIMEDOUT;
}
udelay(5);
@ -264,7 +263,9 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
ptr = pt->cpu;
for (i = 0; i < sglen; i++, list++) {
/*
printk("i:%d, adr:0x%08x, len:%d, offset:%d\n", i,sg_dma_address(list), sg_dma_len(list), list->offset);
pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n",
i, sg_dma_address(list), sg_dma_len(list),
list->offset);
*/
for (p = 0; p * 4096 < list->length; p++, ptr++) {
*ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
@ -281,9 +282,9 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
/*
ptr = pt->cpu;
printk("offset: %d\n",pt->offset);
pr_debug("offset: %d\n", pt->offset);
for(i=0;i<5;i++) {
printk("ptr1 %d: 0x%08x\n",i,ptr[i]);
pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]);
}
*/
return 0;
@ -314,7 +315,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
}
}
if (0 != (isr & (MASK_27))) {
DEB_INT(("irq: RPS0 (0x%08x).\n",isr));
DEB_INT("irq: RPS0 (0x%08x)\n", isr);
if (dev->vv_data && dev->vv_callback)
dev->vv_callback(dev,isr);
isr &= ~MASK_27;
@ -333,14 +334,15 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
} else {
u32 psr = saa7146_read(dev, PSR);
u32 ssr = saa7146_read(dev, SSR);
printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
dev->name, isr, psr, ssr);
pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
dev->name, isr, psr, ssr);
}
isr &= ~(MASK_16|MASK_17);
}
if( 0 != isr ) {
ERR(("warning: interrupt enabled, but not handled properly.(0x%08x)\n",isr));
ERR(("disabling interrupt source(s)!\n"));
ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n",
isr);
ERR("disabling interrupt source(s)!\n");
SAA7146_IER_DISABLE(dev,isr);
}
saa7146_write(dev, ISR, ack_isr);
@ -360,15 +362,15 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
/* clear out mem for sure */
dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
if (!dev) {
ERR(("out of memory.\n"));
ERR("out of memory\n");
goto out;
}
DEB_EE(("pci:%p\n",pci));
DEB_EE("pci:%p\n", pci);
err = pci_enable_device(pci);
if (err < 0) {
ERR(("pci_enable_device() failed.\n"));
ERR("pci_enable_device() failed\n");
goto err_free;
}
@ -389,7 +391,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
dev->mem = ioremap(pci_resource_start(pci, 0),
pci_resource_len(pci, 0));
if (!dev->mem) {
ERR(("ioremap() failed.\n"));
ERR("ioremap() failed\n");
err = -ENODEV;
goto err_release;
}
@ -414,7 +416,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,
dev->name, dev);
if (err < 0) {
ERR(("request_irq() failed.\n"));
ERR("request_irq() failed\n");
goto err_unmap;
}
@ -444,7 +446,9 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
/* create a nice device name */
sprintf(dev->name, "saa7146 (%d)", saa7146_num);
INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device));
pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n",
dev->mem, dev->revision, pci->irq,
pci->subsystem_vendor, pci->subsystem_device);
dev->ext = ext;
mutex_init(&dev->v4l2_lock);
@ -464,12 +468,12 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
err = -ENODEV;
if (ext->probe && ext->probe(dev)) {
DEB_D(("ext->probe() failed for %p. skipping device.\n",dev));
DEB_D("ext->probe() failed for %p. skipping device.\n", dev);
goto err_free_i2c;
}
if (ext->attach(dev, pci_ext)) {
DEB_D(("ext->attach() failed for %p. skipping device.\n",dev));
DEB_D("ext->attach() failed for %p. skipping device.\n", dev);
goto err_free_i2c;
}
/* V4L extensions will set the pci drvdata to the v4l2_device in the
@ -521,7 +525,7 @@ static void saa7146_remove_one(struct pci_dev *pdev)
{ NULL, 0 }
}, *p;
DEB_EE(("dev:%p\n",dev));
DEB_EE("dev:%p\n", dev);
dev->ext->detach(dev);
/* Zero the PCI drvdata after use. */
@ -552,21 +556,21 @@ static void saa7146_remove_one(struct pci_dev *pdev)
int saa7146_register_extension(struct saa7146_extension* ext)
{
DEB_EE(("ext:%p\n",ext));
DEB_EE("ext:%p\n", ext);
ext->driver.name = ext->name;
ext->driver.id_table = ext->pci_tbl;
ext->driver.probe = saa7146_init_one;
ext->driver.remove = saa7146_remove_one;
printk("saa7146: register extension '%s'.\n",ext->name);
pr_info("register extension '%s'\n", ext->name);
return pci_register_driver(&ext->driver);
}
int saa7146_unregister_extension(struct saa7146_extension* ext)
{
DEB_EE(("ext:%p\n",ext));
printk("saa7146: unregister extension '%s'.\n",ext->name);
DEB_EE("ext:%p\n", ext);
pr_info("unregister extension '%s'\n", ext->name);
pci_unregister_driver(&ext->driver);
return 0;
}

View File

@ -1,3 +1,5 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <media/saa7146_vv.h>
/****************************************************************************/
@ -9,21 +11,23 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
struct saa7146_vv *vv = dev->vv_data;
if (fh->resources & bit) {
DEB_D(("already allocated! want: 0x%02x, cur:0x%02x\n",bit,vv->resources));
DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n",
bit, vv->resources);
/* have it already allocated */
return 1;
}
/* is it free? */
if (vv->resources & bit) {
DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n",
vv->resources, bit);
/* no, someone else uses it */
return 0;
}
/* it's free, grab it */
fh->resources |= bit;
fh->resources |= bit;
vv->resources |= bit;
DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources);
return 1;
}
@ -34,9 +38,9 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
BUG_ON((fh->resources & bits) != bits);
fh->resources &= ~bits;
fh->resources &= ~bits;
vv->resources &= ~bits;
DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources);
}
@ -47,7 +51,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
struct saa7146_buf *buf)
{
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
DEB_EE(("dev:%p, buf:%p\n",dev,buf));
DEB_EE("dev:%p, buf:%p\n", dev, buf);
BUG_ON(in_interrupt());
@ -66,18 +70,19 @@ int saa7146_buffer_queue(struct saa7146_dev *dev,
struct saa7146_buf *buf)
{
assert_spin_locked(&dev->slock);
DEB_EE(("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf));
DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf);
BUG_ON(!q);
if (NULL == q->curr) {
q->curr = buf;
DEB_D(("immediately activating buffer %p\n", buf));
DEB_D("immediately activating buffer %p\n", buf);
buf->activate(dev,buf,NULL);
} else {
list_add_tail(&buf->vb.queue,&q->queue);
buf->vb.state = VIDEOBUF_QUEUED;
DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf));
DEB_D("adding buffer %p to queue. (active buffer present)\n",
buf);
}
return 0;
}
@ -87,14 +92,14 @@ void saa7146_buffer_finish(struct saa7146_dev *dev,
int state)
{
assert_spin_locked(&dev->slock);
DEB_EE(("dev:%p, dmaq:%p, state:%d\n", dev, q, state));
DEB_EE(("q->curr:%p\n",q->curr));
DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state);
DEB_EE("q->curr:%p\n", q->curr);
BUG_ON(!q->curr);
/* finish current buffer */
if (NULL == q->curr) {
DEB_D(("aiii. no current buffer\n"));
DEB_D("aiii. no current buffer\n");
return;
}
@ -112,7 +117,7 @@ void saa7146_buffer_next(struct saa7146_dev *dev,
BUG_ON(!q);
DEB_INT(("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi));
DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi);
assert_spin_locked(&dev->slock);
if (!list_empty(&q->queue)) {
@ -122,10 +127,11 @@ void saa7146_buffer_next(struct saa7146_dev *dev,
if (!list_empty(&q->queue))
next = list_entry(q->queue.next,struct saa7146_buf, vb.queue);
q->curr = buf;
DEB_INT(("next buffer: buf:%p, prev:%p, next:%p\n", buf, q->queue.prev,q->queue.next));
DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n",
buf, q->queue.prev, q->queue.next);
buf->activate(dev,buf,next);
} else {
DEB_INT(("no next buffer. stopping.\n"));
DEB_INT("no next buffer. stopping.\n");
if( 0 != vbi ) {
/* turn off video-dma3 */
saa7146_write(dev,MC1, MASK_20);
@ -162,11 +168,11 @@ void saa7146_buffer_timeout(unsigned long data)
struct saa7146_dev *dev = q->dev;
unsigned long flags;
DEB_EE(("dev:%p, dmaq:%p\n", dev, q));
DEB_EE("dev:%p, dmaq:%p\n", dev, q);
spin_lock_irqsave(&dev->slock,flags);
if (q->curr) {
DEB_D(("timeout on %p\n", q->curr));
DEB_D("timeout on %p\n", q->curr);
saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
}
@ -194,12 +200,12 @@ static int fops_open(struct file *file)
enum v4l2_buf_type type;
DEB_EE(("file:%p, dev:%s\n", file, video_device_node_name(vdev)));
DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
if (mutex_lock_interruptible(&saa7146_devices_lock))
return -ERESTARTSYS;
DEB_D(("using: %p\n",dev));
DEB_D("using: %p\n", dev);
type = vdev->vfl_type == VFL_TYPE_GRABBER
? V4L2_BUF_TYPE_VIDEO_CAPTURE
@ -207,7 +213,7 @@ static int fops_open(struct file *file)
/* check if an extension is registered */
if( NULL == dev->ext ) {
DEB_S(("no extension registered for this device.\n"));
DEB_S("no extension registered for this device\n");
result = -ENODEV;
goto out;
}
@ -215,7 +221,7 @@ static int fops_open(struct file *file)
/* allocate per open data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
if (NULL == fh) {
DEB_S(("cannot allocate memory for per open data.\n"));
DEB_S("cannot allocate memory for per open data\n");
result = -ENOMEM;
goto out;
}
@ -225,13 +231,13 @@ static int fops_open(struct file *file)
fh->type = type;
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
DEB_S(("initializing vbi...\n"));
DEB_S("initializing vbi...\n");
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
result = saa7146_vbi_uops.open(dev,file);
if (dev->ext_vv_data->vbi_fops.open)
dev->ext_vv_data->vbi_fops.open(file);
} else {
DEB_S(("initializing video...\n"));
DEB_S("initializing video...\n");
result = saa7146_video_uops.open(dev,file);
}
@ -259,7 +265,7 @@ static int fops_release(struct file *file)
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
DEB_EE(("file:%p\n", file));
DEB_EE("file:%p\n", file);
if (mutex_lock_interruptible(&saa7146_devices_lock))
return -ERESTARTSYS;
@ -289,12 +295,14 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",file, vma));
DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
file, vma);
q = &fh->video_q;
break;
}
case V4L2_BUF_TYPE_VBI_CAPTURE: {
DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",file, vma));
DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
file, vma);
q = &fh->vbi_q;
break;
}
@ -312,14 +320,14 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
struct videobuf_buffer *buf = NULL;
struct videobuf_queue *q;
DEB_EE(("file:%p, poll:%p\n",file, wait));
DEB_EE("file:%p, poll:%p\n", file, wait);
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
if( 0 == fh->vbi_q.streaming )
return videobuf_poll_stream(file, &fh->vbi_q, wait);
q = &fh->vbi_q;
} else {
DEB_D(("using video queue.\n"));
DEB_D("using video queue\n");
q = &fh->video_q;
}
@ -327,17 +335,17 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
if (!buf) {
DEB_D(("buf == NULL!\n"));
DEB_D("buf == NULL!\n");
return POLLERR;
}
poll_wait(file, &buf->done, wait);
if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
DEB_D(("poll succeeded!\n"));
DEB_D("poll succeeded!\n");
return POLLIN|POLLRDNORM;
}
DEB_D(("nothing to poll for, buf->state:%d\n",buf->state));
DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
return 0;
}
@ -346,18 +354,20 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
struct saa7146_fh *fh = file->private_data;
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
// DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", file, data, (unsigned long)count));
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
/*
DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
file, data, (unsigned long)count);
*/
return saa7146_video_uops.read(file,data,count,ppos);
}
case V4L2_BUF_TYPE_VBI_CAPTURE: {
// DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
case V4L2_BUF_TYPE_VBI_CAPTURE:
/*
DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
file, data, (unsigned long)count);
*/
if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
return saa7146_vbi_uops.read(file,data,count,ppos);
else
return -EINVAL;
}
break;
return -EINVAL;
default:
BUG();
return 0;
@ -398,22 +408,22 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
{
u32 isr = status;
DEB_INT(("dev:%p, isr:0x%08x\n",dev,(u32)status));
DEB_INT("dev:%p, isr:0x%08x\n", dev, (u32)status);
if (0 != (isr & (MASK_27))) {
DEB_INT(("irq: RPS0 (0x%08x).\n",isr));
DEB_INT("irq: RPS0 (0x%08x)\n", isr);
saa7146_video_uops.irq_done(dev,isr);
}
if (0 != (isr & (MASK_28))) {
u32 mc2 = saa7146_read(dev, MC2);
if( 0 != (mc2 & MASK_15)) {
DEB_INT(("irq: RPS1 vbi workaround (0x%08x).\n",isr));
DEB_INT("irq: RPS1 vbi workaround (0x%08x)\n", isr);
wake_up(&dev->vv_data->vbi_wq);
saa7146_write(dev,MC2, MASK_31);
return;
}
DEB_INT(("irq: RPS1 (0x%08x).\n",isr));
DEB_INT("irq: RPS1 (0x%08x)\n", isr);
saa7146_vbi_uops.irq_done(dev,isr);
}
}
@ -429,13 +439,13 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
if (vv == NULL) {
ERR(("out of memory. aborting.\n"));
ERR("out of memory. aborting.\n");
return -ENOMEM;
}
ext_vv->ops = saa7146_video_ioctl_ops;
ext_vv->core_ops = &saa7146_video_ioctl_ops;
DEB_EE(("dev:%p\n",dev));
DEB_EE("dev:%p\n", dev);
/* set default values for video parts of the saa7146 */
saa7146_write(dev, BCS_CTRL, 0x80400040);
@ -450,7 +460,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle);
if( NULL == vv->d_clipping.cpu_addr ) {
ERR(("out of memory. aborting.\n"));
ERR("out of memory. aborting.\n");
kfree(vv);
return -1;
}
@ -471,7 +481,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
{
struct saa7146_vv *vv = dev->vv_data;
DEB_EE(("dev:%p\n",dev));
DEB_EE("dev:%p\n", dev);
v4l2_device_unregister(&dev->v4l2_dev);
pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
@ -490,7 +500,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
int err;
int i;
DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type));
DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);
// released by vfd->release
vfd = video_device_alloc();
@ -509,13 +519,13 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
err = video_register_device(vfd, type, -1);
if (err < 0) {
ERR(("cannot register v4l2 device. skipping.\n"));
ERR("cannot register v4l2 device. skipping.\n");
video_device_release(vfd);
return err;
}
INFO(("%s: registered device %s [v4l2]\n",
dev->name, video_device_node_name(vfd)));
pr_info("%s: registered device %s [v4l2]\n",
dev->name, video_device_node_name(vfd));
*vid = vfd;
return 0;
@ -524,7 +534,7 @@ EXPORT_SYMBOL_GPL(saa7146_register_device);
int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
{
DEB_EE(("dev:%p\n",dev));
DEB_EE("dev:%p\n", dev);
video_unregister_device(*vid);
*vid = NULL;

View File

@ -1,3 +1,5 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <media/saa7146_vv.h>
@ -711,8 +713,8 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71
int depth = sfmt->depth;
DEB_CAP(("[size=%dx%d,fields=%s]\n",
width,height,v4l2_field_names[field]));
DEB_CAP("[size=%dx%d,fields=%s]\n",
width, height, v4l2_field_names[field]);
if( bytesperline != 0) {
vdma1.pitch = bytesperline*2;
@ -837,8 +839,8 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71
BUG_ON(0 == buf->pt[1].dma);
BUG_ON(0 == buf->pt[2].dma);
DEB_CAP(("[size=%dx%d,fields=%s]\n",
width,height,v4l2_field_names[field]));
DEB_CAP("[size=%dx%d,fields=%s]\n",
width, height, v4l2_field_names[field]);
/* fixme: look at bytesperline! */
@ -998,12 +1000,12 @@ void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struc
struct saa7146_vv *vv = dev->vv_data;
u32 vdma1_prot_addr;
DEB_CAP(("buf:%p, next:%p\n",buf,next));
DEB_CAP("buf:%p, next:%p\n", buf, next);
vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1);
if( 0 == vdma1_prot_addr ) {
/* clear out beginning of streaming bit (rps register 0)*/
DEB_CAP(("forcing sync to new frame\n"));
DEB_CAP("forcing sync to new frame\n");
saa7146_write(dev, MC2, MASK_27 );
}

View File

@ -1,8 +1,10 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <media/saa7146_vv.h>
static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
{
//fm DEB_I2C(("'%s'.\n", adapter->name));
/* DEB_I2C("'%s'\n", adapter->name); */
return I2C_FUNC_I2C
| I2C_FUNC_SMBUS_QUICK
@ -14,9 +16,7 @@ static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
static inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
{
u32 iicsta = saa7146_read(dev, I2C_STATUS);
/*
DEB_I2C(("status: 0x%08x\n",iicsta));
*/
/* DEB_I2C("status: 0x%08x\n", iicsta); */
return iicsta;
}
@ -39,10 +39,11 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op)
plus one extra byte to address the device */
mem = 1 + ((mem-1) / 3);
/* we assume that op points to a memory of at least SAA7146_I2C_MEM bytes
size. if we exceed this limit... */
if ( (4*mem) > SAA7146_I2C_MEM ) {
//fm DEB_I2C(("cannot prepare i2c-message.\n"));
/* we assume that op points to a memory of at least
* SAA7146_I2C_MEM bytes size. if we exceed this limit...
*/
if ((4 * mem) > SAA7146_I2C_MEM) {
/* DEB_I2C("cannot prepare i2c-message\n"); */
return -ENOMEM;
}
@ -123,7 +124,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
if ( 0 != ( status & SAA7146_I2C_BUSY) ) {
/* yes, kill ongoing operation */
DEB_I2C(("busy_state detected.\n"));
DEB_I2C("busy_state detected\n");
/* set "ABORT-OPERATION"-bit (bit 7)*/
saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
@ -141,7 +142,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
if ( dev->i2c_bitrate != status ) {
DEB_I2C(("error_state detected. status:0x%08x\n",status));
DEB_I2C("error_state detected. status:0x%08x\n", status);
/* Repeat the abort operation. This seems to be necessary
after serious protocol errors caused by e.g. the SAA7740 */
@ -164,7 +165,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
/* if any error is still present, a fatal error has occurred ... */
status = saa7146_i2c_status(dev);
if ( dev->i2c_bitrate != status ) {
DEB_I2C(("fatal error. status:0x%08x\n",status));
DEB_I2C("fatal error. status:0x%08x\n", status);
return -1;
}
@ -181,7 +182,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
unsigned long timeout;
/* write out i2c-command */
DEB_I2C(("before: 0x%08x (status: 0x%08x), %d\n",*dword,saa7146_read(dev, I2C_STATUS), dev->i2c_op));
DEB_I2C("before: 0x%08x (status: 0x%08x), %d\n",
*dword, saa7146_read(dev, I2C_STATUS), dev->i2c_op);
if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
@ -202,7 +204,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
/* a signal arrived */
return -ERESTARTSYS;
printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n",
pr_warn("%s %s [irq]: timed out waiting for end of xfer\n",
dev->name, __func__);
return -EIO;
}
@ -220,7 +222,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
break;
}
if (time_after(jiffies,timeout)) {
printk(KERN_WARNING "%s %s: timed out waiting for MC2\n",
pr_warn("%s %s: timed out waiting for MC2\n",
dev->name, __func__);
return -EIO;
}
@ -237,7 +239,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
/* this is normal when probing the bus
* (no answer from nonexisistant device...)
*/
printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n",
pr_warn("%s %s [poll]: timed out waiting for end of xfer\n",
dev->name, __func__);
return -EIO;
}
@ -257,24 +259,24 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
if ( 0 == (status & SAA7146_I2C_ERR) ||
0 == (status & SAA7146_I2C_BUSY) ) {
/* it may take some time until ERR goes high - ignore */
DEB_I2C(("unexpected i2c status %04x\n", status));
DEB_I2C("unexpected i2c status %04x\n", status);
}
if( 0 != (status & SAA7146_I2C_SPERR) ) {
DEB_I2C(("error due to invalid start/stop condition.\n"));
DEB_I2C("error due to invalid start/stop condition\n");
}
if( 0 != (status & SAA7146_I2C_DTERR) ) {
DEB_I2C(("error in data transmission.\n"));
DEB_I2C("error in data transmission\n");
}
if( 0 != (status & SAA7146_I2C_DRERR) ) {
DEB_I2C(("error when receiving data.\n"));
DEB_I2C("error when receiving data\n");
}
if( 0 != (status & SAA7146_I2C_AL) ) {
DEB_I2C(("error because arbitration lost.\n"));
DEB_I2C("error because arbitration lost\n");
}
/* we handle address-errors here */
if( 0 != (status & SAA7146_I2C_APERR) ) {
DEB_I2C(("error in address phase.\n"));
DEB_I2C("error in address phase\n");
return -EREMOTEIO;
}
@ -284,7 +286,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
/* read back data, just in case we were reading ... */
*dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));
DEB_I2C(("after: 0x%08x\n",*dword));
DEB_I2C("after: 0x%08x\n", *dword);
return 0;
}
@ -299,7 +301,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
return -ERESTARTSYS;
for(i=0;i<num;i++) {
DEB_I2C(("msg:%d/%d\n",i+1,num));
DEB_I2C("msg:%d/%d\n", i+1, num);
}
/* prepare the message(s), get number of u32s to transfer */
@ -316,7 +318,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
/* reset the i2c-device if necessary */
err = saa7146_i2c_reset(dev);
if ( 0 > err ) {
DEB_I2C(("could not reset i2c-device.\n"));
DEB_I2C("could not reset i2c-device\n");
goto out;
}
@ -336,7 +338,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
address error and trust the saa7146 address error detection. */
if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags))
goto out;
DEB_I2C(("error while sending message(s). starting again.\n"));
DEB_I2C("error while sending message(s). starting again\n");
break;
}
}
@ -356,13 +358,13 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
/* if any things had to be read, get the results */
if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) {
DEB_I2C(("could not cleanup i2c-message.\n"));
DEB_I2C("could not cleanup i2c-message\n");
err = -1;
goto out;
}
/* return the number of delivered messages */
DEB_I2C(("transmission successful. (msg:%d).\n",err));
DEB_I2C("transmission successful. (msg:%d)\n", err);
out:
/* another bug in revision 0: the i2c-registers get uploaded randomly by other
uploads, so we better clear them out before continuing */
@ -370,7 +372,7 @@ out:
__le32 zero = 0;
saa7146_i2c_reset(dev);
if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
INFO(("revision 0 error. this should never happen.\n"));
pr_info("revision 0 error. this should never happen\n");
}
}
@ -400,7 +402,7 @@ static struct i2c_algorithm saa7146_algo = {
int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
{
DEB_EE(("bitrate: 0x%08x\n",bitrate));
DEB_EE("bitrate: 0x%08x\n", bitrate);
/* enable i2c-port pins */
saa7146_write(dev, MC1, (MASK_08 | MASK_24));

View File

@ -14,7 +14,7 @@ static int vbi_workaround(struct saa7146_dev *dev)
DECLARE_WAITQUEUE(wait, current);
DEB_VBI(("dev:%p\n",dev));
DEB_VBI("dev:%p\n", dev);
/* once again, a bug in the saa7146: the brs acquisition
is buggy and especially the BXO-counter does not work
@ -40,14 +40,14 @@ static int vbi_workaround(struct saa7146_dev *dev)
WRITE_RPS1(0xc000008c);
/* wait for vbi_a or vbi_b*/
if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
DEB_D(("...using port b\n"));
DEB_D("...using port b\n");
WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B);
WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B);
/*
WRITE_RPS1(CMD_PAUSE | MASK_09);
*/
} else {
DEB_D(("...using port a\n"));
DEB_D("...using port a\n");
WRITE_RPS1(CMD_PAUSE | MASK_10);
}
/* upload brs */
@ -103,7 +103,7 @@ static int vbi_workaround(struct saa7146_dev *dev)
schedule();
DEB_VBI(("brs bug workaround %d/1.\n",i));
DEB_VBI("brs bug workaround %d/1\n", i);
remove_wait_queue(&vv->vbi_wq, &wait);
current->state = TASK_RUNNING;
@ -116,7 +116,8 @@ static int vbi_workaround(struct saa7146_dev *dev)
if(signal_pending(current)) {
DEB_VBI(("aborted (rps:0x%08x).\n",saa7146_read(dev,RPS_ADDR1)));
DEB_VBI("aborted (rps:0x%08x)\n",
saa7146_read(dev, RPS_ADDR1));
/* stop rps1 for sure */
saa7146_write(dev, MC1, MASK_29);
@ -207,7 +208,7 @@ static int buffer_activate(struct saa7146_dev *dev,
struct saa7146_vv *vv = dev->vv_data;
buf->vb.state = VIDEOBUF_ACTIVE;
DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next));
DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
saa7146_set_vbi_capture(dev,buf,next);
mod_timer(&vv->vbi_q.timeout, jiffies+BUFFER_TIMEOUT);
@ -228,10 +229,10 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
llength = vbi_pixel_to_capture;
size = lines * llength;
DEB_VBI(("vb:%p\n",vb));
DEB_VBI("vb:%p\n", vb);
if (0 != buf->vb.baddr && buf->vb.bsize < size) {
DEB_VBI(("size mismatch.\n"));
DEB_VBI("size mismatch\n");
return -EINVAL;
}
@ -263,7 +264,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
return 0;
oops:
DEB_VBI(("error out.\n"));
DEB_VBI("error out\n");
saa7146_dma_free(dev,q,buf);
return err;
@ -279,7 +280,7 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned
*size = lines * llength;
*count = 2;
DEB_VBI(("count:%d, size:%d\n",*count,*size));
DEB_VBI("count:%d, size:%d\n", *count, *size);
return 0;
}
@ -292,7 +293,7 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
struct saa7146_vv *vv = dev->vv_data;
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
DEB_VBI(("vb:%p\n",vb));
DEB_VBI("vb:%p\n", vb);
saa7146_buffer_queue(dev,&vv->vbi_q,buf);
}
@ -303,7 +304,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
struct saa7146_dev *dev = fh->dev;
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
DEB_VBI(("vb:%p\n",vb));
DEB_VBI("vb:%p\n", vb);
saa7146_dma_free(dev,q,buf);
}
@ -321,7 +322,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
unsigned long flags;
DEB_VBI(("dev:%p, fh:%p\n",dev, fh));
DEB_VBI("dev:%p, fh:%p\n", dev, fh);
spin_lock_irqsave(&dev->slock,flags);
@ -354,14 +355,14 @@ static void vbi_read_timeout(unsigned long data)
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
DEB_VBI(("dev:%p, fh:%p\n",dev, fh));
DEB_VBI("dev:%p, fh:%p\n", dev, fh);
vbi_stop(fh, file);
}
static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
{
DEB_VBI(("dev:%p\n",dev));
DEB_VBI("dev:%p\n", dev);
INIT_LIST_HEAD(&vv->vbi_q.queue);
@ -380,11 +381,11 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
int ret = 0;
DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
DEB_VBI("dev:%p, fh:%p\n", dev, fh);
ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS);
if (0 == ret) {
DEB_S(("cannot get vbi RESOURCE_DMA3_BRS resource\n"));
DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n");
return -EBUSY;
}
@ -425,7 +426,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
saa7146_write(dev, BRS_CTRL, 0x00000001);
if (0 != (ret = vbi_workaround(dev))) {
DEB_VBI(("vbi workaround failed!\n"));
DEB_VBI("vbi workaround failed!\n");
/* return ret;*/
}
}
@ -439,7 +440,7 @@ static void vbi_close(struct saa7146_dev *dev, struct file *file)
{
struct saa7146_fh *fh = file->private_data;
struct saa7146_vv *vv = dev->vv_data;
DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
DEB_VBI("dev:%p, fh:%p\n", dev, fh);
if( fh == vv->vbi_streaming ) {
vbi_stop(fh, file);
@ -453,13 +454,13 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
spin_lock(&dev->slock);
if (vv->vbi_q.curr) {
DEB_VBI(("dev:%p, curr:%p\n",dev,vv->vbi_q.curr));
DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_q.curr);
/* this must be += 2, one count for each field */
vv->vbi_fieldcount+=2;
vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount;
saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
} else {
DEB_VBI(("dev:%p\n",dev));
DEB_VBI("dev:%p\n", dev);
}
saa7146_buffer_next(dev,&vv->vbi_q,1);
@ -473,7 +474,7 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
struct saa7146_vv *vv = dev->vv_data;
ssize_t ret = 0;
DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
DEB_VBI("dev:%p, fh:%p\n", dev, fh);
if( NULL == vv->vbi_streaming ) {
// fixme: check if dma3 is available
@ -482,7 +483,8 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
}
if( fh != vv->vbi_streaming ) {
DEB_VBI(("open %p is already using vbi capture.",vv->vbi_streaming));
DEB_VBI("open %p is already using vbi capture\n",
vv->vbi_streaming);
return -EBUSY;
}

View File

@ -1,3 +1,5 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <media/saa7146_vv.h>
#include <media/v4l2-chip-ident.h>
@ -94,7 +96,7 @@ struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fou
}
}
DEB_D(("unknown pixelformat:'%4.4s'\n",(char *)&fourcc));
DEB_D("unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
return NULL;
}
@ -107,32 +109,32 @@ int saa7146_start_preview(struct saa7146_fh *fh)
struct v4l2_format fmt;
int ret = 0, err = 0;
DEB_EE(("dev:%p, fh:%p\n",dev,fh));
DEB_EE("dev:%p, fh:%p\n", dev, fh);
/* check if we have overlay informations */
if( NULL == fh->ov.fh ) {
DEB_D(("no overlay data available. try S_FMT first.\n"));
DEB_D("no overlay data available. try S_FMT first.\n");
return -EAGAIN;
}
/* check if streaming capture is running */
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("streaming capture is active.\n"));
DEB_D("streaming capture is active\n");
return -EBUSY;
}
/* check if overlay is running */
if (IS_OVERLAY_ACTIVE(fh) != 0) {
if (vv->video_fh == fh) {
DEB_D(("overlay is already active.\n"));
DEB_D("overlay is already active\n");
return 0;
}
DEB_D(("overlay is already active in another open.\n"));
DEB_D("overlay is already active in another open\n");
return -EBUSY;
}
if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
DEB_D(("cannot get necessary overlay resources\n"));
DEB_D("cannot get necessary overlay resources\n");
return -EBUSY;
}
@ -145,13 +147,13 @@ int saa7146_start_preview(struct saa7146_fh *fh)
fh->ov.win = fmt.fmt.win;
vv->ov_data = &fh->ov;
DEB_D(("%dx%d+%d+%d %s field=%s\n",
fh->ov.win.w.width,fh->ov.win.w.height,
fh->ov.win.w.left,fh->ov.win.w.top,
vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field]));
DEB_D("%dx%d+%d+%d %s field=%s\n",
fh->ov.win.w.width, fh->ov.win.w.height,
fh->ov.win.w.left, fh->ov.win.w.top,
vv->ov_fmt->name, v4l2_field_names[fh->ov.win.field]);
if (0 != (ret = saa7146_enable_overlay(fh))) {
DEB_D(("enabling overlay failed: %d\n",ret));
DEB_D("enabling overlay failed: %d\n", ret);
saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
return ret;
}
@ -168,22 +170,22 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
DEB_EE(("dev:%p, fh:%p\n",dev,fh));
DEB_EE("dev:%p, fh:%p\n", dev, fh);
/* check if streaming capture is running */
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("streaming capture is active.\n"));
DEB_D("streaming capture is active\n");
return -EBUSY;
}
/* check if overlay is running at all */
if ((vv->video_status & STATUS_OVERLAY) == 0) {
DEB_D(("no active overlay.\n"));
DEB_D("no active overlay\n");
return 0;
}
if (vv->video_fh != fh) {
DEB_D(("overlay is active, but in another open.\n"));
DEB_D("overlay is active, but in another open\n");
return -EBUSY;
}
@ -268,7 +270,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
int length = dma->sglen;
struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
DEB_EE("dev:%p, buf:%p, sg_len:%d\n", dev, buf, length);
if( 0 != IS_PLANAR(sfmt->trans)) {
struct saa7146_pgtable *pt1 = &buf->pt[0];
@ -288,7 +290,8 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
o1 = size%PAGE_SIZE;
o2 = (size+(size/4))%PAGE_SIZE;
DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
size, m1, m2, m3, o1, o2);
break;
}
case 16: {
@ -298,7 +301,8 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
o1 = size%PAGE_SIZE;
o2 = (size+(size/2))%PAGE_SIZE;
DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
size, m1, m2, m3, o1, o2);
break;
}
default: {
@ -387,23 +391,23 @@ static int video_begin(struct saa7146_fh *fh)
unsigned int resource;
int ret = 0, err = 0;
DEB_EE(("dev:%p, fh:%p\n",dev,fh));
DEB_EE("dev:%p, fh:%p\n", dev, fh);
if ((vv->video_status & STATUS_CAPTURE) != 0) {
if (vv->video_fh == fh) {
DEB_S(("already capturing.\n"));
DEB_S("already capturing\n");
return 0;
}
DEB_S(("already capturing in another open.\n"));
DEB_S("already capturing in another open\n");
return -EBUSY;
}
if ((vv->video_status & STATUS_OVERLAY) != 0) {
DEB_S(("warning: suspending overlay video for streaming capture.\n"));
DEB_S("warning: suspending overlay video for streaming capture\n");
vv->ov_suspend = vv->video_fh;
err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
if (0 != err) {
DEB_D(("suspending video failed. aborting\n"));
DEB_D("suspending video failed. aborting\n");
return err;
}
}
@ -420,7 +424,7 @@ static int video_begin(struct saa7146_fh *fh)
ret = saa7146_res_get(fh, resource);
if (0 == ret) {
DEB_S(("cannot get capture resource %d\n",resource));
DEB_S("cannot get capture resource %d\n", resource);
if (vv->ov_suspend != NULL) {
saa7146_start_preview(vv->ov_suspend);
vv->ov_suspend = NULL;
@ -448,15 +452,15 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
unsigned long flags;
unsigned int resource;
u32 dmas = 0;
DEB_EE(("dev:%p, fh:%p\n",dev,fh));
DEB_EE("dev:%p, fh:%p\n", dev, fh);
if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
DEB_S(("not capturing.\n"));
DEB_S("not capturing\n");
return 0;
}
if (vv->video_fh != fh) {
DEB_S(("capturing, but in another open.\n"));
DEB_S("capturing, but in another open\n");
return -EBUSY;
}
@ -530,7 +534,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
struct saa7146_vv *vv = dev->vv_data;
struct saa7146_format *fmt;
DEB_EE(("VIDIOC_S_FBUF\n"));
DEB_EE("VIDIOC_S_FBUF\n");
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
return -EPERM;
@ -542,13 +546,13 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
/* planar formats are not allowed for overlay video, clipping and video dma would clash */
if (fmt->flags & FORMAT_IS_PLANAR)
DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",
(char *)&fmt->pixelformat));
DEB_S("planar pixelformat '%4.4s' not allowed for overlay\n",
(char *)&fmt->pixelformat);
/* check if overlay is running */
if (IS_OVERLAY_ACTIVE(fh) != 0) {
if (vv->video_fh != fh) {
DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n"));
DEB_D("refusing to change framebuffer informations while overlay is active in another open\n");
return -EBUSY;
}
}
@ -559,7 +563,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) {
vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline));
DEB_D("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline);
}
return 0;
}
@ -588,7 +592,7 @@ static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *
if (ctrl == NULL)
return -EINVAL;
DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n", c->id));
DEB_EE("VIDIOC_QUERYCTRL: id:%d\n", c->id);
*c = *ctrl;
return 0;
}
@ -607,25 +611,25 @@ static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
case V4L2_CID_BRIGHTNESS:
value = saa7146_read(dev, BCS_CTRL);
c->value = 0xff & (value >> 24);
DEB_D(("V4L2_CID_BRIGHTNESS: %d\n", c->value));
DEB_D("V4L2_CID_BRIGHTNESS: %d\n", c->value);
break;
case V4L2_CID_CONTRAST:
value = saa7146_read(dev, BCS_CTRL);
c->value = 0x7f & (value >> 16);
DEB_D(("V4L2_CID_CONTRAST: %d\n", c->value));
DEB_D("V4L2_CID_CONTRAST: %d\n", c->value);
break;
case V4L2_CID_SATURATION:
value = saa7146_read(dev, BCS_CTRL);
c->value = 0x7f & (value >> 0);
DEB_D(("V4L2_CID_SATURATION: %d\n", c->value));
DEB_D("V4L2_CID_SATURATION: %d\n", c->value);
break;
case V4L2_CID_VFLIP:
c->value = vv->vflip;
DEB_D(("V4L2_CID_VFLIP: %d\n", c->value));
DEB_D("V4L2_CID_VFLIP: %d\n", c->value);
break;
case V4L2_CID_HFLIP:
c->value = vv->hflip;
DEB_D(("V4L2_CID_HFLIP: %d\n", c->value));
DEB_D("V4L2_CID_HFLIP: %d\n", c->value);
break;
default:
return -EINVAL;
@ -641,7 +645,7 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
ctrl = ctrl_by_id(c->id);
if (NULL == ctrl) {
DEB_D(("unknown control %d\n", c->id));
DEB_D("unknown control %d\n", c->id);
return -EINVAL;
}
@ -686,14 +690,14 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
case V4L2_CID_HFLIP:
/* fixme: we can support changing VFLIP and HFLIP here... */
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
DEB_D("V4L2_CID_HFLIP while active capture\n");
return -EBUSY;
}
vv->hflip = c->value;
break;
case V4L2_CID_VFLIP:
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
DEB_D("V4L2_CID_VFLIP while active capture\n");
return -EBUSY;
}
vv->vflip = c->value;
@ -748,7 +752,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma
int maxw, maxh;
int calc_bpl;
DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat);
if (NULL == fmt)
@ -777,7 +781,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma
vv->last_field = V4L2_FIELD_INTERLACED;
break;
default:
DEB_D(("no known field mode '%d'.\n", field));
DEB_D("no known field mode '%d'\n", field);
return -EINVAL;
}
@ -796,8 +800,9 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma
f->fmt.pix.bytesperline = calc_bpl;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", f->fmt.pix.width,
f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage));
DEB_D("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",
f->fmt.pix.width, f->fmt.pix.height,
f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
return 0;
}
@ -811,22 +816,23 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_f
enum v4l2_field field;
int maxw, maxh;
DEB_EE(("dev:%p\n", dev));
DEB_EE("dev:%p\n", dev);
if (NULL == vv->ov_fb.base) {
DEB_D(("no fb base set.\n"));
DEB_D("no fb base set\n");
return -EINVAL;
}
if (NULL == vv->ov_fmt) {
DEB_D(("no fb fmt set.\n"));
DEB_D("no fb fmt set\n");
return -EINVAL;
}
if (win->w.width < 48 || win->w.height < 32) {
DEB_D(("min width/height. (%d,%d)\n", win->w.width, win->w.height));
DEB_D("min width/height. (%d,%d)\n",
win->w.width, win->w.height);
return -EINVAL;
}
if (win->clipcount > 16) {
DEB_D(("clipcount too big.\n"));
DEB_D("clipcount too big\n");
return -EINVAL;
}
@ -848,7 +854,7 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_f
case V4L2_FIELD_INTERLACED:
break;
default:
DEB_D(("no known field mode '%d'.\n", field));
DEB_D("no known field mode '%d'\n", field);
return -EINVAL;
}
@ -868,16 +874,17 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_forma
struct saa7146_vv *vv = dev->vv_data;
int err;
DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_EE(("streaming capture is active\n"));
DEB_EE("streaming capture is active\n");
return -EBUSY;
}
err = vidioc_try_fmt_vid_cap(file, fh, f);
if (0 != err)
return err;
fh->video_fmt = f->fmt.pix;
DEB_EE(("set to pixelformat '%4.4s'\n", (char *)&fh->video_fmt.pixelformat));
DEB_EE("set to pixelformat '%4.4s'\n",
(char *)&fh->video_fmt.pixelformat);
return 0;
}
@ -888,7 +895,7 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_f
struct saa7146_vv *vv = dev->vv_data;
int err;
DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh));
DEB_EE("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh);
err = vidioc_try_fmt_vid_overlay(file, fh, f);
if (0 != err)
return err;
@ -931,7 +938,7 @@ static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
if (e->index < 0 )
return -EINVAL;
if( e->index < dev->ext_vv_data->num_stds ) {
DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index));
DEB_EE("VIDIOC_ENUMSTD: index:%d\n", e->index);
v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
return 0;
}
@ -946,10 +953,10 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
int found = 0;
int err, i;
DEB_EE(("VIDIOC_S_STD\n"));
DEB_EE("VIDIOC_S_STD\n");
if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
DEB_D(("cannot change video standard while streaming capture is active\n"));
DEB_D("cannot change video standard while streaming capture is active\n");
return -EBUSY;
}
@ -957,7 +964,7 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
vv->ov_suspend = vv->video_fh;
err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
if (0 != err) {
DEB_D(("suspending video failed. aborting\n"));
DEB_D("suspending video failed. aborting\n");
return err;
}
}
@ -978,11 +985,11 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
}
if (!found) {
DEB_EE(("VIDIOC_S_STD: standard not found.\n"));
DEB_EE("VIDIOC_S_STD: standard not found\n");
return -EINVAL;
}
DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name));
DEB_EE("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name);
return 0;
}
@ -990,7 +997,7 @@ static int vidioc_overlay(struct file *file, void *fh, unsigned int on)
{
int err;
DEB_D(("VIDIOC_OVERLAY on:%d\n", on));
DEB_D("VIDIOC_OVERLAY on:%d\n", on);
if (on)
err = saa7146_start_preview(fh);
else
@ -1047,7 +1054,7 @@ static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type typ
struct saa7146_fh *fh = __fh;
int err;
DEB_D(("VIDIOC_STREAMON, type:%d\n", type));
DEB_D("VIDIOC_STREAMON, type:%d\n", type);
err = video_begin(fh);
if (err)
@ -1066,18 +1073,18 @@ static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type ty
struct saa7146_vv *vv = dev->vv_data;
int err;
DEB_D(("VIDIOC_STREAMOFF, type:%d\n", type));
DEB_D("VIDIOC_STREAMOFF, type:%d\n", type);
/* ugly: we need to copy some checks from video_end(),
because videobuf_streamoff() relies on the capture running.
check and fix this */
if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
DEB_S(("not capturing.\n"));
DEB_S("not capturing\n");
return 0;
}
if (vv->video_fh != fh) {
DEB_S(("capturing, but in another open.\n"));
DEB_S("capturing, but in another open\n");
return -EBUSY;
}
@ -1087,7 +1094,7 @@ static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type ty
else if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
err = videobuf_streamoff(&fh->vbi_q);
if (0 != err) {
DEB_D(("warning: videobuf_streamoff() failed.\n"));
DEB_D("warning: videobuf_streamoff() failed\n");
video_end(fh, file);
} else {
err = video_end(fh, file);
@ -1174,25 +1181,27 @@ static int buffer_prepare(struct videobuf_queue *q,
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
int size,err = 0;
DEB_CAP(("vbuf:%p\n",vb));
DEB_CAP("vbuf:%p\n", vb);
/* sanity checks */
if (fh->video_fmt.width < 48 ||
fh->video_fmt.height < 32 ||
fh->video_fmt.width > vv->standard->h_max_out ||
fh->video_fmt.height > vv->standard->v_max_out) {
DEB_D(("w (%d) / h (%d) out of bounds.\n",fh->video_fmt.width,fh->video_fmt.height));
DEB_D("w (%d) / h (%d) out of bounds\n",
fh->video_fmt.width, fh->video_fmt.height);
return -EINVAL;
}
size = fh->video_fmt.sizeimage;
if (0 != buf->vb.baddr && buf->vb.bsize < size) {
DEB_D(("size mismatch.\n"));
DEB_D("size mismatch\n");
return -EINVAL;
}
DEB_CAP(("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
fh->video_fmt.width,fh->video_fmt.height,size,v4l2_field_names[fh->video_fmt.field]));
DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
fh->video_fmt.width, fh->video_fmt.height,
size, v4l2_field_names[fh->video_fmt.field]);
if (buf->vb.width != fh->video_fmt.width ||
buf->vb.bytesperline != fh->video_fmt.bytesperline ||
buf->vb.height != fh->video_fmt.height ||
@ -1238,7 +1247,7 @@ static int buffer_prepare(struct videobuf_queue *q,
return 0;
oops:
DEB_D(("error out.\n"));
DEB_D("error out\n");
saa7146_dma_free(dev,q,buf);
return err;
@ -1259,7 +1268,7 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned
*count = (max_memory*1048576) / *size;
}
DEB_CAP(("%d buffers, %d bytes each.\n",*count,*size));
DEB_CAP("%d buffers, %d bytes each\n", *count, *size);
return 0;
}
@ -1272,7 +1281,7 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
struct saa7146_vv *vv = dev->vv_data;
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
DEB_CAP(("vbuf:%p\n",vb));
DEB_CAP("vbuf:%p\n", vb);
saa7146_buffer_queue(fh->dev,&vv->video_q,buf);
}
@ -1283,7 +1292,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
struct saa7146_dev *dev = fh->dev;
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
DEB_CAP(("vbuf:%p\n",vb));
DEB_CAP("vbuf:%p\n", vb);
saa7146_dma_free(dev,q,buf);
@ -1347,18 +1356,14 @@ static void video_close(struct saa7146_dev *dev, struct file *file)
struct saa7146_fh *fh = file->private_data;
struct saa7146_vv *vv = dev->vv_data;
struct videobuf_queue *q = &fh->video_q;
int err;
if (IS_CAPTURE_ACTIVE(fh) != 0) {
err = video_end(fh, file);
} else if (IS_OVERLAY_ACTIVE(fh) != 0) {
err = saa7146_stop_preview(fh);
}
if (IS_CAPTURE_ACTIVE(fh) != 0)
video_end(fh, file);
else if (IS_OVERLAY_ACTIVE(fh) != 0)
saa7146_stop_preview(fh);
videobuf_stop(q);
/* hmm, why is this function declared void? */
/* return err */
}
@ -1368,7 +1373,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
struct saa7146_dmaqueue *q = &vv->video_q;
spin_lock(&dev->slock);
DEB_CAP(("called.\n"));
DEB_CAP("called\n");
/* only finish the buffer if we have one... */
if( NULL != q->curr ) {
@ -1386,15 +1391,15 @@ static ssize_t video_read(struct file *file, char __user *data, size_t count, lo
struct saa7146_vv *vv = dev->vv_data;
ssize_t ret = 0;
DEB_EE(("called.\n"));
DEB_EE("called\n");
if ((vv->video_status & STATUS_CAPTURE) != 0) {
/* fixme: should we allow read() captures while streaming capture? */
if (vv->video_fh == fh) {
DEB_S(("already capturing.\n"));
DEB_S("already capturing\n");
return -EBUSY;
}
DEB_S(("already capturing in another open.\n"));
DEB_S("already capturing in another open\n");
return -EBUSY;
}

View File

@ -28,5 +28,5 @@ obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
ccflags-y += -Idrivers/media/dvb/dvb-core
ccflags-y += -Idrivers/media/dvb/frontends

View File

@ -430,11 +430,10 @@ static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna)
{
struct microtune_priv *priv = fe->tuner_priv;
unsigned char buf[2];
int ret;
buf[0] = 6;
buf[1] = antenna ? 0x11 : 0x10;
ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
}
@ -574,21 +573,20 @@ static int mt2050_init(struct dvb_frontend *fe)
{
struct microtune_priv *priv = fe->tuner_priv;
unsigned char buf[2];
int ret;
buf[0]=6;
buf[1]=0x10;
ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power
buf[0] = 6;
buf[1] = 0x10;
tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* power */
buf[0]=0x0f;
buf[1]=0x0f;
ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo
buf[0] = 0x0f;
buf[1] = 0x0f;
tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* m1lo */
buf[0]=0x0d;
ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
buf[0] = 0x0d;
tuner_i2c_xfer_send(&priv->i2c_props, buf, 1);
tuner_i2c_xfer_recv(&priv->i2c_props, buf, 1);
tuner_dbg("mt2050: sro is %x\n",buf[0]);
tuner_dbg("mt2050: sro is %x\n", buf[0]);
memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops));

View File

@ -309,7 +309,6 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val);
static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
u8 *RegVal, int *count);
static u32 MXL_GetXtalInt(u32 Xtal_Freq);
static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq);
static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe);
static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe);
@ -2307,14 +2306,6 @@ static u16 MXL_IFSynthInit(struct dvb_frontend *fe)
return status ;
}
static u32 MXL_GetXtalInt(u32 Xtal_Freq)
{
if ((Xtal_Freq % 1000000) == 0)
return (Xtal_Freq / 10000);
else
return (((Xtal_Freq / 1000000) + 1)*100);
}
static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
{
struct mxl5005s_state *state = fe->tuner_priv;
@ -2324,13 +2315,10 @@ static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
u32 Kdbl_RF = 2;
u32 tg_divval;
u32 tg_lo;
u32 Xtal_Int;
u32 Fref_TG;
u32 Fvco;
Xtal_Int = MXL_GetXtalInt(state->Fxtal);
state->RF_IN = RF_Freq;
MXL_SynthRFTGLO_Calc(fe);
@ -2779,6 +2767,16 @@ static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8;
/* below equation is same as above but much harder to debug.
*
* static u32 MXL_GetXtalInt(u32 Xtal_Freq)
* {
* if ((Xtal_Freq % 1000000) == 0)
* return (Xtal_Freq / 10000);
* else
* return (((Xtal_Freq / 1000000) + 1)*100);
* }
*
* u32 Xtal_Int = MXL_GetXtalInt(state->Fxtal);
* tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) -
* ((state->TG_LO/10000)*divider_val *
* (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 *

View File

@ -18,7 +18,20 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "tda18212_priv.h"
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "tda18212.h"
struct tda18212_priv {
struct tda18212_config *cfg;
struct i2c_adapter *i2c;
};
#define dbg(fmt, arg...) \
do { \
if (debug) \
pr_info("%s: " fmt, __func__, ##arg); \
} while (0)
static int debug;
module_param(debug, int, 0644);
@ -46,7 +59,8 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
if (ret == 1) {
ret = 0;
} else {
warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
pr_warn("i2c wr failed ret:%d reg:%02x len:%d\n",
ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
@ -77,7 +91,8 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
memcpy(val, buf, len);
ret = 0;
} else {
warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
pr_warn("i2c rd failed ret:%d reg:%02x len:%d\n",
ret, reg, len);
ret = -EREMOTEIO;
}
@ -129,8 +144,8 @@ static int tda18212_set_params(struct dvb_frontend *fe,
{ 0x92, 0x53, 0x03 }, /* DVB-C */
};
dbg("%s: delsys=%d RF=%d BW=%d", __func__,
c->delivery_system, c->frequency, c->bandwidth_hz);
dbg("delsys=%d RF=%d BW=%d\n",
c->delivery_system, c->frequency, c->bandwidth_hz);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
@ -196,7 +211,7 @@ exit:
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
dbg("failed:%d\n", ret);
goto exit;
}
@ -245,13 +260,13 @@ struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
dbg("ret:%d chip ID:%02x\n", ret, val);
if (ret || val != 0xc7) {
kfree(priv);
return NULL;
}
info("NXP TDA18212HN successfully identified.");
pr_info("NXP TDA18212HN successfully identified\n");
memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
sizeof(struct dvb_tuner_ops));

View File

@ -676,10 +676,28 @@ fail:
return ret;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
* End:
*/
int _tda_printk(struct tda18271_priv *state, const char *level,
const char *func, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
int rtn;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
if (state)
rtn = printk("%s%s: [%d-%04x|%c] %pV",
level, func, i2c_adapter_id(state->i2c_props.adap),
state->i2c_props.addr,
(state->role == TDA18271_MASTER) ? 'M' : 'S',
&vaf);
else
rtn = printk("%s%s: %pV", level, func, &vaf);
va_end(args);
return rtn;
}

View File

@ -1230,7 +1230,7 @@ static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg)
return 0;
}
static struct dvb_tuner_ops tda18271_tuner_ops = {
static const struct dvb_tuner_ops tda18271_tuner_ops = {
.info = {
.name = "NXP TDA18271HD",
.frequency_min = 45000000,

View File

@ -136,29 +136,26 @@ extern int tda18271_debug;
#define DBG_ADV 8
#define DBG_CAL 16
#define tda_printk(st, kern, fmt, arg...) do {\
if (st) { \
struct tda18271_priv *state = st; \
printk(kern "%s: [%d-%04x|%s] " fmt, __func__, \
i2c_adapter_id(state->i2c_props.adap), \
state->i2c_props.addr, \
(state->role == TDA18271_MASTER) \
? "M" : "S", ##arg); \
} else \
printk(kern "%s: " fmt, __func__, ##arg); \
__attribute__((format(printf, 4, 5)))
int _tda_printk(struct tda18271_priv *state, const char *level,
const char *func, const char *fmt, ...);
#define tda_printk(st, lvl, fmt, arg...) \
_tda_printk(st, lvl, __func__, fmt, ##arg)
#define tda_dprintk(st, lvl, fmt, arg...) \
do { \
if (tda18271_debug & lvl) \
tda_printk(st, KERN_DEBUG, fmt, ##arg); \
} while (0)
#define tda_dprintk(st, lvl, fmt, arg...) do {\
if (tda18271_debug & lvl) \
tda_printk(st, KERN_DEBUG, fmt, ##arg); } while (0)
#define tda_info(fmt, arg...) printk(KERN_INFO fmt, ##arg)
#define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg)
#define tda_err(fmt, arg...) tda_printk(priv, KERN_ERR, fmt, ##arg)
#define tda_dbg(fmt, arg...) tda_dprintk(priv, DBG_INFO, fmt, ##arg)
#define tda_map(fmt, arg...) tda_dprintk(priv, DBG_MAP, fmt, ##arg)
#define tda_reg(fmt, arg...) tda_dprintk(priv, DBG_REG, fmt, ##arg)
#define tda_cal(fmt, arg...) tda_dprintk(priv, DBG_CAL, fmt, ##arg)
#define tda_info(fmt, arg...) pr_info(fmt, ##arg)
#define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg)
#define tda_err(fmt, arg...) tda_printk(priv, KERN_ERR, fmt, ##arg)
#define tda_dbg(fmt, arg...) tda_dprintk(priv, DBG_INFO, fmt, ##arg)
#define tda_map(fmt, arg...) tda_dprintk(priv, DBG_MAP, fmt, ##arg)
#define tda_reg(fmt, arg...) tda_dprintk(priv, DBG_REG, fmt, ##arg)
#define tda_cal(fmt, arg...) tda_dprintk(priv, DBG_CAL, fmt, ##arg)
#define tda_fail(ret) \
({ \

View File

@ -176,7 +176,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
if_freq = 5000000;
break;
}
tuner_freq = params->frequency + if_freq;
tuner_freq = params->frequency;
i = 0;
while (tda827x_table[i].lomax < tuner_freq) {
@ -185,6 +185,8 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
i++;
}
tuner_freq += if_freq;
N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);
buf[0] = 0;
buf[1] = (N>>8) | 0x40;
@ -540,7 +542,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
if_freq = 5000000;
break;
}
tuner_freq = params->frequency + if_freq;
tuner_freq = params->frequency;
if (fe->ops.info.type == FE_QAM) {
dprintk("%s select tda827xa_dvbc\n", __func__);
@ -554,6 +556,8 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
i++;
}
tuner_freq += if_freq;
N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd;
buf[0] = 0; // subaddress
buf[1] = N >> 8;

View File

@ -614,6 +614,13 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
p += len;
size -= len;
}
/* silently fail if the frontend doesn't support I2C flush */
rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0);
if ((rc < 0) && (rc != -EINVAL)) {
tuner_err("error executing flush: %d\n", rc);
return rc;
}
}
return 0;
}
@ -933,11 +940,16 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
* that xc2028 will be in a safe state.
* Maybe this might also be needed for DTV.
*/
if (new_type == V4L2_TUNER_ANALOG_TV) {
switch (new_type) {
case V4L2_TUNER_ANALOG_TV:
rc = send_seq(priv, {0x00, 0x00});
/* Analog modes require offset = 0 */
} else {
/* Analog mode requires offset = 0 */
break;
case V4L2_TUNER_RADIO:
/* Radio mode requires offset = 0 */
break;
case V4L2_TUNER_DIGITAL_TV:
/*
* Digital modes require an offset to adjust to the
* proper frequency. The offset depends on what

View File

@ -54,6 +54,7 @@ struct xc2028_config {
/* xc2028 commands for callback */
#define XC2028_TUNER_RESET 0
#define XC2028_RESET_CLK 1
#define XC2028_I2C_FLUSH 2
#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE))
extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,

View File

@ -12,5 +12,5 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
b2c2-flexcop-usb-objs = flexcop-usb.o
obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
EXTRA_CFLAGS += -Idrivers/media/common/tuners/
ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
ccflags-y += -Idrivers/media/common/tuners/

View File

@ -1,6 +1,6 @@
obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
EXTRA_CFLAGS += -Idrivers/media/video/bt8xx
EXTRA_CFLAGS += -Idrivers/media/common/tuners
ccflags-y += -Idrivers/media/dvb/dvb-core
ccflags-y += -Idrivers/media/dvb/frontends
ccflags-y += -Idrivers/media/video/bt8xx
ccflags-y += -Idrivers/media/common/tuners

View File

@ -6,9 +6,9 @@ ddbridge-objs := ddbridge-core.o
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
EXTRA_CFLAGS += -Idrivers/media/common/tuners/
ccflags-y += -Idrivers/media/dvb/dvb-core/
ccflags-y += -Idrivers/media/dvb/frontends/
ccflags-y += -Idrivers/media/common/tuners/
# For the staging CI driver cxd2099
EXTRA_CFLAGS += -Idrivers/staging/cxd2099/
ccflags-y += -Idrivers/staging/cxd2099/

View File

@ -507,15 +507,14 @@ static u32 ddb_input_avail(struct ddb_input *input)
return 0;
}
static size_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
{
struct ddb *dev = input->port->dev;
u32 left = count;
u32 idx, off, free, stat = input->stat;
u32 idx, free, stat = input->stat;
int ret;
idx = (stat >> 11) & 0x1f;
off = (stat & 0x7ff) << 7;
while (left) {
if (input->cbuf == idx)
@ -525,6 +524,8 @@ static size_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
free = left;
ret = copy_to_user(buf, input->vbuf[input->cbuf] +
input->coff, free);
if (ret)
return -EFAULT;
input->coff += free;
if (input->coff == input->dma_buf_size) {
input->coff = 0;
@ -939,6 +940,8 @@ static ssize_t ts_read(struct file *file, char *buf,
break;
}
read = ddb_input_read(input, buf, left);
if (read < 0)
return read;
left -= read;
buf += read;
}
@ -1438,7 +1441,7 @@ static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct ddb *dev = file->private_data;
void *parg = (void *)arg;
int res = -EFAULT;
int res;
switch (cmd) {
case IOCTL_DDB_FLASHIO:
@ -1447,29 +1450,29 @@ static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
u8 *rbuf, *wbuf;
if (copy_from_user(&fio, parg, sizeof(fio)))
break;
if (fio.write_len + fio.read_len > 1028) {
printk(KERN_ERR "IOBUF too small\n");
return -ENOMEM;
}
return -EFAULT;
if (fio.write_len > 1028 || fio.read_len > 1028)
return -EINVAL;
if (fio.write_len + fio.read_len > 1028)
return -EINVAL;
wbuf = &dev->iobuf[0];
if (!wbuf)
return -ENOMEM;
rbuf = wbuf + fio.write_len;
if (copy_from_user(wbuf, fio.write_buf, fio.write_len)) {
vfree(wbuf);
break;
}
res = flashio(dev, wbuf, fio.write_len,
rbuf, fio.read_len);
if (copy_from_user(wbuf, fio.write_buf, fio.write_len))
return -EFAULT;
res = flashio(dev, wbuf, fio.write_len, rbuf, fio.read_len);
if (res)
return res;
if (copy_to_user(fio.read_buf, rbuf, fio.read_len))
res = -EFAULT;
return -EFAULT;
break;
}
default:
break;
return -ENOTTY;
}
return res;
return 0;
}
static const struct file_operations ddb_fops = {

View File

@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_DM1105) += dm1105.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends

View File

@ -149,30 +149,25 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
dprintk ("%s\n", __func__);
if (mutex_lock_interruptible (&events->mtx))
return;
if ((status & FE_HAS_LOCK) && fe->ops.get_frontend)
fe->ops.get_frontend(fe, &fepriv->parameters_out);
mutex_lock(&events->mtx);
wp = (events->eventw + 1) % MAX_EVENT;
if (wp == events->eventr) {
events->overflow = 1;
events->eventr = (events->eventr + 1) % MAX_EVENT;
}
e = &events->events[events->eventw];
if (status & FE_HAS_LOCK)
if (fe->ops.get_frontend)
fe->ops.get_frontend(fe, &fepriv->parameters_out);
e->status = status;
e->parameters = fepriv->parameters_out;
events->eventw = wp;
mutex_unlock(&events->mtx);
e->status = status;
wake_up_interruptible (&events->wait_queue);
}
@ -207,19 +202,24 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
return ret;
}
if (mutex_lock_interruptible (&events->mtx))
return -ERESTARTSYS;
memcpy (event, &events->events[events->eventr],
sizeof(struct dvb_frontend_event));
mutex_lock(&events->mtx);
*event = events->events[events->eventr];
events->eventr = (events->eventr + 1) % MAX_EVENT;
mutex_unlock(&events->mtx);
return 0;
}
static void dvb_frontend_clear_events(struct dvb_frontend *fe)
{
struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dvb_fe_events *events = &fepriv->events;
mutex_lock(&events->mtx);
events->eventr = events->eventw;
mutex_unlock(&events->mtx);
}
static void dvb_frontend_init(struct dvb_frontend *fe)
{
dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
@ -537,7 +537,6 @@ static int dvb_frontend_thread(void *data)
{
struct dvb_frontend *fe = data;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
unsigned long timeout;
fe_status_t s;
enum dvbfe_algo algo;
@ -558,7 +557,7 @@ static int dvb_frontend_thread(void *data)
while (1) {
up(&fepriv->sem); /* is locked when we enter the thread... */
restart:
timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
wait_event_interruptible_timeout(fepriv->wait_queue,
dvb_frontend_should_wakeup(fe) || kthread_should_stop()
|| freezing(current),
fepriv->delay);
@ -577,12 +576,10 @@ restart:
if (fepriv->reinitialise) {
dvb_frontend_init(fe);
if (fepriv->tone != -1) {
if (fe->ops.set_tone && fepriv->tone != -1)
fe->ops.set_tone(fe, fepriv->tone);
}
if (fepriv->voltage != -1) {
if (fe->ops.set_voltage && fepriv->voltage != -1)
fe->ops.set_voltage(fe, fepriv->voltage);
}
fepriv->reinitialise = 0;
}
@ -1019,6 +1016,29 @@ static int is_legacy_delivery_system(fe_delivery_system_t s)
return 0;
}
/* Initialize the cache with some default values derived from the
* legacy frontend_info structure.
*/
static void dtv_property_cache_init(struct dvb_frontend *fe,
struct dtv_frontend_properties *c)
{
switch (fe->ops.info.type) {
case FE_QPSK:
c->modulation = QPSK; /* implied for DVB-S in legacy API */
c->rolloff = ROLLOFF_35;/* implied for DVB-S */
c->delivery_system = SYS_DVBS;
break;
case FE_QAM:
c->delivery_system = SYS_DVBC_ANNEX_AC;
break;
case FE_OFDM:
c->delivery_system = SYS_DVBT;
break;
case FE_ATSC:
break;
}
}
/* Synchronise the legacy tuning parameters into the cache, so that demodulator
* drivers can use a single set_frontend tuning function, regardless of whether
* it's being used for the legacy or new API, reducing code and complexity.
@ -1032,17 +1052,13 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
switch (fe->ops.info.type) {
case FE_QPSK:
c->modulation = QPSK; /* implied for DVB-S in legacy API */
c->rolloff = ROLLOFF_35;/* implied for DVB-S */
c->symbol_rate = p->u.qpsk.symbol_rate;
c->fec_inner = p->u.qpsk.fec_inner;
c->delivery_system = SYS_DVBS;
break;
case FE_QAM:
c->symbol_rate = p->u.qam.symbol_rate;
c->fec_inner = p->u.qam.fec_inner;
c->modulation = p->u.qam.modulation;
c->delivery_system = SYS_DVBC_ANNEX_AC;
break;
case FE_OFDM:
if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
@ -1060,7 +1076,6 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
c->transmission_mode = p->u.ofdm.transmission_mode;
c->guard_interval = p->u.ofdm.guard_interval;
c->hierarchy = p->u.ofdm.hierarchy_information;
c->delivery_system = SYS_DVBT;
break;
case FE_ATSC:
c->modulation = p->u.vsb.modulation;
@ -1132,16 +1147,13 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
p->frequency = c->frequency;
p->inversion = c->inversion;
switch(c->modulation) {
case PSK_8:
case APSK_16:
case APSK_32:
case QPSK:
if (c->delivery_system == SYS_DSS ||
c->delivery_system == SYS_DVBS ||
c->delivery_system == SYS_DVBS2 ||
c->delivery_system == SYS_ISDBS ||
c->delivery_system == SYS_TURBO) {
p->u.qpsk.symbol_rate = c->symbol_rate;
p->u.qpsk.fec_inner = c->fec_inner;
break;
default:
break;
}
/* Fake out a generic DVB-T request so we pass validation in the ioctl */
@ -1824,9 +1836,17 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
memcpy (&fepriv->parameters_in, parg,
sizeof (struct dvb_frontend_parameters));
dtv_property_cache_init(fe, c);
dtv_property_cache_sync(fe, c, &fepriv->parameters_in);
}
/*
* Initialize output parameters to match the values given by
* the user. FE_SET_FRONTEND triggers an initial frontend event
* with status = 0, which copies output parameters to userspace.
*/
fepriv->parameters_out = fepriv->parameters_in;
memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
memcpy(&fetunesettings.parameters, parg,
sizeof (struct dvb_frontend_parameters));
@ -1884,8 +1904,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
/* Request the search algorithm to search */
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
dvb_frontend_wakeup(fe);
dvb_frontend_clear_events(fe);
dvb_frontend_add_event(fe, 0);
dvb_frontend_wakeup(fe);
fepriv->status = 0;
err = 0;
break;

View File

@ -209,6 +209,7 @@ struct dvb_tuner_ops {
int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency);
#define TUNER_STATUS_LOCKED 1
#define TUNER_STATUS_STEREO 2

View File

@ -258,6 +258,19 @@ config DVB_USB_AF9005_REMOTE
Say Y here to support the default remote control decoding for the
Afatech AF9005 based receiver.
config DVB_USB_PCTV452E
tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
depends on DVB_USB
select TTPCI_EEPROM
select DVB_LNBP22 if !DVB_FE_CUSTOMISE
select DVB_STB0899 if !DVB_FE_CUSTOMISE
select DVB_STB6100 if !DVB_FE_CUSTOMISE
help
Support for external USB adapter designed by Pinnacle,
shipped under the brand name 'PCTV HDTV Pro USB'.
Also supports TT Connect S2-3600/3650 cards.
Say Y if you own such a device and want to use it.
config DVB_USB_DW2102
tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support"
depends on DVB_USB
@ -374,3 +387,18 @@ config DVB_USB_TECHNISAT_USB2
select DVB_STV6110x if !DVB_FE_CUSTOMISE
help
Say Y here to support the Technisat USB2 DVB-S/S2 device
config DVB_USB_IT913X
tristate "it913x driver"
depends on DVB_USB
select DVB_IT913X_FE
help
Say Y here to support the it913x device
config DVB_USB_MXL111SF
tristate "MxL111SF DTV USB2.0 support"
depends on DVB_USB
select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
select VIDEO_TVEEPROM
help
Say Y here to support the MxL111SF USB2.0 DTV receiver.

View File

@ -64,6 +64,9 @@ obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
dvb-usb-anysee-objs = anysee.o
obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
dvb-usb-pctv452e-objs = pctv452e.o
obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
dvb-usb-dw2102-objs = dw2102.o
obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
@ -94,7 +97,15 @@ obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
dvb-usb-technisat-usb2-objs = technisat-usb2.o
obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
# due to tuner-xc3028
EXTRA_CFLAGS += -Idrivers/media/common/tuners
dvb-usb-it913x-objs := it913x.o
obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o
dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o
obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o
obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
# due to tuner-xc3028
ccflags-y += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/ttpci

View File

@ -127,6 +127,8 @@ static struct dvb_usb_device_properties a800_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.pid_filter_count = 32,
.streaming_ctrl = dibusb2_0_streaming_ctrl,
@ -147,7 +149,7 @@ static struct dvb_usb_device_properties a800_properties = {
}
}
},
}},
.size_of_priv = sizeof(struct dibusb_state),
},
},

View File

@ -63,11 +63,9 @@ static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi,
u16 reglo, u8 pos, u8 len, u16 value)
{
int ret;
u8 temp;
if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff))))
return ret;
temp = (u8) ((value & 0x0300) >> 8);
return af9005_write_register_bits(d, reghi, pos, len,
(u8) ((value & 0x300) >> 8));
}

View File

@ -815,7 +815,7 @@ static int af9005_frontend_attach(struct dvb_usb_adapter *adap)
debug_dump(buf, 8, printk);
}
}
adap->fe = af9005_fe_attach(adap->dev);
adap->fe_adap[0].fe = af9005_fe_attach(adap->dev);
return 0;
}
@ -999,6 +999,8 @@ static struct dvb_usb_device_properties af9005_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps =
DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@ -1018,6 +1020,7 @@ static struct dvb_usb_device_properties af9005_properties = {
}
}
},
}},
}
},
.power_ctrl = af9005_power_ctrl,

View File

@ -744,29 +744,31 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
};
static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
{ (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_RC,
{ (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_RC,
RC_MAP_TERRATEC_SLIM_2 },
{ (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
{ (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
RC_MAP_TERRATEC_SLIM },
{ (USB_VID_VISIONPLUS << 16) + USB_PID_AZUREWAVE_AD_TU700,
{ (USB_VID_VISIONPLUS << 16) | USB_PID_AZUREWAVE_AD_TU700,
RC_MAP_AZUREWAVE_AD_TU700 },
{ (USB_VID_VISIONPLUS << 16) + USB_PID_TINYTWIN,
{ (USB_VID_VISIONPLUS << 16) | USB_PID_TINYTWIN,
RC_MAP_AZUREWAVE_AD_TU700 },
{ (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III,
{ (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGI_VOX_MINI_III,
RC_MAP_MSI_DIGIVOX_III },
{ (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGIVOX_DUO,
{ (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGIVOX_DUO,
RC_MAP_MSI_DIGIVOX_III },
{ (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD,
{ (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV_DONGLE_GOLD,
RC_MAP_LEADTEK_Y04G0051 },
{ (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X,
{ (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV2000DS,
RC_MAP_LEADTEK_Y04G0051 },
{ (USB_VID_AVERMEDIA << 16) | USB_PID_AVERMEDIA_VOLAR_X,
RC_MAP_AVERMEDIA_M135A },
{ (USB_VID_AFATECH << 16) + USB_PID_TREKSTOR_DVBT,
{ (USB_VID_AFATECH << 16) | USB_PID_TREKSTOR_DVBT,
RC_MAP_TREKSTOR },
{ (USB_VID_KWORLD_2 << 16) + USB_PID_TINYTWIN_2,
{ (USB_VID_KWORLD_2 << 16) | USB_PID_TINYTWIN_2,
RC_MAP_DIGITALNOW_TINYTWIN },
{ (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3,
{ (USB_VID_GTEK << 16) | USB_PID_TINYTWIN_3,
RC_MAP_DIGITALNOW_TINYTWIN },
{ (USB_VID_KWORLD_2 << 16) + USB_PID_SVEON_STV22,
{ (USB_VID_KWORLD_2 << 16) | USB_PID_SVEON_STV22,
RC_MAP_MSI_DIGIVOX_III },
{ }
};
@ -859,13 +861,13 @@ static int af9015_read_config(struct usb_device *udev)
for (i = 0; i < af9015_properties_count; i++) {
/* USB1.1 set smaller buffersize and disable 2nd adapter */
if (udev->speed == USB_SPEED_FULL) {
af9015_properties[i].adapter[0].stream.u.bulk.buffersize
af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize
= TS_USB11_FRAME_SIZE;
/* disable 2nd adapter because we don't have
PID-filters */
af9015_config.dual_mode = 0;
} else {
af9015_properties[i].adapter[0].stream.u.bulk.buffersize
af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize
= TS_USB20_FRAME_SIZE;
}
}
@ -1111,10 +1113,10 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
}
/* attach demodulator */
adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
&adap->dev->i2c_adap);
return adap->fe == NULL ? -ENODEV : 0;
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
static struct mt2060_config af9015_mt2060_config = {
@ -1188,49 +1190,49 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
switch (af9015_af9013_config[adap->id].tuner) {
case AF9013_TUNER_MT2060:
case AF9013_TUNER_MT2060_2:
ret = dvb_attach(mt2060_attach, adap->fe, &adap->dev->i2c_adap,
ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
&af9015_mt2060_config,
af9015_config.mt2060_if1[adap->id])
== NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_QT1010:
case AF9013_TUNER_QT1010A:
ret = dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap,
ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
&af9015_qt1010_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_TDA18271:
ret = dvb_attach(tda18271_attach, adap->fe, 0xc0,
ret = dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0xc0,
&adap->dev->i2c_adap,
&af9015_tda18271_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_TDA18218:
ret = dvb_attach(tda18218_attach, adap->fe,
ret = dvb_attach(tda18218_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap,
&af9015_tda18218_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_MXL5003D:
ret = dvb_attach(mxl5005s_attach, adap->fe,
ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap,
&af9015_mxl5003_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_MXL5005D:
case AF9013_TUNER_MXL5005R:
ret = dvb_attach(mxl5005s_attach, adap->fe,
ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap,
&af9015_mxl5005_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_ENV77H11D5:
ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
ret = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0xc0,
&adap->dev->i2c_adap,
DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_MC44S803:
ret = dvb_attach(mc44s803_attach, adap->fe,
ret = dvb_attach(mc44s803_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap,
&af9015_mc44s803_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_MXL5007T:
ret = dvb_attach(mxl5007t_attach, adap->fe,
ret = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap,
0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
break;
@ -1304,6 +1306,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.num_adapters = 2,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@ -1319,8 +1323,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.count = 6,
.endpoint = 0x84,
},
}},
},
{
.num_frontends = 1,
.fe = {{
.frontend_attach =
af9015_af9013_frontend_attach,
.tuner_attach = af9015_tuner_attach,
@ -1335,6 +1342,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
}
}
},
}},
}
},
@ -1432,6 +1440,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.num_adapters = 2,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@ -1447,8 +1457,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.count = 6,
.endpoint = 0x84,
},
}},
},
{
.num_frontends = 1,
.fe = {{
.frontend_attach =
af9015_af9013_frontend_attach,
.tuner_attach = af9015_tuner_attach,
@ -1463,6 +1476,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
}
}
},
}},
}
},
@ -1549,6 +1563,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.num_adapters = 2,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@ -1564,8 +1580,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.count = 6,
.endpoint = 0x84,
},
}},
},
{
.num_frontends = 1,
.fe = {{
.frontend_attach =
af9015_af9013_frontend_attach,
.tuner_attach = af9015_tuner_attach,
@ -1580,6 +1599,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
}
}
},
}},
}
},

View File

@ -446,6 +446,114 @@ static struct isl6423_config anysee_isl6423_config = {
* IOE[5] STV0903 1=enabled
*/
static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct anysee_state *state = adap->dev->priv;
int ret;
deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
/* no frontend sleep control */
if (onoff == 0)
return 0;
switch (state->hw) {
case ANYSEE_HW_507FA: /* 15 */
/* E30 Combo Plus */
/* E30 C Plus */
if ((fe->id ^ dvb_usb_anysee_delsys) == 0) {
/* disable DVB-T demod on IOD[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
0x01);
if (ret)
goto error;
/* enable DVB-C demod on IOD[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
0x20);
if (ret)
goto error;
/* enable DVB-C tuner on IOE[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
0x01);
if (ret)
goto error;
} else {
/* disable DVB-C demod on IOD[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
0x20);
if (ret)
goto error;
/* enable DVB-T demod on IOD[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
0x01);
if (ret)
goto error;
/* enable DVB-T tuner on IOE[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
0x01);
if (ret)
goto error;
}
break;
case ANYSEE_HW_508TC: /* 18 */
case ANYSEE_HW_508PTC: /* 21 */
/* E7 TC */
/* E7 PTC */
if ((fe->id ^ dvb_usb_anysee_delsys) == 0) {
/* disable DVB-T demod on IOD[6] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
0x40);
if (ret)
goto error;
/* enable DVB-C demod on IOD[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
0x20);
if (ret)
goto error;
/* enable IF route on IOE[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
0x01);
if (ret)
goto error;
} else {
/* disable DVB-C demod on IOD[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
0x20);
if (ret)
goto error;
/* enable DVB-T demod on IOD[6] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
0x40);
if (ret)
goto error;
/* enable IF route on IOE[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
0x01);
if (ret)
goto error;
}
break;
default:
ret = 0;
}
error:
return ret;
}
static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
{
int ret;
@ -466,41 +574,54 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
}
};
/* Check which hardware we have.
* We must do this call two times to get reliable values (hw bug).
*/
ret = anysee_get_hw_info(adap->dev, hw_info);
if (ret)
goto error;
/* detect hardware only once */
if (adap->fe_adap[0].fe == NULL) {
/* Check which hardware we have.
* We must do this call two times to get reliable values (hw bug).
*/
ret = anysee_get_hw_info(adap->dev, hw_info);
if (ret)
goto error;
ret = anysee_get_hw_info(adap->dev, hw_info);
if (ret)
goto error;
ret = anysee_get_hw_info(adap->dev, hw_info);
if (ret)
goto error;
/* Meaning of these info bytes are guessed. */
info("firmware version:%d.%d hardware id:%d",
hw_info[1], hw_info[2], hw_info[0]);
/* Meaning of these info bytes are guessed. */
info("firmware version:%d.%d hardware id:%d",
hw_info[1], hw_info[2], hw_info[0]);
state->hw = hw_info[0];
state->hw = hw_info[0];
}
/* set current frondend ID for devices having two frondends */
if (adap->fe_adap[0].fe)
state->fe_id++;
switch (state->hw) {
case ANYSEE_HW_507T: /* 2 */
/* E30 */
/* attach demod */
adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
&adap->dev->i2c_adap);
if (adap->fe)
if (state->fe_id)
break;
/* attach demod */
adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
adap->fe_adap[0].fe = dvb_attach(mt352_attach, &anysee_mt352_config,
&adap->dev->i2c_adap);
if (adap->fe_adap[0].fe)
break;
/* attach demod */
adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
&adap->dev->i2c_adap);
break;
case ANYSEE_HW_507CD: /* 6 */
/* E30 Plus */
if (state->fe_id)
break;
/* enable DVB-T demod on IOD[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
if (ret)
@ -512,33 +633,39 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
goto error;
/* attach demod */
adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
&adap->dev->i2c_adap);
adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
&anysee_zl10353_config, &adap->dev->i2c_adap);
break;
case ANYSEE_HW_507DC: /* 10 */
/* E30 C Plus */
if (state->fe_id)
break;
/* enable DVB-C demod on IOD[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
if (ret)
goto error;
/* attach demod */
adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
&adap->dev->i2c_adap, 0x48);
adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
&anysee_tda10023_config, &adap->dev->i2c_adap, 0x48);
break;
case ANYSEE_HW_507SI: /* 11 */
/* E30 S2 Plus */
if (state->fe_id)
break;
/* enable DVB-S/S2 demod on IOD[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
if (ret)
goto error;
/* attach demod */
adap->fe = dvb_attach(cx24116_attach, &anysee_cx24116_config,
adap->fe_adap[0].fe = dvb_attach(cx24116_attach, &anysee_cx24116_config,
&adap->dev->i2c_adap);
break;
@ -564,32 +691,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
if (ret)
goto error;
if (dvb_usb_anysee_delsys) {
/* disable DVB-C demod on IOD[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
0x20);
if (ret)
goto error;
/* enable DVB-T demod on IOD[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
0x01);
if (ret)
goto error;
/* attach demod */
if (tmp == 0xc7) {
/* TDA18212 config */
adap->fe = dvb_attach(zl10353_attach,
&anysee_zl10353_tda18212_config2,
&adap->dev->i2c_adap);
} else {
/* PLL config */
adap->fe = dvb_attach(zl10353_attach,
&anysee_zl10353_config,
&adap->dev->i2c_adap);
}
} else {
if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) {
/* disable DVB-T demod on IOD[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
0x01);
@ -605,15 +707,44 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
/* attach demod */
if (tmp == 0xc7) {
/* TDA18212 config */
adap->fe = dvb_attach(tda10023_attach,
adap->fe_adap[state->fe_id].fe = dvb_attach(
tda10023_attach,
&anysee_tda10023_tda18212_config,
&adap->dev->i2c_adap, 0x48);
} else {
/* PLL config */
adap->fe = dvb_attach(tda10023_attach,
adap->fe_adap[state->fe_id].fe = dvb_attach(
tda10023_attach,
&anysee_tda10023_config,
&adap->dev->i2c_adap, 0x48);
}
} else {
/* disable DVB-C demod on IOD[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
0x20);
if (ret)
goto error;
/* enable DVB-T demod on IOD[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
0x01);
if (ret)
goto error;
/* attach demod */
if (tmp == 0xc7) {
/* TDA18212 config */
adap->fe_adap[state->fe_id].fe = dvb_attach(
zl10353_attach,
&anysee_zl10353_tda18212_config2,
&adap->dev->i2c_adap);
} else {
/* PLL config */
adap->fe_adap[state->fe_id].fe = dvb_attach(
zl10353_attach,
&anysee_zl10353_config,
&adap->dev->i2c_adap);
}
}
break;
@ -627,30 +758,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
if (ret)
goto error;
if (dvb_usb_anysee_delsys) {
/* disable DVB-C demod on IOD[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
0x20);
if (ret)
goto error;
/* enable DVB-T demod on IOD[6] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
0x40);
if (ret)
goto error;
/* enable IF route on IOE[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
0x01);
if (ret)
goto error;
/* attach demod */
adap->fe = dvb_attach(zl10353_attach,
&anysee_zl10353_tda18212_config,
&adap->dev->i2c_adap);
} else {
if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) {
/* disable DVB-T demod on IOD[6] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
0x40);
@ -663,16 +771,27 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
if (ret)
goto error;
/* enable IF route on IOE[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
0x01);
/* attach demod */
adap->fe_adap[state->fe_id].fe = dvb_attach(tda10023_attach,
&anysee_tda10023_tda18212_config,
&adap->dev->i2c_adap, 0x48);
} else {
/* disable DVB-C demod on IOD[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
0x20);
if (ret)
goto error;
/* enable DVB-T demod on IOD[6] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
0x40);
if (ret)
goto error;
/* attach demod */
adap->fe = dvb_attach(tda10023_attach,
&anysee_tda10023_tda18212_config,
&adap->dev->i2c_adap, 0x48);
adap->fe_adap[state->fe_id].fe = dvb_attach(zl10353_attach,
&anysee_zl10353_tda18212_config,
&adap->dev->i2c_adap);
}
break;
@ -681,6 +800,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
/* E7 S2 */
/* E7 PS2 */
if (state->fe_id)
break;
/* enable transport stream on IOA[7] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
if (ret)
@ -692,13 +814,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
goto error;
/* attach demod */
adap->fe = dvb_attach(stv0900_attach, &anysee_stv0900_config,
adap->fe_adap[0].fe = dvb_attach(stv0900_attach, &anysee_stv0900_config,
&adap->dev->i2c_adap, 0);
break;
}
if (!adap->fe) {
if (!adap->fe_adap[0].fe) {
/* we have no frontend :-( */
ret = -ENODEV;
err("Unsupported Anysee version. " \
@ -713,14 +835,14 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
struct anysee_state *state = adap->dev->priv;
struct dvb_frontend *fe;
int ret;
deb_info("%s:\n", __func__);
deb_info("%s: fe=%d\n", __func__, state->fe_id);
switch (state->hw) {
case ANYSEE_HW_507T: /* 2 */
/* E30 */
/* attach tuner */
fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1),
fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1),
NULL, DVB_PLL_THOMSON_DTT7579);
break;
@ -728,7 +850,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
/* E30 Plus */
/* attach tuner */
fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1),
fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1),
&adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579);
break;
@ -736,7 +858,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
/* E30 C Plus */
/* attach tuner */
fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1),
fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc0 >> 1),
&adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
break;
@ -744,28 +866,14 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
/* E30 S2 Plus */
/* attach LNB controller */
fe = dvb_attach(isl6423_attach, adap->fe, &adap->dev->i2c_adap,
&anysee_isl6423_config);
fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap, &anysee_isl6423_config);
break;
case ANYSEE_HW_507FA: /* 15 */
/* E30 Combo Plus */
/* E30 C Plus */
if (dvb_usb_anysee_delsys) {
/* enable DVB-T tuner on IOE[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
0x01);
if (ret)
goto error;
} else {
/* enable DVB-C tuner on IOE[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
0x01);
if (ret)
goto error;
}
/* Try first attach TDA18212 silicon tuner on IOE[4], if that
* fails attach old simple PLL. */
@ -775,8 +883,8 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
goto error;
/* attach tuner */
fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap,
&anysee_tda18212_config);
fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
&adap->dev->i2c_adap, &anysee_tda18212_config);
if (fe)
break;
@ -786,8 +894,9 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
goto error;
/* attach tuner */
fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1),
&adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe,
(0xc0 >> 1), &adap->dev->i2c_adap,
DVB_PLL_SAMSUNG_DTOS403IH102A);
break;
case ANYSEE_HW_508TC: /* 18 */
@ -801,8 +910,8 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
goto error;
/* attach tuner */
fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap,
&anysee_tda18212_config);
fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
&adap->dev->i2c_adap, &anysee_tda18212_config);
break;
case ANYSEE_HW_508S2: /* 19 */
@ -811,12 +920,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
/* E7 PS2 */
/* attach tuner */
fe = dvb_attach(stv6110_attach, adap->fe,
fe = dvb_attach(stv6110_attach, adap->fe_adap[0].fe,
&anysee_stv6110_config, &adap->dev->i2c_adap);
if (fe) {
/* attach LNB controller */
fe = dvb_attach(isl6423_attach, adap->fe,
fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap, &anysee_isl6423_config);
}
@ -918,6 +1027,9 @@ static struct dvb_usb_device_properties anysee_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 2,
.frontend_ctrl = anysee_frontend_ctrl,
.fe = {{
.streaming_ctrl = anysee_streaming_ctrl,
.frontend_attach = anysee_frontend_attach,
.tuner_attach = anysee_tuner_attach,
@ -931,6 +1043,21 @@ static struct dvb_usb_device_properties anysee_properties = {
}
}
},
}, {
.streaming_ctrl = anysee_streaming_ctrl,
.frontend_attach = anysee_frontend_attach,
.tuner_attach = anysee_tuner_attach,
.stream = {
.type = USB_BULK,
.count = 8,
.endpoint = 0x82,
.u = {
.bulk = {
.buffersize = (16*512),
}
}
},
}},
}
},

View File

@ -59,6 +59,7 @@ enum cmd {
struct anysee_state {
u8 hw; /* PCB ID */
u8 seq;
u8 fe_id:1; /* frondend ID */
};
#define ANYSEE_HW_507T 2 /* E30 */

View File

@ -140,9 +140,9 @@ static struct zl10353_config au6610_zl10353_config = {
static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
{
adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
&adap->dev->i2c_adap);
if (adap->fe == NULL)
if (adap->fe_adap[0].fe == NULL)
return -ENODEV;
return 0;
@ -155,7 +155,7 @@ static struct qt1010_config au6610_qt1010_config = {
static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
{
return dvb_attach(qt1010_attach,
adap->fe, &adap->dev->i2c_adap,
adap->fe_adap[0].fe, &adap->dev->i2c_adap,
&au6610_qt1010_config) == NULL ? -ENODEV : 0;
}
@ -204,6 +204,8 @@ static struct dvb_usb_device_properties au6610_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.frontend_attach = au6610_zl10353_frontend_attach,
.tuner_attach = au6610_qt1010_tuner_attach,
@ -219,6 +221,7 @@ static struct dvb_usb_device_properties au6610_properties = {
}
}
},
}},
}
},

View File

@ -40,7 +40,6 @@ static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = {
{ STB0899_DISRX_ST0 , 0x04 },
{ STB0899_DISRX_ST1 , 0x00 },
{ STB0899_DISPARITY , 0x00 },
{ STB0899_DISFIFO , 0x00 },
{ STB0899_DISSTATUS , 0x20 },
{ STB0899_DISF22 , 0x99 },
{ STB0899_DISF22RX , 0xa8 },
@ -782,7 +781,6 @@ static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
u8 buf;
int ret;
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct i2c_msg i2c_msg = {
@ -800,17 +798,17 @@ static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
switch (voltage) {
case SEC_VOLTAGE_13:
buf = 1;
ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
break;
case SEC_VOLTAGE_18:
buf = 2;
ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
break;
case SEC_VOLTAGE_OFF:
buf = 0;
ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
break;
default:
@ -910,16 +908,16 @@ static int az6027_frontend_attach(struct dvb_usb_adapter *adap)
az6027_frontend_reset(adap);
deb_info("adap = %p, dev = %p\n", adap, adap->dev);
adap->fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap);
adap->fe_adap[0].fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap);
if (adap->fe) {
if (adap->fe_adap[0].fe) {
deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address);
if (stb6100_attach(adap->fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) {
if (stb6100_attach(adap->fe_adap[0].fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) {
deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address);
adap->fe->ops.set_voltage = az6027_set_voltage;
adap->fe_adap[0].fe->ops.set_voltage = az6027_set_voltage;
az6027_ci_init(adap);
} else {
adap->fe = NULL;
adap->fe_adap[0].fe = NULL;
}
} else
warn("no front-end attached\n");
@ -954,7 +952,6 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int i = 0, j = 0, len = 0;
int ret;
u16 index;
u16 value;
int length;
@ -990,7 +987,7 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
value = msg[i].addr + (msg[i].len << 8);
length = msg[i + 1].len + 6;
ret = az6027_usb_in_op(d, req, value, index, data, length);
az6027_usb_in_op(d, req, value, index, data, length);
len = msg[i + 1].len;
for (j = 0; j < len; j++)
msg[i + 1].buf[j] = data[j + 5];
@ -1017,7 +1014,7 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
index = 0x0;
value = msg[i].addr;
length = msg[i].len + 6;
ret = az6027_usb_in_op(d, req, value, index, data, length);
az6027_usb_in_op(d, req, value, index, data, length);
len = msg[i].len;
for (j = 0; j < len; j++)
msg[i].buf[j] = data[j + 5];
@ -1106,6 +1103,8 @@ static struct dvb_usb_device_properties az6027_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = az6027_streaming_ctrl,
.frontend_attach = az6027_frontend_attach,
@ -1120,6 +1119,7 @@ static struct dvb_usb_device_properties az6027_properties = {
}
}
},
}},
}
},
/*

View File

@ -186,9 +186,9 @@ static struct zl10353_config ce6230_zl10353_config = {
static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
{
deb_info("%s:\n", __func__);
adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
&adap->dev->i2c_adap);
if (adap->fe == NULL)
if (adap->fe_adap[0].fe == NULL)
return -ENODEV;
return 0;
}
@ -214,7 +214,7 @@ static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
{
int ret;
deb_info("%s:\n", __func__);
ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,
ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
&ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
return ret;
}
@ -273,6 +273,8 @@ static struct dvb_usb_device_properties ce6230_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.frontend_attach = ce6230_zl10353_frontend_attach,
.tuner_attach = ce6230_mxl5003s_tuner_attach,
.stream = {
@ -285,6 +287,7 @@ static struct dvb_usb_device_properties ce6230_properties = {
}
}
},
}},
}
},

View File

@ -69,7 +69,7 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
char state[3];
int ret;
adap->fe = cinergyt2_fe_attach(adap->dev);
adap->fe_adap[0].fe = cinergyt2_fe_attach(adap->dev);
ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state,
sizeof(state), 0);
@ -198,6 +198,8 @@ static struct dvb_usb_device_properties cinergyt2_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cinergyt2_streaming_ctrl,
.frontend_attach = cinergyt2_frontend_attach,
@ -212,6 +214,7 @@ static struct dvb_usb_device_properties cinergyt2_properties = {
}
}
},
}},
}
},

View File

@ -347,7 +347,7 @@ static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d)
static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
{
struct usb_data_stream_properties *p = &d->props.adapter[0].stream;
struct usb_data_stream_properties *p = &d->props.adapter[0].fe[0].stream;
const int timeout = 100;
const int junk_len = p->u.bulk.buffersize;
u8 *junk;
@ -725,7 +725,7 @@ static struct max2165_config mygica_d689_max2165_cfg = {
/* Callbacks for DVB USB */
static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(simple_tuner_attach, adap->fe,
dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap, 0x61,
TUNER_PHILIPS_FMD1216ME_MK3);
return 0;
@ -733,27 +733,27 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x61,
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61,
NULL, DVB_PLL_THOMSON_DTT7579);
return 0;
}
static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201);
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_LG_Z201);
return 0;
}
static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
NULL, DVB_PLL_THOMSON_DTT7579);
return 0;
}
static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(simple_tuner_attach, adap->fe,
dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF);
return 0;
}
@ -795,9 +795,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
};
/* FIXME: generalize & move to common area */
adap->fe->callback = dvico_bluebird_xc2028_callback;
adap->fe_adap[0].fe->callback = dvico_bluebird_xc2028_callback;
fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
fe = dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &cfg);
if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
return -EIO;
@ -808,7 +808,7 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(mxl5005s_attach, adap->fe,
dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap, &aver_a868r_tuner);
return 0;
}
@ -816,7 +816,7 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dvb_frontend *fe;
fe = dvb_attach(mxl5005s_attach, adap->fe,
fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap, &d680_dmb_tuner);
return (fe == NULL) ? -EIO : 0;
}
@ -824,7 +824,7 @@ static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dvb_frontend *fe;
fe = dvb_attach(max2165_attach, adap->fe,
fe = dvb_attach(max2165_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap, &mygica_d689_max2165_cfg);
return (fe == NULL) ? -EIO : 0;
}
@ -837,8 +837,9 @@ static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1);
if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config,
&adap->dev->i2c_adap)) != NULL)
adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) != NULL)
return 0;
return -EIO;
@ -851,8 +852,10 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config,
&adap->dev->i2c_adap)) != NULL)
adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach,
&cxusb_lgdt3303_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) != NULL)
return 0;
return -EIO;
@ -860,9 +863,9 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
{
adap->fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config,
adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config,
&adap->dev->i2c_adap);
if (adap->fe != NULL)
if (adap->fe_adap[0].fe != NULL)
return 0;
return -EIO;
@ -876,8 +879,9 @@ static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config,
&adap->dev->i2c_adap)) != NULL)
adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) != NULL)
return 0;
return -EIO;
@ -890,11 +894,15 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config,
&adap->dev->i2c_adap)) != NULL) ||
((adap->fe = dvb_attach(zl10353_attach,
&cxusb_zl10353_dee1601_config,
&adap->dev->i2c_adap)) != NULL))
adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) != NULL)
return 0;
adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
&cxusb_zl10353_dee1601_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) != NULL)
return 0;
return -EIO;
@ -917,9 +925,11 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
if ((adap->fe = dvb_attach(zl10353_attach,
&cxusb_zl10353_xc3028_config_no_i2c_gate,
&adap->dev->i2c_adap)) == NULL)
adap->fe_adap[0].fe =
dvb_attach(zl10353_attach,
&cxusb_zl10353_xc3028_config_no_i2c_gate,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) == NULL)
return -EIO;
/* try to determine if there is no IR decoder on the I2C bus */
@ -1031,9 +1041,9 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
return -ENODEV;
}
adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
&cxusb_dualdig4_rev2_config);
if (adap->fe == NULL)
if (adap->fe_adap[0].fe == NULL)
return -EIO;
return 0;
@ -1084,15 +1094,15 @@ static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
struct i2c_adapter *tun_i2c =
dib7000p_get_i2c_master(adap->fe,
dib7000p_get_i2c_master(adap->fe_adap[0].fe,
DIBX000_I2C_INTERFACE_TUNER, 1);
if (dvb_attach(dib0070_attach, adap->fe, tun_i2c,
if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
&dib7070p_dib0070_config) == NULL)
return -ENODEV;
st->set_param_save = adap->fe->ops.tuner_ops.set_params;
adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override;
st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override;
return 0;
}
@ -1108,14 +1118,16 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
if ((adap->fe = dvb_attach(zl10353_attach,
&cxusb_zl10353_xc3028_config,
&adap->dev->i2c_adap)) != NULL)
adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
&cxusb_zl10353_xc3028_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) != NULL)
return 0;
if ((adap->fe = dvb_attach(mt352_attach,
&cxusb_mt352_xc3028_config,
&adap->dev->i2c_adap)) != NULL)
adap->fe_adap[0].fe = dvb_attach(mt352_attach,
&cxusb_mt352_xc3028_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) != NULL)
return 0;
return -EIO;
@ -1150,7 +1162,7 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
usb_clear_halt(d->udev,
usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
usb_clear_halt(d->udev,
usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint));
usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
/* Drain USB pipes to avoid hang after reboot */
for (n = 0; n < 5; n++) {
@ -1172,8 +1184,8 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
msleep(100);
/* Attach frontend */
adap->fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap);
if (adap->fe == NULL)
adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap);
if (adap->fe_adap[0].fe == NULL)
return -EIO;
return 0;
@ -1207,7 +1219,7 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
usb_clear_halt(d->udev,
usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
usb_clear_halt(d->udev,
usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint));
usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
/* Reset the tuner */
@ -1223,9 +1235,9 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
msleep(100);
/* Attach frontend */
adap->fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg,
adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg,
&d->i2c_adap);
if (adap->fe == NULL)
if (adap->fe_adap[0].fe == NULL)
return -EIO;
return 0;
@ -1383,6 +1395,8 @@ static struct dvb_usb_device_properties cxusb_medion_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_streaming_ctrl,
.frontend_attach = cxusb_cx22702_frontend_attach,
.tuner_attach = cxusb_fmd1216me_tuner_attach,
@ -1397,7 +1411,7 @@ static struct dvb_usb_device_properties cxusb_medion_properties = {
}
}
},
}},
},
},
.power_ctrl = cxusb_power_ctrl,
@ -1429,6 +1443,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_streaming_ctrl,
.frontend_attach = cxusb_lgdt3303_frontend_attach,
.tuner_attach = cxusb_lgh064f_tuner_attach,
@ -1444,6 +1460,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
}
}
},
}},
},
},
@ -1483,6 +1500,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_streaming_ctrl,
.frontend_attach = cxusb_dee1601_frontend_attach,
.tuner_attach = cxusb_dee1601_tuner_attach,
@ -1497,6 +1516,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
}
}
},
}},
},
},
@ -1544,6 +1564,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
.num_adapters = 2,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_streaming_ctrl,
.frontend_attach = cxusb_mt352_frontend_attach,
.tuner_attach = cxusb_lgz201_tuner_attach,
@ -1559,6 +1581,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
}
}
},
}},
},
},
.power_ctrl = cxusb_bluebird_power_ctrl,
@ -1596,6 +1619,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_streaming_ctrl,
.frontend_attach = cxusb_mt352_frontend_attach,
.tuner_attach = cxusb_dtt7579_tuner_attach,
@ -1611,6 +1636,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
}
}
},
}},
},
},
.power_ctrl = cxusb_bluebird_power_ctrl,
@ -1645,6 +1671,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_streaming_ctrl,
.frontend_attach = cxusb_dualdig4_frontend_attach,
.tuner_attach = cxusb_dvico_xc3028_tuner_attach,
@ -1659,6 +1687,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
}
}
},
}},
},
},
@ -1695,6 +1724,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_streaming_ctrl,
.frontend_attach = cxusb_nano2_frontend_attach,
.tuner_attach = cxusb_dvico_xc3028_tuner_attach,
@ -1709,6 +1740,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
}
}
},
}},
},
},
@ -1747,6 +1779,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_streaming_ctrl,
.frontend_attach = cxusb_nano2_frontend_attach,
.tuner_attach = cxusb_dvico_xc3028_tuner_attach,
@ -1761,6 +1795,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
}
}
},
}},
},
},
@ -1796,6 +1831,8 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_aver_streaming_ctrl,
.frontend_attach = cxusb_aver_lgdt3303_frontend_attach,
.tuner_attach = cxusb_mxl5003s_tuner_attach,
@ -1810,7 +1847,7 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
}
}
},
}},
},
},
.power_ctrl = cxusb_aver_power_ctrl,
@ -1839,10 +1876,12 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
.num_adapters = 1,
.adapter = {
{
.size_of_priv = sizeof(struct dib0700_adapter_state),
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_streaming_ctrl,
.frontend_attach = cxusb_dualdig4_rev2_frontend_attach,
.tuner_attach = cxusb_dualdig4_rev2_tuner_attach,
.size_of_priv = sizeof(struct dib0700_adapter_state),
/* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
@ -1854,6 +1893,7 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
}
}
},
}},
},
},
@ -1889,6 +1929,8 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_d680_dmb_streaming_ctrl,
.frontend_attach = cxusb_d680_dmb_frontend_attach,
.tuner_attach = cxusb_d680_dmb_tuner_attach,
@ -1904,6 +1946,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
}
}
},
}},
},
},
@ -1940,6 +1983,8 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_d680_dmb_streaming_ctrl,
.frontend_attach = cxusb_mygica_d689_frontend_attach,
.tuner_attach = cxusb_mygica_d689_tuner_attach,
@ -1955,6 +2000,7 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
}
}
},
}},
},
},

View File

@ -30,6 +30,11 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
struct dib0700_state *st = d->priv;
int ret;
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
return 0;
}
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
REQUEST_GET_VERSION,
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
@ -46,6 +51,7 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
if (fwtype != NULL)
*fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) |
(st->buf[14] << 8) | st->buf[15];
mutex_unlock(&d->usb_mutex);
return ret;
}
@ -108,7 +114,12 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen
int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
{
struct dib0700_state *st = d->priv;
s16 ret;
int ret;
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
return 0;
}
st->buf[0] = REQUEST_SET_GPIO;
st->buf[1] = gpio;
@ -116,6 +127,7 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_
ret = dib0700_ctrl_wr(d, st->buf, 3);
mutex_unlock(&d->usb_mutex);
return ret;
}
@ -125,6 +137,11 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
int ret;
if (st->fw_version >= 0x10201) {
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
return 0;
}
st->buf[0] = REQUEST_SET_USB_XFER_LEN;
st->buf[1] = (nb_ts_packets >> 8) & 0xff;
st->buf[2] = nb_ts_packets & 0xff;
@ -132,6 +149,7 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
ret = dib0700_ctrl_wr(d, st->buf, 3);
mutex_unlock(&d->usb_mutex);
} else {
deb_info("this firmware does not allow to change the USB xfer len\n");
ret = -EIO;
@ -208,6 +226,10 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
} else {
/* Write request */
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
return 0;
}
st->buf[0] = REQUEST_NEW_I2C_WRITE;
st->buf[1] = msg[i].addr << 1;
st->buf[2] = (en_start << 7) | (en_stop << 6) |
@ -227,6 +249,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
USB_TYPE_VENDOR | USB_DIR_OUT,
0, 0, st->buf, msg[i].len + 4,
USB_CTRL_GET_TIMEOUT);
mutex_unlock(&d->usb_mutex);
if (result < 0) {
deb_info("i2c write error (status = %d)\n", result);
break;
@ -249,6 +272,10 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
return 0;
}
for (i = 0; i < num; i++) {
/* fill in the address */
@ -279,6 +306,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
break;
}
}
mutex_unlock(&d->usb_mutex);
mutex_unlock(&d->i2c_mutex);
return i;
@ -337,7 +365,12 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
{
struct dib0700_state *st = d->priv;
s16 ret;
int ret;
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
return 0;
}
st->buf[0] = REQUEST_SET_CLOCK;
st->buf[1] = (en_pll << 7) | (pll_src << 6) |
@ -352,6 +385,7 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
st->buf[9] = dsuScaler & 0xff; /* LSB */
ret = dib0700_ctrl_wr(d, st->buf, 10);
mutex_unlock(&d->usb_mutex);
return ret;
}
@ -360,10 +394,16 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
{
struct dib0700_state *st = d->priv;
u16 divider;
int ret;
if (scl_kHz == 0)
return -EINVAL;
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
return 0;
}
st->buf[0] = REQUEST_SET_I2C_PARAM;
divider = (u16) (30000 / scl_kHz);
st->buf[1] = 0;
@ -379,7 +419,11 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
(st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
return dib0700_ctrl_wr(d, st->buf, 8);
ret = dib0700_ctrl_wr(d, st->buf, 8);
mutex_unlock(&d->usb_mutex);
return ret;
}
@ -484,13 +528,13 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
adap_num++) {
if (fw_version >= 0x10201) {
dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
} else {
/* for fw version older than 1.20.1,
* the buffersize has to be n times 512 */
dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
if (dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize < 512)
dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 512;
dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
if (dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize < 512)
dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 512;
}
}
}
@ -515,6 +559,11 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
}
}
if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
err("could not acquire lock");
return 0;
}
st->buf[0] = REQUEST_ENABLE_VIDEO;
/* this bit gives a kind of command,
* rather than enabling something or not */
@ -530,25 +579,28 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
st->channel_state &= ~0x3;
if ((adap->stream.props.endpoint != 2)
&& (adap->stream.props.endpoint != 3)) {
deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->stream.props.endpoint);
if ((adap->fe_adap[0].stream.props.endpoint != 2)
&& (adap->fe_adap[0].stream.props.endpoint != 3)) {
deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint);
if (onoff)
st->channel_state |= 1 << (adap->id);
else
st->channel_state |= 1 << ~(adap->id);
} else {
if (onoff)
st->channel_state |= 1 << (adap->stream.props.endpoint-2);
st->channel_state |= 1 << (adap->fe_adap[0].stream.props.endpoint-2);
else
st->channel_state |= 1 << (3-adap->stream.props.endpoint);
st->channel_state |= 1 << (3-adap->fe_adap[0].stream.props.endpoint);
}
st->buf[2] |= st->channel_state;
deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
return dib0700_ctrl_wr(adap->dev, st->buf, 4);
ret = dib0700_ctrl_wr(adap->dev, st->buf, 4);
mutex_unlock(&adap->dev->usb_mutex);
return ret;
}
int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
@ -557,6 +609,11 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
struct dib0700_state *st = d->priv;
int new_proto, ret;
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
return 0;
}
st->buf[0] = REQUEST_SET_RC;
st->buf[1] = 0;
st->buf[2] = 0;
@ -567,23 +624,29 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
else if (rc_type == RC_TYPE_NEC)
new_proto = 0;
else if (rc_type == RC_TYPE_RC6) {
if (st->fw_version < 0x10200)
return -EINVAL;
if (st->fw_version < 0x10200) {
ret = -EINVAL;
goto out;
}
new_proto = 2;
} else
return -EINVAL;
} else {
ret = -EINVAL;
goto out;
}
st->buf[1] = new_proto;
ret = dib0700_ctrl_wr(d, st->buf, 3);
if (ret < 0) {
err("ir protocol setup failed");
return ret;
goto out;
}
d->props.rc.core.protocol = rc_type;
out:
mutex_unlock(&d->usb_mutex);
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@ int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
if (adap->priv != NULL) {
struct dibusb_state *st = adap->priv;
if (st->ops.fifo_ctrl != NULL)
if (st->ops.fifo_ctrl(adap->fe,onoff)) {
if (st->ops.fifo_ctrl(adap->fe_adap[0].fe, onoff)) {
err("error while controlling the fifo of the demod.");
return -ENODEV;
}
@ -37,7 +37,8 @@ int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onof
if (adap->priv != NULL) {
struct dibusb_state *st = adap->priv;
if (st->ops.pid_ctrl != NULL)
st->ops.pid_ctrl(adap->fe,index,pid,onoff);
st->ops.pid_ctrl(adap->fe_adap[0].fe,
index, pid, onoff);
}
return 0;
}
@ -48,7 +49,7 @@ int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
if (adap->priv != NULL) {
struct dibusb_state *st = adap->priv;
if (st->ops.pid_parse != NULL)
if (st->ops.pid_parse(adap->fe,onoff) < 0)
if (st->ops.pid_parse(adap->fe_adap[0].fe, onoff) < 0)
err("could not handle pid_parser");
}
return 0;
@ -254,8 +255,16 @@ int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
msleep(1000);
}
if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL ||
(adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) {
adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach,
&adap->dev->i2c_adap,
DEFAULT_DIB3000P_I2C_ADDRESS,
&mod3000p_dib3000p_config);
if ((adap->fe_adap[0].fe) == NULL)
adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach,
&adap->dev->i2c_adap,
DEFAULT_DIB3000MC_I2C_ADDRESS,
&mod3000p_dib3000p_config);
if ((adap->fe_adap[0].fe) != NULL) {
if (adap->priv != NULL) {
struct dibusb_state *st = adap->priv;
st->ops.pid_parse = dib3000mc_pid_parse;
@ -309,15 +318,15 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
}
}
tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1);
if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
/* not found - use panasonic pll parameters */
if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
if (dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
return -ENOMEM;
} else {
st->mt2060_present = 1;
/* set the correct parameters for the dib3000p */
dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config);
dib3000mc_set_config(adap->fe_adap[0].fe, &stk3000p_dib3000p_config);
}
return 0;
}

View File

@ -31,11 +31,12 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
demod_cfg.demod_address = 0x8;
if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg,
&adap->dev->i2c_adap, &st->ops)) == NULL)
adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg,
&adap->dev->i2c_adap, &st->ops);
if ((adap->fe_adap[0].fe) == NULL)
return -ENODEV;
adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
adap->fe_adap[0].fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
return 0;
}
@ -46,7 +47,7 @@ static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
st->tuner_addr = 0x61;
dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap,
DVB_PLL_TUA6010XS);
return 0;
}
@ -57,7 +58,7 @@ static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
st->tuner_addr = 0x60;
dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap,
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap,
DVB_PLL_TDA665X);
return 0;
}
@ -78,16 +79,16 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
if (adap->fe->ops.i2c_gate_ctrl)
adap->fe->ops.i2c_gate_ctrl(adap->fe,1);
if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1);
if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
err("tuner i2c write failed.");
ret = -EREMOTEIO;
}
if (adap->fe->ops.i2c_gate_ctrl)
adap->fe->ops.i2c_gate_ctrl(adap->fe,0);
if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0);
if (b2[0] == 0xfe) {
info("This device has the Thomson Cable onboard. Which is default.");
@ -185,6 +186,8 @@ static struct dvb_usb_device_properties dibusb1_1_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.pid_filter_count = 16,
@ -205,6 +208,7 @@ static struct dvb_usb_device_properties dibusb1_1_properties = {
}
}
},
}},
.size_of_priv = sizeof(struct dibusb_state),
}
},
@ -272,6 +276,8 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER,
.pid_filter_count = 16,
@ -292,6 +298,7 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
}
}
},
}},
.size_of_priv = sizeof(struct dibusb_state),
},
},
@ -338,6 +345,8 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.pid_filter_count = 16,
@ -358,6 +367,7 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = {
}
}
},
}},
.size_of_priv = sizeof(struct dibusb_state),
}
},
@ -398,6 +408,8 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.pid_filter_count = 16,
@ -417,6 +429,7 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = {
}
}
},
}},
.size_of_priv = sizeof(struct dibusb_state),
}
},

View File

@ -57,6 +57,8 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.pid_filter_count = 32,
.streaming_ctrl = dibusb2_0_streaming_ctrl,
@ -76,6 +78,7 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
}
}
},
}},
.size_of_priv = sizeof(struct dibusb_state),
}
},

View File

@ -137,11 +137,16 @@ static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
{
struct digitv_state *st = adap->dev->priv;
if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) {
adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) != NULL) {
st->is_nxt6000 = 0;
return 0;
}
if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) {
adap->fe_adap[0].fe = dvb_attach(nxt6000_attach,
&digitv_nxt6000_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) != NULL) {
st->is_nxt6000 = 1;
return 0;
}
@ -152,11 +157,11 @@ static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
{
struct digitv_state *st = adap->dev->priv;
if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4))
if (!dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_TDED4))
return -ENODEV;
if (st->is_nxt6000)
adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
adap->fe_adap[0].fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
return 0;
}
@ -292,6 +297,8 @@ static struct dvb_usb_device_properties digitv_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.frontend_attach = digitv_frontend_attach,
.tuner_attach = digitv_tuner_attach,
@ -306,6 +313,7 @@ static struct dvb_usb_device_properties digitv_properties = {
}
}
},
}},
}
},
.identify_state = digitv_identify_state,

View File

@ -90,7 +90,7 @@ static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap)
{
adap->fe = dtt200u_fe_attach(adap->dev);
adap->fe_adap[0].fe = dtt200u_fe_attach(adap->dev);
return 0;
}
@ -140,6 +140,8 @@ static struct dvb_usb_device_properties dtt200u_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
.pid_filter_count = 15,
@ -157,6 +159,7 @@ static struct dvb_usb_device_properties dtt200u_properties = {
}
}
},
}},
}
},
.power_ctrl = dtt200u_power_ctrl,
@ -187,6 +190,8 @@ static struct dvb_usb_device_properties wt220u_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
.pid_filter_count = 15,
@ -204,6 +209,7 @@ static struct dvb_usb_device_properties wt220u_properties = {
}
}
},
}},
}
},
.power_ctrl = dtt200u_power_ctrl,
@ -234,6 +240,8 @@ static struct dvb_usb_device_properties wt220u_fc_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
.pid_filter_count = 15,
@ -251,6 +259,7 @@ static struct dvb_usb_device_properties wt220u_fc_properties = {
}
}
},
}},
}
},
.power_ctrl = dtt200u_power_ctrl,
@ -281,6 +290,8 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
.pid_filter_count = 15,
@ -298,6 +309,7 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
}
}
},
}},
}
},
.power_ctrl = dtt200u_power_ctrl,

View File

@ -115,13 +115,13 @@ static struct zl10353_config dtv5100_zl10353_config = {
static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap)
{
adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config,
adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config,
&adap->dev->i2c_adap);
if (adap->fe == NULL)
if (adap->fe_adap[0].fe == NULL)
return -EIO;
/* disable i2c gate, or it won't work... is this safe? */
adap->fe->ops.i2c_gate_ctrl = NULL;
adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL;
return 0;
}
@ -133,7 +133,7 @@ static struct qt1010_config dtv5100_qt1010_config = {
static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap)
{
return dvb_attach(qt1010_attach,
adap->fe, &adap->dev->i2c_adap,
adap->fe_adap[0].fe, &adap->dev->i2c_adap,
&dtv5100_qt1010_config) == NULL ? -ENODEV : 0;
}
@ -180,6 +180,8 @@ static struct dvb_usb_device_properties dtv5100_properties = {
.num_adapters = 1,
.adapter = {{
.num_frontends = 1,
.fe = {{
.frontend_attach = dtv5100_frontend_attach,
.tuner_attach = dtv5100_tuner_attach,
@ -193,6 +195,7 @@ static struct dvb_usb_device_properties dtv5100_properties = {
}
}
},
}},
} },
.i2c_algo = &dtv5100_i2c_algo,

View File

@ -17,15 +17,20 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
if (adap == NULL)
return -ENODEV;
if ((adap->active_fe < 0) ||
(adap->active_fe >= adap->num_frontends_initialized)) {
return -EINVAL;
}
newfeedcount = adap->feedcount + (onoff ? 1 : -1);
/* stop feed before setting a new pid if there will be no pid anymore */
if (newfeedcount == 0) {
deb_ts("stop feeding\n");
usb_urb_kill(&adap->stream);
usb_urb_kill(&adap->fe_adap[adap->active_fe].stream);
if (adap->props.streaming_ctrl != NULL) {
ret = adap->props.streaming_ctrl(adap, 0);
if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0);
if (ret < 0) {
err("error while stopping stream.");
return ret;
@ -36,36 +41,37 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
adap->feedcount = newfeedcount;
/* activate the pid on the device specific pid_filter */
deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",adap->pid_filtering ?
"yes" : "no", dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ?
"on" : "off");
if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
adap->pid_filtering &&
adap->props.pid_filter != NULL)
adap->props.pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid,onoff);
deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",
adap->fe_adap[adap->active_fe].pid_filtering ?
"yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid,
dvbdmxfeed->index, onoff ? "on" : "off");
if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
adap->fe_adap[adap->active_fe].pid_filtering &&
adap->props.fe[adap->active_fe].pid_filter != NULL)
adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
/* start the feed if this was the first feed and there is still a feed
* for reception.
*/
if (adap->feedcount == onoff && adap->feedcount > 0) {
deb_ts("submitting all URBs\n");
usb_urb_submit(&adap->stream);
usb_urb_submit(&adap->fe_adap[adap->active_fe].stream);
deb_ts("controlling pid parser\n");
if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
adap->props.caps &
if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
adap->props.fe[adap->active_fe].caps &
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
adap->props.pid_filter_ctrl != NULL) {
ret = adap->props.pid_filter_ctrl(adap,
adap->pid_filtering);
adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) {
ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap,
adap->fe_adap[adap->active_fe].pid_filtering);
if (ret < 0) {
err("could not handle pid_parser");
return ret;
}
}
deb_ts("start feeding\n");
if (adap->props.streaming_ctrl != NULL) {
ret = adap->props.streaming_ctrl(adap, 1);
if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1);
if (ret < 0) {
err("error while enabling fifo.");
return ret;
@ -90,6 +96,7 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
{
int i;
int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
adap->dev->owner, &adap->dev->udev->dev,
adapter_nums);
@ -112,7 +119,12 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
adap->demux.priv = adap;
adap->demux.feednum = adap->demux.filternum = adap->max_feed_count;
adap->demux.filternum = 0;
for (i = 0; i < adap->props.num_frontends; i++) {
if (adap->demux.filternum < adap->fe_adap[i].max_feed_count)
adap->demux.filternum = adap->fe_adap[i].max_feed_count;
}
adap->demux.feednum = adap->demux.filternum;
adap->demux.start_feed = dvb_usb_start_feed;
adap->demux.stop_feed = dvb_usb_stop_feed;
adap->demux.write_to_decoder = NULL;
@ -156,14 +168,33 @@ int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
return 0;
}
static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
int ret = (adap->props.frontend_ctrl) ?
adap->props.frontend_ctrl(fe, onoff) : 0;
if (ret < 0) {
err("frontend_ctrl request failed");
return ret;
}
if (onoff)
adap->active_fe = fe->id;
return 0;
}
static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
dvb_usb_device_power_ctrl(adap->dev, 1);
if (adap->fe_init)
adap->fe_init(fe);
dvb_usb_set_active_fe(fe, 1);
if (adap->fe_adap[fe->id].fe_init)
adap->fe_adap[fe->id].fe_init(fe);
return 0;
}
@ -172,45 +203,81 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
if (adap->fe_sleep)
adap->fe_sleep(fe);
if (adap->fe_adap[fe->id].fe_sleep)
adap->fe_adap[fe->id].fe_sleep(fe);
dvb_usb_set_active_fe(fe, 0);
return dvb_usb_device_power_ctrl(adap->dev, 0);
}
int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
{
if (adap->props.frontend_attach == NULL) {
err("strange: '%s' #%d doesn't want to attach a frontend.",adap->dev->desc->name, adap->id);
return 0;
}
int ret, i;
/* re-assign sleep and wakeup functions */
if (adap->props.frontend_attach(adap) == 0 && adap->fe != NULL) {
adap->fe_init = adap->fe->ops.init; adap->fe->ops.init = dvb_usb_fe_wakeup;
adap->fe_sleep = adap->fe->ops.sleep; adap->fe->ops.sleep = dvb_usb_fe_sleep;
/* register all given adapter frontends */
for (i = 0; i < adap->props.num_frontends; i++) {
if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
err("Frontend registration failed.");
dvb_frontend_detach(adap->fe);
adap->fe = NULL;
return -ENODEV;
if (adap->props.fe[i].frontend_attach == NULL) {
err("strange: '%s' #%d,%d "
"doesn't want to attach a frontend.",
adap->dev->desc->name, adap->id, i);
return 0;
}
ret = adap->props.fe[i].frontend_attach(adap);
if (ret || adap->fe_adap[i].fe == NULL) {
/* only print error when there is no FE at all */
if (i == 0)
err("no frontend was attached by '%s'",
adap->dev->desc->name);
return 0;
}
adap->fe_adap[i].fe->id = i;
/* re-assign sleep and wakeup functions */
adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init;
adap->fe_adap[i].fe->ops.init = dvb_usb_fe_wakeup;
adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep;
adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep;
if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) {
err("Frontend %d registration failed.", i);
dvb_frontend_detach(adap->fe_adap[i].fe);
adap->fe_adap[i].fe = NULL;
/* In error case, do not try register more FEs,
* still leaving already registered FEs alive. */
if (i == 0)
return -ENODEV;
else
return 0;
}
/* only attach the tuner if the demod is there */
if (adap->props.tuner_attach != NULL)
adap->props.tuner_attach(adap);
} else
err("no frontend was attached by '%s'",adap->dev->desc->name);
if (adap->props.fe[i].tuner_attach != NULL)
adap->props.fe[i].tuner_attach(adap);
adap->num_frontends_initialized++;
}
return 0;
}
int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
{
if (adap->fe != NULL) {
dvb_unregister_frontend(adap->fe);
dvb_frontend_detach(adap->fe);
int i = adap->num_frontends_initialized - 1;
/* unregister all given adapter frontends */
for (; i >= 0; i--) {
if (adap->fe_adap[i].fe != NULL) {
dvb_unregister_frontend(adap->fe_adap[i].fe);
dvb_frontend_detach(adap->fe_adap[i].fe);
}
}
adap->num_frontends_initialized = 0;
return 0;
}

View File

@ -136,6 +136,7 @@
#define USB_PID_KWORLD_PC160_2T 0xc160
#define USB_PID_KWORLD_PC160_T 0xc161
#define USB_PID_KWORLD_UB383_T 0xe383
#define USB_PID_KWORLD_UB499_2T_T09 0xe409
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
@ -240,6 +241,9 @@
#define USB_PID_PCTV_200E 0x020e
#define USB_PID_PCTV_400E 0x020f
#define USB_PID_PCTV_450E 0x0222
#define USB_PID_PCTV_452E 0x021f
#define USB_PID_TECHNOTREND_CONNECT_S2_3600 0x3007
#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI 0x300a
#define USB_PID_NEBULA_DIGITV 0x0201
#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500

View File

@ -29,7 +29,7 @@ MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID
static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
{
struct dvb_usb_adapter *adap;
int ret, n;
int ret, n, o;
for (n = 0; n < d->props.num_adapters; n++) {
adap = &d->adapter[n];
@ -38,31 +38,42 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
for (o = 0; o < adap->props.num_frontends; o++) {
struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o];
/* speed - when running at FULL speed we need a HW PID filter */
if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
return -ENODEV;
}
if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
(adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
info("will use the device's hardware PID filter (table count: %d).", adap->props.pid_filter_count);
adap->pid_filtering = 1;
adap->max_feed_count = adap->props.pid_filter_count;
if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
(props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count);
adap->fe_adap[o].pid_filtering = 1;
adap->fe_adap[o].max_feed_count = props->pid_filter_count;
} else {
info("will pass the complete MPEG2 transport stream to the software demuxer.");
adap->pid_filtering = 0;
adap->max_feed_count = 255;
adap->fe_adap[o].pid_filtering = 0;
adap->fe_adap[o].max_feed_count = 255;
}
if (!adap->pid_filtering &&
if (!adap->fe_adap[o].pid_filtering &&
dvb_usb_force_pid_filter_usage &&
adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) {
props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
info("pid filter enabled by module option.");
adap->pid_filtering = 1;
adap->max_feed_count = adap->props.pid_filter_count;
adap->fe_adap[o].pid_filtering = 1;
adap->fe_adap[o].max_feed_count = props->pid_filter_count;
}
if (props->size_of_priv > 0) {
adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL);
if (adap->fe_adap[o].priv == NULL) {
err("no memory for priv for adapter %d fe %d.", n, o);
return -ENOMEM;
}
}
}
if (adap->props.size_of_priv > 0) {
adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL);
if (adap->priv == NULL) {
@ -77,6 +88,10 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
return ret;
}
/* use exclusive FE lock if there is multiple shared FEs */
if (adap->fe_adap[1].fe)
adap->dvb_adap.mfe_shared = 1;
d->num_adapters_initialized++;
d->state |= DVB_USB_STATE_DVB;
}

View File

@ -82,16 +82,28 @@ static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer
int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
{
adap->stream.udev = adap->dev->udev;
if (adap->props.caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
adap->stream.complete = dvb_usb_data_complete_204;
else
adap->stream.complete = dvb_usb_data_complete;
adap->stream.user_priv = adap;
return usb_urb_init(&adap->stream, &adap->props.stream);
int i, ret = 0;
for (i = 0; i < adap->props.num_frontends; i++) {
adap->fe_adap[i].stream.udev = adap->dev->udev;
if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
adap->fe_adap[i].stream.complete =
dvb_usb_data_complete_204;
else
adap->fe_adap[i].stream.complete = dvb_usb_data_complete;
adap->fe_adap[i].stream.user_priv = adap;
ret = usb_urb_init(&adap->fe_adap[i].stream,
&adap->props.fe[i].stream);
if (ret < 0)
break;
}
return ret;
}
int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap)
{
return usb_urb_exit(&adap->stream);
int i;
for (i = 0; i < adap->props.num_frontends; i++)
usb_urb_exit(&adap->fe_adap[i].stream);
return 0;
}

View File

@ -124,6 +124,8 @@ struct usb_data_stream_properties {
* @caps: capabilities of the DVB USB device.
* @pid_filter_count: number of PID filter position in the optional hardware
* PID-filter.
* @num_frontends: number of frontends of the DVB USB adapter.
* @frontend_ctrl: called to power on/off active frontend.
* @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the
* device (not URB submitting/killing).
* @pid_filter_ctrl: called to en/disable the PID filter, if any.
@ -134,7 +136,7 @@ struct usb_data_stream_properties {
* pll_desc and pll_init_buf of struct dvb_usb_device).
* @stream: configuration of the USB streaming
*/
struct dvb_usb_adapter_properties {
struct dvb_usb_adapter_fe_properties {
#define DVB_USB_ADAP_HAS_PID_FILTER 0x01
#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04
@ -152,9 +154,18 @@ struct dvb_usb_adapter_properties {
struct usb_data_stream_properties stream;
int size_of_priv;
};
#define MAX_NO_OF_FE_PER_ADAP 2
struct dvb_usb_adapter_properties {
int size_of_priv;
int (*frontend_ctrl) (struct dvb_frontend *, int);
int (*fe_ioctl_override) (struct dvb_frontend *,
unsigned int, void *, unsigned int);
int num_frontends;
struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP];
};
/**
@ -345,6 +356,20 @@ struct usb_data_stream {
*
* @stream: the usb data stream.
*/
struct dvb_usb_fe_adapter {
struct dvb_frontend *fe;
int (*fe_init) (struct dvb_frontend *);
int (*fe_sleep) (struct dvb_frontend *);
struct usb_data_stream stream;
int pid_filtering;
int max_feed_count;
void *priv;
};
struct dvb_usb_adapter {
struct dvb_usb_device *dev;
struct dvb_usb_adapter_properties props;
@ -356,20 +381,16 @@ struct dvb_usb_adapter {
u8 id;
int feedcount;
int pid_filtering;
/* dvb */
struct dvb_adapter dvb_adap;
struct dmxdev dmxdev;
struct dvb_demux demux;
struct dvb_net dvb_net;
struct dvb_frontend *fe;
int max_feed_count;
int (*fe_init) (struct dvb_frontend *);
int (*fe_sleep) (struct dvb_frontend *);
struct usb_data_stream stream;
struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP];
int active_fe;
int num_frontends_initialized;
void *priv;
};

View File

@ -992,18 +992,18 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
struct dvb_tuner_ops *tuner_ops = NULL;
if (demod_probe & 4) {
d->fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
&d->dev->i2c_adap, 0);
if (d->fe != NULL) {
if (dvb_attach(stb6100_attach, d->fe,
if (d->fe_adap[0].fe != NULL) {
if (dvb_attach(stb6100_attach, d->fe_adap[0].fe,
&dw2104a_stb6100_config,
&d->dev->i2c_adap)) {
tuner_ops = &d->fe->ops.tuner_ops;
tuner_ops = &d->fe_adap[0].fe->ops.tuner_ops;
tuner_ops->set_frequency = stb6100_set_freq;
tuner_ops->get_frequency = stb6100_get_freq;
tuner_ops->set_bandwidth = stb6100_set_bandw;
tuner_ops->get_bandwidth = stb6100_get_bandw;
d->fe->ops.set_voltage = dw210x_set_voltage;
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached STV0900+STB6100!\n");
return 0;
}
@ -1011,13 +1011,13 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
}
if (demod_probe & 2) {
d->fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
&d->dev->i2c_adap, 0);
if (d->fe != NULL) {
if (dvb_attach(stv6110_attach, d->fe,
if (d->fe_adap[0].fe != NULL) {
if (dvb_attach(stv6110_attach, d->fe_adap[0].fe,
&dw2104_stv6110_config,
&d->dev->i2c_adap)) {
d->fe->ops.set_voltage = dw210x_set_voltage;
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached STV0900+STV6110A!\n");
return 0;
}
@ -1025,19 +1025,19 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
}
if (demod_probe & 1) {
d->fe = dvb_attach(cx24116_attach, &dw2104_config,
d->fe_adap[0].fe = dvb_attach(cx24116_attach, &dw2104_config,
&d->dev->i2c_adap);
if (d->fe != NULL) {
d->fe->ops.set_voltage = dw210x_set_voltage;
if (d->fe_adap[0].fe != NULL) {
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached cx24116!\n");
return 0;
}
}
d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
&d->dev->i2c_adap);
if (d->fe != NULL) {
d->fe->ops.set_voltage = dw210x_set_voltage;
if (d->fe_adap[0].fe != NULL) {
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached DS3000!\n");
return 0;
}
@ -1053,22 +1053,22 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
{
if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
/*dw2102_properties.adapter->tuner_attach = NULL;*/
d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
&d->dev->i2c_adap);
if (d->fe != NULL) {
d->fe->ops.set_voltage = dw210x_set_voltage;
if (d->fe_adap[0].fe != NULL) {
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached si21xx!\n");
return 0;
}
}
if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
d->fe = dvb_attach(stv0288_attach, &earda_config,
d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
&d->dev->i2c_adap);
if (d->fe != NULL) {
if (dvb_attach(stb6000_attach, d->fe, 0x61,
if (d->fe_adap[0].fe != NULL) {
if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61,
&d->dev->i2c_adap)) {
d->fe->ops.set_voltage = dw210x_set_voltage;
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached stv0288!\n");
return 0;
}
@ -1077,10 +1077,10 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
&d->dev->i2c_adap);
if (d->fe != NULL) {
d->fe->ops.set_voltage = dw210x_set_voltage;
if (d->fe_adap[0].fe != NULL) {
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached stv0299!\n");
return 0;
}
@ -1090,9 +1090,9 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
{
d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
&d->dev->i2c_adap, 0x48);
if (d->fe != NULL) {
if (d->fe_adap[0].fe != NULL) {
info("Attached tda10023!\n");
return 0;
}
@ -1101,12 +1101,12 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
static int zl100313_frontend_attach(struct dvb_usb_adapter *d)
{
d->fe = dvb_attach(mt312_attach, &zl313_config,
d->fe_adap[0].fe = dvb_attach(mt312_attach, &zl313_config,
&d->dev->i2c_adap);
if (d->fe != NULL) {
if (dvb_attach(zl10039_attach, d->fe, 0x60,
if (d->fe_adap[0].fe != NULL) {
if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60,
&d->dev->i2c_adap)) {
d->fe->ops.set_voltage = dw210x_set_voltage;
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached zl100313+zl10039!\n");
return 0;
}
@ -1119,16 +1119,16 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d)
{
u8 obuf[] = {7, 1};
d->fe = dvb_attach(stv0288_attach, &earda_config,
d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
&d->dev->i2c_adap);
if (d->fe == NULL)
if (d->fe_adap[0].fe == NULL)
return -EIO;
if (NULL == dvb_attach(stb6000_attach, d->fe, 0x61, &d->dev->i2c_adap))
if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap))
return -EIO;
d->fe->ops.set_voltage = dw210x_set_voltage;
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
@ -1143,14 +1143,14 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
struct s6x0_state *st = (struct s6x0_state *)d->dev->priv;
u8 obuf[] = {7, 1};
d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
&d->dev->i2c_adap);
if (d->fe == NULL)
if (d->fe_adap[0].fe == NULL)
return -EIO;
st->old_set_voltage = d->fe->ops.set_voltage;
d->fe->ops.set_voltage = s660_set_voltage;
st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage;
d->fe_adap[0].fe->ops.set_voltage = s660_set_voltage;
dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
@ -1163,12 +1163,12 @@ static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
{
u8 obuf[] = {7, 1};
d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
d->fe_adap[0].fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
&d->dev->i2c_adap, 0);
if (d->fe == NULL)
if (d->fe_adap[0].fe == NULL)
return -EIO;
d->fe->ops.set_voltage = dw210x_set_voltage;
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
@ -1204,9 +1204,9 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
err("command 0x51 transfer failed.");
d->fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
d->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
&d->dev->i2c_adap);
if (d->fe == NULL)
if (d->fe_adap[0].fe == NULL)
return -EIO;
info("Attached DS3000!\n");
@ -1216,14 +1216,14 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
&adap->dev->i2c_adap, DVB_PLL_OPERA1);
return 0;
}
static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
&adap->dev->i2c_adap, DVB_PLL_TUA6034);
return 0;
@ -1535,7 +1535,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
DW210X_READ_MSG);
if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
dw2102_properties.i2c_algo = &dw2102_i2c_algo;
dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach;
break;
} else {
/* check STV0288 frontend */
@ -1591,6 +1591,8 @@ static struct dvb_usb_device_properties dw2102_properties = {
.read_mac_address = dw210x_read_mac_address,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.frontend_attach = dw2102_frontend_attach,
.stream = {
.type = USB_BULK,
@ -1602,6 +1604,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
}
}
},
}},
}
},
.num_device_descs = 3,
@ -1642,6 +1645,8 @@ static struct dvb_usb_device_properties dw2104_properties = {
.read_mac_address = dw210x_read_mac_address,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.frontend_attach = dw2104_frontend_attach,
.stream = {
.type = USB_BULK,
@ -1653,6 +1658,7 @@ static struct dvb_usb_device_properties dw2104_properties = {
}
}
},
}},
}
},
.num_device_descs = 2,
@ -1689,6 +1695,8 @@ static struct dvb_usb_device_properties dw3101_properties = {
.read_mac_address = dw210x_read_mac_address,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.frontend_attach = dw3101_frontend_attach,
.tuner_attach = dw3101_tuner_attach,
.stream = {
@ -1701,6 +1709,7 @@ static struct dvb_usb_device_properties dw3101_properties = {
}
}
},
}},
}
},
.num_device_descs = 1,
@ -1733,6 +1742,8 @@ static struct dvb_usb_device_properties s6x0_properties = {
.read_mac_address = s6x0_read_mac_address,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.frontend_attach = zl100313_frontend_attach,
.stream = {
.type = USB_BULK,
@ -1744,6 +1755,7 @@ static struct dvb_usb_device_properties s6x0_properties = {
}
}
},
}},
}
},
.num_device_descs = 1,
@ -1810,6 +1822,8 @@ static struct dvb_usb_device_properties su3000_properties = {
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = su3000_streaming_ctrl,
.frontend_attach = su3000_frontend_attach,
.stream = {
@ -1822,6 +1836,7 @@ static struct dvb_usb_device_properties su3000_properties = {
}
}
}
}},
}
},
.num_device_descs = 3,
@ -1855,7 +1870,7 @@ static int dw2102_probe(struct usb_interface *intf,
p1100->devices[0] = d1100;
p1100->rc.legacy.rc_map_table = rc_map_tbs_table;
p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
p1100->adapter->frontend_attach = stv0288_frontend_attach;
p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach;
s660 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
if (!s660) {
@ -1869,7 +1884,7 @@ static int dw2102_probe(struct usb_interface *intf,
s660->devices[0] = d660;
s660->devices[1] = d480_1;
s660->devices[2] = d480_2;
s660->adapter->frontend_attach = ds3000_frontend_attach;
s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach;
p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
if (!p7500) {
@ -1883,7 +1898,7 @@ static int dw2102_probe(struct usb_interface *intf,
p7500->devices[0] = d7500;
p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
p7500->adapter->frontend_attach = prof_7500_frontend_attach;
p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach;
if (0 == dvb_usb_device_init(intf, &dw2102_properties,
THIS_MODULE, NULL, adapter_nr) ||

View File

@ -200,9 +200,9 @@ static struct ec100_config ec168_ec100_config = {
static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)
{
deb_info("%s:\n", __func__);
adap->fe = dvb_attach(ec100_attach, &ec168_ec100_config,
adap->fe_adap[0].fe = dvb_attach(ec100_attach, &ec168_ec100_config,
&adap->dev->i2c_adap);
if (adap->fe == NULL)
if (adap->fe_adap[0].fe == NULL)
return -ENODEV;
return 0;
@ -228,7 +228,7 @@ static struct mxl5005s_config ec168_mxl5003s_config = {
static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
{
deb_info("%s:\n", __func__);
return dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,
return dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
&ec168_mxl5003s_config) == NULL ? -ENODEV : 0;
}
@ -382,6 +382,8 @@ static struct dvb_usb_device_properties ec168_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = ec168_streaming_ctrl,
.frontend_attach = ec168_ec100_frontend_attach,
.tuner_attach = ec168_mxl5003s_tuner_attach,
@ -395,6 +397,7 @@ static struct dvb_usb_device_properties ec168_properties = {
}
}
},
}},
}
},

View File

@ -403,8 +403,8 @@ static int friio_frontend_attach(struct dvb_usb_adapter *adap)
if (friio_initialize(adap->dev) < 0)
return -EIO;
adap->fe = jdvbt90502_attach(adap->dev);
if (adap->fe == NULL)
adap->fe_adap[0].fe = jdvbt90502_attach(adap->dev);
if (adap->fe_adap[0].fe == NULL)
return -EIO;
return 0;
@ -473,6 +473,8 @@ static struct dvb_usb_device_properties friio_properties = {
/* caps:0 => no pid filter, 188B TS packet */
/* GL861 has a HW pid filter, but no info available. */
{
.num_frontends = 1,
.fe = {{
.caps = 0,
.frontend_attach = friio_frontend_attach,
@ -490,6 +492,7 @@ static struct dvb_usb_device_properties friio_properties = {
}
}
},
}},
}
},
.i2c_algo = &gl861_i2c_algo,

View File

@ -103,9 +103,9 @@ static struct zl10353_config gl861_zl10353_config = {
static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
{
adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
&adap->dev->i2c_adap);
if (adap->fe == NULL)
if (adap->fe_adap[0].fe == NULL)
return -EIO;
return 0;
@ -118,7 +118,7 @@ static struct qt1010_config gl861_qt1010_config = {
static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
{
return dvb_attach(qt1010_attach,
adap->fe, &adap->dev->i2c_adap,
adap->fe_adap[0].fe, &adap->dev->i2c_adap,
&gl861_qt1010_config) == NULL ? -ENODEV : 0;
}
@ -167,6 +167,8 @@ static struct dvb_usb_device_properties gl861_properties = {
.num_adapters = 1,
.adapter = {{
.num_frontends = 1,
.fe = {{
.frontend_attach = gl861_frontend_attach,
.tuner_attach = gl861_tuner_attach,
@ -181,6 +183,7 @@ static struct dvb_usb_device_properties gl861_properties = {
}
}
},
}},
} },
.i2c_algo = &gl861_i2c_algo,

View File

@ -144,19 +144,25 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
cmd[6] = (freq >> 16) & 0xff;
cmd[7] = (freq >> 24) & 0xff;
/* backwards compatibility: DVB-S + 8-PSK were used for Turbo-FEC */
if (c->delivery_system == SYS_DVBS && c->modulation == PSK_8)
c->delivery_system = SYS_TURBO;
switch (c->delivery_system) {
case SYS_DVBS:
/* Allow QPSK and 8PSK (even for DVB-S) */
if (c->modulation != QPSK && c->modulation != PSK_8) {
if (c->modulation != QPSK) {
deb_fe("%s: unsupported modulation selected (%d)\n",
__func__, c->modulation);
return -EOPNOTSUPP;
}
c->fec_inner = FEC_AUTO;
break;
case SYS_DVBS2:
case SYS_DVBS2: /* kept for backwards compatibility */
deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
break;
case SYS_TURBO:
deb_fe("%s: Turbo-FEC delivery system selected\n", __func__);
break;
default:
deb_fe("%s: unsupported delivery system selected (%d)\n",
@ -189,7 +195,10 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
default:
cmd[9] = 5; break;
}
cmd[8] = ADV_MOD_DVB_QPSK;
if (c->delivery_system == SYS_TURBO)
cmd[8] = ADV_MOD_TURBO_QPSK;
else
cmd[8] = ADV_MOD_DVB_QPSK;
break;
case PSK_8: /* PSK_8 is for compatibility with DN */
cmd[8] = ADV_MOD_TURBO_8PSK;

View File

@ -230,7 +230,7 @@ static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap)
{
adap->fe = gp8psk_fe_attach(adap->dev);
adap->fe_adap[0].fe = gp8psk_fe_attach(adap->dev);
return 0;
}
@ -268,6 +268,8 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = gp8psk_streaming_ctrl,
.frontend_attach = gp8psk_frontend_attach,
/* parameter for the MPEG2-data transfer */
@ -281,6 +283,7 @@ static struct dvb_usb_device_properties gp8psk_properties = {
}
}
},
}},
}
},
.power_ctrl = gp8psk_power_ctrl,

View File

@ -0,0 +1,651 @@
/* DVB USB compliant linux driver for IT9137
*
* Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
* IT9137 (C) ITE Tech Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License Version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
* see Documentation/dvb/README.dvb-usb for more information
* see Documentation/dvb/it9137.txt for firmware information
*
*/
#define DVB_USB_LOG_PREFIX "it913x"
#include <linux/usb.h>
#include <linux/usb/input.h>
#include <media/rc-core.h>
#include "dvb-usb.h"
#include "it913x-fe.h"
/* debug */
static int dvb_usb_it913x_debug;
#define l_dprintk(var, level, args...) do { \
if ((var >= level)) \
printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \
} while (0)
#define deb_info(level, args...) l_dprintk(dvb_usb_it913x_debug, level, args)
#define debug_data_snipet(level, name, p) \
deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
*p, *(p+1), *(p+2), *(p+3), *(p+4), \
*(p+5), *(p+6), *(p+7));
module_param_named(debug, dvb_usb_it913x_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."
DVB_USB_DEBUG_STATUS);
static int pid_filter;
module_param_named(pid, pid_filter, int, 0644);
MODULE_PARM_DESC(pid, "set default 0=on 1=off");
int cmd_counter;
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct it913x_state {
u8 id;
};
static int it913x_bulk_write(struct usb_device *dev,
u8 *snd, int len, u8 pipe)
{
int ret, actual_l;
ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
snd, len , &actual_l, 100);
return ret;
}
static int it913x_bulk_read(struct usb_device *dev,
u8 *rev, int len, u8 pipe)
{
int ret, actual_l;
ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
rev, len , &actual_l, 200);
return ret;
}
static u16 check_sum(u8 *p, u8 len)
{
u16 sum = 0;
u8 i = 1;
while (i < len)
sum += (i++ & 1) ? (*p++) << 8 : *p++;
return ~sum;
}
static int it913x_io(struct usb_device *udev, u8 mode, u8 pro,
u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
{
int ret = 0, i, buf_size = 1;
u8 *buff;
u8 rlen;
u16 chk_sum;
buff = kzalloc(256, GFP_KERNEL);
if (!buff) {
info("USB Buffer Failed");
return -ENOMEM;
}
buff[buf_size++] = pro;
buff[buf_size++] = cmd;
buff[buf_size++] = cmd_counter;
switch (mode) {
case READ_LONG:
case WRITE_LONG:
buff[buf_size++] = len;
buff[buf_size++] = 2;
buff[buf_size++] = (reg >> 24);
buff[buf_size++] = (reg >> 16) & 0xff;
buff[buf_size++] = (reg >> 8) & 0xff;
buff[buf_size++] = reg & 0xff;
break;
case READ_SHORT:
buff[buf_size++] = addr;
break;
case WRITE_SHORT:
buff[buf_size++] = len;
buff[buf_size++] = addr;
buff[buf_size++] = (reg >> 8) & 0xff;
buff[buf_size++] = reg & 0xff;
break;
case READ_DATA:
case WRITE_DATA:
break;
case WRITE_CMD:
mode = 7;
break;
default:
kfree(buff);
return -EINVAL;
}
if (mode & 1) {
for (i = 0; i < len ; i++)
buff[buf_size++] = data[i];
}
chk_sum = check_sum(&buff[1], buf_size);
buff[buf_size++] = chk_sum >> 8;
buff[0] = buf_size;
buff[buf_size++] = (chk_sum & 0xff);
ret = it913x_bulk_write(udev, buff, buf_size , 0x02);
ret |= it913x_bulk_read(udev, buff, (mode & 1) ?
5 : len + 5 , 0x01);
rlen = (mode & 0x1) ? 0x1 : len;
if (mode & 1)
ret |= buff[2];
else
memcpy(data, &buff[3], rlen);
cmd_counter++;
kfree(buff);
return (ret < 0) ? -ENODEV : 0;
}
static int it913x_wr_reg(struct usb_device *udev, u8 pro, u32 reg , u8 data)
{
int ret;
u8 b[1];
b[0] = data;
ret = it913x_io(udev, WRITE_LONG, pro,
CMD_DEMOD_WRITE, reg, 0, b, sizeof(b));
return ret;
}
static int it913x_read_reg(struct usb_device *udev, u32 reg)
{
int ret;
u8 data[1];
ret = it913x_io(udev, READ_LONG, DEV_0,
CMD_DEMOD_READ, reg, 0, &data[0], 1);
return (ret < 0) ? ret : data[0];
}
static u32 it913x_query(struct usb_device *udev, u8 pro)
{
int ret;
u32 res = 0;
u8 data[4];
ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ,
0x1222, 0, &data[0], 1);
if (data[0] == 0x1) {
ret = it913x_io(udev, READ_SHORT, pro,
CMD_QUERYINFO, 0, 0x1, &data[0], 4);
res = (data[0] << 24) + (data[1] << 16) +
(data[2] << 8) + data[3];
}
return (ret < 0) ? 0 : res;
}
static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
int ret = 0;
u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
return -EAGAIN;
deb_info(1, "PID_C (%02x)", onoff);
if (!onoff)
ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1);
mutex_unlock(&adap->dev->i2c_mutex);
return ret;
}
static int it913x_pid_filter(struct dvb_usb_adapter *adap,
int index, u16 pid, int onoff)
{
struct usb_device *udev = adap->dev->udev;
int ret = 0;
u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
if (pid_filter > 0)
return 0;
if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
return -EAGAIN;
deb_info(1, "PID_F (%02x)", onoff);
if (onoff) {
ret = it913x_wr_reg(udev, pro, PID_EN, 0x1);
ret |= it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff));
ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8));
ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff);
ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f));
}
mutex_unlock(&adap->dev->i2c_mutex);
return 0;
}
static int it913x_return_status(struct usb_device *udev)
{
u32 firm = 0;
firm = it913x_query(udev, DEV_0);
if (firm > 0)
info("Firmware Version %d", firm);
return (firm > 0) ? firm : 0;
}
static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
static u8 data[256];
int ret;
u32 reg;
u8 pro;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
debug_data_snipet(1, "Message out", msg[0].buf);
deb_info(2, "num of messages %d address %02x", num, msg[0].addr);
pro = (msg[0].addr & 0x2) ? DEV_0_DMOD : 0x0;
pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0;
memcpy(data, msg[0].buf, msg[0].len);
reg = (data[0] << 24) + (data[1] << 16) +
(data[2] << 8) + data[3];
if (num == 2) {
ret = it913x_io(d->udev, READ_LONG, pro,
CMD_DEMOD_READ, reg, 0, data, msg[1].len);
memcpy(msg[1].buf, data, msg[1].len);
} else
ret = it913x_io(d->udev, WRITE_LONG, pro, CMD_DEMOD_WRITE,
reg, 0, &data[4], msg[0].len - 4);
mutex_unlock(&d->i2c_mutex);
return ret;
}
static u32 it913x_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C;
}
static struct i2c_algorithm it913x_i2c_algo = {
.master_xfer = it913x_i2c_xfer,
.functionality = it913x_i2c_func,
};
/* Callbacks for DVB USB */
#define IT913X_POLL 250
static int it913x_rc_query(struct dvb_usb_device *d)
{
u8 ibuf[4];
int ret;
u32 key;
/* Avoid conflict with frontends*/
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET,
0, 0, &ibuf[0], sizeof(ibuf));
if ((ibuf[2] + ibuf[3]) == 0xff) {
key = ibuf[2];
key += ibuf[0] << 8;
deb_info(1, "INT Key =%08x", key);
if (d->rc_dev != NULL)
rc_keydown(d->rc_dev, key, 0);
}
mutex_unlock(&d->i2c_mutex);
return ret;
}
static int it913x_identify_state(struct usb_device *udev,
struct dvb_usb_device_properties *props,
struct dvb_usb_device_description **desc,
int *cold)
{
int ret = 0, firm_no;
u8 reg, adap, ep, tun0, tun1;
firm_no = it913x_return_status(udev);
ep = it913x_read_reg(udev, 0x49ac);
adap = it913x_read_reg(udev, 0x49c5);
tun0 = it913x_read_reg(udev, 0x49d0);
info("No. Adapters=%x Endpoints=%x Tuner Type=%x", adap, ep, tun0);
if (firm_no > 0) {
*cold = 0;
return 0;
}
if (adap > 2) {
tun1 = it913x_read_reg(udev, 0x49e0);
ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1);
ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1);
ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1);
msleep(50); /* Delay noticed reset cycle ? */
ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0);
msleep(50);
reg = it913x_read_reg(udev, GPIOH1_O);
if (reg == 0) {
ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1);
ret |= it913x_return_status(udev);
if (ret != 0)
ret = it913x_wr_reg(udev, DEV_0,
GPIOH1_O, 0x0);
}
} else
props->num_adapters = 1;
reg = it913x_read_reg(udev, IO_MUX_POWER_CLK);
ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR);
ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1);
*cold = 1;
return (ret < 0) ? -ENODEV : 0;
}
static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
int ret = 0;
u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
return -EAGAIN;
deb_info(1, "STM (%02x)", onoff);
if (!onoff)
ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1);
mutex_unlock(&adap->dev->i2c_mutex);
return ret;
}
static int it913x_download_firmware(struct usb_device *udev,
const struct firmware *fw)
{
int ret = 0, i;
u8 packet_size, dlen, tun1;
u8 *fw_data;
packet_size = 0x29;
tun1 = it913x_read_reg(udev, 0x49e0);
ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100);
info("FRM Starting Firmware Download");
/* This uses scatter write firmware headers follow */
/* 03 XX 00 XX = chip number? */
for (i = 0; i < fw->size; i += packet_size) {
if (i > 0)
packet_size = 0x39;
fw_data = (u8 *)(fw->data + i);
dlen = ((i + packet_size) > fw->size)
? (fw->size - i) : packet_size;
ret |= it913x_io(udev, WRITE_DATA, DEV_0,
CMD_SCATTER_WRITE, 0, 0, fw_data, dlen);
udelay(1000);
}
ret |= it913x_io(udev, WRITE_CMD, DEV_0,
CMD_BOOT, 0, 0, NULL, 0);
msleep(100);
if (ret < 0)
info("FRM Firmware Download Failed (%04x)" , ret);
else
info("FRM Firmware Download Completed - Resetting Device");
ret |= it913x_return_status(udev);
msleep(30);
ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400);
/* Tuner function */
ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0);
ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0);
ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0);
if (tun1 > 0) {
ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0);
ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0);
}
return (ret < 0) ? -ENODEV : 0;
}
static int it913x_name(struct dvb_usb_adapter *adap)
{
const char *desc = adap->dev->desc->name;
char *fe_name[] = {"_1", "_2", "_3", "_4"};
char *name = adap->fe_adap[0].fe->ops.info.name;
strlcpy(name, desc, 128);
strlcat(name, fe_name[adap->id], 128);
return 0;
}
static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
{
struct usb_device *udev = adap->dev->udev;
int ret = 0;
u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK);
u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize;
adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach,
&adap->dev->i2c_adap, adap_addr, adf, IT9137);
if (adap->id == 0 && adap->fe_adap[0].fe) {
ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1);
ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_SW_RST, 0x1);
ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x0f);
ret = it913x_wr_reg(udev, DEV_0, EP0_TX_NAK, 0x1b);
ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x2f);
ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_LSB,
ep_size & 0xff);
ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8);
ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, 0x80);
} else if (adap->id == 1 && adap->fe_adap[0].fe) {
ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x6f);
ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_LSB,
ep_size & 0xff);
ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8);
ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, 0x80);
ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_EN, 0x1);
ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_SERIAL, 0x1);
ret = it913x_wr_reg(udev, DEV_1, TOP_HOSTB_SER_MODE, 0x1);
ret = it913x_wr_reg(udev, DEV_0_DMOD, TSIS_ENABLE, 0x1);
ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x0);
ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_SW_RST, 0x0);
ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0);
ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF_STOP_EN, 0x1);
ret = it913x_wr_reg(udev, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0);
ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_STOP_EN, 0x0);
} else
return -ENODEV;
ret = it913x_name(adap);
return ret;
}
/* DVB USB Driver */
static struct dvb_usb_device_properties it913x_properties;
static int it913x_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
cmd_counter = 0;
if (0 == dvb_usb_device_init(intf, &it913x_properties,
THIS_MODULE, NULL, adapter_nr)) {
info("DEV registering device driver");
return 0;
}
info("DEV it913x Error");
return -ENODEV;
}
static struct usb_device_id it913x_table[] = {
{ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, it913x_table);
static struct dvb_usb_device_properties it913x_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
.download_firmware = it913x_download_firmware,
.firmware = "dvb-usb-it9137-01.fw",
.no_reconnect = 1,
.size_of_priv = sizeof(struct it913x_state),
.num_adapters = 2,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER|
DVB_USB_ADAP_NEED_PID_FILTERING|
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.streaming_ctrl = it913x_streaming_ctrl,
.pid_filter_count = 31,
.pid_filter = it913x_pid_filter,
.pid_filter_ctrl = it913x_pid_filter_ctrl,
.frontend_attach = it913x_frontend_attach,
/* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
.count = 10,
.endpoint = 0x04,
.u = {/* Keep Low if PID filter on */
.bulk = {
.buffersize = 3584,
}
}
}
}},
},
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER|
DVB_USB_ADAP_NEED_PID_FILTERING|
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.streaming_ctrl = it913x_streaming_ctrl,
.pid_filter_count = 31,
.pid_filter = it913x_pid_filter,
.pid_filter_ctrl = it913x_pid_filter_ctrl,
.frontend_attach = it913x_frontend_attach,
/* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
.count = 5,
.endpoint = 0x05,
.u = {
.bulk = {
.buffersize = 3584,
}
}
}
}},
}
},
.identify_state = it913x_identify_state,
.rc.core = {
.protocol = RC_TYPE_NEC,
.module_name = "it913x",
.rc_query = it913x_rc_query,
.rc_interval = IT913X_POLL,
.allowed_protos = RC_TYPE_NEC,
.rc_codes = RC_MAP_KWORLD_315U,
},
.i2c_algo = &it913x_i2c_algo,
.num_device_descs = 1,
.devices = {
{ "Kworld UB499-2T T09(IT9137)",
{ &it913x_table[0], NULL },
},
}
};
static struct usb_driver it913x_driver = {
.name = "it913x",
.probe = it913x_probe,
.disconnect = dvb_usb_device_exit,
.id_table = it913x_table,
};
/* module stuff */
static int __init it913x_module_init(void)
{
int result = usb_register(&it913x_driver);
if (result) {
err("usb_register failed. Error number %d", result);
return result;
}
return 0;
}
static void __exit it913x_module_exit(void)
{
/* deregister this driver from the USB subsystem */
usb_deregister(&it913x_driver);
}
module_init(it913x_module_init);
module_exit(it913x_module_exit);
MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
MODULE_DESCRIPTION("it913x USB 2 Driver");
MODULE_VERSION("1.06");
MODULE_LICENSE("GPL");

View File

@ -162,7 +162,7 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
int ret = 0;
if (st->usb_buffer == NULL) {
st->usb_buffer = kmalloc(512, GFP_KERNEL);
st->usb_buffer = kmalloc(64, GFP_KERNEL);
if (st->usb_buffer == NULL) {
info("MEM Error no memory");
return -ENOMEM;
@ -175,8 +175,8 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
if (ret < 0)
return -EAGAIN;
/* the read/write capped at 512 */
memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
/* the read/write capped at 64 */
memcpy(buff, wbuf, (wlen < 64) ? wlen : 64);
ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
@ -186,8 +186,8 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01));
ret |= lme2510_bulk_read(d->udev, buff, (rlen > 512) ?
512 : rlen , 0x01);
ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ?
rlen : 64 , 0x01);
if (rlen > 0)
memcpy(rbuf, buff, rlen);
@ -333,7 +333,7 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
if (lme_int->lme_urb == NULL)
return -ENOMEM;
lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 5000, GFP_ATOMIC,
lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 128, GFP_ATOMIC,
&lme_int->lme_urb->transfer_dma);
if (lme_int->buffer == NULL)
@ -343,10 +343,10 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
adap->dev->udev,
usb_rcvintpipe(adap->dev->udev, 0xa),
lme_int->buffer,
4096,
128,
lme2510_int_response,
adap,
11);
8);
lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@ -580,7 +580,7 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct lme2510_state *st = d->priv;
static u8 obuf[64], ibuf[512];
static u8 obuf[64], ibuf[64];
int i, read, read_o;
u16 len;
u8 gate = st->i2c_gate;
@ -621,7 +621,7 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
len = msg[i].len+3;
}
if (lme2510_msg(d, obuf, len, ibuf, 512) < 0) {
if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) {
deb_info(1, "i2c transfer failed.");
return -EAGAIN;
}
@ -941,7 +941,7 @@ static int lme_name(struct dvb_usb_adapter *adap)
const char *desc = adap->dev->desc->name;
char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
" SHARP:BS2F7HZ0194"};
char *name = adap->fe->ops.info.name;
char *name = adap->fe_adap[0].fe->ops.info.name;
strlcpy(name, desc, 128);
strlcat(name, fe_name[st->tuner_config], 128);
@ -958,10 +958,10 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
st->i2c_talk_onoff = 1;
st->i2c_gate = 4;
adap->fe = dvb_attach(tda10086_attach, &tda10086_config,
adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config,
&adap->dev->i2c_adap);
if (adap->fe) {
if (adap->fe_adap[0].fe) {
info("TUN Found Frontend TDA10086");
st->i2c_tuner_gate_w = 4;
st->i2c_tuner_gate_r = 4;
@ -975,9 +975,9 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
}
st->i2c_gate = 4;
adap->fe = dvb_attach(stv0299_attach, &sharp_z0194_config,
adap->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194_config,
&adap->dev->i2c_adap);
if (adap->fe) {
if (adap->fe_adap[0].fe) {
info("FE Found Stv0299");
st->i2c_tuner_gate_w = 4;
st->i2c_tuner_gate_r = 5;
@ -991,9 +991,9 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
}
st->i2c_gate = 5;
adap->fe = dvb_attach(stv0288_attach, &lme_config,
adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config,
&adap->dev->i2c_adap);
if (adap->fe) {
if (adap->fe_adap[0].fe) {
info("FE Found Stv0288");
st->i2c_tuner_gate_w = 4;
st->i2c_tuner_gate_r = 5;
@ -1010,15 +1010,15 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
end: if (ret) {
if (adap->fe) {
dvb_frontend_detach(adap->fe);
adap->fe = NULL;
if (adap->fe_adap[0].fe) {
dvb_frontend_detach(adap->fe_adap[0].fe);
adap->fe_adap[0].fe = NULL;
}
adap->dev->props.rc.core.rc_codes = NULL;
return -ENODEV;
}
adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
adap->fe_adap[0].fe->ops.set_voltage = dm04_lme2510_set_voltage;
ret = lme_name(adap);
return ret;
}
@ -1031,17 +1031,17 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
switch (st->tuner_config) {
case TUNER_LG:
if (dvb_attach(tda826x_attach, adap->fe, 0xc0,
if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0xc0,
&adap->dev->i2c_adap, 1))
ret = st->tuner_config;
break;
case TUNER_S7395:
if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner,
if (dvb_attach(ix2505v_attach , adap->fe_adap[0].fe, &lme_tuner,
&adap->dev->i2c_adap))
ret = st->tuner_config;
break;
case TUNER_S0194:
if (dvb_attach(dvb_pll_attach , adap->fe, 0xc0,
if (dvb_attach(dvb_pll_attach , adap->fe_adap[0].fe, 0xc0,
&adap->dev->i2c_adap, DVB_PLL_OPERA1))
ret = st->tuner_config;
break;
@ -1145,6 +1145,8 @@ static struct dvb_usb_device_properties lme2510_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER|
DVB_USB_ADAP_NEED_PID_FILTERING|
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@ -1166,6 +1168,7 @@ static struct dvb_usb_device_properties lme2510_properties = {
}
}
}
}},
}
},
.rc.core = {
@ -1193,6 +1196,8 @@ static struct dvb_usb_device_properties lme2510c_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER|
DVB_USB_ADAP_NEED_PID_FILTERING|
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@ -1214,6 +1219,7 @@ static struct dvb_usb_device_properties lme2510c_properties = {
}
}
}
}},
}
},
.rc.core = {
@ -1241,7 +1247,7 @@ static void *lme2510_exit_int(struct dvb_usb_device *d)
void *buffer = NULL;
if (adap != NULL) {
lme2510_kill_urb(&adap->stream);
lme2510_kill_urb(&adap->fe_adap[0].stream);
adap->feedcount = 0;
}
@ -1255,7 +1261,7 @@ static void *lme2510_exit_int(struct dvb_usb_device *d)
if (st->lme_urb != NULL) {
usb_kill_urb(st->lme_urb);
usb_free_coherent(d->udev, 5000, st->buffer,
usb_free_coherent(d->udev, 128, st->buffer,
st->lme_urb->transfer_dma);
info("Interrupt Service Stopped");
}
@ -1306,5 +1312,5 @@ module_exit(lme2510_module_exit);
MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
MODULE_VERSION("1.88");
MODULE_VERSION("1.90");
MODULE_LICENSE("GPL");

View File

@ -86,12 +86,12 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
}
for (i = 0; i < d->props.num_adapters; i++)
flags |= d->adapter[i].props.caps;
flags |= d->adapter[i].props.fe[0].caps;
/* Some devices(Dposh) might crash if we attempt touch at all. */
if (flags & DVB_USB_ADAP_HAS_PID_FILTER) {
for (i = 0; i < d->props.num_adapters; i++) {
epi = d->adapter[i].props.stream.endpoint - 0x81;
epi = d->adapter[i].props.fe[0].stream.endpoint - 0x81;
if (epi < 0 || epi >= M9206_MAX_ADAPTERS) {
printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n");
@ -292,7 +292,7 @@ static int m920x_update_filters(struct dvb_usb_adapter *adap)
struct m920x_state *m = adap->dev->priv;
int enabled = m->filtering_enabled[adap->id];
int i, ret = 0, filter = 0;
int ep = adap->props.stream.endpoint;
int ep = adap->props.fe[0].stream.endpoint;
for (i = 0; i < M9206_MAX_FILTERS; i++)
if (m->filters[adap->id][i] == 8192)
@ -501,9 +501,10 @@ static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap)
{
deb("%s\n",__func__);
if ((adap->fe = dvb_attach(mt352_attach,
&m920x_mt352_config,
&adap->dev->i2c_adap)) == NULL)
adap->fe_adap[0].fe = dvb_attach(mt352_attach,
&m920x_mt352_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) == NULL)
return -EIO;
return 0;
@ -513,9 +514,10 @@ static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap)
{
deb("%s\n",__func__);
if ((adap->fe = dvb_attach(tda10046_attach,
&m920x_tda10046_08_config,
&adap->dev->i2c_adap)) == NULL)
adap->fe_adap[0].fe = dvb_attach(tda10046_attach,
&m920x_tda10046_08_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) == NULL)
return -EIO;
return 0;
@ -525,9 +527,10 @@ static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap)
{
deb("%s\n",__func__);
if ((adap->fe = dvb_attach(tda10046_attach,
&m920x_tda10046_0b_config,
&adap->dev->i2c_adap)) == NULL)
adap->fe_adap[0].fe = dvb_attach(tda10046_attach,
&m920x_tda10046_0b_config,
&adap->dev->i2c_adap);
if ((adap->fe_adap[0].fe) == NULL)
return -EIO;
return 0;
@ -537,7 +540,7 @@ static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
{
deb("%s\n",__func__);
if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL)
if (dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL)
return -ENODEV;
return 0;
@ -547,7 +550,7 @@ static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap)
{
deb("%s\n",__func__);
if (dvb_attach(tda827x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL)
if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL)
return -ENODEV;
return 0;
@ -557,7 +560,7 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap)
{
deb("%s\n",__func__);
if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL)
if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL)
return -ENODEV;
return 0;
@ -565,7 +568,7 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap)
static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(simple_tuner_attach, adap->fe,
dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap, 0x61,
TUNER_PHILIPS_FMD1216ME_MK3);
return 0;
@ -807,6 +810,9 @@ static struct dvb_usb_device_properties megasky_properties = {
.identify_state = m920x_identify_state,
.num_adapters = 1,
.adapter = {{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@ -827,6 +833,7 @@ static struct dvb_usb_device_properties megasky_properties = {
}
}
},
}},
}},
.i2c_algo = &m920x_i2c_algo,
@ -851,6 +858,9 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = {
.identify_state = m920x_identify_state,
.num_adapters = 1,
.adapter = {{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@ -871,6 +881,7 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = {
}
}
},
}},
}},
.i2c_algo = &m920x_i2c_algo,
@ -910,6 +921,9 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
.identify_state = m920x_identify_state,
.num_adapters = 2,
.adapter = {{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@ -929,7 +943,11 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
.buffersize = 512,
}
}
}},
}},{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@ -949,6 +967,7 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
.buffersize = 512,
}
}
}},
},
}},
.i2c_algo = &m920x_i2c_algo,
@ -974,6 +993,8 @@ static struct dvb_usb_device_properties dposh_properties = {
.identify_state = m920x_identify_state,
.num_adapters = 1,
.adapter = {{
.num_frontends = 1,
.fe = {{
/* Hardware pid filters don't work with this device/firmware */
.frontend_attach = m920x_mt352_frontend_attach,
@ -989,6 +1010,7 @@ static struct dvb_usb_device_properties dposh_properties = {
}
}
},
}},
}},
.i2c_algo = &m920x_i2c_algo,
@ -1019,6 +1041,9 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
.identify_state = m920x_identify_state,
.num_adapters = 1,
.adapter = {{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@ -1041,6 +1066,7 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
}
}
},
}},
} },
.i2c_algo = &m920x_i2c_algo,

View File

@ -0,0 +1,763 @@
/*
* mxl111sf-gpio.c - driver for the MaxLinear MXL111SF
*
* Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mxl111sf-gpio.h"
#include "mxl111sf-i2c.h"
#include "mxl111sf.h"
/* ------------------------------------------------------------------------- */
#define MXL_GPIO_MUX_REG_0 0x84
#define MXL_GPIO_MUX_REG_1 0x89
#define MXL_GPIO_MUX_REG_2 0x82
#define MXL_GPIO_DIR_INPUT 0
#define MXL_GPIO_DIR_OUTPUT 1
static int mxl111sf_set_gpo_state(struct mxl111sf_state *state, u8 pin, u8 val)
{
int ret;
u8 tmp;
mxl_debug_adv("(%d, %d)", pin, val);
if ((pin > 0) && (pin < 8)) {
ret = mxl111sf_read_reg(state, 0x19, &tmp);
if (mxl_fail(ret))
goto fail;
tmp &= ~(1 << (pin - 1));
tmp |= (val << (pin - 1));
ret = mxl111sf_write_reg(state, 0x19, tmp);
if (mxl_fail(ret))
goto fail;
} else if (pin <= 10) {
if (pin == 0)
pin += 7;
ret = mxl111sf_read_reg(state, 0x30, &tmp);
if (mxl_fail(ret))
goto fail;
tmp &= ~(1 << (pin - 3));
tmp |= (val << (pin - 3));
ret = mxl111sf_write_reg(state, 0x30, tmp);
if (mxl_fail(ret))
goto fail;
} else
ret = -EINVAL;
fail:
return ret;
}
static int mxl111sf_get_gpi_state(struct mxl111sf_state *state, u8 pin, u8 *val)
{
int ret;
u8 tmp;
mxl_debug("(0x%02x)", pin);
*val = 0;
switch (pin) {
case 0:
case 1:
case 2:
case 3:
ret = mxl111sf_read_reg(state, 0x23, &tmp);
if (mxl_fail(ret))
goto fail;
*val = (tmp >> (pin + 4)) & 0x01;
break;
case 4:
case 5:
case 6:
case 7:
ret = mxl111sf_read_reg(state, 0x2f, &tmp);
if (mxl_fail(ret))
goto fail;
*val = (tmp >> pin) & 0x01;
break;
case 8:
case 9:
case 10:
ret = mxl111sf_read_reg(state, 0x22, &tmp);
if (mxl_fail(ret))
goto fail;
*val = (tmp >> (pin - 3)) & 0x01;
break;
default:
return -EINVAL; /* invalid pin */
}
fail:
return ret;
}
struct mxl_gpio_cfg {
u8 pin;
u8 dir;
u8 val;
};
static int mxl111sf_config_gpio_pins(struct mxl111sf_state *state,
struct mxl_gpio_cfg *gpio_cfg)
{
int ret;
u8 tmp;
mxl_debug_adv("(%d, %d)", gpio_cfg->pin, gpio_cfg->dir);
switch (gpio_cfg->pin) {
case 0:
case 1:
case 2:
case 3:
ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_0, &tmp);
if (mxl_fail(ret))
goto fail;
tmp &= ~(1 << (gpio_cfg->pin + 4));
tmp |= (gpio_cfg->dir << (gpio_cfg->pin + 4));
ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_0, tmp);
if (mxl_fail(ret))
goto fail;
break;
case 4:
case 5:
case 6:
case 7:
ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_1, &tmp);
if (mxl_fail(ret))
goto fail;
tmp &= ~(1 << gpio_cfg->pin);
tmp |= (gpio_cfg->dir << gpio_cfg->pin);
ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_1, tmp);
if (mxl_fail(ret))
goto fail;
break;
case 8:
case 9:
case 10:
ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_2, &tmp);
if (mxl_fail(ret))
goto fail;
tmp &= ~(1 << (gpio_cfg->pin - 3));
tmp |= (gpio_cfg->dir << (gpio_cfg->pin - 3));
ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_2, tmp);
if (mxl_fail(ret))
goto fail;
break;
default:
return -EINVAL; /* invalid pin */
}
ret = (MXL_GPIO_DIR_OUTPUT == gpio_cfg->dir) ?
mxl111sf_set_gpo_state(state,
gpio_cfg->pin, gpio_cfg->val) :
mxl111sf_get_gpi_state(state,
gpio_cfg->pin, &gpio_cfg->val);
mxl_fail(ret);
fail:
return ret;
}
static int mxl111sf_hw_do_set_gpio(struct mxl111sf_state *state,
int gpio, int direction, int val)
{
struct mxl_gpio_cfg gpio_config = {
.pin = gpio,
.dir = direction,
.val = val,
};
mxl_debug("(%d, %d, %d)", gpio, direction, val);
return mxl111sf_config_gpio_pins(state, &gpio_config);
}
/* ------------------------------------------------------------------------- */
#define PIN_MUX_MPEG_MODE_MASK 0x40 /* 0x17 <6> */
#define PIN_MUX_MPEG_PAR_EN_MASK 0x01 /* 0x18 <0> */
#define PIN_MUX_MPEG_SER_EN_MASK 0x02 /* 0x18 <1> */
#define PIN_MUX_MPG_IN_MUX_MASK 0x80 /* 0x3D <7> */
#define PIN_MUX_BT656_ENABLE_MASK 0x04 /* 0x12 <2> */
#define PIN_MUX_I2S_ENABLE_MASK 0x40 /* 0x15 <6> */
#define PIN_MUX_SPI_MODE_MASK 0x10 /* 0x3D <4> */
#define PIN_MUX_MCLK_EN_CTRL_MASK 0x10 /* 0x82 <4> */
#define PIN_MUX_MPSYN_EN_CTRL_MASK 0x20 /* 0x82 <5> */
#define PIN_MUX_MDVAL_EN_CTRL_MASK 0x40 /* 0x82 <6> */
#define PIN_MUX_MPERR_EN_CTRL_MASK 0x80 /* 0x82 <7> */
#define PIN_MUX_MDAT_EN_0_MASK 0x10 /* 0x84 <4> */
#define PIN_MUX_MDAT_EN_1_MASK 0x20 /* 0x84 <5> */
#define PIN_MUX_MDAT_EN_2_MASK 0x40 /* 0x84 <6> */
#define PIN_MUX_MDAT_EN_3_MASK 0x80 /* 0x84 <7> */
#define PIN_MUX_MDAT_EN_4_MASK 0x10 /* 0x89 <4> */
#define PIN_MUX_MDAT_EN_5_MASK 0x20 /* 0x89 <5> */
#define PIN_MUX_MDAT_EN_6_MASK 0x40 /* 0x89 <6> */
#define PIN_MUX_MDAT_EN_7_MASK 0x80 /* 0x89 <7> */
int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state,
enum mxl111sf_mux_config pin_mux_config)
{
u8 r12, r15, r17, r18, r3D, r82, r84, r89;
int ret;
mxl_debug("(%d)", pin_mux_config);
ret = mxl111sf_read_reg(state, 0x17, &r17);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_read_reg(state, 0x18, &r18);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_read_reg(state, 0x12, &r12);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_read_reg(state, 0x15, &r15);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_read_reg(state, 0x82, &r82);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_read_reg(state, 0x84, &r84);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_read_reg(state, 0x89, &r89);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_read_reg(state, 0x3D, &r3D);
if (mxl_fail(ret))
goto fail;
switch (pin_mux_config) {
case PIN_MUX_TS_OUT_PARALLEL:
/* mpeg_mode = 1 */
r17 |= PIN_MUX_MPEG_MODE_MASK;
/* mpeg_par_en = 1 */
r18 |= PIN_MUX_MPEG_PAR_EN_MASK;
/* mpeg_ser_en = 0 */
r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
/* mpg_in_mux = 0 */
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
/* bt656_enable = 0 */
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
/* i2s_enable = 0 */
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
/* spi_mode = 0 */
r3D &= ~PIN_MUX_SPI_MODE_MASK;
/* mclk_en_ctrl = 1 */
r82 |= PIN_MUX_MCLK_EN_CTRL_MASK;
/* mperr_en_ctrl = 1 */
r82 |= PIN_MUX_MPERR_EN_CTRL_MASK;
/* mdval_en_ctrl = 1 */
r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK;
/* mpsyn_en_ctrl = 1 */
r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK;
/* mdat_en_ctrl[3:0] = 0xF */
r84 |= 0xF0;
/* mdat_en_ctrl[7:4] = 0xF */
r89 |= 0xF0;
break;
case PIN_MUX_TS_OUT_SERIAL:
/* mpeg_mode = 1 */
r17 |= PIN_MUX_MPEG_MODE_MASK;
/* mpeg_par_en = 0 */
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
/* mpeg_ser_en = 1 */
r18 |= PIN_MUX_MPEG_SER_EN_MASK;
/* mpg_in_mux = 0 */
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
/* bt656_enable = 0 */
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
/* i2s_enable = 0 */
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
/* spi_mode = 0 */
r3D &= ~PIN_MUX_SPI_MODE_MASK;
/* mclk_en_ctrl = 1 */
r82 |= PIN_MUX_MCLK_EN_CTRL_MASK;
/* mperr_en_ctrl = 1 */
r82 |= PIN_MUX_MPERR_EN_CTRL_MASK;
/* mdval_en_ctrl = 1 */
r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK;
/* mpsyn_en_ctrl = 1 */
r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK;
/* mdat_en_ctrl[3:0] = 0xF */
r84 |= 0xF0;
/* mdat_en_ctrl[7:4] = 0xF */
r89 |= 0xF0;
break;
case PIN_MUX_GPIO_MODE:
/* mpeg_mode = 0 */
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
/* mpeg_par_en = 0 */
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
/* mpeg_ser_en = 0 */
r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
/* mpg_in_mux = 0 */
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
/* bt656_enable = 0 */
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
/* i2s_enable = 0 */
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
/* spi_mode = 0 */
r3D &= ~PIN_MUX_SPI_MODE_MASK;
/* mclk_en_ctrl = 0 */
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
/* mperr_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
/* mdval_en_ctrl = 0 */
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
/* mpsyn_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
/* mdat_en_ctrl[3:0] = 0x0 */
r84 &= 0x0F;
/* mdat_en_ctrl[7:4] = 0x0 */
r89 &= 0x0F;
break;
case PIN_MUX_TS_SERIAL_IN_MODE_0:
/* mpeg_mode = 0 */
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
/* mpeg_par_en = 0 */
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
/* mpeg_ser_en = 1 */
r18 |= PIN_MUX_MPEG_SER_EN_MASK;
/* mpg_in_mux = 0 */
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
/* bt656_enable = 0 */
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
/* i2s_enable = 0 */
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
/* spi_mode = 0 */
r3D &= ~PIN_MUX_SPI_MODE_MASK;
/* mclk_en_ctrl = 0 */
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
/* mperr_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
/* mdval_en_ctrl = 0 */
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
/* mpsyn_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
/* mdat_en_ctrl[3:0] = 0x0 */
r84 &= 0x0F;
/* mdat_en_ctrl[7:4] = 0x0 */
r89 &= 0x0F;
break;
case PIN_MUX_TS_SERIAL_IN_MODE_1:
/* mpeg_mode = 0 */
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
/* mpeg_par_en = 0 */
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
/* mpeg_ser_en = 1 */
r18 |= PIN_MUX_MPEG_SER_EN_MASK;
/* mpg_in_mux = 1 */
r3D |= PIN_MUX_MPG_IN_MUX_MASK;
/* bt656_enable = 0 */
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
/* i2s_enable = 0 */
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
/* spi_mode = 0 */
r3D &= ~PIN_MUX_SPI_MODE_MASK;
/* mclk_en_ctrl = 0 */
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
/* mperr_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
/* mdval_en_ctrl = 0 */
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
/* mpsyn_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
/* mdat_en_ctrl[3:0] = 0x0 */
r84 &= 0x0F;
/* mdat_en_ctrl[7:4] = 0x0 */
r89 &= 0x0F;
break;
case PIN_MUX_TS_SPI_IN_MODE_1:
/* mpeg_mode = 0 */
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
/* mpeg_par_en = 0 */
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
/* mpeg_ser_en = 1 */
r18 |= PIN_MUX_MPEG_SER_EN_MASK;
/* mpg_in_mux = 1 */
r3D |= PIN_MUX_MPG_IN_MUX_MASK;
/* bt656_enable = 0 */
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
/* i2s_enable = 1 */
r15 |= PIN_MUX_I2S_ENABLE_MASK;
/* spi_mode = 1 */
r3D |= PIN_MUX_SPI_MODE_MASK;
/* mclk_en_ctrl = 0 */
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
/* mperr_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
/* mdval_en_ctrl = 0 */
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
/* mpsyn_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
/* mdat_en_ctrl[3:0] = 0x0 */
r84 &= 0x0F;
/* mdat_en_ctrl[7:4] = 0x0 */
r89 &= 0x0F;
break;
case PIN_MUX_TS_SPI_IN_MODE_0:
/* mpeg_mode = 0 */
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
/* mpeg_par_en = 0 */
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
/* mpeg_ser_en = 1 */
r18 |= PIN_MUX_MPEG_SER_EN_MASK;
/* mpg_in_mux = 0 */
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
/* bt656_enable = 0 */
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
/* i2s_enable = 1 */
r15 |= PIN_MUX_I2S_ENABLE_MASK;
/* spi_mode = 1 */
r3D |= PIN_MUX_SPI_MODE_MASK;
/* mclk_en_ctrl = 0 */
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
/* mperr_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
/* mdval_en_ctrl = 0 */
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
/* mpsyn_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
/* mdat_en_ctrl[3:0] = 0x0 */
r84 &= 0x0F;
/* mdat_en_ctrl[7:4] = 0x0 */
r89 &= 0x0F;
break;
case PIN_MUX_TS_PARALLEL_IN:
/* mpeg_mode = 0 */
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
/* mpeg_par_en = 1 */
r18 |= PIN_MUX_MPEG_PAR_EN_MASK;
/* mpeg_ser_en = 0 */
r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
/* mpg_in_mux = 0 */
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
/* bt656_enable = 0 */
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
/* i2s_enable = 0 */
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
/* spi_mode = 0 */
r3D &= ~PIN_MUX_SPI_MODE_MASK;
/* mclk_en_ctrl = 0 */
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
/* mperr_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
/* mdval_en_ctrl = 0 */
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
/* mpsyn_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
/* mdat_en_ctrl[3:0] = 0x0 */
r84 &= 0x0F;
/* mdat_en_ctrl[7:4] = 0x0 */
r89 &= 0x0F;
break;
case PIN_MUX_BT656_I2S_MODE:
/* mpeg_mode = 0 */
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
/* mpeg_par_en = 0 */
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
/* mpeg_ser_en = 0 */
r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
/* mpg_in_mux = 0 */
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
/* bt656_enable = 1 */
r12 |= PIN_MUX_BT656_ENABLE_MASK;
/* i2s_enable = 1 */
r15 |= PIN_MUX_I2S_ENABLE_MASK;
/* spi_mode = 0 */
r3D &= ~PIN_MUX_SPI_MODE_MASK;
/* mclk_en_ctrl = 0 */
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
/* mperr_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
/* mdval_en_ctrl = 0 */
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
/* mpsyn_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
/* mdat_en_ctrl[3:0] = 0x0 */
r84 &= 0x0F;
/* mdat_en_ctrl[7:4] = 0x0 */
r89 &= 0x0F;
break;
case PIN_MUX_DEFAULT:
default:
/* mpeg_mode = 1 */
r17 |= PIN_MUX_MPEG_MODE_MASK;
/* mpeg_par_en = 0 */
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
/* mpeg_ser_en = 0 */
r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
/* mpg_in_mux = 0 */
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
/* bt656_enable = 0 */
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
/* i2s_enable = 0 */
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
/* spi_mode = 0 */
r3D &= ~PIN_MUX_SPI_MODE_MASK;
/* mclk_en_ctrl = 0 */
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
/* mperr_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
/* mdval_en_ctrl = 0 */
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
/* mpsyn_en_ctrl = 0 */
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
/* mdat_en_ctrl[3:0] = 0x0 */
r84 &= 0x0F;
/* mdat_en_ctrl[7:4] = 0x0 */
r89 &= 0x0F;
break;
}
ret = mxl111sf_write_reg(state, 0x17, r17);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, 0x18, r18);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, 0x12, r12);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, 0x15, r15);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, 0x82, r82);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, 0x84, r84);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, 0x89, r89);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, 0x3D, r3D);
if (mxl_fail(ret))
goto fail;
fail:
return ret;
}
/* ------------------------------------------------------------------------- */
static int mxl111sf_hw_set_gpio(struct mxl111sf_state *state, int gpio, int val)
{
return mxl111sf_hw_do_set_gpio(state, gpio, MXL_GPIO_DIR_OUTPUT, val);
}
static int mxl111sf_hw_gpio_initialize(struct mxl111sf_state *state)
{
u8 gpioval = 0x07; /* write protect enabled, signal LEDs off */
int i, ret;
mxl_debug("()");
for (i = 3; i < 8; i++) {
ret = mxl111sf_hw_set_gpio(state, i, (gpioval >> i) & 0x01);
if (mxl_fail(ret))
break;
}
return ret;
}
#define PCA9534_I2C_ADDR (0x40 >> 1)
static int pca9534_set_gpio(struct mxl111sf_state *state, int gpio, int val)
{
u8 w[2] = { 1, 0 };
u8 r = 0;
struct i2c_msg msg[] = {
{ .addr = PCA9534_I2C_ADDR,
.flags = 0, .buf = w, .len = 1 },
{ .addr = PCA9534_I2C_ADDR,
.flags = I2C_M_RD, .buf = &r, .len = 1 },
};
mxl_debug("(%d, %d)", gpio, val);
/* read current GPIO levels from flip-flop */
i2c_transfer(&state->d->i2c_adap, msg, 2);
/* prepare write buffer with current GPIO levels */
msg[0].len = 2;
#if 0
w[0] = 1;
#endif
w[1] = r;
/* clear the desired GPIO */
w[1] &= ~(1 << gpio);
/* set the desired GPIO value */
w[1] |= ((val ? 1 : 0) << gpio);
/* write new GPIO levels to flip-flop */
i2c_transfer(&state->d->i2c_adap, &msg[0], 1);
return 0;
}
static int pca9534_init_port_expander(struct mxl111sf_state *state)
{
u8 w[2] = { 1, 0x07 }; /* write protect enabled, signal LEDs off */
struct i2c_msg msg = {
.addr = PCA9534_I2C_ADDR,
.flags = 0, .buf = w, .len = 2
};
mxl_debug("()");
i2c_transfer(&state->d->i2c_adap, &msg, 1);
/* configure all pins as outputs */
w[0] = 3;
w[1] = 0;
i2c_transfer(&state->d->i2c_adap, &msg, 1);
return 0;
}
int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val)
{
mxl_debug("(%d, %d)", gpio, val);
switch (state->gpio_port_expander) {
default:
mxl_printk(KERN_ERR,
"gpio_port_expander undefined, assuming PCA9534");
/* fall-thru */
case mxl111sf_PCA9534:
return pca9534_set_gpio(state, gpio, val);
case mxl111sf_gpio_hw:
return mxl111sf_hw_set_gpio(state, gpio, val);
}
}
static int mxl111sf_probe_port_expander(struct mxl111sf_state *state)
{
int ret;
u8 w = 1;
u8 r = 0;
struct i2c_msg msg[] = {
{ .flags = 0, .buf = &w, .len = 1 },
{ .flags = I2C_M_RD, .buf = &r, .len = 1 },
};
mxl_debug("()");
msg[0].addr = 0x70 >> 1;
msg[1].addr = 0x70 >> 1;
/* read current GPIO levels from flip-flop */
ret = i2c_transfer(&state->d->i2c_adap, msg, 2);
if (ret == 2) {
state->port_expander_addr = msg[0].addr;
state->gpio_port_expander = mxl111sf_PCA9534;
mxl_debug("found port expander at 0x%02x",
state->port_expander_addr);
return 0;
}
msg[0].addr = 0x40 >> 1;
msg[1].addr = 0x40 >> 1;
ret = i2c_transfer(&state->d->i2c_adap, msg, 2);
if (ret == 2) {
state->port_expander_addr = msg[0].addr;
state->gpio_port_expander = mxl111sf_PCA9534;
mxl_debug("found port expander at 0x%02x",
state->port_expander_addr);
return 0;
}
state->port_expander_addr = 0xff;
state->gpio_port_expander = mxl111sf_gpio_hw;
mxl_debug("using hardware gpio");
return 0;
}
int mxl111sf_init_port_expander(struct mxl111sf_state *state)
{
mxl_debug("()");
if (0x00 == state->port_expander_addr)
mxl111sf_probe_port_expander(state);
switch (state->gpio_port_expander) {
default:
mxl_printk(KERN_ERR,
"gpio_port_expander undefined, assuming PCA9534");
/* fall-thru */
case mxl111sf_PCA9534:
return pca9534_init_port_expander(state);
case mxl111sf_gpio_hw:
return mxl111sf_hw_gpio_initialize(state);
}
}
/* ------------------------------------------------------------------------ */
int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode)
{
/* GPO:
* 3 - ATSC/MH# | 1 = ATSC transport, 0 = MH transport | default 0
* 4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset | default 0
* 5 - ATSC_EN | 1 = ATSC power enable, 0 = ATSC power off | default 0
* 6 - MH_RESET# | 1 = MH enable, 0 = MH Reset | default 0
* 7 - MH_EN | 1 = MH power enable, 0 = MH power off | default 0
*/
mxl_debug("(%d)", mode);
switch (mode) {
case MXL111SF_GPIO_MOD_MH:
mxl111sf_set_gpio(state, 4, 0);
mxl111sf_set_gpio(state, 5, 0);
msleep(50);
mxl111sf_set_gpio(state, 7, 1);
msleep(50);
mxl111sf_set_gpio(state, 6, 1);
msleep(50);
mxl111sf_set_gpio(state, 3, 0);
break;
case MXL111SF_GPIO_MOD_ATSC:
mxl111sf_set_gpio(state, 6, 0);
mxl111sf_set_gpio(state, 7, 0);
msleep(50);
mxl111sf_set_gpio(state, 5, 1);
msleep(50);
mxl111sf_set_gpio(state, 4, 1);
msleep(50);
mxl111sf_set_gpio(state, 3, 1);
break;
default: /* DVBT / STANDBY */
mxl111sf_init_port_expander(state);
break;
}
return 0;
}
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@ -0,0 +1,56 @@
/*
* mxl111sf-gpio.h - driver for the MaxLinear MXL111SF
*
* Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _DVB_USB_MXL111SF_GPIO_H_
#define _DVB_USB_MXL111SF_GPIO_H_
#include "mxl111sf.h"
int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val);
int mxl111sf_init_port_expander(struct mxl111sf_state *state);
#define MXL111SF_GPIO_MOD_DVBT 0
#define MXL111SF_GPIO_MOD_MH 1
#define MXL111SF_GPIO_MOD_ATSC 2
int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode);
enum mxl111sf_mux_config {
PIN_MUX_DEFAULT = 0,
PIN_MUX_TS_OUT_PARALLEL,
PIN_MUX_TS_OUT_SERIAL,
PIN_MUX_GPIO_MODE,
PIN_MUX_TS_SERIAL_IN_MODE_0,
PIN_MUX_TS_SERIAL_IN_MODE_1,
PIN_MUX_TS_SPI_IN_MODE_0,
PIN_MUX_TS_SPI_IN_MODE_1,
PIN_MUX_TS_PARALLEL_IN,
PIN_MUX_BT656_I2S_MODE,
};
int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state,
enum mxl111sf_mux_config pin_mux_config);
#endif /* _DVB_USB_MXL111SF_GPIO_H_ */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@ -0,0 +1,851 @@
/*
* mxl111sf-i2c.c - driver for the MaxLinear MXL111SF
*
* Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mxl111sf-i2c.h"
#include "mxl111sf.h"
/* SW-I2C ----------------------------------------------------------------- */
#define SW_I2C_ADDR 0x1a
#define SW_I2C_EN 0x02
#define SW_SCL_OUT 0x04
#define SW_SDA_OUT 0x08
#define SW_SDA_IN 0x04
#define SW_I2C_BUSY_ADDR 0x2f
#define SW_I2C_BUSY 0x02
static int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state,
u8 byte)
{
int i, ret;
u8 data = 0;
mxl_i2c("(0x%02x)", byte);
ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
if (mxl_fail(ret))
goto fail;
for (i = 0; i < 8; i++) {
data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | data);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | data | SW_SCL_OUT);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | data);
if (mxl_fail(ret))
goto fail;
}
/* last bit was 0 so we need to release SDA */
if (!(byte & 1)) {
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SDA_OUT);
if (mxl_fail(ret))
goto fail;
}
/* CLK high for ACK readback */
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
if (mxl_fail(ret))
goto fail;
/* drop the CLK after getting ACK, SDA will go high right away */
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SDA_OUT);
if (mxl_fail(ret))
goto fail;
if (data & SW_SDA_IN)
ret = -EIO;
fail:
return ret;
}
static int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state,
u8 *pbyte)
{
int i, ret;
u8 byte = 0;
u8 data = 0;
mxl_i2c("()");
*pbyte = 0;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SDA_OUT);
if (mxl_fail(ret))
goto fail;
for (i = 0; i < 8; i++) {
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN |
SW_SCL_OUT | SW_SDA_OUT);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
if (mxl_fail(ret))
goto fail;
if (data & SW_SDA_IN)
byte |= (0x80 >> i);
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SDA_OUT);
if (mxl_fail(ret))
goto fail;
}
*pbyte = byte;
fail:
return ret;
}
static int mxl111sf_i2c_start(struct mxl111sf_state *state)
{
int ret;
mxl_i2c("()");
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SCL_OUT);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN); /* start */
mxl_fail(ret);
fail:
return ret;
}
static int mxl111sf_i2c_stop(struct mxl111sf_state *state)
{
int ret;
mxl_i2c("()");
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN); /* stop */
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SCL_OUT);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_SCL_OUT | SW_SDA_OUT);
mxl_fail(ret);
fail:
return ret;
}
static int mxl111sf_i2c_ack(struct mxl111sf_state *state)
{
int ret;
u8 b = 0;
mxl_i2c("()");
ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN);
if (mxl_fail(ret))
goto fail;
/* pull SDA low */
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SCL_OUT);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SDA_OUT);
mxl_fail(ret);
fail:
return ret;
}
static int mxl111sf_i2c_nack(struct mxl111sf_state *state)
{
int ret;
mxl_i2c("()");
/* SDA high to signal last byte read from slave */
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
0x10 | SW_I2C_EN | SW_SDA_OUT);
mxl_fail(ret);
fail:
return ret;
}
/* ------------------------------------------------------------------------ */
static int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state,
struct i2c_msg *msg)
{
int i, ret;
mxl_i2c("()");
if (msg->flags & I2C_M_RD) {
ret = mxl111sf_i2c_start(state);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_i2c_bitbang_sendbyte(state,
(msg->addr << 1) | 0x01);
if (mxl_fail(ret)) {
mxl111sf_i2c_stop(state);
goto fail;
}
for (i = 0; i < msg->len; i++) {
ret = mxl111sf_i2c_bitbang_recvbyte(state,
&msg->buf[i]);
if (mxl_fail(ret)) {
mxl111sf_i2c_stop(state);
goto fail;
}
if (i < msg->len - 1)
mxl111sf_i2c_ack(state);
}
mxl111sf_i2c_nack(state);
ret = mxl111sf_i2c_stop(state);
if (mxl_fail(ret))
goto fail;
} else {
ret = mxl111sf_i2c_start(state);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_i2c_bitbang_sendbyte(state,
(msg->addr << 1) & 0xfe);
if (mxl_fail(ret)) {
mxl111sf_i2c_stop(state);
goto fail;
}
for (i = 0; i < msg->len; i++) {
ret = mxl111sf_i2c_bitbang_sendbyte(state,
msg->buf[i]);
if (mxl_fail(ret)) {
mxl111sf_i2c_stop(state);
goto fail;
}
}
/* FIXME: we only want to do this on the last transaction */
mxl111sf_i2c_stop(state);
}
fail:
return ret;
}
/* HW-I2C ----------------------------------------------------------------- */
#define USB_WRITE_I2C_CMD 0x99
#define USB_READ_I2C_CMD 0xdd
#define USB_END_I2C_CMD 0xfe
#define USB_WRITE_I2C_CMD_LEN 26
#define USB_READ_I2C_CMD_LEN 24
#define I2C_MUX_REG 0x30
#define I2C_CONTROL_REG 0x00
#define I2C_SLAVE_ADDR_REG 0x08
#define I2C_DATA_REG 0x0c
#define I2C_INT_STATUS_REG 0x10
static int mxl111sf_i2c_send_data(struct mxl111sf_state *state,
u8 index, u8 *wdata)
{
int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
&wdata[1], 25, NULL, 0);
mxl_fail(ret);
return ret;
}
static int mxl111sf_i2c_get_data(struct mxl111sf_state *state,
u8 index, u8 *wdata, u8 *rdata)
{
int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
&wdata[1], 25, rdata, 24);
mxl_fail(ret);
return ret;
}
static u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state)
{
u8 status = 0;
u8 buf[26];
mxl_i2c_adv("()");
buf[0] = USB_READ_I2C_CMD;
buf[1] = 0x00;
buf[2] = I2C_INT_STATUS_REG;
buf[3] = 0x00;
buf[4] = 0x00;
buf[5] = USB_END_I2C_CMD;
mxl111sf_i2c_get_data(state, 0, buf, buf);
if (buf[1] & 0x04)
status = 1;
return status;
}
static u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state)
{
u8 status = 0;
u8 buf[26];
mxl_i2c("()");
buf[0] = USB_READ_I2C_CMD;
buf[1] = 0x00;
buf[2] = I2C_MUX_REG;
buf[3] = 0x00;
buf[4] = 0x00;
buf[5] = I2C_INT_STATUS_REG;
buf[6] = 0x00;
buf[7] = 0x00;
buf[8] = USB_END_I2C_CMD;
mxl111sf_i2c_get_data(state, 0, buf, buf);
if (0x08 == (buf[1] & 0x08))
status = 1;
if ((buf[5] & 0x02) == 0x02)
mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */
return status;
}
static int mxl111sf_i2c_readagain(struct mxl111sf_state *state,
u8 count, u8 *rbuf)
{
u8 i2c_w_data[26];
u8 i2c_r_data[24];
u8 i = 0;
u8 fifo_status = 0;
int ret;
int status = 0;
mxl_i2c("read %d bytes", count);
while ((fifo_status == 0) && (i++ < 5))
fifo_status = mxl111sf_i2c_check_fifo(state);
i2c_w_data[0] = 0xDD;
i2c_w_data[1] = 0x00;
for (i = 2; i < 26; i++)
i2c_w_data[i] = 0xFE;
for (i = 0; i < count; i++) {
i2c_w_data[2+(i*3)] = 0x0C;
i2c_w_data[3+(i*3)] = 0x00;
i2c_w_data[4+(i*3)] = 0x00;
}
ret = mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data);
/* Check for I2C NACK status */
if (mxl111sf_i2c_check_status(state) == 1) {
mxl_i2c("error!");
} else {
for (i = 0; i < count; i++) {
rbuf[i] = i2c_r_data[(i*3)+1];
mxl_i2c("%02x\t %02x",
i2c_r_data[(i*3)+1],
i2c_r_data[(i*3)+2]);
}
status = 1;
}
return status;
}
#define HWI2C400 1
static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state,
struct i2c_msg *msg)
{
int i, k, ret = 0;
u16 index = 0;
u8 buf[26];
u8 i2c_r_data[24];
u16 block_len;
u16 left_over_len;
u8 rd_status[8];
u8 ret_status;
u8 readbuff[26];
mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d",
msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0,
(!(msg->flags & I2C_M_RD)) ? msg->len : 0);
for (index = 0; index < 26; index++)
buf[index] = USB_END_I2C_CMD;
/* command to indicate data payload is destined for I2C interface */
buf[0] = USB_WRITE_I2C_CMD;
buf[1] = 0x00;
/* enable I2C interface */
buf[2] = I2C_MUX_REG;
buf[3] = 0x80;
buf[4] = 0x00;
/* enable I2C interface */
buf[5] = I2C_MUX_REG;
buf[6] = 0x81;
buf[7] = 0x00;
/* set Timeout register on I2C interface */
buf[8] = 0x14;
buf[9] = 0xff;
buf[10] = 0x00;
#if 0
/* enable Interrupts on I2C interface */
buf[8] = 0x24;
buf[9] = 0xF7;
buf[10] = 0x00;
#endif
buf[11] = 0x24;
buf[12] = 0xF7;
buf[13] = 0x00;
ret = mxl111sf_i2c_send_data(state, 0, buf);
/* write data on I2C bus */
if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) {
mxl_i2c("%d\t%02x", msg->len, msg->buf[0]);
/* control register on I2C interface to initialize I2C bus */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0x5E;
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
/* I2C Slave device Address */
buf[5] = I2C_SLAVE_ADDR_REG;
buf[6] = (msg->addr);
buf[7] = 0x00;
buf[8] = USB_END_I2C_CMD;
ret = mxl111sf_i2c_send_data(state, 0, buf);
/* check for slave device status */
if (mxl111sf_i2c_check_status(state) == 1) {
mxl_i2c("NACK writing slave address %02x",
msg->addr);
/* if NACK, stop I2C bus and exit */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0x4E;
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
ret = -EIO;
goto exit;
}
/* I2C interface can do I2C operations in block of 8 bytes of
I2C data. calculation to figure out number of blocks of i2c
data required to program */
block_len = (msg->len / 8);
left_over_len = (msg->len % 8);
index = 0;
mxl_i2c("block_len %d, left_over_len %d",
block_len, left_over_len);
for (index = 0; index < block_len; index++) {
for (i = 0; i < 8; i++) {
/* write data on I2C interface */
buf[2+(i*3)] = I2C_DATA_REG;
buf[3+(i*3)] = msg->buf[(index*8)+i];
buf[4+(i*3)] = 0x00;
}
ret = mxl111sf_i2c_send_data(state, 0, buf);
/* check for I2C NACK status */
if (mxl111sf_i2c_check_status(state) == 1) {
mxl_i2c("NACK writing slave address %02x",
msg->addr);
/* if NACK, stop I2C bus and exit */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0x4E;
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
ret = -EIO;
goto exit;
}
}
if (left_over_len) {
for (k = 0; k < 26; k++)
buf[k] = USB_END_I2C_CMD;
buf[0] = 0x99;
buf[1] = 0x00;
for (i = 0; i < left_over_len; i++) {
buf[2+(i*3)] = I2C_DATA_REG;
buf[3+(i*3)] = msg->buf[(index*8)+i];
mxl_i2c("index = %d %d data %d",
index, i, msg->buf[(index*8)+i]);
buf[4+(i*3)] = 0x00;
}
ret = mxl111sf_i2c_send_data(state, 0, buf);
/* check for I2C NACK status */
if (mxl111sf_i2c_check_status(state) == 1) {
mxl_i2c("NACK writing slave address %02x",
msg->addr);
/* if NACK, stop I2C bus and exit */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0x4E;
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
ret = -EIO;
goto exit;
}
}
/* issue I2C STOP after write */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0x4E;
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
}
/* read data from I2C bus */
if ((msg->flags & I2C_M_RD) && (msg->len > 0)) {
mxl_i2c("read buf len %d", msg->len);
/* command to indicate data payload is
destined for I2C interface */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0xDF;
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
/* I2C xfer length */
buf[5] = 0x14;
buf[6] = (msg->len & 0xFF);
buf[7] = 0;
/* I2C slave device Address */
buf[8] = I2C_SLAVE_ADDR_REG;
buf[9] = msg->addr;
buf[10] = 0x00;
buf[11] = USB_END_I2C_CMD;
ret = mxl111sf_i2c_send_data(state, 0, buf);
/* check for I2C NACK status */
if (mxl111sf_i2c_check_status(state) == 1) {
mxl_i2c("NACK reading slave address %02x",
msg->addr);
/* if NACK, stop I2C bus and exit */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0xC7;
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
ret = -EIO;
goto exit;
}
/* I2C interface can do I2C operations in block of 8 bytes of
I2C data. calculation to figure out number of blocks of
i2c data required to program */
block_len = ((msg->len) / 8);
left_over_len = ((msg->len) % 8);
index = 0;
mxl_i2c("block_len %d, left_over_len %d",
block_len, left_over_len);
/* command to read data from I2C interface */
buf[0] = USB_READ_I2C_CMD;
buf[1] = 0x00;
for (index = 0; index < block_len; index++) {
/* setup I2C read request packet on I2C interface */
for (i = 0; i < 8; i++) {
buf[2+(i*3)] = I2C_DATA_REG;
buf[3+(i*3)] = 0x00;
buf[4+(i*3)] = 0x00;
}
ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data);
/* check for I2C NACK status */
if (mxl111sf_i2c_check_status(state) == 1) {
mxl_i2c("NACK reading slave address %02x",
msg->addr);
/* if NACK, stop I2C bus and exit */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0xC7;
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
ret = -EIO;
goto exit;
}
/* copy data from i2c data payload to read buffer */
for (i = 0; i < 8; i++) {
rd_status[i] = i2c_r_data[(i*3)+2];
if (rd_status[i] == 0x04) {
if (i < 7) {
mxl_i2c("i2c fifo empty!"
" @ %d", i);
msg->buf[(index*8)+i] =
i2c_r_data[(i*3)+1];
/* read again */
ret_status =
mxl111sf_i2c_readagain(
state, 8-(i+1),
readbuff);
if (ret_status == 1) {
for (k = 0;
k < 8-(i+1);
k++) {
msg->buf[(index*8)+(k+i+1)] =
readbuff[k];
mxl_i2c("read data: %02x\t %02x",
msg->buf[(index*8)+(k+i)],
(index*8)+(k+i));
mxl_i2c("read data: %02x\t %02x",
msg->buf[(index*8)+(k+i+1)],
readbuff[k]);
}
goto stop_copy;
} else {
mxl_i2c("readagain "
"ERROR!");
}
} else {
msg->buf[(index*8)+i] =
i2c_r_data[(i*3)+1];
}
} else {
msg->buf[(index*8)+i] =
i2c_r_data[(i*3)+1];
}
}
stop_copy:
;
}
if (left_over_len) {
for (k = 0; k < 26; k++)
buf[k] = USB_END_I2C_CMD;
buf[0] = 0xDD;
buf[1] = 0x00;
for (i = 0; i < left_over_len; i++) {
buf[2+(i*3)] = I2C_DATA_REG;
buf[3+(i*3)] = 0x00;
buf[4+(i*3)] = 0x00;
}
ret = mxl111sf_i2c_get_data(state, 0, buf,
i2c_r_data);
/* check for I2C NACK status */
if (mxl111sf_i2c_check_status(state) == 1) {
mxl_i2c("NACK reading slave address %02x",
msg->addr);
/* if NACK, stop I2C bus and exit */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0xC7;
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
ret = -EIO;
goto exit;
}
for (i = 0; i < left_over_len; i++) {
msg->buf[(block_len*8)+i] =
i2c_r_data[(i*3)+1];
mxl_i2c("read data: %02x\t %02x",
i2c_r_data[(i*3)+1],
i2c_r_data[(i*3)+2]);
}
}
/* indicate I2C interface to issue NACK
after next I2C read op */
buf[0] = USB_WRITE_I2C_CMD;
buf[1] = 0x00;
/* control register */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0x17;
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
buf[5] = USB_END_I2C_CMD;
ret = mxl111sf_i2c_send_data(state, 0, buf);
/* control register */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0xC7;
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
}
exit:
/* STOP and disable I2C MUX */
buf[0] = USB_WRITE_I2C_CMD;
buf[1] = 0x00;
/* de-initilize I2C BUS */
buf[5] = USB_END_I2C_CMD;
mxl111sf_i2c_send_data(state, 0, buf);
/* Control Register */
buf[2] = I2C_CONTROL_REG;
buf[3] = 0xDF;
buf[4] = 0x03;
/* disable I2C interface */
buf[5] = I2C_MUX_REG;
buf[6] = 0x00;
buf[7] = 0x00;
/* de-initilize I2C BUS */
buf[8] = USB_END_I2C_CMD;
mxl111sf_i2c_send_data(state, 0, buf);
/* disable I2C interface */
buf[2] = I2C_MUX_REG;
buf[3] = 0x81;
buf[4] = 0x00;
/* disable I2C interface */
buf[5] = I2C_MUX_REG;
buf[6] = 0x00;
buf[7] = 0x00;
/* disable I2C interface */
buf[8] = I2C_MUX_REG;
buf[9] = 0x00;
buf[10] = 0x00;
buf[11] = USB_END_I2C_CMD;
mxl111sf_i2c_send_data(state, 0, buf);
return ret;
}
/* ------------------------------------------------------------------------ */
int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg msg[], int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct mxl111sf_state *state = d->priv;
int hwi2c = (state->chip_rev > MXL111SF_V6);
int i, ret;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
for (i = 0; i < num; i++) {
ret = (hwi2c) ?
mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) :
mxl111sf_i2c_sw_xfer_msg(state, &msg[i]);
if (mxl_fail(ret)) {
mxl_debug_adv("failed with error %d on i2c "
"transaction %d of %d, %sing %d bytes "
"to/from 0x%02x", ret, i+1, num,
(msg[i].flags & I2C_M_RD) ?
"read" : "writ",
msg[i].len, msg[i].addr);
break;
}
}
mutex_unlock(&d->i2c_mutex);
return i == num ? num : -EREMOTEIO;
}
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@ -0,0 +1,35 @@
/*
* mxl111sf-i2c.h - driver for the MaxLinear MXL111SF
*
* Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _DVB_USB_MXL111SF_I2C_H_
#define _DVB_USB_MXL111SF_I2C_H_
#include <linux/i2c.h>
int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg msg[], int num);
#endif /* _DVB_USB_MXL111SF_I2C_H_ */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@ -0,0 +1,342 @@
/*
* mxl111sf-phy.c - driver for the MaxLinear MXL111SF
*
* Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mxl111sf-phy.h"
#include "mxl111sf-reg.h"
int mxl111sf_init_tuner_demod(struct mxl111sf_state *state)
{
struct mxl111sf_reg_ctrl_info mxl_111_overwrite_default[] = {
{0x07, 0xff, 0x0c},
{0x58, 0xff, 0x9d},
{0x09, 0xff, 0x00},
{0x06, 0xff, 0x06},
{0xc8, 0xff, 0x40}, /* ED_LE_WIN_OLD = 0 */
{0x8d, 0x01, 0x01}, /* NEGATE_Q */
{0x32, 0xff, 0xac}, /* DIG_RFREFSELECT = 12 */
{0x42, 0xff, 0x43}, /* DIG_REG_AMP = 4 */
{0x74, 0xff, 0xc4}, /* SSPUR_FS_PRIO = 4 */
{0x71, 0xff, 0xe6}, /* SPUR_ROT_PRIO_VAL = 1 */
{0x83, 0xff, 0x64}, /* INF_FILT1_THD_SC = 100 */
{0x85, 0xff, 0x64}, /* INF_FILT2_THD_SC = 100 */
{0x88, 0xff, 0xf0}, /* INF_THD = 240 */
{0x6f, 0xf0, 0xb0}, /* DFE_DLY = 11 */
{0x00, 0xff, 0x01}, /* Change to page 1 */
{0x81, 0xff, 0x11}, /* DSM_FERR_BYPASS = 1 */
{0xf4, 0xff, 0x07}, /* DIG_FREQ_CORR = 1 */
{0xd4, 0x1f, 0x0f}, /* SPUR_TEST_NOISE_TH = 15 */
{0xd6, 0xff, 0x0c}, /* SPUR_TEST_NOISE_PAPR = 12 */
{0x00, 0xff, 0x00}, /* Change to page 0 */
{0, 0, 0}
};
mxl_debug("()");
return mxl111sf_ctrl_program_regs(state, mxl_111_overwrite_default);
}
int mxl1x1sf_soft_reset(struct mxl111sf_state *state)
{
int ret;
mxl_debug("()");
ret = mxl111sf_write_reg(state, 0xff, 0x00); /* AIC */
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, 0x02, 0x01); /* get out of reset */
mxl_fail(ret);
fail:
return ret;
}
int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode)
{
int ret;
mxl_debug("(%s)", MXL_SOC_MODE == mode ?
"MXL_SOC_MODE" : "MXL_TUNER_MODE");
/* set device mode */
ret = mxl111sf_write_reg(state, 0x03,
MXL_SOC_MODE == mode ? 0x01 : 0x00);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg_mask(state,
0x7d, 0x40, MXL_SOC_MODE == mode ?
0x00 : /* enable impulse noise filter,
INF_BYP = 0 */
0x40); /* disable impulse noise filter,
INF_BYP = 1 */
if (mxl_fail(ret))
goto fail;
state->device_mode = mode;
fail:
return ret;
}
/* power up tuner */
int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff)
{
mxl_debug("(%d)", onoff);
return mxl111sf_write_reg(state, 0x01, onoff ? 0x01 : 0x00);
}
int mxl111sf_disable_656_port(struct mxl111sf_state *state)
{
mxl_debug("()");
return mxl111sf_write_reg_mask(state, 0x12, 0x04, 0x00);
}
int mxl111sf_enable_usb_output(struct mxl111sf_state *state)
{
mxl_debug("()");
return mxl111sf_write_reg_mask(state, 0x17, 0x40, 0x00);
}
/* initialize TSIF as input port of MxL1X1SF for MPEG2 data transfer */
int mxl111sf_config_mpeg_in(struct mxl111sf_state *state,
unsigned int parallel_serial,
unsigned int msb_lsb_1st,
unsigned int clock_phase,
unsigned int mpeg_valid_pol,
unsigned int mpeg_sync_pol)
{
int ret;
u8 mode, tmp;
mxl_debug("(%u,%u,%u,%u,%u)", parallel_serial, msb_lsb_1st,
clock_phase, mpeg_valid_pol, mpeg_sync_pol);
/* Enable PIN MUX */
ret = mxl111sf_write_reg(state, V6_PIN_MUX_MODE_REG, V6_ENABLE_PIN_MUX);
mxl_fail(ret);
/* Configure MPEG Clock phase */
mxl111sf_read_reg(state, V6_MPEG_IN_CLK_INV_REG, &mode);
if (clock_phase == TSIF_NORMAL)
mode &= ~V6_INVERTED_CLK_PHASE;
else
mode |= V6_INVERTED_CLK_PHASE;
ret = mxl111sf_write_reg(state, V6_MPEG_IN_CLK_INV_REG, mode);
mxl_fail(ret);
/* Configure data input mode, MPEG Valid polarity, MPEG Sync polarity
* Get current configuration */
ret = mxl111sf_read_reg(state, V6_MPEG_IN_CTRL_REG, &mode);
mxl_fail(ret);
/* Data Input mode */
if (parallel_serial == TSIF_INPUT_PARALLEL) {
/* Disable serial mode */
mode &= ~V6_MPEG_IN_DATA_SERIAL;
/* Enable Parallel mode */
mode |= V6_MPEG_IN_DATA_PARALLEL;
} else {
/* Disable Parallel mode */
mode &= ~V6_MPEG_IN_DATA_PARALLEL;
/* Enable Serial Mode */
mode |= V6_MPEG_IN_DATA_SERIAL;
/* If serial interface is chosen, configure
MSB or LSB order in transmission */
ret = mxl111sf_read_reg(state,
V6_MPEG_INOUT_BIT_ORDER_CTRL_REG,
&tmp);
mxl_fail(ret);
if (msb_lsb_1st == MPEG_SER_MSB_FIRST_ENABLED)
tmp |= V6_MPEG_SER_MSB_FIRST;
else
tmp &= ~V6_MPEG_SER_MSB_FIRST;
ret = mxl111sf_write_reg(state,
V6_MPEG_INOUT_BIT_ORDER_CTRL_REG,
tmp);
mxl_fail(ret);
}
/* MPEG Sync polarity */
if (mpeg_sync_pol == TSIF_NORMAL)
mode &= ~V6_INVERTED_MPEG_SYNC;
else
mode |= V6_INVERTED_MPEG_SYNC;
/* MPEG Valid polarity */
if (mpeg_valid_pol == 0)
mode &= ~V6_INVERTED_MPEG_VALID;
else
mode |= V6_INVERTED_MPEG_VALID;
ret = mxl111sf_write_reg(state, V6_MPEG_IN_CTRL_REG, mode);
mxl_fail(ret);
return ret;
}
int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size)
{
static struct mxl111sf_reg_ctrl_info init_i2s[] = {
{0x1b, 0xff, 0x1e}, /* pin mux mode, Choose 656/I2S input */
{0x15, 0x60, 0x60}, /* Enable I2S */
{0x17, 0xe0, 0x20}, /* Input, MPEG MODE USB,
Inverted 656 Clock, I2S_SOFT_RESET,
0 : Normal operation, 1 : Reset State */
#if 0
{0x12, 0x01, 0x00}, /* AUDIO_IRQ_CLR (Overflow Indicator) */
#endif
{0x00, 0xff, 0x02}, /* Change to Control Page */
{0x26, 0x0d, 0x0d}, /* I2S_MODE & BT656_SRC_SEL for FPGA only */
{0x00, 0xff, 0x00},
{0, 0, 0}
};
int ret;
mxl_debug("(0x%02x)", sample_size);
ret = mxl111sf_ctrl_program_regs(state, init_i2s);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, V6_I2S_NUM_SAMPLES_REG, sample_size);
mxl_fail(ret);
fail:
return ret;
}
int mxl111sf_disable_i2s_port(struct mxl111sf_state *state)
{
static struct mxl111sf_reg_ctrl_info disable_i2s[] = {
{0x15, 0x40, 0x00},
{0, 0, 0}
};
mxl_debug("()");
return mxl111sf_ctrl_program_regs(state, disable_i2s);
}
int mxl111sf_config_i2s(struct mxl111sf_state *state,
u8 msb_start_pos, u8 data_width)
{
int ret;
u8 tmp;
mxl_debug("(0x%02x, 0x%02x)", msb_start_pos, data_width);
ret = mxl111sf_read_reg(state, V6_I2S_STREAM_START_BIT_REG, &tmp);
if (mxl_fail(ret))
goto fail;
tmp &= 0xe0;
tmp |= msb_start_pos;
ret = mxl111sf_write_reg(state, V6_I2S_STREAM_START_BIT_REG, tmp);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_read_reg(state, V6_I2S_STREAM_END_BIT_REG, &tmp);
if (mxl_fail(ret))
goto fail;
tmp &= 0xe0;
tmp |= data_width;
ret = mxl111sf_write_reg(state, V6_I2S_STREAM_END_BIT_REG, tmp);
mxl_fail(ret);
fail:
return ret;
}
int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff)
{
u8 val;
int ret;
mxl_debug("(%d)", onoff);
ret = mxl111sf_write_reg(state, 0x00, 0x02);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_read_reg(state, V8_SPI_MODE_REG, &val);
if (mxl_fail(ret))
goto fail;
if (onoff)
val |= 0x04;
else
val &= ~0x04;
ret = mxl111sf_write_reg(state, V8_SPI_MODE_REG, val);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_write_reg(state, 0x00, 0x00);
if (mxl_fail(ret))
goto fail;
fail:
return ret;
}
int mxl111sf_idac_config(struct mxl111sf_state *state,
u8 control_mode, u8 current_setting,
u8 current_value, u8 hysteresis_value)
{
int ret;
u8 val;
/* current value will be set for both automatic & manual IDAC control */
val = current_value;
if (control_mode == IDAC_MANUAL_CONTROL) {
/* enable manual control of IDAC */
val |= IDAC_MANUAL_CONTROL_BIT_MASK;
if (current_setting == IDAC_CURRENT_SINKING_ENABLE)
/* enable current sinking in manual mode */
val |= IDAC_CURRENT_SINKING_BIT_MASK;
else
/* disable current sinking in manual mode */
val &= ~IDAC_CURRENT_SINKING_BIT_MASK;
} else {
/* disable manual control of IDAC */
val &= ~IDAC_MANUAL_CONTROL_BIT_MASK;
/* set hysteresis value reg: 0x0B<5:0> */
ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG,
(hysteresis_value & 0x3F));
}
ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val);
return val;
}
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@ -0,0 +1,53 @@
/*
* mxl111sf-phy.h - driver for the MaxLinear MXL111SF
*
* Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _DVB_USB_MXL111SF_PHY_H_
#define _DVB_USB_MXL111SF_PHY_H_
#include "mxl111sf.h"
int mxl1x1sf_soft_reset(struct mxl111sf_state *state);
int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode);
int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff);
int mxl111sf_disable_656_port(struct mxl111sf_state *state);
int mxl111sf_init_tuner_demod(struct mxl111sf_state *state);
int mxl111sf_enable_usb_output(struct mxl111sf_state *state);
int mxl111sf_config_mpeg_in(struct mxl111sf_state *state,
unsigned int parallel_serial,
unsigned int msb_lsb_1st,
unsigned int clock_phase,
unsigned int mpeg_valid_pol,
unsigned int mpeg_sync_pol);
int mxl111sf_config_i2s(struct mxl111sf_state *state,
u8 msb_start_pos, u8 data_width);
int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size);
int mxl111sf_disable_i2s_port(struct mxl111sf_state *state);
int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff);
int mxl111sf_idac_config(struct mxl111sf_state *state,
u8 control_mode, u8 current_setting,
u8 current_value, u8 hysteresis_value);
#endif /* _DVB_USB_MXL111SF_PHY_H_ */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@ -0,0 +1,179 @@
/*
* mxl111sf-reg.h - driver for the MaxLinear MXL111SF
*
* Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _DVB_USB_MXL111SF_REG_H_
#define _DVB_USB_MXL111SF_REG_H_
#define CHIP_ID_REG 0xFC
#define TOP_CHIP_REV_ID_REG 0xFA
#define V6_SNR_RB_LSB_REG 0x27
#define V6_SNR_RB_MSB_REG 0x28
#define V6_N_ACCUMULATE_REG 0x11
#define V6_RS_AVG_ERRORS_LSB_REG 0x2C
#define V6_RS_AVG_ERRORS_MSB_REG 0x2D
#define V6_IRQ_STATUS_REG 0x24
#define IRQ_MASK_FEC_LOCK 0x10
#define V6_SYNC_LOCK_REG 0x28
#define SYNC_LOCK_MASK 0x10
#define V6_RS_LOCK_DET_REG 0x28
#define RS_LOCK_DET_MASK 0x08
#define V6_INITACQ_NODETECT_REG 0x20
#define V6_FORCE_NFFT_CPSIZE_REG 0x20
#define V6_CODE_RATE_TPS_REG 0x29
#define V6_CODE_RATE_TPS_MASK 0x07
#define V6_CP_LOCK_DET_REG 0x28
#define V6_CP_LOCK_DET_MASK 0x04
#define V6_TPS_HIERACHY_REG 0x29
#define V6_TPS_HIERARCHY_INFO_MASK 0x40
#define V6_MODORDER_TPS_REG 0x2A
#define V6_PARAM_CONSTELLATION_MASK 0x30
#define V6_MODE_TPS_REG 0x2A
#define V6_PARAM_FFT_MODE_MASK 0x0C
#define V6_CP_TPS_REG 0x29
#define V6_PARAM_GI_MASK 0x30
#define V6_TPS_LOCK_REG 0x2A
#define V6_PARAM_TPS_LOCK_MASK 0x40
#define V6_FEC_PER_COUNT_REG 0x2E
#define V6_FEC_PER_SCALE_REG 0x2B
#define V6_FEC_PER_SCALE_MASK 0x03
#define V6_FEC_PER_CLR_REG 0x20
#define V6_FEC_PER_CLR_MASK 0x01
#define V6_PIN_MUX_MODE_REG 0x1B
#define V6_ENABLE_PIN_MUX 0x1E
#define V6_I2S_NUM_SAMPLES_REG 0x16
#define V6_MPEG_IN_CLK_INV_REG 0x17
#define V6_MPEG_IN_CTRL_REG 0x18
#define V6_INVERTED_CLK_PHASE 0x20
#define V6_MPEG_IN_DATA_PARALLEL 0x01
#define V6_MPEG_IN_DATA_SERIAL 0x02
#define V6_INVERTED_MPEG_SYNC 0x04
#define V6_INVERTED_MPEG_VALID 0x08
#define TSIF_INPUT_PARALLEL 0
#define TSIF_INPUT_SERIAL 1
#define TSIF_NORMAL 0
#define V6_MPEG_INOUT_BIT_ORDER_CTRL_REG 0x19
#define V6_MPEG_SER_MSB_FIRST 0x80
#define MPEG_SER_MSB_FIRST_ENABLED 0x01
#define V6_656_I2S_BUFF_STATUS_REG 0x2F
#define V6_656_OVERFLOW_MASK_BIT 0x08
#define V6_I2S_OVERFLOW_MASK_BIT 0x01
#define V6_I2S_STREAM_START_BIT_REG 0x14
#define V6_I2S_STREAM_END_BIT_REG 0x15
#define I2S_RIGHT_JUSTIFIED 0
#define I2S_LEFT_JUSTIFIED 1
#define I2S_DATA_FORMAT 2
#define V6_TUNER_LOOP_THRU_CONTROL_REG 0x09
#define V6_ENABLE_LOOP_THRU 0x01
#define TOTAL_NUM_IF_OUTPUT_FREQ 16
#define TUNER_NORMAL_IF_SPECTRUM 0x0
#define TUNER_INVERT_IF_SPECTRUM 0x10
#define V6_TUNER_IF_SEL_REG 0x06
#define V6_TUNER_IF_FCW_REG 0x3C
#define V6_TUNER_IF_FCW_BYP_REG 0x3D
#define V6_RF_LOCK_STATUS_REG 0x23
#define NUM_DIG_TV_CHANNEL 1000
#define V6_DIG_CLK_FREQ_SEL_REG 0x07
#define V6_REF_SYNTH_INT_REG 0x5C
#define V6_REF_SYNTH_REMAIN_REG 0x58
#define V6_DIG_RFREFSELECT_REG 0x32
#define V6_XTAL_CLK_OUT_GAIN_REG 0x31
#define V6_TUNER_LOOP_THRU_CTRL_REG 0x09
#define V6_DIG_XTAL_ENABLE_REG 0x06
#define V6_DIG_XTAL_BIAS_REG 0x66
#define V6_XTAL_CAP_REG 0x08
#define V6_GPO_CTRL_REG 0x18
#define MXL_GPO_0 0x00
#define MXL_GPO_1 0x01
#define V6_GPO_0_MASK 0x10
#define V6_GPO_1_MASK 0x20
#define V6_111SF_GPO_CTRL_REG 0x19
#define MXL_111SF_GPO_1 0x00
#define MXL_111SF_GPO_2 0x01
#define MXL_111SF_GPO_3 0x02
#define MXL_111SF_GPO_4 0x03
#define MXL_111SF_GPO_5 0x04
#define MXL_111SF_GPO_6 0x05
#define MXL_111SF_GPO_7 0x06
#define MXL_111SF_GPO_0_MASK 0x01
#define MXL_111SF_GPO_1_MASK 0x02
#define MXL_111SF_GPO_2_MASK 0x04
#define MXL_111SF_GPO_3_MASK 0x08
#define MXL_111SF_GPO_4_MASK 0x10
#define MXL_111SF_GPO_5_MASK 0x20
#define MXL_111SF_GPO_6_MASK 0x40
#define V6_ATSC_CONFIG_REG 0x0A
#define MXL_MODE_REG 0x03
#define START_TUNE_REG 0x1C
#define V6_IDAC_HYSTERESIS_REG 0x0B
#define V6_IDAC_SETTINGS_REG 0x0C
#define IDAC_MANUAL_CONTROL 1
#define IDAC_CURRENT_SINKING_ENABLE 1
#define IDAC_MANUAL_CONTROL_BIT_MASK 0x80
#define IDAC_CURRENT_SINKING_BIT_MASK 0x40
#define V8_SPI_MODE_REG 0xE9
#define V6_DIG_RF_PWR_LSB_REG 0x46
#define V6_DIG_RF_PWR_MSB_REG 0x47
#endif /* _DVB_USB_MXL111SF_REG_H_ */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@ -0,0 +1,476 @@
/*
* mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner
*
* Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mxl111sf-tuner.h"
#include "mxl111sf-phy.h"
#include "mxl111sf-reg.h"
/* debug */
static int mxl111sf_tuner_debug;
module_param_named(debug, mxl111sf_tuner_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
#define mxl_dbg(fmt, arg...) \
if (mxl111sf_tuner_debug) \
mxl_printk(KERN_DEBUG, fmt, ##arg)
/* ------------------------------------------------------------------------ */
struct mxl111sf_tuner_state {
struct mxl111sf_state *mxl_state;
struct mxl111sf_tuner_config *cfg;
u32 frequency;
u32 bandwidth;
};
static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state,
u8 addr, u8 *data)
{
return (state->cfg->read_reg) ?
state->cfg->read_reg(state->mxl_state, addr, data) :
-EINVAL;
}
static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state,
u8 addr, u8 data)
{
return (state->cfg->write_reg) ?
state->cfg->write_reg(state->mxl_state, addr, data) :
-EINVAL;
}
static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state,
struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
{
return (state->cfg->program_regs) ?
state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
-EINVAL;
}
static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state,
int onoff)
{
return (state->cfg->top_master_ctrl) ?
state->cfg->top_master_ctrl(state->mxl_state, onoff) :
-EINVAL;
}
/* ------------------------------------------------------------------------ */
static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = {
{0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3,
DIG_MODEINDEX, _A, _CSF, */
{0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */
{0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */
{0, 0, 0}
};
/* ------------------------------------------------------------------------ */
static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq,
u8 bw)
{
u8 filt_bw;
/* set channel bandwidth */
switch (bw) {
case 0: /* ATSC */
filt_bw = 25;
break;
case 1: /* QAM */
filt_bw = 69;
break;
case 6:
filt_bw = 21;
break;
case 7:
filt_bw = 42;
break;
case 8:
filt_bw = 63;
break;
default:
err("%s: invalid bandwidth setting!", __func__);
return NULL;
}
/* calculate RF channel */
freq /= 1000000;
freq *= 64;
#if 0
/* do round */
freq += 0.5;
#endif
/* set bandwidth */
mxl_phy_tune_rf[0].data = filt_bw;
/* set RF */
mxl_phy_tune_rf[1].data = (freq & 0xff);
mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff;
/* start tune */
return mxl_phy_tune_rf;
}
static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state)
{
int ret;
u8 ctrl;
#if 0
u16 iffcw;
u32 if_freq;
#endif
mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)",
state->cfg->invert_spectrum, state->cfg->if_freq);
/* set IF polarity */
ctrl = state->cfg->invert_spectrum;
ctrl |= state->cfg->if_freq;
ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl);
if (mxl_fail(ret))
goto fail;
#if 0
if_freq /= 1000000;
/* do round */
if_freq += 0.5;
if (MXL_IF_LO == state->cfg->if_freq) {
ctrl = 0x08;
iffcw = (u16)(if_freq / (108 * 4096));
} else if (MXL_IF_HI == state->cfg->if_freq) {
ctrl = 0x08;
iffcw = (u16)(if_freq / (216 * 4096));
} else {
ctrl = 0;
iffcw = 0;
}
ctrl |= (iffcw >> 8);
#endif
ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl);
if (mxl_fail(ret))
goto fail;
ctrl &= 0xf0;
ctrl |= 0x90;
ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl);
if (mxl_fail(ret))
goto fail;
#if 0
ctrl = iffcw & 0x00ff;
#endif
ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl);
mxl_fail(ret);
fail:
return ret;
}
static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw)
{
struct mxl111sf_tuner_state *state = fe->tuner_priv;
static struct mxl111sf_reg_ctrl_info *reg_ctrl_array;
int ret;
u8 mxl_mode;
mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw);
/* stop tune */
ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0);
if (mxl_fail(ret))
goto fail;
/* check device mode */
ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode);
if (mxl_fail(ret))
goto fail;
/* Fill out registers for channel tune */
reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw);
if (!reg_ctrl_array)
return -EINVAL;
ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array);
if (mxl_fail(ret))
goto fail;
if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) {
/* IF tuner mode only */
mxl1x1sf_tuner_top_master_ctrl(state, 0);
mxl1x1sf_tuner_top_master_ctrl(state, 1);
mxl1x1sf_tuner_set_if_output_freq(state);
}
ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1);
if (mxl_fail(ret))
goto fail;
if (state->cfg->ant_hunt)
state->cfg->ant_hunt(fe);
fail:
return ret;
}
static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state,
int *rf_synth_lock,
int *ref_synth_lock)
{
int ret;
u8 data;
*rf_synth_lock = 0;
*ref_synth_lock = 0;
ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data);
if (mxl_fail(ret))
goto fail;
*ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0;
*rf_synth_lock = ((data & 0x0c) == 0x0c) ? 1 : 0;
fail:
return ret;
}
#if 0
static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state,
int onoff)
{
return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG,
onoff ? 1 : 0);
}
#endif
/* ------------------------------------------------------------------------ */
static int mxl111sf_tuner_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
struct mxl111sf_tuner_state *state = fe->tuner_priv;
int ret;
u8 bw;
mxl_dbg("()");
if (fe->ops.info.type == FE_ATSC) {
switch (params->u.vsb.modulation) {
case VSB_8:
case VSB_16:
bw = 0; /* ATSC */
break;
case QAM_64:
case QAM_256:
bw = 1; /* US CABLE */
break;
default:
err("%s: modulation not set!", __func__);
return -EINVAL;
}
} else if (fe->ops.info.type == FE_OFDM) {
switch (params->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
bw = 6;
break;
case BANDWIDTH_7_MHZ:
bw = 7;
break;
case BANDWIDTH_8_MHZ:
bw = 8;
break;
default:
err("%s: bandwidth not set!", __func__);
return -EINVAL;
}
} else {
err("%s: modulation type not supported!", __func__);
return -EINVAL;
}
ret = mxl1x1sf_tune_rf(fe, params->frequency, bw);
if (mxl_fail(ret))
goto fail;
state->frequency = params->frequency;
state->bandwidth = (fe->ops.info.type == FE_OFDM) ?
params->u.ofdm.bandwidth : 0;
fail:
return ret;
}
/* ------------------------------------------------------------------------ */
#if 0
static int mxl111sf_tuner_init(struct dvb_frontend *fe)
{
struct mxl111sf_tuner_state *state = fe->tuner_priv;
int ret;
/* wake from standby handled by usb driver */
return ret;
}
static int mxl111sf_tuner_sleep(struct dvb_frontend *fe)
{
struct mxl111sf_tuner_state *state = fe->tuner_priv;
int ret;
/* enter standby mode handled by usb driver */
return ret;
}
#endif
/* ------------------------------------------------------------------------ */
static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status)
{
struct mxl111sf_tuner_state *state = fe->tuner_priv;
int rf_locked, ref_locked, ret;
*status = 0;
ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked);
if (mxl_fail(ret))
goto fail;
mxl_info("%s%s", rf_locked ? "rf locked " : "",
ref_locked ? "ref locked" : "");
if ((rf_locked) || (ref_locked))
*status |= TUNER_STATUS_LOCKED;
fail:
return ret;
}
static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
{
struct mxl111sf_tuner_state *state = fe->tuner_priv;
u8 val1, val2;
int ret;
*strength = 0;
ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2);
if (mxl_fail(ret))
goto fail;
*strength = val1 | ((val2 & 0x07) << 8);
fail:
ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00);
mxl_fail(ret);
return ret;
}
/* ------------------------------------------------------------------------ */
static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct mxl111sf_tuner_state *state = fe->tuner_priv;
*frequency = state->frequency;
return 0;
}
static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
{
struct mxl111sf_tuner_state *state = fe->tuner_priv;
*bandwidth = state->bandwidth;
return 0;
}
static int mxl111sf_tuner_release(struct dvb_frontend *fe)
{
struct mxl111sf_tuner_state *state = fe->tuner_priv;
mxl_dbg("()");
kfree(state);
fe->tuner_priv = NULL;
return 0;
}
/* ------------------------------------------------------------------------- */
static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
.info = {
.name = "MaxLinear MxL111SF",
#if 0
.frequency_min = ,
.frequency_max = ,
.frequency_step = ,
#endif
},
#if 0
.init = mxl111sf_tuner_init,
.sleep = mxl111sf_tuner_sleep,
#endif
.set_params = mxl111sf_tuner_set_params,
.get_status = mxl111sf_tuner_get_status,
.get_rf_strength = mxl111sf_get_rf_strength,
.get_frequency = mxl111sf_tuner_get_frequency,
.get_bandwidth = mxl111sf_tuner_get_bandwidth,
.release = mxl111sf_tuner_release,
};
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
struct mxl111sf_state *mxl_state,
struct mxl111sf_tuner_config *cfg)
{
struct mxl111sf_tuner_state *state = NULL;
mxl_dbg("()");
state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL);
if (state == NULL)
return NULL;
state->mxl_state = mxl_state;
state->cfg = cfg;
memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops,
sizeof(struct dvb_tuner_ops));
fe->tuner_priv = state;
return fe;
}
EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach);
MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver");
MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@ -0,0 +1,89 @@
/*
* mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner
*
* Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __MXL111SF_TUNER_H__
#define __MXL111SF_TUNER_H__
#include "dvb_frontend.h"
#include "mxl111sf.h"
enum mxl_if_freq {
#if 0
MXL_IF_LO = 0x00, /* other IF < 9MHz */
#endif
MXL_IF_4_0 = 0x01, /* 4.0 MHz */
MXL_IF_4_5 = 0x02, /* 4.5 MHz */
MXL_IF_4_57 = 0x03, /* 4.57 MHz */
MXL_IF_5_0 = 0x04, /* 5.0 MHz */
MXL_IF_5_38 = 0x05, /* 5.38 MHz */
MXL_IF_6_0 = 0x06, /* 6.0 MHz */
MXL_IF_6_28 = 0x07, /* 6.28 MHz */
MXL_IF_7_2 = 0x08, /* 7.2 MHz */
MXL_IF_35_25 = 0x09, /* 35.25 MHz */
MXL_IF_36 = 0x0a, /* 36 MHz */
MXL_IF_36_15 = 0x0b, /* 36.15 MHz */
MXL_IF_44 = 0x0c, /* 44 MHz */
#if 0
MXL_IF_HI = 0x0f, /* other IF > 35 MHz and < 45 MHz */
#endif
};
struct mxl111sf_tuner_config {
enum mxl_if_freq if_freq;
unsigned int invert_spectrum:1;
int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data);
int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data);
int (*program_regs)(struct mxl111sf_state *state,
struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
int (*top_master_ctrl)(struct mxl111sf_state *state, int onoff);
int (*ant_hunt)(struct dvb_frontend *fe);
};
/* ------------------------------------------------------------------------ */
#if defined(CONFIG_DVB_USB_MXL111SF) || \
(defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE))
extern
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
struct mxl111sf_state *mxl_state,
struct mxl111sf_tuner_config *cfg);
#else
static inline
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
struct mxl111sf_state *mxl_state
struct mxl111sf_tuner_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
#endif /* __MXL111SF_TUNER_H__ */
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@ -0,0 +1,864 @@
/*
* Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include <linux/vmalloc.h>
#include <linux/i2c.h>
#include "mxl111sf.h"
#include "mxl111sf-reg.h"
#include "mxl111sf-phy.h"
#include "mxl111sf-i2c.h"
#include "mxl111sf-gpio.h"
#include "mxl111sf-tuner.h"
#include "lgdt3305.h"
int dvb_usb_mxl111sf_debug;
module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level "
"(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able)).");
int dvb_usb_mxl111sf_isoc;
module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
#define ANT_PATH_AUTO 0
#define ANT_PATH_EXTERNAL 1
#define ANT_PATH_INTERNAL 2
int dvb_usb_mxl111sf_rfswitch =
#if 0
ANT_PATH_AUTO;
#else
ANT_PATH_EXTERNAL;
#endif
module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644);
MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int).");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define deb_info(args...) dprintk(dvb_usb_mxl111sf_debug, 0x13, args)
#define deb_reg(args...) dprintk(dvb_usb_mxl111sf_debug, 0x08, args)
#define deb_adv(args...) dprintk(dvb_usb_mxl111sf_debug, MXL_ADV_DBG, args)
int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
{
int wo = (rbuf == NULL || rlen == 0); /* write-only */
int ret;
u8 sndbuf[1+wlen];
deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
memset(sndbuf, 0, 1+wlen);
sndbuf[0] = cmd;
memcpy(&sndbuf[1], wbuf, wlen);
ret = (wo) ? dvb_usb_generic_write(d, sndbuf, 1+wlen) :
dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
mxl_fail(ret);
return ret;
}
/* ------------------------------------------------------------------------ */
#define MXL_CMD_REG_READ 0xaa
#define MXL_CMD_REG_WRITE 0x55
int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
{
u8 buf[2];
int ret;
ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2);
if (mxl_fail(ret)) {
mxl_debug("error reading reg: 0x%02x", addr);
goto fail;
}
if (buf[0] == addr)
*data = buf[1];
else {
err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
addr, buf[0], buf[1]);
ret = -EINVAL;
}
deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data);
fail:
return ret;
}
int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data)
{
u8 buf[] = { addr, data };
int ret;
deb_reg("W: (0x%02x, 0x%02x)\n", addr, data);
ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
if (mxl_fail(ret))
err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
return ret;
}
/* ------------------------------------------------------------------------ */
int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
u8 addr, u8 mask, u8 data)
{
int ret;
u8 val;
if (mask != 0xff) {
ret = mxl111sf_read_reg(state, addr, &val);
#if 1
/* dont know why this usually errors out on the first try */
if (mxl_fail(ret))
err("error writing addr: 0x%02x, mask: 0x%02x, "
"data: 0x%02x, retrying...", addr, mask, data);
ret = mxl111sf_read_reg(state, addr, &val);
#endif
if (mxl_fail(ret))
goto fail;
}
val &= ~mask;
val |= data;
ret = mxl111sf_write_reg(state, addr, val);
mxl_fail(ret);
fail:
return ret;
}
/* ------------------------------------------------------------------------ */
int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
{
int i, ret = 0;
for (i = 0; ctrl_reg_info[i].addr |
ctrl_reg_info[i].mask |
ctrl_reg_info[i].data; i++) {
ret = mxl111sf_write_reg_mask(state,
ctrl_reg_info[i].addr,
ctrl_reg_info[i].mask,
ctrl_reg_info[i].data);
if (mxl_fail(ret)) {
err("failed on reg #%d (0x%02x)", i,
ctrl_reg_info[i].addr);
break;
}
}
return ret;
}
/* ------------------------------------------------------------------------ */
static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state)
{
int ret;
u8 id, ver;
char *mxl_chip, *mxl_rev;
if ((state->chip_id) && (state->chip_ver))
return 0;
ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id);
if (mxl_fail(ret))
goto fail;
state->chip_id = id;
ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver);
if (mxl_fail(ret))
goto fail;
state->chip_ver = ver;
switch (id) {
case 0x61:
mxl_chip = "MxL101SF";
break;
case 0x63:
mxl_chip = "MxL111SF";
break;
default:
mxl_chip = "UNKNOWN MxL1X1";
break;
}
switch (ver) {
case 0x36:
state->chip_rev = MXL111SF_V6;
mxl_rev = "v6";
break;
case 0x08:
state->chip_rev = MXL111SF_V8_100;
mxl_rev = "v8_100";
break;
case 0x18:
state->chip_rev = MXL111SF_V8_200;
mxl_rev = "v8_200";
break;
default:
state->chip_rev = 0;
mxl_rev = "UNKNOWN REVISION";
break;
}
info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
fail:
return ret;
}
#define get_chip_info(state) \
({ \
int ___ret; \
___ret = mxl1x1sf_get_chip_info(state); \
if (mxl_fail(___ret)) { \
mxl_debug("failed to get chip info" \
" on first probe attempt"); \
___ret = mxl1x1sf_get_chip_info(state); \
if (mxl_fail(___ret)) \
err("failed to get chip info during probe"); \
else \
mxl_debug("probe needed a retry " \
"in order to succeed."); \
} \
___ret; \
})
/* ------------------------------------------------------------------------ */
static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff)
{
/* power control depends on which adapter is being woken:
* save this for init, instead, via mxl111sf_adap_fe_init */
return 0;
}
static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dvb_usb_device *d = adap->dev;
struct mxl111sf_state *state = d->priv;
struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv;
int err;
/* exit if we didnt initialize the driver yet */
if (!state->chip_id) {
mxl_debug("driver not yet initialized, exit.");
goto fail;
}
deb_info("%s()\n", __func__);
mutex_lock(&state->fe_lock);
state->alt_mode = adap_state->alt_mode;
if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
err("set interface failed");
err = mxl1x1sf_soft_reset(state);
mxl_fail(err);
err = mxl111sf_init_tuner_demod(state);
mxl_fail(err);
err = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
mxl_fail(err);
mxl111sf_enable_usb_output(state);
mxl_fail(err);
mxl1x1sf_top_master_ctrl(state, 1);
mxl_fail(err);
if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) &&
(state->chip_rev > MXL111SF_V6)) {
mxl111sf_config_pin_mux_modes(state,
PIN_MUX_TS_SPI_IN_MODE_1);
mxl_fail(err);
}
err = mxl111sf_init_port_expander(state);
if (!mxl_fail(err)) {
state->gpio_mode = adap_state->gpio_mode;
err = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
mxl_fail(err);
#if 0
err = fe->ops.init(fe);
#endif
msleep(100); /* add short delay after enabling
* the demod before touching it */
}
return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0;
fail:
return -ENODEV;
}
static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dvb_usb_device *d = adap->dev;
struct mxl111sf_state *state = d->priv;
struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv;
int err;
/* exit if we didnt initialize the driver yet */
if (!state->chip_id) {
mxl_debug("driver not yet initialized, exit.");
goto fail;
}
deb_info("%s()\n", __func__);
err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0;
mutex_unlock(&state->fe_lock);
return err;
fail:
return -ENODEV;
}
static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
struct dvb_usb_device *d = adap->dev;
struct mxl111sf_state *state = d->priv;
struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv;
int ret = 0;
u8 tmp;
deb_info("%s(%d)\n", __func__, onoff);
if (onoff) {
ret = mxl111sf_enable_usb_output(state);
mxl_fail(ret);
ret = mxl111sf_config_mpeg_in(state, 1, 1,
adap_state->ep6_clockphase,
0, 0);
mxl_fail(ret);
} else {
ret = mxl111sf_disable_656_port(state);
mxl_fail(ret);
}
mxl111sf_read_reg(state, 0x12, &tmp);
tmp &= ~0x04;
mxl111sf_write_reg(state, 0x12, tmp);
return ret;
}
/* ------------------------------------------------------------------------ */
static struct lgdt3305_config hauppauge_lgdt3305_config = {
.i2c_addr = 0xb2 >> 1,
.mpeg_mode = LGDT3305_MPEG_SERIAL,
.tpclk_edge = LGDT3305_TPCLK_RISING_EDGE,
.tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
.deny_i2c_rptr = 1,
.spectral_inversion = 0,
.qam_if_khz = 6000,
.vsb_if_khz = 6000,
};
static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap->dev;
struct mxl111sf_state *state = d->priv;
int fe_id = adap->num_frontends_initialized;
struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
int ret;
deb_adv("%s()\n", __func__);
/* save a pointer to the dvb_usb_device in device state */
state->d = d;
adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
state->alt_mode = adap_state->alt_mode;
if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
err("set interface failed");
state->gpio_mode = MXL111SF_GPIO_MOD_ATSC;
adap_state->gpio_mode = state->gpio_mode;
adap_state->device_mode = MXL_TUNER_MODE;
adap_state->ep6_clockphase = 1;
ret = mxl1x1sf_soft_reset(state);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_init_tuner_demod(state);
if (mxl_fail(ret))
goto fail;
ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_enable_usb_output(state);
if (mxl_fail(ret))
goto fail;
ret = mxl1x1sf_top_master_ctrl(state, 1);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_init_port_expander(state);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
if (mxl_fail(ret))
goto fail;
adap->fe_adap[fe_id].fe = dvb_attach(lgdt3305_attach,
&hauppauge_lgdt3305_config,
&adap->dev->i2c_adap);
if (adap->fe_adap[fe_id].fe) {
adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
return 0;
}
ret = -EIO;
fail:
return ret;
}
static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state,
int antpath)
{
return mxl111sf_idac_config(state, 1, 1,
(antpath == ANT_PATH_INTERNAL) ?
0x3f : 0x00, 0);
}
#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \
err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
__func__, __LINE__, \
(ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \
pwr0, pwr1, pwr2, pwr3)
#define ANT_HUNT_SLEEP 90
#define ANT_EXT_TWEAK 0
static int mxl111sf_ant_hunt(struct dvb_frontend *fe)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dvb_usb_device *d = adap->dev;
struct mxl111sf_state *state = d->priv;
int antctrl = dvb_usb_mxl111sf_rfswitch;
u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2;
/* FIXME: must force EXTERNAL for QAM - done elsewhere */
mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ?
ANT_PATH_EXTERNAL : antctrl);
if (antctrl == ANT_PATH_AUTO) {
#if 0
msleep(ANT_HUNT_SLEEP);
#endif
fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA);
mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
msleep(ANT_HUNT_SLEEP);
fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0);
mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
msleep(ANT_HUNT_SLEEP);
fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1);
mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL);
msleep(ANT_HUNT_SLEEP);
fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2);
if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) {
/* return with EXTERNAL enabled */
mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA,
rxPwr0, rxPwr1, rxPwr2);
} else {
/* return with INTERNAL enabled */
DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA,
rxPwr0, rxPwr1, rxPwr2);
}
}
return 0;
}
static struct mxl111sf_tuner_config mxl_tuner_config = {
.if_freq = MXL_IF_6_0, /* applies to external IF output, only */
.invert_spectrum = 0,
.read_reg = mxl111sf_read_reg,
.write_reg = mxl111sf_write_reg,
.program_regs = mxl111sf_ctrl_program_regs,
.top_master_ctrl = mxl1x1sf_top_master_ctrl,
.ant_hunt = mxl111sf_ant_hunt,
};
static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap->dev;
struct mxl111sf_state *state = d->priv;
int fe_id = adap->num_frontends_initialized;
deb_adv("%s()\n", __func__);
if (NULL != dvb_attach(mxl111sf_tuner_attach,
adap->fe_adap[fe_id].fe, state,
&mxl_tuner_config))
return 0;
return -EIO;
}
static int mxl111sf_fe_ioctl_override(struct dvb_frontend *fe,
unsigned int cmd, void *parg,
unsigned int stage)
{
int err = 0;
switch (stage) {
case DVB_FE_IOCTL_PRE:
switch (cmd) {
case FE_READ_SIGNAL_STRENGTH:
err = fe->ops.tuner_ops.get_rf_strength(fe, parg);
/* If no error occurs, prevent dvb-core from handling
* this IOCTL, otherwise return the error */
if (0 == err)
err = 1;
break;
}
break;
case DVB_FE_IOCTL_POST:
/* no post-ioctl handling required */
break;
}
return err;
};
static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C;
}
struct i2c_algorithm mxl111sf_i2c_algo = {
.master_xfer = mxl111sf_i2c_xfer,
.functionality = mxl111sf_i2c_func,
#ifdef NEED_ALGO_CONTROL
.algo_control = dummy_algo_control,
#endif
};
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties;
static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties;
static int mxl111sf_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct dvb_usb_device *d = NULL;
deb_adv("%s()\n", __func__);
if (((dvb_usb_mxl111sf_isoc) &&
(0 == dvb_usb_device_init(intf,
&mxl111sf_atsc_isoc_properties,
THIS_MODULE, &d, adapter_nr))) ||
0 == dvb_usb_device_init(intf,
&mxl111sf_atsc_bulk_properties,
THIS_MODULE, &d, adapter_nr) || 0) {
struct mxl111sf_state *state = d->priv;
static u8 eeprom[256];
struct i2c_client c;
int ret;
ret = get_chip_info(state);
if (mxl_fail(ret))
err("failed to get chip info during probe");
mutex_init(&state->fe_lock);
if (state->chip_rev > MXL111SF_V6)
mxl111sf_config_pin_mux_modes(state,
PIN_MUX_TS_SPI_IN_MODE_1);
c.adapter = &d->i2c_adap;
c.addr = 0xa0 >> 1;
ret = tveeprom_read(&c, eeprom, sizeof(eeprom));
if (mxl_fail(ret))
return 0;
tveeprom_hauppauge_analog(&c, &state->tv,
(0x84 == eeprom[0xa0]) ?
eeprom + 0xa0 : eeprom + 0x80);
#if 0
switch (state->tv.model) {
case 117001:
case 126001:
case 138001:
break;
default:
printk(KERN_WARNING "%s: warning: "
"unknown hauppauge model #%d\n",
__func__, state->tv.model);
}
#endif
return 0;
}
err("Your device is not yet supported by this driver. "
"See kernellabs.com for more info");
return -EINVAL;
}
static struct usb_device_id mxl111sf_table[] = {
/* 0 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600) }, /* ATSC+ IR */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601) }, /* ATSC */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602) }, /* + */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603) }, /* ATSC+ */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604) }, /* DVBT */
/* 5 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609) }, /* ATSC IR */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a) }, /* + IR */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b) }, /* ATSC+ IR */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c) }, /* DVBT IR */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653) }, /* ATSC+ */
/*10 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b) }, /* ATSC+ IR */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700) }, /* ATSC+ sw */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701) }, /* ATSC sw */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702) }, /* + sw */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703) }, /* ATSC+ sw */
/*15 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704) }, /* DVBT sw */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753) }, /* ATSC+ sw */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763) }, /* ATSC+ no */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764) }, /* DVBT no */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853) }, /* ATSC+ sw */
/*20 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854) }, /* DVBT sw */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863) }, /* ATSC+ no */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864) }, /* DVBT no */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3) }, /* ATSC+ sw */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4) }, /* DVBT sw */
/*25 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3) }, /* ATSC+ no */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4) }, /* DVBT no */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff) }, /* ATSC+ */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612) }, /* + */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613) }, /* ATSC+ */
/*30 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a) }, /* + IR */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b) }, /* ATSC+ IR */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757) }, /* ATSC+DVBT sw */
{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767) }, /* ATSC+DVBT no */
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, mxl111sf_table);
#define MXL111SF_EP6_BULK_STREAMING_CONFIG \
.streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \
.stream = { \
.type = USB_BULK, \
.count = 5, \
.endpoint = 0x06, \
.u = { \
.bulk = { \
.buffersize = 8192, \
} \
} \
}
/* FIXME */
#define MXL111SF_EP6_ISOC_STREAMING_CONFIG \
.streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \
.stream = { \
.type = USB_ISOC, \
.count = 5, \
.endpoint = 0x06, \
.u = { \
.isoc = { \
.framesperurb = 24, \
.framesize = 3072, \
.interval = 1, \
} \
} \
}
#define MXL111SF_DEFAULT_DEVICE_PROPERTIES \
.caps = DVB_USB_IS_AN_I2C_ADAPTER, \
.usb_ctrl = DEVICE_SPECIFIC, \
/* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), \
EP6 BULK transfer (atsc/qam), \
use usb alt setting 2 for EP4 BULK transfer (dvb-t), \
EP6 ISOC transfer (atsc/qam), \
*/ \
.power_ctrl = mxl111sf_power_ctrl, \
.i2c_algo = &mxl111sf_i2c_algo, \
.generic_bulk_ctrl_endpoint = MXL_EP2_REG_WRITE, \
.generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \
.size_of_priv = sizeof(struct mxl111sf_state)
static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
MXL111SF_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
{
.fe_ioctl_override = mxl111sf_fe_ioctl_override,
.num_frontends = 1,
.fe = {{
.size_of_priv = sizeof(struct mxl111sf_adap_state),
.frontend_attach = mxl111sf_lgdt3305_frontend_attach,
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP6_BULK_STREAMING_CONFIG,
}},
},
},
.num_device_descs = 6,
.devices = {
{ "Hauppauge 126xxx ATSC (bulk)",
{ NULL },
{ &mxl111sf_table[1], &mxl111sf_table[5],
NULL },
},
{ "Hauppauge 117xxx ATSC (bulk)",
{ NULL },
{ &mxl111sf_table[12],
NULL },
},
{ "Hauppauge 126xxx ATSC+ (bulk)",
{ NULL },
{ &mxl111sf_table[0], &mxl111sf_table[3],
&mxl111sf_table[7], &mxl111sf_table[9],
&mxl111sf_table[10], NULL },
},
{ "Hauppauge 117xxx ATSC+ (bulk)",
{ NULL },
{ &mxl111sf_table[11], &mxl111sf_table[14],
&mxl111sf_table[16], &mxl111sf_table[17],
&mxl111sf_table[32], &mxl111sf_table[33],
NULL },
},
{ "Hauppauge Mercury (tp-bulk)",
{ NULL },
{ &mxl111sf_table[19], &mxl111sf_table[21],
&mxl111sf_table[23], &mxl111sf_table[25],
&mxl111sf_table[27], NULL },
},
{ "Hauppauge WinTV-Aero-M",
{ NULL },
{ &mxl111sf_table[29], &mxl111sf_table[31],
NULL },
},
}
};
static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
MXL111SF_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
{
.fe_ioctl_override = mxl111sf_fe_ioctl_override,
.num_frontends = 1,
.fe = {{
.size_of_priv = sizeof(struct mxl111sf_adap_state),
.frontend_attach = mxl111sf_lgdt3305_frontend_attach,
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP6_ISOC_STREAMING_CONFIG,
}},
},
},
.num_device_descs = 6,
.devices = {
{ "Hauppauge 126xxx ATSC (isoc)",
{ NULL },
{ &mxl111sf_table[1], &mxl111sf_table[5],
NULL },
},
{ "Hauppauge 117xxx ATSC (isoc)",
{ NULL },
{ &mxl111sf_table[12],
NULL },
},
{ "Hauppauge 126xxx ATSC+ (isoc)",
{ NULL },
{ &mxl111sf_table[0], &mxl111sf_table[3],
&mxl111sf_table[7], &mxl111sf_table[9],
&mxl111sf_table[10], NULL },
},
{ "Hauppauge 117xxx ATSC+ (isoc)",
{ NULL },
{ &mxl111sf_table[11], &mxl111sf_table[14],
&mxl111sf_table[16], &mxl111sf_table[17],
&mxl111sf_table[32], &mxl111sf_table[33],
NULL },
},
{ "Hauppauge Mercury (tp-isoc)",
{ NULL },
{ &mxl111sf_table[19], &mxl111sf_table[21],
&mxl111sf_table[23], &mxl111sf_table[25],
&mxl111sf_table[27], NULL },
},
{ "Hauppauge WinTV-Aero-M (tp-isoc)",
{ NULL },
{ &mxl111sf_table[29], &mxl111sf_table[31],
NULL },
},
}
};
static struct usb_driver mxl111sf_driver = {
.name = "dvb_usb_mxl111sf",
.probe = mxl111sf_probe,
.disconnect = dvb_usb_device_exit,
.id_table = mxl111sf_table,
};
static int __init mxl111sf_module_init(void)
{
int result = usb_register(&mxl111sf_driver);
if (result) {
err("usb_register failed. Error number %d", result);
return result;
}
return 0;
}
static void __exit mxl111sf_module_exit(void)
{
usb_deregister(&mxl111sf_driver);
}
module_init(mxl111sf_module_init);
module_exit(mxl111sf_module_exit);
MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@ -0,0 +1,158 @@
/*
* Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#ifndef _DVB_USB_MXL111SF_H_
#define _DVB_USB_MXL111SF_H_
#ifdef DVB_USB_LOG_PREFIX
#undef DVB_USB_LOG_PREFIX
#endif
#define DVB_USB_LOG_PREFIX "mxl111sf"
#include "dvb-usb.h"
#include <media/tveeprom.h>
#define MXL_EP1_REG_READ 1
#define MXL_EP2_REG_WRITE 2
#define MXL_EP3_INTERRUPT 3
#define MXL_EP4_MPEG2 4
#define MXL_EP5_I2S 5
#define MXL_EP6_656 6
#define MXL_EP6_MPEG2 6
#ifdef USING_ENUM_mxl111sf_current_mode
enum mxl111sf_current_mode {
mxl_mode_dvbt = MXL_EP4_MPEG2,
mxl_mode_mh = MXL_EP5_I2S,
mxl_mode_atsc = MXL_EP6_MPEG2,
};
#endif
enum mxl111sf_gpio_port_expander {
mxl111sf_gpio_hw,
mxl111sf_PCA9534,
};
struct mxl111sf_state {
struct dvb_usb_device *d;
enum mxl111sf_gpio_port_expander gpio_port_expander;
u8 port_expander_addr;
u8 chip_id;
u8 chip_ver;
#define MXL111SF_V6 1
#define MXL111SF_V8_100 2
#define MXL111SF_V8_200 3
u8 chip_rev;
#ifdef USING_ENUM_mxl111sf_current_mode
enum mxl111sf_current_mode current_mode;
#endif
#define MXL_TUNER_MODE 0
#define MXL_SOC_MODE 1
#define MXL_DEV_MODE_MASK 0x01
#if 1
int device_mode;
#endif
/* use usb alt setting 1 for EP4 ISOC transfer (dvb-t),
EP5 BULK transfer (atsc-mh),
EP6 BULK transfer (atsc/qam),
use usb alt setting 2 for EP4 BULK transfer (dvb-t),
EP5 ISOC transfer (atsc-mh),
EP6 ISOC transfer (atsc/qam),
*/
int alt_mode;
int gpio_mode;
struct tveeprom tv;
struct mutex fe_lock;
};
struct mxl111sf_adap_state {
int alt_mode;
int gpio_mode;
int device_mode;
int ep6_clockphase;
int (*fe_init)(struct dvb_frontend *);
int (*fe_sleep)(struct dvb_frontend *);
};
int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data);
int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data);
struct mxl111sf_reg_ctrl_info {
u8 addr;
u8 mask;
u8 data;
};
int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
u8 addr, u8 mask, u8 data);
int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
/* needed for hardware i2c functions in mxl111sf-i2c.c:
* mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */
int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen);
#define mxl_printk(kern, fmt, arg...) \
printk(kern "%s: " fmt "\n", __func__, ##arg)
#define mxl_info(fmt, arg...) \
mxl_printk(KERN_INFO, fmt, ##arg)
extern int dvb_usb_mxl111sf_debug;
#define mxl_debug(fmt, arg...) \
if (dvb_usb_mxl111sf_debug) \
mxl_printk(KERN_DEBUG, fmt, ##arg)
#define MXL_I2C_DBG 0x04
#define MXL_ADV_DBG 0x10
#define mxl_debug_adv(fmt, arg...) \
if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \
mxl_printk(KERN_DEBUG, fmt, ##arg)
#define mxl_i2c(fmt, arg...) \
if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \
mxl_printk(KERN_DEBUG, fmt, ##arg)
#define mxl_i2c_adv(fmt, arg...) \
if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \
(MXL_I2C_DBG | MXL_ADV_DBG)) \
mxl_printk(KERN_DEBUG, fmt, ##arg)
/* The following allows the mxl_fail() macro defined below to work
* in externel modules, such as mxl111sf-tuner.ko, even though
* dvb_usb_mxl111sf_debug is not defined within those modules */
#ifdef __MXL111SF_TUNER_H__
#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG
#else
#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug
#endif
#define mxl_fail(ret) \
({ \
int __ret; \
__ret = (ret < 0); \
if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG)) \
mxl_printk(KERN_ERR, "error %d on line %d", \
ret, __LINE__); \
__ret; \
})
#endif /* _DVB_USB_MXL111SF_H_ */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@ -166,6 +166,8 @@ static struct dvb_usb_device_properties nova_t_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.pid_filter_count = 32,
@ -186,7 +188,7 @@ static struct dvb_usb_device_properties nova_t_properties = {
}
}
},
}},
.size_of_priv = sizeof(struct dibusb_state),
}
},

View File

@ -263,10 +263,10 @@ static struct stv0299_config opera1_stv0299_config = {
static int opera1_frontend_attach(struct dvb_usb_adapter *d)
{
if ((d->fe =
dvb_attach(stv0299_attach, &opera1_stv0299_config,
&d->dev->i2c_adap)) != NULL) {
d->fe->ops.set_voltage = opera1_set_voltage;
d->fe_adap[0].fe = dvb_attach(stv0299_attach, &opera1_stv0299_config,
&d->dev->i2c_adap);
if ((d->fe_adap[0].fe) != NULL) {
d->fe_adap[0].fe->ops.set_voltage = opera1_set_voltage;
return 0;
}
info("not attached stv0299");
@ -276,7 +276,7 @@ static int opera1_frontend_attach(struct dvb_usb_adapter *d)
static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(
dvb_pll_attach, adap->fe, 0xc0>>1,
dvb_pll_attach, adap->fe_adap[0].fe, 0xc0>>1,
&adap->dev->i2c_adap, DVB_PLL_OPERA1
);
return 0;
@ -516,6 +516,8 @@ static struct dvb_usb_device_properties opera1_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.frontend_attach = opera1_frontend_attach,
.streaming_ctrl = opera1_streaming_ctrl,
.tuner_attach = opera1_tuner_attach,
@ -535,6 +537,7 @@ static struct dvb_usb_device_properties opera1_properties = {
}
}
},
}},
}
},
.num_device_descs = 1,

File diff suppressed because it is too large Load Diff

View File

@ -292,7 +292,7 @@ static void technisat_usb2_green_led_control(struct work_struct *work)
{
struct technisat_usb2_state *state =
container_of(work, struct technisat_usb2_state, green_led_work.work);
struct dvb_frontend *fe = state->dev->adapter[0].fe;
struct dvb_frontend *fe = state->dev->adapter[0].fe_adap[0].fe;
if (state->power_state == 0)
goto schedule;
@ -505,14 +505,14 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
struct usb_device *udev = a->dev->udev;
int ret;
a->fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config,
a->fe_adap[0].fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config,
&a->dev->i2c_adap, STV090x_DEMODULATOR_0);
if (a->fe) {
if (a->fe_adap[0].fe) {
struct stv6110x_devctl *ctl;
ctl = dvb_attach(stv6110x_attach,
a->fe,
a->fe_adap[0].fe,
&technisat_usb2_stv6110x_config,
&a->dev->i2c_adap);
@ -532,8 +532,8 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
/* call the init function once to initialize
tuner's clock output divider and demod's
master clock */
if (a->fe->ops.init)
a->fe->ops.init(a->fe);
if (a->fe_adap[0].fe->ops.init)
a->fe_adap[0].fe->ops.init(a->fe_adap[0].fe);
if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0)
return -EAGAIN;
@ -548,20 +548,20 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
if (ret != 0)
err("could not set IF_CLK to external");
a->fe->ops.set_voltage = technisat_usb2_set_voltage;
a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage;
/* if everything was successful assign a nice name to the frontend */
strlcpy(a->fe->ops.info.name, a->dev->desc->name,
sizeof(a->fe->ops.info.name));
strlcpy(a->fe_adap[0].fe->ops.info.name, a->dev->desc->name,
sizeof(a->fe_adap[0].fe->ops.info.name));
} else {
dvb_frontend_detach(a->fe);
a->fe = NULL;
dvb_frontend_detach(a->fe_adap[0].fe);
a->fe_adap[0].fe = NULL;
}
}
technisat_usb2_set_led_timer(a->dev, 1, 1);
return a->fe == NULL ? -ENODEV : 0;
return a->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
/* Remote control */
@ -697,6 +697,8 @@ static struct dvb_usb_device_properties technisat_usb2_devices = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.frontend_attach = technisat_usb2_frontend_attach,
.stream = {
@ -711,7 +713,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = {
}
}
},
}},
.size_of_priv = 0,
},
},

View File

@ -30,18 +30,43 @@
#include "tda826x.h"
#include "tda10086.h"
#include "tda1002x.h"
#include "tda10048.h"
#include "tda827x.h"
#include "lnbp21.h"
/* CA */
#include "dvb_ca_en50221.h"
/* debug */
static int dvb_usb_ttusb2_debug;
#define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args)
module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS);
static int dvb_usb_ttusb2_debug_ci;
module_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644);
MODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS);
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define ci_dbg(format, arg...) \
do { \
if (dvb_usb_ttusb2_debug_ci) \
printk(KERN_DEBUG DVB_USB_LOG_PREFIX \
": %s " format "\n" , __func__, ## arg); \
} while (0)
enum {
TT3650_CMD_CI_TEST = 0x40,
TT3650_CMD_CI_RD_CTRL,
TT3650_CMD_CI_WR_CTRL,
TT3650_CMD_CI_RD_ATTR,
TT3650_CMD_CI_WR_ATTR,
TT3650_CMD_CI_RESET,
TT3650_CMD_CI_SET_VIDEO_PORT
};
struct ttusb2_state {
struct dvb_ca_en50221 ca;
struct mutex ca_mutex;
u8 id;
u16 last_rc_key;
};
@ -78,11 +103,260 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
return 0;
}
/* ci */
static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
{
int ret;
u8 rx[60];/* (64 -4) */
ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len);
if (!ret)
memcpy(data, rx, read_len);
return ret;
}
static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
{
struct dvb_usb_device *d = ca->data;
struct ttusb2_state *state = d->priv;
int ret;
mutex_lock(&state->ca_mutex);
ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
mutex_unlock(&state->ca_mutex);
return ret;
}
static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
{
u8 buf[3];
int ret = 0;
if (slot)
return -EINVAL;
buf[0] = (address >> 8) & 0x0F;
buf[1] = address;
ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]);
if (ret < 0)
return ret;
return buf[2];
}
static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
{
u8 buf[3];
ci_dbg("%d 0x%04x 0x%02x", slot, address, value);
if (slot)
return -EINVAL;
buf[0] = (address >> 8) & 0x0F;
buf[1] = address;
buf[2] = value;
return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
}
static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
{
u8 buf[2];
int ret;
if (slot)
return -EINVAL;
buf[0] = address & 3;
ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]);
if (ret < 0)
return ret;
return buf[1];
}
static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
{
u8 buf[2];
ci_dbg("%d 0x%02x 0x%02x", slot, address, value);
if (slot)
return -EINVAL;
buf[0] = address;
buf[1] = value;
return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
}
static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable)
{
u8 buf[1];
int ret;
ci_dbg("%d %d", slot, enable);
if (slot)
return -EINVAL;
buf[0] = enable;
ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
if (ret < 0)
return ret;
if (enable != buf[0]) {
err("CI not %sabled.", enable ? "en" : "dis");
return -EIO;
}
return 0;
}
static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
{
return tt3650_ci_set_video_port(ca, slot, 0);
}
static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
{
return tt3650_ci_set_video_port(ca, slot, 1);
}
static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
{
struct dvb_usb_device *d = ca->data;
struct ttusb2_state *state = d->priv;
u8 buf[1];
int ret;
ci_dbg("%d", slot);
if (slot)
return -EINVAL;
buf[0] = 0;
mutex_lock(&state->ca_mutex);
ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
if (ret)
goto failed;
msleep(500);
buf[0] = 1;
ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
if (ret)
goto failed;
msleep(500);
buf[0] = 0; /* FTA */
ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
msleep(1100);
failed:
mutex_unlock(&state->ca_mutex);
return ret;
}
static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
{
u8 buf[1];
int ret;
if (slot)
return -EINVAL;
ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
if (ret)
return ret;
if (1 == buf[0]) {
return DVB_CA_EN50221_POLL_CAM_PRESENT |
DVB_CA_EN50221_POLL_CAM_READY;
}
return 0;
}
static void tt3650_ci_uninit(struct dvb_usb_device *d)
{
struct ttusb2_state *state;
ci_dbg("");
if (NULL == d)
return;
state = d->priv;
if (NULL == state)
return;
if (NULL == state->ca.data)
return;
dvb_ca_en50221_release(&state->ca);
memset(&state->ca, 0, sizeof(state->ca));
}
static int tt3650_ci_init(struct dvb_usb_adapter *a)
{
struct dvb_usb_device *d = a->dev;
struct ttusb2_state *state = d->priv;
int ret;
ci_dbg("");
mutex_init(&state->ca_mutex);
state->ca.owner = THIS_MODULE;
state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
state->ca.read_cam_control = tt3650_ci_read_cam_control;
state->ca.write_cam_control = tt3650_ci_write_cam_control;
state->ca.slot_reset = tt3650_ci_slot_reset;
state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
state->ca.data = d;
ret = dvb_ca_en50221_init(&a->dvb_adap,
&state->ca,
/* flags */ 0,
/* n_slots */ 1);
if (ret) {
err("Cannot initialize CI: Error %d.", ret);
memset(&state->ca, 0, sizeof(state->ca));
return ret;
}
info("CI initialized.");
return 0;
}
static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
static u8 obuf[60], ibuf[60];
int i,read;
int i, write_read, read;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
@ -91,28 +365,35 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
warn("more than 2 i2c messages at a time is not handled yet. TODO.");
for (i = 0; i < num; i++) {
read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
read = msg[i].flags & I2C_M_RD;
obuf[0] = (msg[i].addr << 1) | read;
obuf[1] = msg[i].len;
obuf[0] = (msg[i].addr << 1) | (write_read | read);
if (read)
obuf[1] = 0;
else
obuf[1] = msg[i].len;
/* read request */
if (read)
if (write_read)
obuf[2] = msg[i+1].len;
else if (read)
obuf[2] = msg[i].len;
else
obuf[2] = 0;
memcpy(&obuf[3],msg[i].buf,msg[i].len);
memcpy(&obuf[3], msg[i].buf, msg[i].len);
if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) {
err("i2c transfer failed.");
break;
}
if (read) {
memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len);
if (write_read) {
memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len);
i++;
}
} else if (read)
memcpy(msg[i].buf, &ibuf[3], msg[i].len);
}
mutex_unlock(&d->i2c_mutex);
@ -190,12 +471,31 @@ static struct tda10023_config tda10023_config = {
.deltaf = 0xa511,
};
static struct tda10048_config tda10048_config = {
.demod_address = 0x10 >> 1,
.output_mode = TDA10048_PARALLEL_OUTPUT,
.inversion = TDA10048_INVERSION_ON,
.dtv6_if_freq_khz = TDA10048_IF_4000,
.dtv7_if_freq_khz = TDA10048_IF_4500,
.dtv8_if_freq_khz = TDA10048_IF_5000,
.clk_freq_khz = TDA10048_CLK_16000,
.no_firmware = 1,
.set_pll = true ,
.pll_m = 5,
.pll_n = 3,
.pll_p = 0,
};
static struct tda827x_config tda827x_config = {
.config = 0,
};
static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
{
if (usb_set_interface(adap->dev->udev,0,3) < 0)
err("set interface to alts=3 failed");
if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
deb_info("TDA10086 attach failed\n");
return -ENODEV;
}
@ -203,20 +503,57 @@ static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
return 0;
}
static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable);
}
static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
{
if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
err("set interface to alts=3 failed");
if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) {
deb_info("TDA10023 attach failed\n");
return -ENODEV;
if (adap->fe_adap[0].fe == NULL) {
/* FE 0 DVB-C */
adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
&tda10023_config, &adap->dev->i2c_adap, 0x48);
if (adap->fe_adap[0].fe == NULL) {
deb_info("TDA10023 attach failed\n");
return -ENODEV;
}
tt3650_ci_init(adap);
} else {
adap->fe_adap[1].fe = dvb_attach(tda10048_attach,
&tda10048_config, &adap->dev->i2c_adap);
if (adap->fe_adap[1].fe == NULL) {
deb_info("TDA10048 attach failed\n");
return -ENODEV;
}
/* tuner is behind TDA10023 I2C-gate */
adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl;
}
return 0;
}
static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
{
if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) {
struct dvb_frontend *fe;
/* MFE: select correct FE to attach tuner since that's called twice */
if (adap->fe_adap[1].fe == NULL)
fe = adap->fe_adap[0].fe;
else
fe = adap->fe_adap[1].fe;
/* attach tuner */
if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) {
printk(KERN_ERR "%s: No tda827x found!\n", __func__);
return -ENODEV;
}
@ -225,12 +562,12 @@ static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap)
{
if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
deb_info("TDA8263 attach failed\n");
return -ENODEV;
}
if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
deb_info("LNBP21 attach failed\n");
return -ENODEV;
}
@ -242,6 +579,14 @@ static struct dvb_usb_device_properties ttusb2_properties;
static struct dvb_usb_device_properties ttusb2_properties_s2400;
static struct dvb_usb_device_properties ttusb2_properties_ct3650;
static void ttusb2_usb_disconnect(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
tt3650_ci_uninit(d);
dvb_usb_device_exit(intf);
}
static int ttusb2_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@ -277,6 +622,8 @@ static struct dvb_usb_device_properties ttusb2_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = NULL, // ttusb2_streaming_ctrl,
.frontend_attach = ttusb2_frontend_tda10086_attach,
@ -295,6 +642,7 @@ static struct dvb_usb_device_properties ttusb2_properties = {
}
}
}
}},
}
},
@ -329,6 +677,8 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = NULL,
.frontend_attach = ttusb2_frontend_tda10086_attach,
@ -347,6 +697,7 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
}
}
}
}},
}
},
@ -383,6 +734,8 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 2,
.fe = {{
.streaming_ctrl = NULL,
.frontend_attach = ttusb2_frontend_tda10023_attach,
@ -401,6 +754,26 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
}
}
}
}, {
.streaming_ctrl = NULL,
.frontend_attach = ttusb2_frontend_tda10023_attach,
.tuner_attach = ttusb2_tuner_tda827x_attach,
/* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_ISOC,
.count = 5,
.endpoint = 0x02,
.u = {
.isoc = {
.framesperurb = 4,
.framesize = 940,
.interval = 1,
}
}
}
}},
},
},
@ -422,7 +795,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
static struct usb_driver ttusb2_driver = {
.name = "dvb_usb_ttusb2",
.probe = ttusb2_probe,
.disconnect = dvb_usb_device_exit,
.disconnect = ttusb2_usb_disconnect,
.id_table = ttusb2_table,
};

View File

@ -60,14 +60,14 @@ static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
umt_config.demod_init = umt_mt352_demod_init;
umt_config.demod_address = 0xf;
adap->fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap);
adap->fe_adap[0].fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap);
return 0;
}
static int umt_tuner_attach (struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034);
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_TUA6034);
return 0;
}
@ -100,6 +100,8 @@ static struct dvb_usb_device_properties umt_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = dibusb2_0_streaming_ctrl,
.frontend_attach = umt_mt352_frontend_attach,
.tuner_attach = umt_tuner_attach,
@ -115,7 +117,7 @@ static struct dvb_usb_device_properties umt_properties = {
}
}
},
}},
.size_of_priv = sizeof(struct dibusb_state),
}
},

View File

@ -148,7 +148,7 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream)
if (!stream->urb_list[i]) {
deb_mem("not enough memory for urb_alloc_urb!.\n");
for (j = 0; j < i; j++)
usb_free_urb(stream->urb_list[i]);
usb_free_urb(stream->urb_list[j]);
return -ENOMEM;
}
usb_fill_bulk_urb( stream->urb_list[i], stream->udev,
@ -181,7 +181,7 @@ static int usb_isoc_urb_init(struct usb_data_stream *stream)
if (!stream->urb_list[i]) {
deb_mem("not enough memory for urb_alloc_urb!\n");
for (j = 0; j < i; j++)
usb_free_urb(stream->urb_list[i]);
usb_free_urb(stream->urb_list[j]);
return -ENOMEM;
}

View File

@ -320,7 +320,7 @@ static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
vp702x_init_pid_filter(adap);
adap->fe = vp702x_fe_attach(adap->dev);
adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev);
vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
return 0;
@ -383,6 +383,8 @@ static struct dvb_usb_device_properties vp702x_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
.streaming_ctrl = vp702x_streaming_ctrl,
@ -399,6 +401,7 @@ static struct dvb_usb_device_properties vp702x_properties = {
}
}
},
}},
.size_of_priv = sizeof(struct vp702x_adapter_state),
}
},

View File

@ -214,7 +214,7 @@ static int vp7045_frontend_attach(struct dvb_usb_adapter *adap)
/* Dump the EEPROM */
/* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
adap->fe = vp7045_fe_attach(adap->dev);
adap->fe_adap[0].fe = vp7045_fe_attach(adap->dev);
return 0;
}
@ -245,6 +245,8 @@ static struct dvb_usb_device_properties vp7045_properties = {
.num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
.fe = {{
.frontend_attach = vp7045_frontend_attach,
/* parameter for the MPEG2-data transfer */
.stream = {
@ -257,6 +259,7 @@ static struct dvb_usb_device_properties vp7045_properties = {
}
}
},
}},
}
},
.power_ctrl = vp7045_power_ctrl,

View File

@ -236,6 +236,13 @@ config DVB_MB86A16
A DVB-S/DSS Direct Conversion reveiver.
Say Y when you want to support this frontend.
config DVB_TDA10071
tristate "NXP TDA10071"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
Say Y when you want to support this frontend.
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
@ -600,6 +607,16 @@ config DVB_LNBP21
help
An SEC control chips.
config DVB_LNBP22
tristate "LNBP22 SEC controllers"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
LNB power supply and control voltage
regulator chip with step-up converter
and I2C interface.
Say Y when you want to support this chip.
config DVB_ISL6405
tristate "ISL6405 SEC controller"
depends on DVB_CORE && I2C
@ -621,6 +638,11 @@ config DVB_ISL6423
help
A SEC controller chip from Intersil
config DVB_A8293
tristate "Allegro A8293"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
config DVB_LGS8GL5
tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
depends on DVB_CORE && I2C
@ -661,6 +683,14 @@ config DVB_IX2505V
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_IT913X_FE
tristate "it913x frontend and it9137 tuner"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A DVB-T tuner module.
Say Y when you want to support this frontend.
comment "Tools to develop new frontends"
config DVB_DUMMY_FE

View File

@ -2,8 +2,8 @@
# Makefile for the kernel DVB frontend device drivers.
#
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
EXTRA_CFLAGS += -Idrivers/media/common/tuners/
ccflags-y += -Idrivers/media/dvb/dvb-core/
ccflags-y += -Idrivers/media/common/tuners/
stb0899-objs = stb0899_drv.o stb0899_algo.o
stv0900-objs = stv0900_core.o stv0900_sw.o
@ -52,6 +52,7 @@ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
obj-$(CONFIG_DVB_ISL6405) += isl6405.o
obj-$(CONFIG_DVB_ISL6421) += isl6421.o
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
@ -91,4 +92,7 @@ obj-$(CONFIG_DVB_STV0367) += stv0367.o
obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
obj-$(CONFIG_DVB_DRXK) += drxk.o
obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
obj-$(CONFIG_DVB_A8293) += a8293.o
obj-$(CONFIG_DVB_TDA10071) += tda10071.o

View File

@ -0,0 +1,184 @@
/*
* Allegro A8293 SEC driver
*
* Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#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;
u8 reg[2];
};
static int a8293_i2c(struct a8293_priv *priv, u8 *val, int len, bool rd)
{
int ret;
struct i2c_msg msg[1] = {
{
.addr = priv->cfg->i2c_addr,
.len = len,
.buf = val,
}
};
if (rd)
msg[0].flags = I2C_M_RD;
else
msg[0].flags = 0;
ret = i2c_transfer(priv->i2c, msg, 1);
if (ret == 1) {
ret = 0;
} else {
warn("i2c failed=%d rd=%d", ret, rd);
ret = -EREMOTEIO;
}
return ret;
}
static int a8293_wr(struct a8293_priv *priv, u8 *val, int len)
{
return a8293_i2c(priv, val, len, 0);
}
static int a8293_rd(struct a8293_priv *priv, u8 *val, int len)
{
return a8293_i2c(priv, val, len, 1);
}
static int a8293_set_voltage(struct dvb_frontend *fe,
fe_sec_voltage_t fe_sec_voltage)
{
struct a8293_priv *priv = fe->sec_priv;
int ret;
dbg("%s: fe_sec_voltage=%d", __func__, fe_sec_voltage);
switch (fe_sec_voltage) {
case SEC_VOLTAGE_OFF:
/* ENB=0 */
priv->reg[0] = 0x10;
break;
case SEC_VOLTAGE_13:
/* VSEL0=1, VSEL1=0, VSEL2=0, VSEL3=0, ENB=1*/
priv->reg[0] = 0x31;
break;
case SEC_VOLTAGE_18:
/* VSEL0=0, VSEL1=0, VSEL2=0, VSEL3=1, ENB=1*/
priv->reg[0] = 0x38;
break;
default:
ret = -EINVAL;
goto err;
};
ret = a8293_wr(priv, &priv->reg[0], 1);
if (ret)
goto err;
return ret;
err:
dbg("%s: failed=%d", __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);
fe->sec_priv = NULL;
}
struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, const struct a8293_config *cfg)
{
int ret;
struct a8293_priv *priv = NULL;
u8 buf[2];
/* allocate memory for the internal priv */
priv = kzalloc(sizeof(struct a8293_priv), GFP_KERNEL);
if (priv == NULL) {
ret = -ENOMEM;
goto err;
}
/* setup the priv */
priv->i2c = i2c;
priv->cfg = cfg;
fe->sec_priv = priv;
/* check if the SEC is there */
ret = a8293_rd(priv, buf, 2);
if (ret)
goto err;
/* ENB=0 */
priv->reg[0] = 0x10;
ret = a8293_wr(priv, &priv->reg[1], 1);
if (ret)
goto err;
/* TMODE=0, TGATE=1 */
priv->reg[1] = 0x82;
ret = a8293_wr(priv, &priv->reg[1], 1);
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;
return fe;
err:
dbg("%s: failed=%d", __func__, ret);
kfree(priv);
return NULL;
}
EXPORT_SYMBOL(a8293_attach);
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Allegro A8293 SEC driver");
MODULE_LICENSE("GPL");

View File

@ -1,5 +1,5 @@
/*
* NXP TDA18212HN silicon tuner driver
* Allegro A8293 SEC driver
*
* Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
*
@ -18,27 +18,24 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef TDA18212_PRIV_H
#define TDA18212_PRIV_H
#ifndef A8293_H
#define A8293_H
#include "tda18212.h"
#define LOG_PREFIX "tda18212"
#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 tda18212_priv {
struct tda18212_config *cfg;
struct i2c_adapter *i2c;
struct a8293_config {
u8 i2c_addr;
};
#if defined(CONFIG_DVB_A8293) || \
(defined(CONFIG_DVB_A8293_MODULE) && defined(MODULE))
extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, const struct a8293_config *cfg);
#else
static inline struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, const struct a8293_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
#endif /* A8293_H */

Some files were not shown because too many files have changed in this diff Show More