Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into rmobile-latest

This commit is contained in:
Paul Mundt 2011-05-24 15:24:52 +09:00
commit d08fe47512
266 changed files with 19089 additions and 5024 deletions

View File

@ -8,3 +8,4 @@
*.dvi
*.log
*.out
media/

View File

@ -34,6 +34,14 @@
<revhistory>
<!-- Put document revisions here, newest first. -->
<revision>
<revnumber>2.0.4</revnumber>
<date>2011-05-06</date>
<authorinitials>mcc</authorinitials>
<revremark>
Add more information about DVB APIv5, better describing the frontend GET/SET props ioctl's.
</revremark>
</revision>
<revision>
<revnumber>2.0.3</revnumber>
<date>2010-07-03</date>

View File

@ -1,6 +1,327 @@
<section id="FE_GET_PROPERTY">
<section id="FE_GET_SET_PROPERTY">
<title>FE_GET_PROPERTY/FE_SET_PROPERTY</title>
<programlisting>
/* Reserved fields should be set to 0 */
struct dtv_property {
__u32 cmd;
union {
__u32 data;
struct {
__u8 data[32];
__u32 len;
__u32 reserved1[3];
void *reserved2;
} buffer;
} u;
int result;
} __attribute__ ((packed));
/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
#define DTV_IOCTL_MAX_MSGS 64
struct dtv_properties {
__u32 num;
struct dtv_property *props;
};
</programlisting>
<section id="FE_GET_PROPERTY">
<title>FE_GET_PROPERTY</title>
<para>DESCRIPTION
</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>This ioctl call returns one or more frontend properties. This call only
requires read-only access to the device.</para>
</entry>
</row></tbody></tgroup></informaltable>
<para>SYNOPSIS
</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>int ioctl(int fd, int request = <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>,
dtv_properties &#x22C6;props);</para>
</entry>
</row></tbody></tgroup></informaltable>
<para>PARAMETERS
</para>
<informaltable><tgroup cols="2"><tbody><row><entry align="char">
<para>int fd</para>
</entry><entry
align="char">
<para>File descriptor returned by a previous call to open().</para>
</entry>
</row><row><entry
align="char">
<para>int num</para>
</entry><entry
align="char">
<para>Equals <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link> for this command.</para>
</entry>
</row><row><entry
align="char">
<para>struct dtv_property *props</para>
</entry><entry
align="char">
<para>Points to the location where the front-end property commands are stored.</para>
</entry>
</row></tbody></tgroup></informaltable>
<para>ERRORS</para>
<informaltable><tgroup cols="2"><tbody><row>
<entry align="char"><para>EINVAL</para></entry>
<entry align="char"><para>Invalid parameter(s) received or number of parameters out of the range.</para></entry>
</row><row>
<entry align="char"><para>ENOMEM</para></entry>
<entry align="char"><para>Out of memory.</para></entry>
</row><row>
<entry align="char"><para>EFAULT</para></entry>
<entry align="char"><para>Failure while copying data from/to userspace.</para></entry>
</row><row>
<entry align="char"><para>EOPNOTSUPP</para></entry>
<entry align="char"><para>Property type not supported.</para></entry>
</row></tbody></tgroup></informaltable>
</section>
<section id="FE_SET_PROPERTY">
<title>FE_SET_PROPERTY</title>
<para>DESCRIPTION
</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>This ioctl call sets one or more frontend properties. This call only
requires read-only access to the device.</para>
</entry>
</row></tbody></tgroup></informaltable>
<para>SYNOPSIS
</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>int ioctl(int fd, int request = <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
dtv_properties &#x22C6;props);</para>
</entry>
</row></tbody></tgroup></informaltable>
<para>PARAMETERS
</para>
<informaltable><tgroup cols="2"><tbody><row><entry align="char">
<para>int fd</para>
</entry><entry
align="char">
<para>File descriptor returned by a previous call to open().</para>
</entry>
</row><row><entry
align="char">
<para>int num</para>
</entry><entry
align="char">
<para>Equals <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link> for this command.</para>
</entry>
</row><row><entry
align="char">
<para>struct dtv_property *props</para>
</entry><entry
align="char">
<para>Points to the location where the front-end property commands are stored.</para>
</entry>
</row></tbody></tgroup></informaltable>
<para>ERRORS
</para>
<informaltable><tgroup cols="2"><tbody><row>
<entry align="char"><para>EINVAL</para></entry>
<entry align="char"><para>Invalid parameter(s) received or number of parameters out of the range.</para></entry>
</row><row>
<entry align="char"><para>ENOMEM</para></entry>
<entry align="char"><para>Out of memory.</para></entry>
</row><row>
<entry align="char"><para>EFAULT</para></entry>
<entry align="char"><para>Failure while copying data from/to userspace.</para></entry>
</row><row>
<entry align="char"><para>EOPNOTSUPP</para></entry>
<entry align="char"><para>Property type not supported.</para></entry>
</row></tbody></tgroup></informaltable>
</section>
<para>
On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
get/set up to 64 properties. The actual meaning of each property is described on the next sections.
</para>
<para>The Available frontend property types are:</para>
<programlisting>
#define DTV_UNDEFINED 0
#define DTV_TUNE 1
#define DTV_CLEAR 2
#define DTV_FREQUENCY 3
#define DTV_MODULATION 4
#define DTV_BANDWIDTH_HZ 5
#define DTV_INVERSION 6
#define DTV_DISEQC_MASTER 7
#define DTV_SYMBOL_RATE 8
#define DTV_INNER_FEC 9
#define DTV_VOLTAGE 10
#define DTV_TONE 11
#define DTV_PILOT 12
#define DTV_ROLLOFF 13
#define DTV_DISEQC_SLAVE_REPLY 14
#define DTV_FE_CAPABILITY_COUNT 15
#define DTV_FE_CAPABILITY 16
#define DTV_DELIVERY_SYSTEM 17
#define DTV_ISDBT_PARTIAL_RECEPTION 18
#define DTV_ISDBT_SOUND_BROADCASTING 19
#define DTV_ISDBT_SB_SUBCHANNEL_ID 20
#define DTV_ISDBT_SB_SEGMENT_IDX 21
#define DTV_ISDBT_SB_SEGMENT_COUNT 22
#define DTV_ISDBT_LAYERA_FEC 23
#define DTV_ISDBT_LAYERA_MODULATION 24
#define DTV_ISDBT_LAYERA_SEGMENT_COUNT 25
#define DTV_ISDBT_LAYERA_TIME_INTERLEAVING 26
#define DTV_ISDBT_LAYERB_FEC 27
#define DTV_ISDBT_LAYERB_MODULATION 28
#define DTV_ISDBT_LAYERB_SEGMENT_COUNT 29
#define DTV_ISDBT_LAYERB_TIME_INTERLEAVING 30
#define DTV_ISDBT_LAYERC_FEC 31
#define DTV_ISDBT_LAYERC_MODULATION 32
#define DTV_ISDBT_LAYERC_SEGMENT_COUNT 33
#define DTV_ISDBT_LAYERC_TIME_INTERLEAVING 34
#define DTV_API_VERSION 35
#define DTV_CODE_RATE_HP 36
#define DTV_CODE_RATE_LP 37
#define DTV_GUARD_INTERVAL 38
#define DTV_TRANSMISSION_MODE 39
#define DTV_HIERARCHY 40
#define DTV_ISDBT_LAYER_ENABLED 41
#define DTV_ISDBS_TS_ID 42
</programlisting>
<section id="fe_property_common">
<title>Parameters that are common to all Digital TV standards</title>
<section id="DTV_FREQUENCY">
<title><constant>DTV_FREQUENCY</constant></title>
<para>Central frequency of the channel, in HZ.</para>
<para>Notes:</para>
<para>1)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
the channel which is 6MHz.</para>
<para>2)As in ISDB-Tsb the channel consists of only one or three segments the
frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
central frequency of the channel is expected.</para>
</section>
<section id="DTV_BANDWIDTH_HZ">
<title><constant>DTV_BANDWIDTH_HZ</constant></title>
<para>Bandwidth for the channel, in HZ.</para>
<para>Possible values:
<constant>1712000</constant>,
<constant>5000000</constant>,
<constant>6000000</constant>,
<constant>7000000</constant>,
<constant>8000000</constant>,
<constant>10000000</constant>.
</para>
<para>Notes:</para>
<para>1) For ISDB-T it should be always 6000000Hz (6MHz)</para>
<para>2) For ISDB-Tsb it can vary depending on the number of connected segments</para>
<para>3) Bandwidth doesn't apply for DVB-C transmissions, as the bandwidth
for DVB-C depends on the symbol rate</para>
<para>4) Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from
other parameters (DTV_ISDBT_SB_SEGMENT_IDX,
DTV_ISDBT_SB_SEGMENT_COUNT).</para>
<para>5) DVB-T supports 6, 7 and 8MHz.</para>
<para>6) In addition, DVB-T2 supports 1.172, 5 and 10MHz.</para>
</section>
<section id="DTV_DELIVERY_SYSTEM">
<title><constant>DTV_DELIVERY_SYSTEM</constant></title>
<para>Specifies the type of Delivery system</para>
<para>Possible values: </para>
<programlisting>
typedef enum fe_delivery_system {
SYS_UNDEFINED,
SYS_DVBC_ANNEX_AC,
SYS_DVBC_ANNEX_B,
SYS_DVBT,
SYS_DSS,
SYS_DVBS,
SYS_DVBS2,
SYS_DVBH,
SYS_ISDBT,
SYS_ISDBS,
SYS_ISDBC,
SYS_ATSC,
SYS_ATSCMH,
SYS_DMBTH,
SYS_CMMB,
SYS_DAB,
SYS_DVBT2,
} fe_delivery_system_t;
</programlisting>
</section>
<section id="DTV_TRANSMISSION_MODE">
<title><constant>DTV_TRANSMISSION_MODE</constant></title>
<para>Specifies the number of carriers used by the standard</para>
<para>Possible values are:</para>
<programlisting>
typedef enum fe_transmit_mode {
TRANSMISSION_MODE_2K,
TRANSMISSION_MODE_8K,
TRANSMISSION_MODE_AUTO,
TRANSMISSION_MODE_4K,
TRANSMISSION_MODE_1K,
TRANSMISSION_MODE_16K,
TRANSMISSION_MODE_32K,
} fe_transmit_mode_t;
</programlisting>
<para>Notes:</para>
<para>1) ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
<para>2) If <constant>DTV_TRANSMISSION_MODE</constant> is set the <constant>TRANSMISSION_MODE_AUTO</constant> the
hardware will try to find the correct FFT-size (if capable) and will
use TMCC to fill in the missing parameters.</para>
<para>3) DVB-T specifies 2K and 8K as valid sizes.</para>
<para>4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K.</para>
</section>
<section id="DTV_GUARD_INTERVAL">
<title><constant>DTV_GUARD_INTERVAL</constant></title>
<para>Possible values are:</para>
<programlisting>
typedef enum fe_guard_interval {
GUARD_INTERVAL_1_32,
GUARD_INTERVAL_1_16,
GUARD_INTERVAL_1_8,
GUARD_INTERVAL_1_4,
GUARD_INTERVAL_AUTO,
GUARD_INTERVAL_1_128,
GUARD_INTERVAL_19_128,
GUARD_INTERVAL_19_256,
} fe_guard_interval_t;
</programlisting>
<para>Notes:</para>
<para>1) If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
try to find the correct guard interval (if capable) and will use TMCC to fill
in the missing parameters.</para>
<para>2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present</para>
</section>
</section>
<section id="isdbt">
<title>ISDB-T frontend</title>
<para>This section describes shortly what are the possible parameters in the Linux
@ -32,73 +353,6 @@
<para>Parameters used by ISDB-T and ISDB-Tsb.</para>
<section id="isdbt-parms">
<title>Parameters that are common with DVB-T and ATSC</title>
<section id="isdbt-freq">
<title><constant>DTV_FREQUENCY</constant></title>
<para>Central frequency of the channel.</para>
<para>For ISDB-T the channels are usually transmitted with an offset of 143kHz. E.g. a
valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
the channel which is 6MHz.</para>
<para>As in ISDB-Tsb the channel consists of only one or three segments the
frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
central frequency of the channel is expected.</para>
</section>
<section id="isdbt-bw">
<title><constant>DTV_BANDWIDTH_HZ</constant> (optional)</title>
<para>Possible values:</para>
<para>For ISDB-T it should be always 6000000Hz (6MHz)</para>
<para>For ISDB-Tsb it can vary depending on the number of connected segments</para>
<para>Note: Hardware specific values might be given here, but standard
applications should not bother to set a value to this field as
standard demods are ignoring it anyway.</para>
<para>Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from
other parameters (DTV_ISDBT_SB_SEGMENT_IDX,
DTV_ISDBT_SB_SEGMENT_COUNT).</para>
</section>
<section id="isdbt-delivery-sys">
<title><constant>DTV_DELIVERY_SYSTEM</constant></title>
<para>Possible values: <constant>SYS_ISDBT</constant></para>
</section>
<section id="isdbt-tx-mode">
<title><constant>DTV_TRANSMISSION_MODE</constant></title>
<para>ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
<para>Possible values: <constant>TRANSMISSION_MODE_2K</constant>, <constant>TRANSMISSION_MODE_8K</constant>,
<constant>TRANSMISSION_MODE_AUTO</constant>, <constant>TRANSMISSION_MODE_4K</constant></para>
<para>If <constant>DTV_TRANSMISSION_MODE</constant> is set the <constant>TRANSMISSION_MODE_AUTO</constant> the
hardware will try to find the correct FFT-size (if capable) and will
use TMCC to fill in the missing parameters.</para>
<para><constant>TRANSMISSION_MODE_4K</constant> is added at the same time as the other new parameters.</para>
</section>
<section id="isdbt-guard-interval">
<title><constant>DTV_GUARD_INTERVAL</constant></title>
<para>Possible values: <constant>GUARD_INTERVAL_1_32</constant>, <constant>GUARD_INTERVAL_1_16</constant>, <constant>GUARD_INTERVAL_1_8</constant>,
<constant>GUARD_INTERVAL_1_4</constant>, <constant>GUARD_INTERVAL_AUTO</constant></para>
<para>If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
try to find the correct guard interval (if capable) and will use TMCC to fill
in the missing parameters.</para>
</section>
</section>
<section id="isdbt-new-parms">
<title>ISDB-T only parameters</title>
@ -314,5 +568,20 @@
</section>
</section>
</section>
<section id="dvbt2-params">
<title>DVB-T2 parameters</title>
<para>This section covers parameters that apply only to the DVB-T2 delivery method. DVB-T2
support is currently in the early stages development so expect this section to grow
and become more detailed with time.</para>
<section id="dvbt2-plp-id">
<title><constant>DTV_DVBT2_PLP_ID</constant></title>
<para>DVB-T2 supports Physical Layer Pipes (PLP) to allow transmission of
many data types via a single multiplex. The API will soon support this
at which point this section will be expanded.</para>
</section>
</section>
</section>
</section>

View File

@ -176,14 +176,20 @@ typedef enum fe_transmit_mode {
TRANSMISSION_MODE_2K,
TRANSMISSION_MODE_8K,
TRANSMISSION_MODE_AUTO,
TRANSMISSION_MODE_4K
TRANSMISSION_MODE_4K,
TRANSMISSION_MODE_1K,
TRANSMISSION_MODE_16K,
TRANSMISSION_MODE_32K,
} fe_transmit_mode_t;
typedef enum fe_bandwidth {
BANDWIDTH_8_MHZ,
BANDWIDTH_7_MHZ,
BANDWIDTH_6_MHZ,
BANDWIDTH_AUTO
BANDWIDTH_AUTO,
BANDWIDTH_5_MHZ,
BANDWIDTH_10_MHZ,
BANDWIDTH_1_712_MHZ,
} fe_bandwidth_t;
@ -192,7 +198,10 @@ typedef enum fe_guard_interval {
GUARD_INTERVAL_1_16,
GUARD_INTERVAL_1_8,
GUARD_INTERVAL_1_4,
GUARD_INTERVAL_AUTO
GUARD_INTERVAL_AUTO,
GUARD_INTERVAL_1_128,
GUARD_INTERVAL_19_128,
GUARD_INTERVAL_19_256,
} fe_guard_interval_t;
@ -306,7 +315,9 @@ struct dvb_frontend_event {
#define DTV_ISDBS_TS_ID 42
#define DTV_MAX_COMMAND DTV_ISDBS_TS_ID
#define DTV_DVBT2_PLP_ID 43
#define DTV_MAX_COMMAND DTV_DVBT2_PLP_ID
typedef enum fe_pilot {
PILOT_ON,
@ -338,6 +349,7 @@ typedef enum fe_delivery_system {
SYS_DMBTH,
SYS_CMMB,
SYS_DAB,
SYS_DVBT2,
} fe_delivery_system_t;
struct dtv_cmds_h {

View File

@ -270,6 +270,7 @@
<!ENTITY sub-write SYSTEM "v4l/func-write.xml">
<!ENTITY sub-io SYSTEM "v4l/io.xml">
<!ENTITY sub-grey SYSTEM "v4l/pixfmt-grey.xml">
<!ENTITY sub-m420 SYSTEM "v4l/pixfmt-m420.xml">
<!ENTITY sub-nv12 SYSTEM "v4l/pixfmt-nv12.xml">
<!ENTITY sub-nv12m SYSTEM "v4l/pixfmt-nv12m.xml">
<!ENTITY sub-nv12mt SYSTEM "v4l/pixfmt-nv12mt.xml">
@ -295,6 +296,7 @@
<!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
<!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml">
<!ENTITY sub-y12 SYSTEM "v4l/pixfmt-y12.xml">
<!ENTITY sub-y10b SYSTEM "v4l/pixfmt-y10b.xml">
<!ENTITY sub-pixfmt SYSTEM "v4l/pixfmt.xml">
<!ENTITY sub-cropcap SYSTEM "v4l/vidioc-cropcap.xml">
<!ENTITY sub-dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">

View File

@ -0,0 +1,147 @@
<refentry id="V4L2-PIX-FMT-M420">
<refmeta>
<refentrytitle>V4L2_PIX_FMT_M420 ('M420')</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
<refname><constant>V4L2_PIX_FMT_M420</constant></refname>
<refpurpose>Format with &frac12; horizontal and vertical chroma
resolution, also known as YUV 4:2:0. Hybrid plane line-interleaved
layout.</refpurpose>
</refnamediv>
<refsect1>
<title>Description</title>
<para>M420 is a YUV format with &frac12; horizontal and vertical chroma
subsampling (YUV 4:2:0). Pixels are organized as interleaved luma and
chroma planes. Two lines of luma data are followed by one line of chroma
data.</para>
<para>The luma plane has one byte per pixel. The chroma plane contains
interleaved CbCr pixels subsampled by &frac12; in the horizontal and
vertical directions. Each CbCr pair belongs to four pixels. For example,
Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
Y'<subscript>10</subscript>, Y'<subscript>11</subscript>.</para>
<para>All line lengths are identical: if the Y lines include pad bytes
so do the CbCr lines.</para>
<example>
<title><constant>V4L2_PIX_FMT_M420</constant> 4 &times; 4
pixel image</title>
<formalpara>
<title>Byte Order.</title>
<para>Each cell is one byte.
<informaltable frame="none">
<tgroup cols="5" align="center">
<colspec align="left" colwidth="2*" />
<tbody valign="top">
<row>
<entry>start&nbsp;+&nbsp;0:</entry>
<entry>Y'<subscript>00</subscript></entry>
<entry>Y'<subscript>01</subscript></entry>
<entry>Y'<subscript>02</subscript></entry>
<entry>Y'<subscript>03</subscript></entry>
</row>
<row>
<entry>start&nbsp;+&nbsp;4:</entry>
<entry>Y'<subscript>10</subscript></entry>
<entry>Y'<subscript>11</subscript></entry>
<entry>Y'<subscript>12</subscript></entry>
<entry>Y'<subscript>13</subscript></entry>
</row>
<row>
<entry>start&nbsp;+&nbsp;8:</entry>
<entry>Cb<subscript>00</subscript></entry>
<entry>Cr<subscript>00</subscript></entry>
<entry>Cb<subscript>01</subscript></entry>
<entry>Cr<subscript>01</subscript></entry>
</row>
<row>
<entry>start&nbsp;+&nbsp;16:</entry>
<entry>Y'<subscript>20</subscript></entry>
<entry>Y'<subscript>21</subscript></entry>
<entry>Y'<subscript>22</subscript></entry>
<entry>Y'<subscript>23</subscript></entry>
</row>
<row>
<entry>start&nbsp;+&nbsp;20:</entry>
<entry>Y'<subscript>30</subscript></entry>
<entry>Y'<subscript>31</subscript></entry>
<entry>Y'<subscript>32</subscript></entry>
<entry>Y'<subscript>33</subscript></entry>
</row>
<row>
<entry>start&nbsp;+&nbsp;24:</entry>
<entry>Cb<subscript>10</subscript></entry>
<entry>Cr<subscript>10</subscript></entry>
<entry>Cb<subscript>11</subscript></entry>
<entry>Cr<subscript>11</subscript></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</formalpara>
<formalpara>
<title>Color Sample Location.</title>
<para>
<informaltable frame="none">
<tgroup cols="7" align="center">
<tbody valign="top">
<row>
<entry></entry>
<entry>0</entry><entry></entry><entry>1</entry><entry></entry>
<entry>2</entry><entry></entry><entry>3</entry>
</row>
<row>
<entry>0</entry>
<entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
<entry>Y</entry><entry></entry><entry>Y</entry>
</row>
<row>
<entry></entry>
<entry></entry><entry>C</entry><entry></entry><entry></entry>
<entry></entry><entry>C</entry><entry></entry>
</row>
<row>
<entry>1</entry>
<entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
<entry>Y</entry><entry></entry><entry>Y</entry>
</row>
<row>
<entry></entry>
</row>
<row>
<entry>2</entry>
<entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
<entry>Y</entry><entry></entry><entry>Y</entry>
</row>
<row>
<entry></entry>
<entry></entry><entry>C</entry><entry></entry><entry></entry>
<entry></entry><entry>C</entry><entry></entry>
</row>
<row>
<entry>3</entry>
<entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
<entry>Y</entry><entry></entry><entry>Y</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</formalpara>
</example>
</refsect1>
</refentry>
<!--
Local Variables:
mode: sgml
sgml-parent-document: "pixfmt.sgml"
indent-tabs-mode: nil
End:
-->

View File

@ -0,0 +1,43 @@
<refentry id="V4L2-PIX-FMT-Y10BPACK">
<refmeta>
<refentrytitle>V4L2_PIX_FMT_Y10BPACK ('Y10B')</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
<refname><constant>V4L2_PIX_FMT_Y10BPACK</constant></refname>
<refpurpose>Grey-scale image as a bit-packed array</refpurpose>
</refnamediv>
<refsect1>
<title>Description</title>
<para>This is a packed grey-scale image format with a depth of 10 bits per
pixel. Pixels are stored in a bit-packed array of 10bit bits per pixel,
with no padding between them and with the most significant bits coming
first from the left.</para>
<example>
<title><constant>V4L2_PIX_FMT_Y10BPACK</constant> 4 pixel data stream taking 5 bytes</title>
<formalpara>
<title>Bit-packed representation</title>
<para>pixels cross the byte boundary and have a ratio of 5 bytes for each 4
pixels.
<informaltable frame="all">
<tgroup cols="5" align="center">
<colspec align="left" colwidth="2*" />
<tbody valign="top">
<row>
<entry>Y'<subscript>00[9:2]</subscript></entry>
<entry>Y'<subscript>00[1:0]</subscript>Y'<subscript>01[9:4]</subscript></entry>
<entry>Y'<subscript>01[3:0]</subscript>Y'<subscript>02[9:6]</subscript></entry>
<entry>Y'<subscript>02[5:0]</subscript>Y'<subscript>03[9:8]</subscript></entry>
<entry>Y'<subscript>03[7:0]</subscript></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</formalpara>
</example>
</refsect1>
</refentry>

View File

@ -697,6 +697,7 @@ information.</para>
&sub-grey;
&sub-y10;
&sub-y12;
&sub-y10b;
&sub-y16;
&sub-yuyv;
&sub-uyvy;
@ -712,6 +713,7 @@ information.</para>
&sub-nv12m;
&sub-nv12mt;
&sub-nv16;
&sub-m420;
</section>
<section>

View File

@ -2522,5 +2522,51 @@
</tgroup>
</table>
</section>
<section>
<title>JPEG Compressed Formats</title>
<para>Those data formats consist of an ordered sequence of 8-bit bytes
obtained from JPEG compression process. Additionally to the
<constant>_JPEG</constant> prefix the format code is made of
the following information.
<itemizedlist>
<listitem>The number of bus samples per entropy encoded byte.</listitem>
<listitem>The bus width.</listitem>
</itemizedlist>
<para>For instance, for a JPEG baseline process and an 8-bit bus width
the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>.
</para>
</para>
<para>The following table lists existing JPEG compressed formats.</para>
<table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-jpeg">
<title>JPEG Formats</title>
<tgroup cols="3">
<colspec colname="id" align="left" />
<colspec colname="code" align="left"/>
<colspec colname="remarks" align="left"/>
<thead>
<row>
<entry>Identifier</entry>
<entry>Code</entry>
<entry>Remarks</entry>
</row>
</thead>
<tbody valign="top">
<row id="V4L2-MBUS-FMT-JPEG-1X8">
<entry>V4L2_MBUS_FMT_JPEG_1X8</entry>
<entry>0x4001</entry>
<entry>Besides of its usage for the parallel bus this format is
recommended for transmission of JPEG data over MIPI CSI bus
using the User Defined 8-bit Data types.
</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
</section>
</section>

View File

@ -311,6 +311,9 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
#define <link linkend="V4L2-PIX-FMT-Y10">V4L2_PIX_FMT_Y10</link> v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */
#define <link linkend="V4L2-PIX-FMT-Y16">V4L2_PIX_FMT_Y16</link> v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */
/* Grey bit-packed formats */
#define <link linkend="V4L2-PIX-FMT-Y10BPACK">V4L2_PIX_FMT_Y10BPACK</link> v4l2_fourcc('Y', '1', '0', 'B') /* 10 Greyscale bit-packed */
/* Palette formats */
#define <link linkend="V4L2-PIX-FMT-PAL8">V4L2_PIX_FMT_PAL8</link> v4l2_fourcc('P', 'A', 'L', '8') /* 8 8-bit palette */
@ -333,6 +336,7 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
#define <link linkend="V4L2-PIX-FMT-YUV420">V4L2_PIX_FMT_YUV420</link> v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
#define <link linkend="V4L2-PIX-FMT-HI240">V4L2_PIX_FMT_HI240</link> v4l2_fourcc('H', 'I', '2', '4') /* 8 8-bit color */
#define <link linkend="V4L2-PIX-FMT-HM12">V4L2_PIX_FMT_HM12</link> v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */
#define <link linkend="V4L2-PIX-FMT-M420">V4L2_PIX_FMT_M420</link> v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */
/* two planes -- one Y, one Cr + Cb interleaved */
#define <link linkend="V4L2-PIX-FMT-NV12">V4L2_PIX_FMT_NV12</link> v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */

View File

@ -551,3 +551,26 @@ Why: These legacy callbacks should no longer be used as i2c-core offers
Who: Jean Delvare <khali@linux-fr.org>
----------------------------
What: Support for UVCIOC_CTRL_ADD in the uvcvideo driver
When: 2.6.42
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: 2.6.42
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: 2.6.42
Why: Superseded by the UVCIOC_CTRL_QUERY ioctl.
Who: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
----------------------------

View File

@ -166,7 +166,6 @@ Code Seq#(hex) Include File Comments
'T' all arch/x86/include/asm/ioctls.h conflict!
'T' C0-DF linux/if_tun.h conflict!
'U' all sound/asound.h conflict!
'U' 00-0F drivers/media/video/uvc/uvcvideo.h conflict!
'U' 00-CF linux/uinput.h conflict!
'U' 00-EF linux/usbdevice_fs.h
'U' C0-CF drivers/bluetooth/hci_uart.h
@ -259,6 +258,7 @@ Code Seq#(hex) Include File Comments
't' 80-8F linux/isdn_ppp.h
't' 90 linux/toshiba.h
'u' 00-1F linux/smb_fs.h gone
'u' 20-3F linux/uvcvideo.h USB video class host driver
'v' 00-1F linux/ext2_fs.h conflict!
'v' 00-1F linux/fs.h conflict!
'v' 00-0F linux/sonypi.h conflict!

View File

@ -54,7 +54,7 @@
53 -> Pinnacle Hybrid Pro (em2881)
54 -> Kworld VS-DVB-T 323UR (em2882) [eb1a:e323]
55 -> Terratec Cinnergy Hybrid T USB XS (em2882) (em2882) [0ccd:005e,0ccd:0042]
56 -> Pinnacle Hybrid Pro (2) (em2882) [2304:0226]
56 -> Pinnacle Hybrid Pro (330e) (em2882) [2304:0226]
57 -> Kworld PlusTV HD Hybrid 330 (em2883) [eb1a:a316]
58 -> Compro VideoMate ForYou/Stereo (em2820/em2840) [185b:2041]
60 -> Hauppauge WinTV HVR 850 (em2883) [2040:651f]

View File

@ -130,7 +130,6 @@ Card number: 4
Note: No module for the mse3000 is available yet
Note: No module for the vpx3224 is available yet
Note: use encoder=X or decoder=X for non-default i2c chips
===========================

View File

@ -275,6 +275,7 @@ pac7302 093a:2629 Genious iSlim 300
pac7302 093a:262a Webcam 300k
pac7302 093a:262c Philips SPC 230 NC
jeilinj 0979:0280 Sakar 57379
jeilinj 0979:0280 Sportscam DV15
zc3xx 0ac8:0302 Z-star Vimicro zc0302
vc032x 0ac8:0321 Vimicro generic vc0321
vc032x 0ac8:0323 Vimicro Vc0323

View File

@ -0,0 +1,239 @@
Linux USB Video Class (UVC) driver
==================================
This file documents some driver-specific aspects of the UVC driver, such as
driver-specific ioctls and implementation notes.
Questions and remarks can be sent to the Linux UVC development mailing list at
linux-uvc-devel@lists.berlios.de.
Extension Unit (XU) support
---------------------------
1. Introduction
The UVC specification allows for vendor-specific extensions through extension
units (XUs). The Linux UVC driver supports extension unit controls (XU controls)
through two separate mechanisms:
- through mappings of XU controls to V4L2 controls
- through a driver-specific ioctl interface
The first one allows generic V4L2 applications to use XU controls by mapping
certain XU controls onto V4L2 controls, which then show up during ordinary
control enumeration.
The second mechanism requires uvcvideo-specific knowledge for the application to
access XU controls but exposes the entire UVC XU concept to user space for
maximum flexibility.
Both mechanisms complement each other and are described in more detail below.
2. Control mappings
The UVC driver provides an API for user space applications to define so-called
control mappings at runtime. These allow for individual XU controls or byte
ranges thereof to be mapped to new V4L2 controls. Such controls appear and
function exactly like normal V4L2 controls (i.e. the stock controls, such as
brightness, contrast, etc.). However, reading or writing of such a V4L2 controls
triggers a read or write of the associated XU control.
The ioctl used to create these control mappings is called UVCIOC_CTRL_MAP.
Previous driver versions (before 0.2.0) required another ioctl to be used
beforehand (UVCIOC_CTRL_ADD) to pass XU control information to the UVC driver.
This is no longer necessary as newer uvcvideo versions query the information
directly from the device.
For details on the UVCIOC_CTRL_MAP ioctl please refer to the section titled
"IOCTL reference" below.
3. Driver specific XU control interface
For applications that need to access XU controls directly, e.g. for testing
purposes, firmware upload, or accessing binary controls, a second mechanism to
access XU controls is provided in the form of a driver-specific ioctl, namely
UVCIOC_CTRL_QUERY.
A call to this ioctl allows applications to send queries to the UVC driver that
directly map to the low-level UVC control requests.
In order to make such a request the UVC unit ID of the control's extension unit
and the control selector need to be known. This information either needs to be
hardcoded in the application or queried using other ways such as by parsing the
UVC descriptor or, if available, using the media controller API to enumerate a
device's entities.
Unless the control size is already known it is necessary to first make a
UVC_GET_LEN requests in order to be able to allocate a sufficiently large buffer
and set the buffer size to the correct value. Similarly, to find out whether
UVC_GET_CUR or UVC_SET_CUR are valid requests for a given control, a
UVC_GET_INFO request should be made. The bits 0 (GET supported) and 1 (SET
supported) of the resulting byte indicate which requests are valid.
With the addition of the UVCIOC_CTRL_QUERY ioctl the UVCIOC_CTRL_GET and
UVCIOC_CTRL_SET ioctls have become obsolete since their functionality is a
subset of the former ioctl. For the time being they are still supported but
application developers are encouraged to use UVCIOC_CTRL_QUERY instead.
For details on the UVCIOC_CTRL_QUERY ioctl please refer to the section titled
"IOCTL reference" below.
4. Security
The API doesn't currently provide a fine-grained access control facility. The
UVCIOC_CTRL_ADD and UVCIOC_CTRL_MAP ioctls require super user permissions.
Suggestions on how to improve this are welcome.
5. Debugging
In order to debug problems related to XU controls or controls in general it is
recommended to enable the UVC_TRACE_CONTROL bit in the module parameter 'trace'.
This causes extra output to be written into the system log.
6. IOCTL reference
---- UVCIOC_CTRL_MAP - Map a UVC control to a V4L2 control ----
Argument: struct uvc_xu_control_mapping
Description:
This ioctl creates a mapping between a UVC control or part of a UVC
control and a V4L2 control. Once mappings are defined, userspace
applications can access vendor-defined UVC control through the V4L2
control API.
To create a mapping, applications fill the uvc_xu_control_mapping
structure with information about an existing UVC control defined with
UVCIOC_CTRL_ADD and a new V4L2 control.
A UVC control can be mapped to several V4L2 controls. For instance,
a UVC pan/tilt control could be mapped to separate pan and tilt V4L2
controls. The UVC control is divided into non overlapping fields using
the 'size' and 'offset' fields and are then independantly mapped to
V4L2 control.
For signed integer V4L2 controls the data_type field should be set to
UVC_CTRL_DATA_TYPE_SIGNED. Other values are currently ignored.
Return value:
On success 0 is returned. On error -1 is returned and errno is set
appropriately.
ENOMEM
Not enough memory to perform the operation.
EPERM
Insufficient privileges (super user privileges are required).
EINVAL
No such UVC control.
EOVERFLOW
The requested offset and size would overflow the UVC control.
EEXIST
Mapping already exists.
Data types:
* struct uvc_xu_control_mapping
__u32 id V4L2 control identifier
__u8 name[32] V4L2 control name
__u8 entity[16] UVC extension unit GUID
__u8 selector UVC control selector
__u8 size V4L2 control size (in bits)
__u8 offset V4L2 control offset (in bits)
enum v4l2_ctrl_type
v4l2_type V4L2 control type
enum uvc_control_data_type
data_type UVC control data type
struct uvc_menu_info
*menu_info Array of menu entries (for menu controls only)
__u32 menu_count Number of menu entries (for menu controls only)
* struct uvc_menu_info
__u32 value Menu entry value used by the device
__u8 name[32] Menu entry name
* enum uvc_control_data_type
UVC_CTRL_DATA_TYPE_RAW Raw control (byte array)
UVC_CTRL_DATA_TYPE_SIGNED Signed integer
UVC_CTRL_DATA_TYPE_UNSIGNED Unsigned integer
UVC_CTRL_DATA_TYPE_BOOLEAN Boolean
UVC_CTRL_DATA_TYPE_ENUM Enumeration
UVC_CTRL_DATA_TYPE_BITMASK Bitmask
---- UVCIOC_CTRL_QUERY - Query a UVC XU control ----
Argument: struct uvc_xu_control_query
Description:
This ioctl queries a UVC XU control identified by its extension unit ID
and control selector.
There are a number of different queries available that closely
correspond to the low-level control requests described in the UVC
specification. These requests are:
UVC_GET_CUR
Obtain the current value of the control.
UVC_GET_MIN
Obtain the minimum value of the control.
UVC_GET_MAX
Obtain the maximum value of the control.
UVC_GET_DEF
Obtain the default value of the control.
UVC_GET_RES
Query the resolution of the control, i.e. the step size of the
allowed control values.
UVC_GET_LEN
Query the size of the control in bytes.
UVC_GET_INFO
Query the control information bitmap, which indicates whether
get/set requests are supported.
UVC_SET_CUR
Update the value of the control.
Applications must set the 'size' field to the correct length for the
control. Exceptions are the UVC_GET_LEN and UVC_GET_INFO queries, for
which the size must be set to 2 and 1, respectively. The 'data' field
must point to a valid writable buffer big enough to hold the indicated
number of data bytes.
Data is copied directly from the device without any driver-side
processing. Applications are responsible for data buffer formatting,
including little-endian/big-endian conversion. This is particularly
important for the result of the UVC_GET_LEN requests, which is always
returned as a little-endian 16-bit integer by the device.
Return value:
On success 0 is returned. On error -1 is returned and errno is set
appropriately.
ENOENT
The device does not support the given control or the specified
extension unit could not be found.
ENOBUFS
The specified buffer size is incorrect (too big or too small).
EINVAL
An invalid request code was passed.
EBADRQC
The given request is not supported by the given control.
EFAULT
The data pointer references an inaccessible memory area.
Data types:
* struct uvc_xu_control_query
__u8 unit Extension unit ID
__u8 selector Control selector
__u8 query Request code to send to the device
__u16 size Control data size (in bytes)
__u8 *data Control value

View File

@ -21,6 +21,7 @@ config SUPERH
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_GENERIC_HARDIRQS
select HAVE_SPARSE_IRQ
select IRQ_FORCED_THREADING
select RTC_LIB
select GENERIC_ATOMIC64
select GENERIC_IRQ_SHOW

View File

@ -482,7 +482,7 @@ static struct i2c_board_info ts_i2c_clients = {
.irq = IRQ0,
};
#if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
/* SDHI0 */
static void sdhi0_set_pwr(struct platform_device *pdev, int state)
{
@ -522,7 +522,7 @@ static struct platform_device sdhi0_device = {
},
};
#if !defined(CONFIG_MMC_SH_MMCIF)
#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
/* SDHI1 */
static void sdhi1_set_pwr(struct platform_device *pdev, int state)
{
@ -836,7 +836,7 @@ static struct platform_device vou_device = {
},
};
#if defined(CONFIG_MMC_SH_MMCIF)
#if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
/* SH_MMCIF */
static void mmcif_set_pwr(struct platform_device *pdev, int state)
{
@ -898,9 +898,9 @@ static struct platform_device *ecovec_devices[] __initdata = {
&ceu0_device,
&ceu1_device,
&keysc_device,
#if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
&sdhi0_device,
#if !defined(CONFIG_MMC_SH_MMCIF)
#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
&sdhi1_device,
#endif
#else
@ -912,7 +912,7 @@ static struct platform_device *ecovec_devices[] __initdata = {
&fsi_device,
&irda_device,
&vou_device,
#if defined(CONFIG_MMC_SH_MMCIF)
#if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
&sh_mmcif_device,
#endif
};
@ -1180,7 +1180,7 @@ static int __init arch_setup(void)
gpio_direction_input(GPIO_PTR5);
gpio_direction_input(GPIO_PTR6);
#if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
/* enable SDHI0 on CN11 (needs DS2.4 set to ON) */
gpio_request(GPIO_FN_SDHI0CD, NULL);
gpio_request(GPIO_FN_SDHI0WP, NULL);
@ -1193,7 +1193,7 @@ static int __init arch_setup(void)
gpio_request(GPIO_PTB6, NULL);
gpio_direction_output(GPIO_PTB6, 0);
#if !defined(CONFIG_MMC_SH_MMCIF)
#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
/* enable SDHI1 on CN12 (needs DS2.6,7 set to ON,OFF) */
gpio_request(GPIO_FN_SDHI1CD, NULL);
gpio_request(GPIO_FN_SDHI1WP, NULL);
@ -1284,7 +1284,7 @@ static int __init arch_setup(void)
gpio_request(GPIO_PTU5, NULL);
gpio_direction_output(GPIO_PTU5, 0);
#if defined(CONFIG_MMC_SH_MMCIF)
#if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
/* enable MMCIF (needs DS2.6,7 set to OFF,ON) */
gpio_request(GPIO_FN_MMC_D7, NULL);
gpio_request(GPIO_FN_MMC_D6, NULL);

View File

@ -115,7 +115,7 @@ CONFIG_USB_GADGET=y
CONFIG_USB_FILE_STORAGE=m
CONFIG_MMC=y
CONFIG_MMC_SPI=y
CONFIG_MMC_TMIO=y
CONFIG_MMC_SDHI=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_RS5C372=y
CONFIG_UIO=y

View File

@ -70,7 +70,7 @@ CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_MMC=y
CONFIG_MMC_TMIO=y
CONFIG_MMC_SDHI=y
CONFIG_MMC_SH_MMCIF=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y

View File

@ -6,7 +6,7 @@
#include <linux/io.h>
#include "pci-sh4.h"
int __init pcibios_map_platform_irq(u8 slot, u8 pin)
int __init pcibios_map_platform_irq(struct pci_dev *, u8 slot, u8 pin)
{
switch (slot) {
case 0: return 13;

View File

@ -10,9 +10,6 @@
/* Generic stack tracer with callbacks */
struct stacktrace_ops {
void (*warning)(void *data, char *msg);
/* msg must contain %s for the symbol */
void (*warning_symbol)(void *data, char *msg, unsigned long symbol);
void (*address)(void *data, unsigned long address, int reliable);
/* On negative return stop dumping */
int (*stack)(void *data, char *name);

View File

@ -373,8 +373,9 @@
#define __NR_open_by_handle_at 360
#define __NR_clock_adjtime 361
#define __NR_syncfs 362
#define __NR_sendmmsg 363
#define NR_syscalls 363
#define NR_syscalls 364
#ifdef __KERNEL__

View File

@ -394,10 +394,11 @@
#define __NR_open_by_handle_at 371
#define __NR_clock_adjtime 372
#define __NR_syncfs 373
#define __NR_sendmmsg 374
#ifdef __KERNEL__
#define NR_syscalls 374
#define NR_syscalls 375
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR

View File

@ -17,7 +17,5 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/
obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG_LEGACY) += clock-cpg.o
obj-$(CONFIG_SH_FPU) += fpu.o
obj-$(CONFIG_SH_FPU_EMU) += fpu.o
obj-y += irq/ init.o clock.o hwblk.o proc.o
obj-y += irq/ init.o clock.o fpu.o hwblk.o proc.o

View File

@ -157,7 +157,7 @@ static int default_platform_runtime_suspend(struct device *dev)
might_sleep();
/* catch misconfigured drivers not starting with resume */
if (test_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags)) {
if (test_bit(PDEV_ARCHDATA_FLAG_INIT, &ad->flags)) {
ret = -EINVAL;
goto out;
}
@ -170,8 +170,8 @@ static int default_platform_runtime_suspend(struct device *dev)
/* put device on idle list */
spin_lock_irqsave(&hwblk_lock, flags);
list_add_tail(&pdev->archdata.entry, &hwblk_idle_list);
__set_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags);
list_add_tail(&ad->entry, &hwblk_idle_list);
__set_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags);
spin_unlock_irqrestore(&hwblk_lock, flags);
/* increase idle count */

View File

@ -69,19 +69,6 @@ stack_reader_dump(struct task_struct *task, struct pt_regs *regs,
}
}
static void
print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
{
printk(data);
print_symbol(msg, symbol);
printk("\n");
}
static void print_trace_warning(void *data, char *msg)
{
printk("%s%s\n", (char *)data, msg);
}
static int print_trace_stack(void *data, char *name)
{
printk("%s <%s> ", (char *)data, name);
@ -98,8 +85,6 @@ static void print_trace_address(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops print_trace_ops = {
.warning = print_trace_warning,
.warning_symbol = print_trace_warning_symbol,
.stack = print_trace_stack,
.address = print_trace_address,
};

View File

@ -93,6 +93,8 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
#endif
switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_SH_NONE:
break;
case R_SH_DIR32:
value = get_unaligned(location);
value += relocation;

View File

@ -14,16 +14,6 @@
#include <asm/unwinder.h>
#include <asm/ptrace.h>
static void callchain_warning(void *data, char *msg)
{
}
static void
callchain_warning_symbol(void *data, char *msg, unsigned long symbol)
{
}
static int callchain_stack(void *data, char *name)
{
return 0;
@ -38,8 +28,6 @@ static void callchain_address(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops callchain_ops = {
.warning = callchain_warning,
.warning_symbol = callchain_warning_symbol,
.stack = callchain_stack,
.address = callchain_address,
};

View File

@ -17,15 +17,6 @@
#include <asm/ptrace.h>
#include <asm/stacktrace.h>
static void save_stack_warning(void *data, char *msg)
{
}
static void
save_stack_warning_symbol(void *data, char *msg, unsigned long symbol)
{
}
static int save_stack_stack(void *data, char *name)
{
return 0;
@ -51,8 +42,6 @@ static void save_stack_address(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops save_stack_ops = {
.warning = save_stack_warning,
.warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address,
};
@ -88,8 +77,6 @@ save_stack_address_nosched(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops save_stack_ops_nosched = {
.warning = save_stack_warning,
.warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address_nosched,
};

View File

@ -380,3 +380,4 @@ ENTRY(sys_call_table)
.long sys_open_by_handle_at /* 360 */
.long sys_clock_adjtime
.long sys_syncfs
.long sys_sendmmsg

View File

@ -400,3 +400,4 @@ sys_call_table:
.long sys_open_by_handle_at
.long sys_clock_adjtime
.long sys_syncfs
.long sys_sendmmsg

View File

@ -23,17 +23,6 @@
#include <asm/sections.h>
#include <asm/stacktrace.h>
static void backtrace_warning_symbol(void *data, char *msg,
unsigned long symbol)
{
/* Ignore warnings */
}
static void backtrace_warning(void *data, char *msg)
{
/* Ignore warnings */
}
static int backtrace_stack(void *data, char *name)
{
/* Yes, we want all stacks */
@ -49,8 +38,6 @@ static void backtrace_address(void *data, unsigned long addr, int reliable)
}
static struct stacktrace_ops backtrace_ops = {
.warning = backtrace_warning,
.warning_symbol = backtrace_warning_symbol,
.stack = backtrace_stack,
.address = backtrace_address,
};

View File

@ -24,6 +24,7 @@
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/irq.h>
#include <linux/err.h>
#include <linux/clocksource.h>
@ -152,10 +153,12 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
{
int ret;
/* enable clock */
/* wake up device and enable clock */
pm_runtime_get_sync(&p->pdev->dev);
ret = clk_enable(p->clk);
if (ret) {
dev_err(&p->pdev->dev, "cannot enable clock\n");
pm_runtime_put_sync(&p->pdev->dev);
return ret;
}
@ -187,8 +190,9 @@ static void sh_cmt_disable(struct sh_cmt_priv *p)
/* disable interrupts in CMT block */
sh_cmt_write(p, CMCSR, 0);
/* stop clock */
/* stop clock and mark device as idle */
clk_disable(p->clk);
pm_runtime_put_sync(&p->pdev->dev);
}
/* private flags */
@ -416,11 +420,15 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
static int sh_cmt_clocksource_enable(struct clocksource *cs)
{
int ret;
struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
p->total_cycles = 0;
return sh_cmt_start(p, FLAG_CLOCKSOURCE);
ret = sh_cmt_start(p, FLAG_CLOCKSOURCE);
if (!ret)
__clocksource_updatefreq_hz(cs, p->rate);
return ret;
}
static void sh_cmt_clocksource_disable(struct clocksource *cs)
@ -448,19 +456,10 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
/* clk_get_rate() needs an enabled clock */
clk_enable(p->clk);
p->rate = clk_get_rate(p->clk) / ((p->width == 16) ? 512 : 8);
clk_disable(p->clk);
/* TODO: calculate good shift from rate and counter bit width */
cs->shift = 0;
cs->mult = clocksource_hz2mult(p->rate, cs->shift);
dev_info(&p->pdev->dev, "used as clock source\n");
clocksource_register(cs);
/* Register with dummy 1 Hz value, gets updated in ->enable() */
clocksource_register_hz(cs, 1);
return 0;
}
@ -665,6 +664,7 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
if (p) {
dev_info(&pdev->dev, "kept as earlytimer\n");
pm_runtime_enable(&pdev->dev);
return 0;
}
@ -679,6 +679,9 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
kfree(p);
platform_set_drvdata(pdev, NULL);
}
if (!is_early_platform_device(pdev))
pm_runtime_enable(&pdev->dev);
return ret;
}

View File

@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/irq.h>
#include <linux/err.h>
#include <linux/clocksource.h>
@ -109,10 +110,12 @@ static int sh_tmu_enable(struct sh_tmu_priv *p)
{
int ret;
/* enable clock */
/* wake up device and enable clock */
pm_runtime_get_sync(&p->pdev->dev);
ret = clk_enable(p->clk);
if (ret) {
dev_err(&p->pdev->dev, "cannot enable clock\n");
pm_runtime_put_sync(&p->pdev->dev);
return ret;
}
@ -141,8 +144,9 @@ static void sh_tmu_disable(struct sh_tmu_priv *p)
/* disable interrupts in TMU block */
sh_tmu_write(p, TCR, 0x0000);
/* stop clock */
/* stop clock and mark device as idle */
clk_disable(p->clk);
pm_runtime_put_sync(&p->pdev->dev);
}
static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
@ -199,8 +203,12 @@ static cycle_t sh_tmu_clocksource_read(struct clocksource *cs)
static int sh_tmu_clocksource_enable(struct clocksource *cs)
{
struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
int ret;
return sh_tmu_enable(p);
ret = sh_tmu_enable(p);
if (!ret)
__clocksource_updatefreq_hz(cs, p->rate);
return ret;
}
static void sh_tmu_clocksource_disable(struct clocksource *cs)
@ -221,17 +229,10 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
cs->mask = CLOCKSOURCE_MASK(32);
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
/* clk_get_rate() needs an enabled clock */
clk_enable(p->clk);
/* channel will be configured at parent clock / 4 */
p->rate = clk_get_rate(p->clk) / 4;
clk_disable(p->clk);
/* TODO: calculate good shift from rate and counter bit width */
cs->shift = 10;
cs->mult = clocksource_hz2mult(p->rate, cs->shift);
dev_info(&p->pdev->dev, "used as clock source\n");
clocksource_register(cs);
/* Register with dummy 1 Hz value, gets updated in ->enable() */
clocksource_register_hz(cs, 1);
return 0;
}
@ -414,6 +415,7 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
if (p) {
dev_info(&pdev->dev, "kept as earlytimer\n");
pm_runtime_enable(&pdev->dev);
return 0;
}
@ -428,6 +430,9 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
kfree(p);
platform_set_drvdata(pdev, NULL);
}
if (!is_early_platform_device(pdev))
pm_runtime_enable(&pdev->dev);
return ret;
}

View File

@ -48,7 +48,7 @@ enum sh_dmae_desc_status {
/*
* Used for write-side mutual exclusion for the global device list,
* read-side synchronization by way of RCU.
* read-side synchronization by way of RCU, and per-controller data.
*/
static DEFINE_SPINLOCK(sh_dmae_lock);
static LIST_HEAD(sh_dmae_devices);
@ -85,22 +85,35 @@ static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
*/
static void sh_dmae_ctl_stop(struct sh_dmae_device *shdev)
{
unsigned short dmaor = dmaor_read(shdev);
unsigned short dmaor;
unsigned long flags;
spin_lock_irqsave(&sh_dmae_lock, flags);
dmaor = dmaor_read(shdev);
dmaor_write(shdev, dmaor & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME));
spin_unlock_irqrestore(&sh_dmae_lock, flags);
}
static int sh_dmae_rst(struct sh_dmae_device *shdev)
{
unsigned short dmaor;
unsigned long flags;
sh_dmae_ctl_stop(shdev);
dmaor = dmaor_read(shdev) | shdev->pdata->dmaor_init;
spin_lock_irqsave(&sh_dmae_lock, flags);
dmaor_write(shdev, dmaor);
if (dmaor_read(shdev) & (DMAOR_AE | DMAOR_NMIF)) {
pr_warning("dma-sh: Can't initialize DMAOR.\n");
return -EINVAL;
dmaor = dmaor_read(shdev) & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME);
dmaor_write(shdev, dmaor | shdev->pdata->dmaor_init);
dmaor = dmaor_read(shdev);
spin_unlock_irqrestore(&sh_dmae_lock, flags);
if (dmaor & (DMAOR_AE | DMAOR_NMIF)) {
dev_warn(shdev->common.dev, "Can't initialize DMAOR.\n");
return -EIO;
}
return 0;
}
@ -184,7 +197,7 @@ static void dmae_init(struct sh_dmae_chan *sh_chan)
static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
{
/* When DMA was working, can not set data to CHCR */
/* If DMA is active, cannot set CHCR. TODO: remove this superfluous check */
if (dmae_is_busy(sh_chan))
return -EBUSY;
@ -374,7 +387,12 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
LIST_HEAD(list);
int descs = sh_chan->descs_allocated;
/* Protect against ISR */
spin_lock_irq(&sh_chan->desc_lock);
dmae_halt(sh_chan);
spin_unlock_irq(&sh_chan->desc_lock);
/* Now no new interrupts will occur */
/* Prepared and not submitted descriptors can still be on the queue */
if (!list_empty(&sh_chan->ld_queue))
@ -384,6 +402,7 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
/* The caller is holding dma_list_mutex */
struct sh_dmae_slave *param = chan->private;
clear_bit(param->slave_id, sh_dmae_slave_used);
chan->private = NULL;
}
spin_lock_bh(&sh_chan->desc_lock);
@ -563,8 +582,6 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy(
if (!chan || !len)
return NULL;
chan->private = NULL;
sh_chan = to_sh_chan(chan);
sg_init_table(&sg, 1);
@ -620,9 +637,9 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
if (!chan)
return -EINVAL;
spin_lock_bh(&sh_chan->desc_lock);
dmae_halt(sh_chan);
spin_lock_bh(&sh_chan->desc_lock);
if (!list_empty(&sh_chan->ld_queue)) {
/* Record partial transfer */
struct sh_desc *desc = list_entry(sh_chan->ld_queue.next,
@ -716,6 +733,14 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all
list_move(&desc->node, &sh_chan->ld_free);
}
}
if (all && !callback)
/*
* Terminating and the loop completed normally: forgive
* uncompleted cookies
*/
sh_chan->completed_cookie = sh_chan->common.cookie;
spin_unlock_bh(&sh_chan->desc_lock);
if (callback)
@ -733,10 +758,6 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all)
{
while (__ld_cleanup(sh_chan, all))
;
if (all)
/* Terminating - forgive uncompleted cookies */
sh_chan->completed_cookie = sh_chan->common.cookie;
}
static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
@ -782,8 +803,10 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan,
sh_dmae_chan_ld_cleanup(sh_chan, false);
last_used = chan->cookie;
/* First read completed cookie to avoid a skew */
last_complete = sh_chan->completed_cookie;
rmb();
last_used = chan->cookie;
BUG_ON(last_complete < 0);
dma_set_tx_state(txstate, last_complete, last_used, 0);
@ -813,8 +836,12 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan,
static irqreturn_t sh_dmae_interrupt(int irq, void *data)
{
irqreturn_t ret = IRQ_NONE;
struct sh_dmae_chan *sh_chan = (struct sh_dmae_chan *)data;
u32 chcr = sh_dmae_readl(sh_chan, CHCR);
struct sh_dmae_chan *sh_chan = data;
u32 chcr;
spin_lock(&sh_chan->desc_lock);
chcr = sh_dmae_readl(sh_chan, CHCR);
if (chcr & CHCR_TE) {
/* DMA stop */
@ -824,10 +851,13 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data)
tasklet_schedule(&sh_chan->tasklet);
}
spin_unlock(&sh_chan->desc_lock);
return ret;
}
static unsigned int sh_dmae_reset(struct sh_dmae_device *shdev)
/* Called from error IRQ or NMI */
static bool sh_dmae_reset(struct sh_dmae_device *shdev)
{
unsigned int handled = 0;
int i;
@ -839,22 +869,32 @@ static unsigned int sh_dmae_reset(struct sh_dmae_device *shdev)
for (i = 0; i < SH_DMAC_MAX_CHANNELS; i++) {
struct sh_dmae_chan *sh_chan = shdev->chan[i];
struct sh_desc *desc;
LIST_HEAD(dl);
if (!sh_chan)
continue;
spin_lock(&sh_chan->desc_lock);
/* Stop the channel */
dmae_halt(sh_chan);
list_splice_init(&sh_chan->ld_queue, &dl);
spin_unlock(&sh_chan->desc_lock);
/* Complete all */
list_for_each_entry(desc, &sh_chan->ld_queue, node) {
list_for_each_entry(desc, &dl, node) {
struct dma_async_tx_descriptor *tx = &desc->async_tx;
desc->mark = DESC_IDLE;
if (tx->callback)
tx->callback(tx->callback_param);
}
list_splice_init(&sh_chan->ld_queue, &sh_chan->ld_free);
spin_lock(&sh_chan->desc_lock);
list_splice(&dl, &sh_chan->ld_free);
spin_unlock(&sh_chan->desc_lock);
handled++;
}
@ -867,10 +907,11 @@ static irqreturn_t sh_dmae_err(int irq, void *data)
{
struct sh_dmae_device *shdev = data;
if (dmaor_read(shdev) & DMAOR_AE)
return IRQ_RETVAL(sh_dmae_reset(data));
else
if (!(dmaor_read(shdev) & DMAOR_AE))
return IRQ_NONE;
sh_dmae_reset(data);
return IRQ_HANDLED;
}
static void dmae_do_tasklet(unsigned long data)
@ -902,17 +943,11 @@ static void dmae_do_tasklet(unsigned long data)
static bool sh_dmae_nmi_notify(struct sh_dmae_device *shdev)
{
unsigned int handled;
/* Fast path out if NMIF is not asserted for this controller */
if ((dmaor_read(shdev) & DMAOR_NMIF) == 0)
return false;
handled = sh_dmae_reset(shdev);
if (handled)
return true;
return false;
return sh_dmae_reset(shdev);
}
static int sh_dmae_nmi_handler(struct notifier_block *self,
@ -982,9 +1017,6 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
tasklet_init(&new_sh_chan->tasklet, dmae_do_tasklet,
(unsigned long)new_sh_chan);
/* Init the channel */
dmae_init(new_sh_chan);
spin_lock_init(&new_sh_chan->desc_lock);
/* Init descripter manage list */
@ -1045,7 +1077,6 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
struct sh_dmae_pdata *pdata = pdev->dev.platform_data;
unsigned long irqflags = IRQF_DISABLED,
chan_flag[SH_DMAC_MAX_CHANNELS] = {};
unsigned long flags;
int errirq, chan_irq[SH_DMAC_MAX_CHANNELS];
int err, i, irq_cnt = 0, irqres = 0;
struct sh_dmae_device *shdev;
@ -1111,11 +1142,11 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
spin_lock_irqsave(&sh_dmae_lock, flags);
spin_lock_irq(&sh_dmae_lock);
list_add_tail_rcu(&shdev->node, &sh_dmae_devices);
spin_unlock_irqrestore(&sh_dmae_lock, flags);
spin_unlock_irq(&sh_dmae_lock);
/* reset dma controller */
/* reset dma controller - only needed as a test */
err = sh_dmae_rst(shdev);
if (err)
goto rst_err;
@ -1218,15 +1249,18 @@ eirqres:
eirq_err:
#endif
rst_err:
spin_lock_irqsave(&sh_dmae_lock, flags);
spin_lock_irq(&sh_dmae_lock);
list_del_rcu(&shdev->node);
spin_unlock_irqrestore(&sh_dmae_lock, flags);
spin_unlock_irq(&sh_dmae_lock);
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
if (dmars)
iounmap(shdev->dmars);
emapdmars:
iounmap(shdev->chan_reg);
synchronize_rcu();
emapchan:
kfree(shdev);
ealloc:
@ -1242,7 +1276,6 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
{
struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
struct resource *res;
unsigned long flags;
int errirq = platform_get_irq(pdev, 0);
dma_async_device_unregister(&shdev->common);
@ -1250,9 +1283,9 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
if (errirq > 0)
free_irq(errirq, shdev);
spin_lock_irqsave(&sh_dmae_lock, flags);
spin_lock_irq(&sh_dmae_lock);
list_del_rcu(&shdev->node);
spin_unlock_irqrestore(&sh_dmae_lock, flags);
spin_unlock_irq(&sh_dmae_lock);
/* channel data remove */
sh_dmae_chan_remove(shdev);
@ -1263,6 +1296,7 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
iounmap(shdev->dmars);
iounmap(shdev->chan_reg);
synchronize_rcu();
kfree(shdev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -1281,12 +1315,78 @@ static void sh_dmae_shutdown(struct platform_device *pdev)
sh_dmae_ctl_stop(shdev);
}
static int sh_dmae_runtime_suspend(struct device *dev)
{
return 0;
}
static int sh_dmae_runtime_resume(struct device *dev)
{
struct sh_dmae_device *shdev = dev_get_drvdata(dev);
return sh_dmae_rst(shdev);
}
#ifdef CONFIG_PM
static int sh_dmae_suspend(struct device *dev)
{
struct sh_dmae_device *shdev = dev_get_drvdata(dev);
int i;
for (i = 0; i < shdev->pdata->channel_num; i++) {
struct sh_dmae_chan *sh_chan = shdev->chan[i];
if (sh_chan->descs_allocated)
sh_chan->pm_error = pm_runtime_put_sync(dev);
}
return 0;
}
static int sh_dmae_resume(struct device *dev)
{
struct sh_dmae_device *shdev = dev_get_drvdata(dev);
int i;
for (i = 0; i < shdev->pdata->channel_num; i++) {
struct sh_dmae_chan *sh_chan = shdev->chan[i];
struct sh_dmae_slave *param = sh_chan->common.private;
if (!sh_chan->descs_allocated)
continue;
if (!sh_chan->pm_error)
pm_runtime_get_sync(dev);
if (param) {
const struct sh_dmae_slave_config *cfg = param->config;
dmae_set_dmars(sh_chan, cfg->mid_rid);
dmae_set_chcr(sh_chan, cfg->chcr);
} else {
dmae_init(sh_chan);
}
}
return 0;
}
#else
#define sh_dmae_suspend NULL
#define sh_dmae_resume NULL
#endif
const struct dev_pm_ops sh_dmae_pm = {
.suspend = sh_dmae_suspend,
.resume = sh_dmae_resume,
.runtime_suspend = sh_dmae_runtime_suspend,
.runtime_resume = sh_dmae_runtime_resume,
};
static struct platform_driver sh_dmae_driver = {
.remove = __exit_p(sh_dmae_remove),
.shutdown = sh_dmae_shutdown,
.driver = {
.owner = THIS_MODULE,
.name = "sh-dma-engine",
.pm = &sh_dmae_pm,
},
};

View File

@ -37,6 +37,7 @@ struct sh_dmae_chan {
int id; /* Raw id of this channel */
u32 __iomem *base;
char dev_id[16]; /* unique name per DMAC of channel */
int pm_error;
};
struct sh_dmae_device {

View File

@ -506,7 +506,13 @@ static int create_core_data(struct platform_data *pdata,
if (attr_no > MAX_CORE_DATA - 1)
return -ERANGE;
/* Skip if it is a HT core, Not an error */
/*
* Provide a single set of attributes for all HT siblings of a core
* to avoid duplicate sensors (the processor ID and core ID of all
* HT siblings of a core is the same).
* Skip if a HT sibling of this core is already online.
* This is not an error.
*/
if (pdata->core_data[attr_no] != NULL)
return 0;
@ -763,10 +769,20 @@ static void __cpuinit put_core_offline(unsigned int cpu)
if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu)
coretemp_remove_core(pdata, &pdev->dev, indx);
/* Online the HT version of this core, if any */
/*
* If a core is taken offline, but a HT sibling of the same core is
* still online, register the alternate sibling. This ensures that
* exactly one set of attributes is provided as long as at least one
* HT sibling of a core is online.
*/
for_each_sibling(i, cpu) {
if (i != cpu) {
get_core_online(i);
/*
* Display temperature sensor data for one HT sibling
* per core only, so abort the loop after one such
* sibling has been found.
*/
break;
}
}

View File

@ -729,3 +729,4 @@ module_exit(sh_mobile_i2c_adap_exit);
MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");
MODULE_AUTHOR("Magnus Damm");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:i2c-sh_mobile");

View File

@ -378,12 +378,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
dev->pci = pci;
/* get chip-revision; this is needed to enable bug-fixes */
err = pci_read_config_dword(pci, PCI_CLASS_REVISION, &dev->revision);
if (err < 0) {
ERR(("pci_read_config_dword() failed.\n"));
goto err_disable;
}
dev->revision &= 0xf;
dev->revision = pci->revision;
/* remap the memory from virtual to physical address */

View File

@ -186,4 +186,12 @@ config MEDIA_TUNER_TDA18218
default m if MEDIA_TUNER_CUSTOMISE
help
NXP TDA18218 silicon tuner driver.
config MEDIA_TUNER_TDA18212
tristate "NXP TDA18212 silicon tuner"
depends on VIDEO_MEDIA && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
NXP TDA18212 silicon tuner driver.
endmenu

View File

@ -25,6 +25,7 @@ obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
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

View File

@ -4024,6 +4024,8 @@ static int mxl5005s_set_params(struct dvb_frontend *fe,
case BANDWIDTH_8_MHZ:
req_bw = MXL5005S_BANDWIDTH_8MHZ;
break;
default:
return -EINVAL;
}
}

View File

@ -0,0 +1,265 @@
/*
* NXP TDA18212HN silicon tuner 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 "tda18212_priv.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
/* write multiple registers */
static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
int len)
{
int ret;
u8 buf[len+1];
struct i2c_msg msg[1] = {
{
.addr = priv->cfg->i2c_address,
.flags = 0,
.len = sizeof(buf),
.buf = buf,
}
};
buf[0] = reg;
memcpy(&buf[1], val, len);
ret = i2c_transfer(priv->i2c, msg, 1);
if (ret == 1) {
ret = 0;
} else {
warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
/* read multiple registers */
static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
int len)
{
int ret;
u8 buf[len];
struct i2c_msg msg[2] = {
{
.addr = priv->cfg->i2c_address,
.flags = 0,
.len = 1,
.buf = &reg,
}, {
.addr = priv->cfg->i2c_address,
.flags = I2C_M_RD,
.len = sizeof(buf),
.buf = buf,
}
};
ret = i2c_transfer(priv->i2c, msg, 2);
if (ret == 2) {
memcpy(val, buf, len);
ret = 0;
} else {
warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
/* write single register */
static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val)
{
return tda18212_wr_regs(priv, reg, &val, 1);
}
/* read single register */
static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val)
{
return tda18212_rd_regs(priv, reg, val, 1);
}
#if 0 /* keep, useful when developing driver */
static void tda18212_dump_regs(struct tda18212_priv *priv)
{
int i;
u8 buf[256];
#define TDA18212_RD_LEN 32
for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN)
tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN);
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf,
sizeof(buf), true);
return;
}
#endif
static int tda18212_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct tda18212_priv *priv = fe->tuner_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
u32 if_khz;
u8 buf[9];
static const u8 bw_params[][3] = {
/* 0f 13 23 */
{ 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */
{ 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */
{ 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */
{ 0x92, 0x53, 0x03 }, /* DVB-C */
};
dbg("%s: delsys=%d RF=%d BW=%d", __func__,
c->delivery_system, c->frequency, c->bandwidth_hz);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
switch (c->delivery_system) {
case SYS_DVBT:
switch (c->bandwidth_hz) {
case 6000000:
if_khz = priv->cfg->if_dvbt_6;
i = 0;
break;
case 7000000:
if_khz = priv->cfg->if_dvbt_7;
i = 1;
break;
case 8000000:
if_khz = priv->cfg->if_dvbt_8;
i = 2;
break;
default:
ret = -EINVAL;
goto error;
}
break;
case SYS_DVBC_ANNEX_AC:
if_khz = priv->cfg->if_dvbc;
i = 3;
break;
default:
ret = -EINVAL;
goto error;
}
ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]);
if (ret)
goto error;
ret = tda18212_wr_reg(priv, 0x06, 0x00);
if (ret)
goto error;
ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]);
if (ret)
goto error;
buf[0] = 0x02;
buf[1] = bw_params[i][1];
buf[2] = 0x03; /* default value */
buf[3] = if_khz / 50;
buf[4] = ((c->frequency / 1000) >> 16) & 0xff;
buf[5] = ((c->frequency / 1000) >> 8) & 0xff;
buf[6] = ((c->frequency / 1000) >> 0) & 0xff;
buf[7] = 0xc1;
buf[8] = 0x01;
ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf));
if (ret)
goto error;
exit:
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
goto exit;
}
static int tda18212_release(struct dvb_frontend *fe)
{
kfree(fe->tuner_priv);
fe->tuner_priv = NULL;
return 0;
}
static const struct dvb_tuner_ops tda18212_tuner_ops = {
.info = {
.name = "NXP TDA18212",
.frequency_min = 48000000,
.frequency_max = 864000000,
.frequency_step = 1000,
},
.release = tda18212_release,
.set_params = tda18212_set_params,
};
struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tda18212_config *cfg)
{
struct tda18212_priv *priv = NULL;
int ret;
u8 val;
priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
if (priv == NULL)
return NULL;
priv->cfg = cfg;
priv->i2c = i2c;
fe->tuner_priv = priv;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
/* check if the tuner is there */
ret = tda18212_rd_reg(priv, 0x00, &val);
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);
if (ret || val != 0xc7) {
kfree(priv);
return NULL;
}
info("NXP TDA18212HN successfully identified.");
memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
sizeof(struct dvb_tuner_ops));
return fe;
}
EXPORT_SYMBOL(tda18212_attach);
MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,48 @@
/*
* NXP TDA18212HN silicon tuner 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.
*/
#ifndef TDA18212_H
#define TDA18212_H
#include "dvb_frontend.h"
struct tda18212_config {
u8 i2c_address;
u16 if_dvbt_6;
u16 if_dvbt_7;
u16 if_dvbt_8;
u16 if_dvbc;
};
#if defined(CONFIG_MEDIA_TUNER_TDA18212) || \
(defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE))
extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tda18212_config *cfg);
#else
static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tda18212_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
#endif

View File

@ -0,0 +1,44 @@
/*
* NXP TDA18212HN silicon tuner 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.
*/
#ifndef TDA18212_PRIV_H
#define TDA18212_PRIV_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;
};
#endif

View File

@ -976,6 +976,10 @@ static int tda18271_set_params(struct dvb_frontend *fe,
tda_warn("bandwidth not set!\n");
return -EINVAL;
}
} else if (fe->ops.info.type == FE_QAM) {
/* DVB-C */
map = &std_map->qam_8;
bw = 8000000;
} else {
tda_warn("modulation type not supported!\n");
return -EINVAL;

View File

@ -628,6 +628,15 @@ static void xc_debug_dump(struct xc5000_priv *priv)
dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
}
/*
* As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
* So, the amount of the needed bandwith is given by:
* Bw = Symbol_rate * (1 + 0.15)
* As such, the maximum symbol rate supported by 6 MHz is given by:
* max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
*/
#define MAX_SYMBOL_RATE_6MHz 5217391
static int xc5000_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
@ -688,21 +697,32 @@ static int xc5000_set_params(struct dvb_frontend *fe,
}
priv->rf_mode = XC_RF_MODE_AIR;
} else if (fe->ops.info.type == FE_QAM) {
dprintk(1, "%s() QAM\n", __func__);
switch (params->u.qam.modulation) {
case QAM_256:
case QAM_AUTO:
case QAM_16:
case QAM_32:
case QAM_64:
case QAM_128:
case QAM_256:
case QAM_AUTO:
dprintk(1, "%s() QAM modulation\n", __func__);
priv->bandwidth = BANDWIDTH_8_MHZ;
priv->video_standard = DTV7_8;
priv->freq_hz = params->frequency - 2750000;
priv->rf_mode = XC_RF_MODE_CABLE;
/*
* Using a 8MHz bandwidth sometimes fail
* with 6MHz-spaced channels, due to inter-carrier
* interference. So, use DTV6 firmware
*/
if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) {
priv->bandwidth = BANDWIDTH_6_MHZ;
priv->video_standard = DTV6;
priv->freq_hz = params->frequency - 1750000;
} else {
priv->bandwidth = BANDWIDTH_8_MHZ;
priv->video_standard = DTV7_8;
priv->freq_hz = params->frequency - 2750000;
}
break;
default:
dprintk(1, "%s() Unsupported QAM type\n", __func__);
return -EINVAL;
}
} else {

View File

@ -290,10 +290,8 @@ static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci)
static int flexcop_pci_init(struct flexcop_pci *fc_pci)
{
int ret;
u8 card_rev;
pci_read_config_byte(fc_pci->pdev, PCI_CLASS_REVISION, &card_rev);
info("card revision %x", card_rev);
info("card revision %x", fc_pci->pdev->revision);
if ((ret = pci_enable_device(fc_pci->pdev)) != 0)
return ret;

View File

@ -460,7 +460,7 @@ static int __devinit bt878_probe(struct pci_dev *dev,
goto fail0;
}
pci_read_config_byte(dev, PCI_CLASS_REVISION, &bt->revision);
bt->revision = dev->revision;
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);

View File

@ -478,97 +478,94 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
static inline int find_next_packet(const u8 *buf, int pos, size_t count,
const int pktsize)
{
int start = pos, lost;
while (pos < count) {
if (buf[pos] == 0x47 ||
(pktsize == 204 && buf[pos] == 0xB8))
break;
pos++;
}
lost = pos - start;
if (lost) {
/* This garbage is part of a valid packet? */
int backtrack = pos - pktsize;
if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
(pktsize == 204 && buf[backtrack] == 0xB8)))
return backtrack;
}
return pos;
}
/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
size_t count, const int pktsize)
{
int p = 0, i, j;
const u8 *q;
spin_lock(&demux->lock);
if (demux->tsbufp) {
if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
i = demux->tsbufp;
j = 188 - i;
j = pktsize - i;
if (count < j) {
memcpy(&demux->tsbuf[i], buf, count);
demux->tsbufp += count;
goto bailout;
}
memcpy(&demux->tsbuf[i], buf, j);
if (demux->tsbuf[0] == 0x47)
if (demux->tsbuf[0] == 0x47) /* double check */
dvb_dmx_swfilter_packet(demux, demux->tsbuf);
demux->tsbufp = 0;
p += j;
}
while (p < count) {
if (buf[p] == 0x47) {
if (count - p >= 188) {
dvb_dmx_swfilter_packet(demux, &buf[p]);
p += 188;
} else {
i = count - p;
memcpy(demux->tsbuf, &buf[p], i);
demux->tsbufp = i;
goto bailout;
}
} else
p++;
while (1) {
p = find_next_packet(buf, p, count, pktsize);
if (p >= count)
break;
if (count - p < pktsize)
break;
q = &buf[p];
if (pktsize == 204 && (*q == 0xB8)) {
memcpy(demux->tsbuf, q, 188);
demux->tsbuf[0] = 0x47;
q = demux->tsbuf;
}
dvb_dmx_swfilter_packet(demux, q);
p += pktsize;
}
i = count - p;
if (i) {
memcpy(demux->tsbuf, &buf[p], i);
demux->tsbufp = i;
if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
demux->tsbuf[0] = 0x47;
}
bailout:
spin_unlock(&demux->lock);
}
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
{
_dvb_dmx_swfilter(demux, buf, count, 188);
}
EXPORT_SYMBOL(dvb_dmx_swfilter);
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
{
int p = 0, i, j;
u8 tmppack[188];
spin_lock(&demux->lock);
if (demux->tsbufp) {
i = demux->tsbufp;
j = 204 - i;
if (count < j) {
memcpy(&demux->tsbuf[i], buf, count);
demux->tsbufp += count;
goto bailout;
}
memcpy(&demux->tsbuf[i], buf, j);
if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
memcpy(tmppack, demux->tsbuf, 188);
if (tmppack[0] == 0xB8)
tmppack[0] = 0x47;
dvb_dmx_swfilter_packet(demux, tmppack);
}
demux->tsbufp = 0;
p += j;
}
while (p < count) {
if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
if (count - p >= 204) {
memcpy(tmppack, &buf[p], 188);
if (tmppack[0] == 0xB8)
tmppack[0] = 0x47;
dvb_dmx_swfilter_packet(demux, tmppack);
p += 204;
} else {
i = count - p;
memcpy(demux->tsbuf, &buf[p], i);
demux->tsbufp = i;
goto bailout;
}
} else {
p++;
}
}
bailout:
spin_unlock(&demux->lock);
_dvb_dmx_swfilter(demux, buf, count, 204);
}
EXPORT_SYMBOL(dvb_dmx_swfilter_204);
static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)

View File

@ -105,7 +105,8 @@ struct dvb_frontend_private {
/* thread/frontend values */
struct dvb_device *dvbdev;
struct dvb_frontend_parameters parameters;
struct dvb_frontend_parameters parameters_in;
struct dvb_frontend_parameters parameters_out;
struct dvb_fe_events events;
struct semaphore sem;
struct list_head list_head;
@ -160,12 +161,11 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
e = &events->events[events->eventw];
memcpy (&e->parameters, &fepriv->parameters,
sizeof (struct dvb_frontend_parameters));
if (status & FE_HAS_LOCK)
if (fe->ops.get_frontend)
fe->ops.get_frontend(fe, &e->parameters);
fe->ops.get_frontend(fe, &fepriv->parameters_out);
e->parameters = fepriv->parameters_out;
events->eventw = wp;
@ -277,12 +277,12 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
int ready = 0;
int fe_set_err = 0;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
int original_inversion = fepriv->parameters.inversion;
u32 original_frequency = fepriv->parameters.frequency;
int original_inversion = fepriv->parameters_in.inversion;
u32 original_frequency = fepriv->parameters_in.frequency;
/* are we using autoinversion? */
autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO));
(fepriv->parameters_in.inversion == INVERSION_AUTO));
/* setup parameters correctly */
while(!ready) {
@ -348,18 +348,19 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
/* set the frontend itself */
fepriv->parameters.frequency += fepriv->lnb_drift;
fepriv->parameters_in.frequency += fepriv->lnb_drift;
if (autoinversion)
fepriv->parameters.inversion = fepriv->inversion;
fepriv->parameters_in.inversion = fepriv->inversion;
if (fe->ops.set_frontend)
fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters);
fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in);
fepriv->parameters_out = fepriv->parameters_in;
if (fe_set_err < 0) {
fepriv->state = FESTATE_ERROR;
return fe_set_err;
}
fepriv->parameters.frequency = original_frequency;
fepriv->parameters.inversion = original_inversion;
fepriv->parameters_in.frequency = original_frequency;
fepriv->parameters_in.inversion = original_inversion;
fepriv->auto_sub_step++;
return 0;
@ -383,7 +384,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
if (fepriv->state & FESTATE_RETUNE) {
if (fe->ops.set_frontend)
retval = fe->ops.set_frontend(fe,
&fepriv->parameters);
&fepriv->parameters_in);
fepriv->parameters_out = fepriv->parameters_in;
if (retval < 0)
fepriv->state = FESTATE_ERROR;
else
@ -413,8 +415,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
/* if we're tuned, then we have determined the correct inversion */
if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO)) {
fepriv->parameters.inversion = fepriv->inversion;
(fepriv->parameters_in.inversion == INVERSION_AUTO)) {
fepriv->parameters_in.inversion = fepriv->inversion;
}
return;
}
@ -594,12 +596,14 @@ restart:
if (fepriv->state & FESTATE_RETUNE) {
dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
params = &fepriv->parameters;
params = &fepriv->parameters_in;
fepriv->state = FESTATE_TUNED;
}
if (fe->ops.tune)
fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
if (params)
fepriv->parameters_out = *params;
if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
dprintk("%s: state changed, adding current state\n", __func__);
@ -612,11 +616,9 @@ restart:
dvb_frontend_swzigzag(fe);
break;
case DVBFE_ALGO_CUSTOM:
params = NULL; /* have we been asked to RETUNE ? */
dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
if (fepriv->state & FESTATE_RETUNE) {
dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
params = &fepriv->parameters;
fepriv->state = FESTATE_TUNED;
}
/* Case where we are going to search for a carrier
@ -625,7 +627,7 @@ restart:
*/
if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
if (fe->ops.search) {
fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in);
/* We did do a search as was requested, the flags are
* now unset as well and has the flags wrt to search.
*/
@ -636,11 +638,12 @@ restart:
/* Track the carrier if the search was successful */
if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
if (fe->ops.track)
fe->ops.track(fe, &fepriv->parameters);
fe->ops.track(fe, &fepriv->parameters_in);
} else {
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
fepriv->delay = HZ / 2;
}
fepriv->parameters_out = fepriv->parameters_in;
fe->ops.read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s); /* update event list */
@ -860,34 +863,34 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int i;
memset(&(fe->dtv_property_cache), 0,
sizeof(struct dtv_frontend_properties));
memset(c, 0, sizeof(struct dtv_frontend_properties));
fe->dtv_property_cache.state = DTV_CLEAR;
fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
fe->dtv_property_cache.inversion = INVERSION_AUTO;
fe->dtv_property_cache.fec_inner = FEC_AUTO;
fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
fe->dtv_property_cache.bandwidth_hz = BANDWIDTH_AUTO;
fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
fe->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
fe->dtv_property_cache.symbol_rate = QAM_AUTO;
fe->dtv_property_cache.code_rate_HP = FEC_AUTO;
fe->dtv_property_cache.code_rate_LP = FEC_AUTO;
c->state = DTV_CLEAR;
c->delivery_system = SYS_UNDEFINED;
c->inversion = INVERSION_AUTO;
c->fec_inner = FEC_AUTO;
c->transmission_mode = TRANSMISSION_MODE_AUTO;
c->bandwidth_hz = BANDWIDTH_AUTO;
c->guard_interval = GUARD_INTERVAL_AUTO;
c->hierarchy = HIERARCHY_AUTO;
c->symbol_rate = QAM_AUTO;
c->code_rate_HP = FEC_AUTO;
c->code_rate_LP = FEC_AUTO;
fe->dtv_property_cache.isdbt_partial_reception = -1;
fe->dtv_property_cache.isdbt_sb_mode = -1;
fe->dtv_property_cache.isdbt_sb_subchannel = -1;
fe->dtv_property_cache.isdbt_sb_segment_idx = -1;
fe->dtv_property_cache.isdbt_sb_segment_count = -1;
fe->dtv_property_cache.isdbt_layer_enabled = 0x7;
c->isdbt_partial_reception = -1;
c->isdbt_sb_mode = -1;
c->isdbt_sb_subchannel = -1;
c->isdbt_sb_segment_idx = -1;
c->isdbt_sb_segment_count = -1;
c->isdbt_layer_enabled = 0x7;
for (i = 0; i < 3; i++) {
fe->dtv_property_cache.layer[i].fec = FEC_AUTO;
fe->dtv_property_cache.layer[i].modulation = QAM_AUTO;
fe->dtv_property_cache.layer[i].interleaving = -1;
fe->dtv_property_cache.layer[i].segment_count = -1;
c->layer[i].fec = FEC_AUTO;
c->layer[i].modulation = QAM_AUTO;
c->layer[i].interleaving = -1;
c->layer[i].segment_count = -1;
}
return 0;
@ -1020,10 +1023,9 @@ static int is_legacy_delivery_system(fe_delivery_system_t s)
* it's being used for the legacy or new API, reducing code and complexity.
*/
static void dtv_property_cache_sync(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
struct dtv_frontend_properties *c,
const struct dvb_frontend_parameters *p)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
c->frequency = p->frequency;
c->inversion = p->inversion;
@ -1074,9 +1076,9 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
*/
static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dvb_frontend_parameters *p = &fepriv->parameters;
struct dvb_frontend_parameters *p = &fepriv->parameters_in;
p->frequency = c->frequency;
p->inversion = c->inversion;
@ -1086,14 +1088,12 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
dprintk("%s() Preparing QPSK req\n", __func__);
p->u.qpsk.symbol_rate = c->symbol_rate;
p->u.qpsk.fec_inner = c->fec_inner;
c->delivery_system = SYS_DVBS;
break;
case FE_QAM:
dprintk("%s() Preparing QAM req\n", __func__);
p->u.qam.symbol_rate = c->symbol_rate;
p->u.qam.fec_inner = c->fec_inner;
p->u.qam.modulation = c->modulation;
c->delivery_system = SYS_DVBC_ANNEX_AC;
break;
case FE_OFDM:
dprintk("%s() Preparing OFDM req\n", __func__);
@ -1111,15 +1111,10 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
p->u.ofdm.transmission_mode = c->transmission_mode;
p->u.ofdm.guard_interval = c->guard_interval;
p->u.ofdm.hierarchy_information = c->hierarchy;
c->delivery_system = SYS_DVBT;
break;
case FE_ATSC:
dprintk("%s() Preparing VSB req\n", __func__);
p->u.vsb.modulation = c->modulation;
if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
c->delivery_system = SYS_ATSC;
else
c->delivery_system = SYS_DVBC_ANNEX_B;
break;
}
}
@ -1129,9 +1124,9 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
*/
static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dvb_frontend_parameters *p = &fepriv->parameters;
struct dvb_frontend_parameters *p = &fepriv->parameters_in;
p->frequency = c->frequency;
p->inversion = c->inversion;
@ -1148,10 +1143,9 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
break;
}
if(c->delivery_system == SYS_ISDBT) {
/* Fake out a generic DVB-T request so we pass validation in the ioctl */
p->frequency = c->frequency;
p->inversion = c->inversion;
/* Fake out a generic DVB-T request so we pass validation in the ioctl */
if ((c->delivery_system == SYS_ISDBT) ||
(c->delivery_system == SYS_DVBT2)) {
p->u.ofdm.constellation = QAM_AUTO;
p->u.ofdm.code_rate_HP = FEC_AUTO;
p->u.ofdm.code_rate_LP = FEC_AUTO;
@ -1171,7 +1165,7 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
static void dtv_property_cache_submit(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
/* For legacy delivery systems we don't need the delivery_system to
* be specified, but we populate the older structures from the cache
@ -1204,133 +1198,149 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
struct dtv_property *tvp,
struct file *file)
{
int r = 0;
const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dtv_frontend_properties cdetected;
int r;
/* Allow the frontend to validate incoming properties */
if (fe->ops.get_property)
r = fe->ops.get_property(fe, tvp);
if (r < 0)
return r;
/*
* If the driver implements a get_frontend function, then convert
* detected parameters to S2API properties.
*/
if (fe->ops.get_frontend) {
cdetected = *c;
dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out);
c = &cdetected;
}
switch(tvp->cmd) {
case DTV_FREQUENCY:
tvp->u.data = fe->dtv_property_cache.frequency;
tvp->u.data = c->frequency;
break;
case DTV_MODULATION:
tvp->u.data = fe->dtv_property_cache.modulation;
tvp->u.data = c->modulation;
break;
case DTV_BANDWIDTH_HZ:
tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
tvp->u.data = c->bandwidth_hz;
break;
case DTV_INVERSION:
tvp->u.data = fe->dtv_property_cache.inversion;
tvp->u.data = c->inversion;
break;
case DTV_SYMBOL_RATE:
tvp->u.data = fe->dtv_property_cache.symbol_rate;
tvp->u.data = c->symbol_rate;
break;
case DTV_INNER_FEC:
tvp->u.data = fe->dtv_property_cache.fec_inner;
tvp->u.data = c->fec_inner;
break;
case DTV_PILOT:
tvp->u.data = fe->dtv_property_cache.pilot;
tvp->u.data = c->pilot;
break;
case DTV_ROLLOFF:
tvp->u.data = fe->dtv_property_cache.rolloff;
tvp->u.data = c->rolloff;
break;
case DTV_DELIVERY_SYSTEM:
tvp->u.data = fe->dtv_property_cache.delivery_system;
tvp->u.data = c->delivery_system;
break;
case DTV_VOLTAGE:
tvp->u.data = fe->dtv_property_cache.voltage;
tvp->u.data = c->voltage;
break;
case DTV_TONE:
tvp->u.data = fe->dtv_property_cache.sectone;
tvp->u.data = c->sectone;
break;
case DTV_API_VERSION:
tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
break;
case DTV_CODE_RATE_HP:
tvp->u.data = fe->dtv_property_cache.code_rate_HP;
tvp->u.data = c->code_rate_HP;
break;
case DTV_CODE_RATE_LP:
tvp->u.data = fe->dtv_property_cache.code_rate_LP;
tvp->u.data = c->code_rate_LP;
break;
case DTV_GUARD_INTERVAL:
tvp->u.data = fe->dtv_property_cache.guard_interval;
tvp->u.data = c->guard_interval;
break;
case DTV_TRANSMISSION_MODE:
tvp->u.data = fe->dtv_property_cache.transmission_mode;
tvp->u.data = c->transmission_mode;
break;
case DTV_HIERARCHY:
tvp->u.data = fe->dtv_property_cache.hierarchy;
tvp->u.data = c->hierarchy;
break;
/* ISDB-T Support here */
case DTV_ISDBT_PARTIAL_RECEPTION:
tvp->u.data = fe->dtv_property_cache.isdbt_partial_reception;
tvp->u.data = c->isdbt_partial_reception;
break;
case DTV_ISDBT_SOUND_BROADCASTING:
tvp->u.data = fe->dtv_property_cache.isdbt_sb_mode;
tvp->u.data = c->isdbt_sb_mode;
break;
case DTV_ISDBT_SB_SUBCHANNEL_ID:
tvp->u.data = fe->dtv_property_cache.isdbt_sb_subchannel;
tvp->u.data = c->isdbt_sb_subchannel;
break;
case DTV_ISDBT_SB_SEGMENT_IDX:
tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_idx;
tvp->u.data = c->isdbt_sb_segment_idx;
break;
case DTV_ISDBT_SB_SEGMENT_COUNT:
tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_count;
tvp->u.data = c->isdbt_sb_segment_count;
break;
case DTV_ISDBT_LAYER_ENABLED:
tvp->u.data = fe->dtv_property_cache.isdbt_layer_enabled;
tvp->u.data = c->isdbt_layer_enabled;
break;
case DTV_ISDBT_LAYERA_FEC:
tvp->u.data = fe->dtv_property_cache.layer[0].fec;
tvp->u.data = c->layer[0].fec;
break;
case DTV_ISDBT_LAYERA_MODULATION:
tvp->u.data = fe->dtv_property_cache.layer[0].modulation;
tvp->u.data = c->layer[0].modulation;
break;
case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
tvp->u.data = fe->dtv_property_cache.layer[0].segment_count;
tvp->u.data = c->layer[0].segment_count;
break;
case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
tvp->u.data = fe->dtv_property_cache.layer[0].interleaving;
tvp->u.data = c->layer[0].interleaving;
break;
case DTV_ISDBT_LAYERB_FEC:
tvp->u.data = fe->dtv_property_cache.layer[1].fec;
tvp->u.data = c->layer[1].fec;
break;
case DTV_ISDBT_LAYERB_MODULATION:
tvp->u.data = fe->dtv_property_cache.layer[1].modulation;
tvp->u.data = c->layer[1].modulation;
break;
case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
tvp->u.data = fe->dtv_property_cache.layer[1].segment_count;
tvp->u.data = c->layer[1].segment_count;
break;
case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
tvp->u.data = fe->dtv_property_cache.layer[1].interleaving;
tvp->u.data = c->layer[1].interleaving;
break;
case DTV_ISDBT_LAYERC_FEC:
tvp->u.data = fe->dtv_property_cache.layer[2].fec;
tvp->u.data = c->layer[2].fec;
break;
case DTV_ISDBT_LAYERC_MODULATION:
tvp->u.data = fe->dtv_property_cache.layer[2].modulation;
tvp->u.data = c->layer[2].modulation;
break;
case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
tvp->u.data = fe->dtv_property_cache.layer[2].segment_count;
tvp->u.data = c->layer[2].segment_count;
break;
case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
tvp->u.data = fe->dtv_property_cache.layer[2].interleaving;
tvp->u.data = c->layer[2].interleaving;
break;
case DTV_ISDBS_TS_ID:
tvp->u.data = fe->dtv_property_cache.isdbs_ts_id;
tvp->u.data = c->isdbs_ts_id;
break;
case DTV_DVBT2_PLP_ID:
tvp->u.data = c->dvbt2_plp_id;
break;
default:
r = -1;
return -EINVAL;
}
/* Allow the frontend to override outgoing properties */
if (fe->ops.get_property) {
r = fe->ops.get_property(fe, tvp);
if (r < 0)
return r;
}
dtv_property_dump(tvp);
return r;
return 0;
}
static int dtv_property_process_set(struct dvb_frontend *fe,
@ -1338,15 +1348,16 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
struct file *file)
{
int r = 0;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
dtv_property_dump(tvp);
/* Allow the frontend to validate incoming properties */
if (fe->ops.set_property)
if (fe->ops.set_property) {
r = fe->ops.set_property(fe, tvp);
if (r < 0)
return r;
if (r < 0)
return r;
}
switch(tvp->cmd) {
case DTV_CLEAR:
@ -1361,126 +1372,129 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
* tunerequest so we can pass validation in the FE_SET_FRONTEND
* ioctl.
*/
fe->dtv_property_cache.state = tvp->cmd;
c->state = tvp->cmd;
dprintk("%s() Finalised property cache\n", __func__);
dtv_property_cache_submit(fe);
r |= dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
&fepriv->parameters);
r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
&fepriv->parameters_in);
break;
case DTV_FREQUENCY:
fe->dtv_property_cache.frequency = tvp->u.data;
c->frequency = tvp->u.data;
break;
case DTV_MODULATION:
fe->dtv_property_cache.modulation = tvp->u.data;
c->modulation = tvp->u.data;
break;
case DTV_BANDWIDTH_HZ:
fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
c->bandwidth_hz = tvp->u.data;
break;
case DTV_INVERSION:
fe->dtv_property_cache.inversion = tvp->u.data;
c->inversion = tvp->u.data;
break;
case DTV_SYMBOL_RATE:
fe->dtv_property_cache.symbol_rate = tvp->u.data;
c->symbol_rate = tvp->u.data;
break;
case DTV_INNER_FEC:
fe->dtv_property_cache.fec_inner = tvp->u.data;
c->fec_inner = tvp->u.data;
break;
case DTV_PILOT:
fe->dtv_property_cache.pilot = tvp->u.data;
c->pilot = tvp->u.data;
break;
case DTV_ROLLOFF:
fe->dtv_property_cache.rolloff = tvp->u.data;
c->rolloff = tvp->u.data;
break;
case DTV_DELIVERY_SYSTEM:
fe->dtv_property_cache.delivery_system = tvp->u.data;
c->delivery_system = tvp->u.data;
break;
case DTV_VOLTAGE:
fe->dtv_property_cache.voltage = tvp->u.data;
c->voltage = tvp->u.data;
r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
(void *)fe->dtv_property_cache.voltage);
(void *)c->voltage);
break;
case DTV_TONE:
fe->dtv_property_cache.sectone = tvp->u.data;
c->sectone = tvp->u.data;
r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
(void *)fe->dtv_property_cache.sectone);
(void *)c->sectone);
break;
case DTV_CODE_RATE_HP:
fe->dtv_property_cache.code_rate_HP = tvp->u.data;
c->code_rate_HP = tvp->u.data;
break;
case DTV_CODE_RATE_LP:
fe->dtv_property_cache.code_rate_LP = tvp->u.data;
c->code_rate_LP = tvp->u.data;
break;
case DTV_GUARD_INTERVAL:
fe->dtv_property_cache.guard_interval = tvp->u.data;
c->guard_interval = tvp->u.data;
break;
case DTV_TRANSMISSION_MODE:
fe->dtv_property_cache.transmission_mode = tvp->u.data;
c->transmission_mode = tvp->u.data;
break;
case DTV_HIERARCHY:
fe->dtv_property_cache.hierarchy = tvp->u.data;
c->hierarchy = tvp->u.data;
break;
/* ISDB-T Support here */
case DTV_ISDBT_PARTIAL_RECEPTION:
fe->dtv_property_cache.isdbt_partial_reception = tvp->u.data;
c->isdbt_partial_reception = tvp->u.data;
break;
case DTV_ISDBT_SOUND_BROADCASTING:
fe->dtv_property_cache.isdbt_sb_mode = tvp->u.data;
c->isdbt_sb_mode = tvp->u.data;
break;
case DTV_ISDBT_SB_SUBCHANNEL_ID:
fe->dtv_property_cache.isdbt_sb_subchannel = tvp->u.data;
c->isdbt_sb_subchannel = tvp->u.data;
break;
case DTV_ISDBT_SB_SEGMENT_IDX:
fe->dtv_property_cache.isdbt_sb_segment_idx = tvp->u.data;
c->isdbt_sb_segment_idx = tvp->u.data;
break;
case DTV_ISDBT_SB_SEGMENT_COUNT:
fe->dtv_property_cache.isdbt_sb_segment_count = tvp->u.data;
c->isdbt_sb_segment_count = tvp->u.data;
break;
case DTV_ISDBT_LAYER_ENABLED:
fe->dtv_property_cache.isdbt_layer_enabled = tvp->u.data;
c->isdbt_layer_enabled = tvp->u.data;
break;
case DTV_ISDBT_LAYERA_FEC:
fe->dtv_property_cache.layer[0].fec = tvp->u.data;
c->layer[0].fec = tvp->u.data;
break;
case DTV_ISDBT_LAYERA_MODULATION:
fe->dtv_property_cache.layer[0].modulation = tvp->u.data;
c->layer[0].modulation = tvp->u.data;
break;
case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
fe->dtv_property_cache.layer[0].segment_count = tvp->u.data;
c->layer[0].segment_count = tvp->u.data;
break;
case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
fe->dtv_property_cache.layer[0].interleaving = tvp->u.data;
c->layer[0].interleaving = tvp->u.data;
break;
case DTV_ISDBT_LAYERB_FEC:
fe->dtv_property_cache.layer[1].fec = tvp->u.data;
c->layer[1].fec = tvp->u.data;
break;
case DTV_ISDBT_LAYERB_MODULATION:
fe->dtv_property_cache.layer[1].modulation = tvp->u.data;
c->layer[1].modulation = tvp->u.data;
break;
case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
fe->dtv_property_cache.layer[1].segment_count = tvp->u.data;
c->layer[1].segment_count = tvp->u.data;
break;
case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
fe->dtv_property_cache.layer[1].interleaving = tvp->u.data;
c->layer[1].interleaving = tvp->u.data;
break;
case DTV_ISDBT_LAYERC_FEC:
fe->dtv_property_cache.layer[2].fec = tvp->u.data;
c->layer[2].fec = tvp->u.data;
break;
case DTV_ISDBT_LAYERC_MODULATION:
fe->dtv_property_cache.layer[2].modulation = tvp->u.data;
c->layer[2].modulation = tvp->u.data;
break;
case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
fe->dtv_property_cache.layer[2].segment_count = tvp->u.data;
c->layer[2].segment_count = tvp->u.data;
break;
case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
fe->dtv_property_cache.layer[2].interleaving = tvp->u.data;
c->layer[2].interleaving = tvp->u.data;
break;
case DTV_ISDBS_TS_ID:
fe->dtv_property_cache.isdbs_ts_id = tvp->u.data;
c->isdbs_ts_id = tvp->u.data;
break;
case DTV_DVBT2_PLP_ID:
c->dvbt2_plp_id = tvp->u.data;
break;
default:
r = -1;
return -EINVAL;
}
return r;
@ -1491,6 +1505,7 @@ static int dvb_frontend_ioctl(struct file *file,
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend *fe = dvbdev->priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
int err = -EOPNOTSUPP;
@ -1510,7 +1525,7 @@ static int dvb_frontend_ioctl(struct file *file,
if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
err = dvb_frontend_ioctl_properties(file, cmd, parg);
else {
fe->dtv_property_cache.state = DTV_UNDEFINED;
c->state = DTV_UNDEFINED;
err = dvb_frontend_ioctl_legacy(file, cmd, parg);
}
@ -1523,6 +1538,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend *fe = dvbdev->priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int err = 0;
struct dtv_properties *tvps = NULL;
@ -1554,11 +1570,13 @@ static int dvb_frontend_ioctl_properties(struct file *file,
}
for (i = 0; i < tvps->num; i++) {
(tvp + i)->result = dtv_property_process_set(fe, tvp + i, file);
err |= (tvp + i)->result;
err = dtv_property_process_set(fe, tvp + i, file);
if (err < 0)
goto out;
(tvp + i)->result = err;
}
if(fe->dtv_property_cache.state == DTV_TUNE)
if (c->state == DTV_TUNE)
dprintk("%s() Property cache is full, tuning\n", __func__);
} else
@ -1586,8 +1604,10 @@ static int dvb_frontend_ioctl_properties(struct file *file,
}
for (i = 0; i < tvps->num; i++) {
(tvp + i)->result = dtv_property_process_get(fe, tvp + i, file);
err |= (tvp + i)->result;
err = dtv_property_process_get(fe, tvp + i, file);
if (err < 0)
goto out;
(tvp + i)->result = err;
}
if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
@ -1787,10 +1807,11 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
break;
case FE_SET_FRONTEND: {
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_tune_settings fetunesettings;
if(fe->dtv_property_cache.state == DTV_TUNE) {
if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
if (c->state == DTV_TUNE) {
if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) {
err = -EINVAL;
break;
}
@ -1800,9 +1821,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
break;
}
memcpy (&fepriv->parameters, parg,
memcpy (&fepriv->parameters_in, parg,
sizeof (struct dvb_frontend_parameters));
dtv_property_cache_sync(fe, &fepriv->parameters);
dtv_property_cache_sync(fe, c, &fepriv->parameters_in);
}
memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
@ -1811,15 +1832,15 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
/* force auto frequency inversion if requested */
if (dvb_force_auto_inversion) {
fepriv->parameters.inversion = INVERSION_AUTO;
fepriv->parameters_in.inversion = INVERSION_AUTO;
fetunesettings.parameters.inversion = INVERSION_AUTO;
}
if (fe->ops.info.type == FE_OFDM) {
/* without hierarchical coding code_rate_LP is irrelevant,
* so we tolerate the otherwise invalid FEC_NONE setting */
if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE)
fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE)
fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO;
}
/* get frontend-specific tuning settings */
@ -1832,8 +1853,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
switch(fe->ops.info.type) {
case FE_QPSK:
fepriv->min_delay = HZ/20;
fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000;
fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000;
fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000;
break;
case FE_QAM:
@ -1875,8 +1896,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_GET_FRONTEND:
if (fe->ops.get_frontend) {
memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
err = fe->ops.get_frontend(fe, &fepriv->parameters_out);
memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters));
}
break;

View File

@ -358,6 +358,9 @@ struct dtv_frontend_properties {
/* ISDB-T specifics */
u32 isdbs_ts_id;
/* DVB-T2 specifics */
u32 dvbt2_plp_id;
};
struct dvb_frontend {

View File

@ -292,6 +292,11 @@ config DVB_USB_ANYSEE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE
select DVB_CX24116 if !DVB_FE_CUSTOMISE
select DVB_STV0900 if !DVB_FE_CUSTOMISE
select DVB_STV6110 if !DVB_FE_CUSTOMISE
select DVB_ISL6423 if !DVB_FE_CUSTOMISE
help
Say Y here to support the Anysee E30, Anysee E30 Plus or
Anysee E30 C Plus DVB USB2.0 receiver.

View File

@ -78,17 +78,26 @@ static struct rc_map_table rc_map_a800_table[] = {
static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 key[5];
int ret;
u8 *key = kmalloc(5, GFP_KERNEL);
if (!key)
return -ENOMEM;
if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
2000) != 5)
return -ENODEV;
2000) != 5) {
ret = -ENODEV;
goto out;
}
/* call the universal NEC remote processor, to find out the key's state and event */
dvb_usb_nec_rc_key_to_event(d,key,event,state);
if (key[0] != 0)
deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
return 0;
ret = 0;
out:
kfree(key);
return ret;
}
/* USB Driver stuff */

View File

@ -36,6 +36,11 @@
#include "mt352.h"
#include "mt352_priv.h"
#include "zl10353.h"
#include "tda18212.h"
#include "cx24116.h"
#include "stv0900.h"
#include "stv6110.h"
#include "isl6423.h"
/* debug */
static int dvb_usb_anysee_debug;
@ -105,6 +110,27 @@ static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
}
/* write single register with mask */
static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
u8 mask)
{
int ret;
u8 tmp;
/* no need for read if whole reg is written */
if (mask != 0xff) {
ret = anysee_read_reg(d, reg, &tmp);
if (ret)
return ret;
val &= mask;
tmp &= ~mask;
val |= tmp;
}
return anysee_write_reg(d, reg, val);
}
static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
{
u8 buf[] = {CMD_GET_HW_INFO};
@ -162,18 +188,18 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
u8 buf[6];
buf[0] = CMD_I2C_READ;
buf[1] = msg[i].addr + 1;
buf[1] = (msg[i].addr << 1) | 0x01;
buf[2] = msg[i].buf[0];
buf[3] = 0x00;
buf[4] = 0x00;
buf[5] = 0x01;
buf[3] = msg[i].buf[1];
buf[4] = msg[i].len-1;
buf[5] = msg[i+1].len;
ret = anysee_ctrl_msg(d, buf, sizeof(buf), msg[i+1].buf,
msg[i+1].len);
inc = 2;
} else {
u8 buf[4+msg[i].len];
buf[0] = CMD_I2C_WRITE;
buf[1] = msg[i].addr;
buf[1] = (msg[i].addr << 1);
buf[2] = msg[i].len;
buf[3] = 0x01;
memcpy(&buf[4], msg[i].buf, msg[i].len);
@ -224,7 +250,7 @@ static int anysee_mt352_demod_init(struct dvb_frontend *fe)
/* Callbacks for DVB USB */
static struct tda10023_config anysee_tda10023_config = {
.demod_address = 0x1a,
.demod_address = (0x1a >> 1),
.invert = 0,
.xtal = 16000000,
.pll_m = 11,
@ -235,143 +261,539 @@ static struct tda10023_config anysee_tda10023_config = {
};
static struct mt352_config anysee_mt352_config = {
.demod_address = 0x1e,
.demod_address = (0x1e >> 1),
.demod_init = anysee_mt352_demod_init,
};
static struct zl10353_config anysee_zl10353_config = {
.demod_address = 0x1e,
.demod_address = (0x1e >> 1),
.parallel_ts = 1,
};
static struct zl10353_config anysee_zl10353_tda18212_config2 = {
.demod_address = (0x1e >> 1),
.parallel_ts = 1,
.disable_i2c_gate_ctrl = 1,
.no_tuner = 1,
.if2 = 41500,
};
static struct zl10353_config anysee_zl10353_tda18212_config = {
.demod_address = (0x18 >> 1),
.parallel_ts = 1,
.disable_i2c_gate_ctrl = 1,
.no_tuner = 1,
.if2 = 41500,
};
static struct tda10023_config anysee_tda10023_tda18212_config = {
.demod_address = (0x1a >> 1),
.xtal = 16000000,
.pll_m = 12,
.pll_p = 3,
.pll_n = 1,
.output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
.deltaf = 0xba02,
};
static struct tda18212_config anysee_tda18212_config = {
.i2c_address = (0xc0 >> 1),
.if_dvbt_6 = 4150,
.if_dvbt_7 = 4150,
.if_dvbt_8 = 4150,
.if_dvbc = 5000,
};
static struct cx24116_config anysee_cx24116_config = {
.demod_address = (0xaa >> 1),
.mpg_clk_pos_pol = 0x00,
.i2c_wr_max = 48,
};
static struct stv0900_config anysee_stv0900_config = {
.demod_address = (0xd0 >> 1),
.demod_mode = 0,
.xtal = 8000000,
.clkmode = 3,
.diseqc_mode = 2,
.tun1_maddress = 0,
.tun1_adc = 1, /* 1 Vpp */
.path1_mode = 3,
};
static struct stv6110_config anysee_stv6110_config = {
.i2c_address = (0xc0 >> 1),
.mclk = 16000000,
.clk_div = 1,
};
static struct isl6423_config anysee_isl6423_config = {
.current_max = SEC_CURRENT_800m,
.curlim = SEC_CURRENT_LIM_OFF,
.mod_extern = 1,
.addr = (0x10 >> 1),
};
/*
* New USB device strings: Mfr=1, Product=2, SerialNumber=0
* Manufacturer: AMT.CO.KR
*
* E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
* PCB: ?
* parts: DNOS404ZH102A(MT352, DTT7579(?))
*
* E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
* PCB: ?
* parts: DNOS404ZH103A(ZL10353, DTT7579(?))
*
* E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee"
* PCB: 507CD (rev1.1)
* parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01
* OEA=80 OEB=00 OEC=00 OED=ff OEF=fe
* IOA=4f IOB=ff IOC=00 IOD=06 IOF=01
* IOD[0] ZL10353 1=enabled
* IOA[7] TS 0=enabled
* tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not)
*
* E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)"
* PCB: 507DC (rev0.2)
* parts: TDA10023, DTOS403IH102B TM, CST56I01
* OEA=80 OEB=00 OEC=00 OED=ff OEF=fe
* IOA=4f IOB=ff IOC=00 IOD=26 IOF=01
* IOD[0] TDA10023 1=enabled
*
* E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)"
* PCB: 507SI (rev2.1)
* parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024
* OEA=80 OEB=00 OEC=ff OED=ff OEF=fe
* IOA=4d IOB=ff IOC=00 IOD=26 IOF=01
* IOD[0] CX24116 1=enabled
*
* E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
* PCB: 507FA (rev0.4)
* parts: TDA10023, DTOS403IH102B TM, TDA8024
* OEA=80 OEB=00 OEC=ff OED=ff OEF=ff
* IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0
* IOD[5] TDA10023 1=enabled
* IOE[0] tuner 1=enabled
*
* E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
* PCB: 507FA (rev1.1)
* parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024
* OEA=80 OEB=00 OEC=ff OED=ff OEF=ff
* IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0
* DVB-C:
* IOD[5] TDA10023 1=enabled
* IOE[0] tuner 1=enabled
* DVB-T:
* IOD[0] ZL10353 1=enabled
* IOE[0] tuner 0=enabled
* tuner is behind ZL10353 I2C-gate
*
* E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)"
* PCB: 508TC (rev0.6)
* parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
* OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff
* IOA=4d IOB=00 IOC=cc IOD=48 IOF=e4
* IOA[7] TS 1=enabled
* IOE[4] TDA18212 1=enabled
* DVB-C:
* IOD[6] ZL10353 0=disabled
* IOD[5] TDA10023 1=enabled
* IOE[0] IF 1=enabled
* DVB-T:
* IOD[5] TDA10023 0=disabled
* IOD[6] ZL10353 1=enabled
* IOE[0] IF 0=enabled
*
* E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)"
* PCB: 508S2 (rev0.7)
* parts: DNBU10512IST(STV0903, STV6110), ISL6423
* OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff
* IOA=4d IOB=00 IOC=c4 IOD=08 IOF=e4
* IOA[7] TS 1=enabled
* IOE[5] STV0903 1=enabled
*
*/
static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
{
int ret;
struct anysee_state *state = adap->dev->priv;
u8 hw_info[3];
u8 io_d; /* IO port D */
u8 tmp;
struct i2c_msg msg[2] = {
{
.addr = anysee_tda18212_config.i2c_address,
.flags = 0,
.len = 1,
.buf = "\x00",
}, {
.addr = anysee_tda18212_config.i2c_address,
.flags = I2C_M_RD,
.len = 1,
.buf = &tmp,
}
};
/* check which hardware we have
We must do this call two times to get reliable values (hw bug). */
/* 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)
return ret;
goto error;
ret = anysee_get_hw_info(adap->dev, hw_info);
if (ret)
return ret;
goto error;
/* Meaning of these info bytes are guessed. */
info("firmware version:%d.%d.%d hardware id:%d",
0, hw_info[1], hw_info[2], hw_info[0]);
info("firmware version:%d.%d hardware id:%d",
hw_info[1], hw_info[2], hw_info[0]);
ret = anysee_read_reg(adap->dev, 0xb0, &io_d); /* IO port D */
if (ret)
return ret;
deb_info("%s: IO port D:%02x\n", __func__, io_d);
state->hw = hw_info[0];
/* Select demod using trial and error method. */
switch (state->hw) {
case ANYSEE_HW_02: /* 2 */
/* E30 */
/* Try to attach demodulator in following order:
model demod hw firmware
1. E30 MT352 02 0.2.1
2. E30 ZL10353 02 0.2.1
3. E30 Combo ZL10353 0f 0.1.2 DVB-T/C combo
4. E30 Plus ZL10353 06 0.1.0
5. E30C Plus TDA10023 0a 0.1.0 rev 0.2
E30C Plus TDA10023 0f 0.1.2 rev 0.4
E30 Combo TDA10023 0f 0.1.2 DVB-T/C combo
*/
/* attach demod */
adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
&adap->dev->i2c_adap);
if (adap->fe)
break;
/* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
&adap->dev->i2c_adap);
if (adap->fe != NULL) {
state->tuner = DVB_PLL_THOMSON_DTT7579;
return 0;
}
/* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
&adap->dev->i2c_adap);
if (adap->fe != NULL) {
state->tuner = DVB_PLL_THOMSON_DTT7579;
return 0;
}
/* for E30 Combo Plus DVB-T demodulator */
if (dvb_usb_anysee_delsys) {
ret = anysee_write_reg(adap->dev, 0xb0, 0x01);
if (ret)
return ret;
/* Zarlink ZL10353 DVB-T demod */
/* attach demod */
adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
&adap->dev->i2c_adap);
if (adap->fe != NULL) {
state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
return 0;
&adap->dev->i2c_adap);
break;
case ANYSEE_HW_507CD: /* 6 */
/* E30 Plus */
/* enable DVB-T demod on IOD[0] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
if (ret)
goto error;
/* enable transport stream on IOA[7] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (0 << 7), 0x80);
if (ret)
goto error;
/* attach demod */
adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
&adap->dev->i2c_adap);
break;
case ANYSEE_HW_507DC: /* 10 */
/* E30 C Plus */
/* 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);
break;
case ANYSEE_HW_507SI: /* 11 */
/* E30 S2 Plus */
/* 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->dev->i2c_adap);
break;
case ANYSEE_HW_507FA: /* 15 */
/* E30 Combo Plus */
/* E30 C Plus */
/* enable tuner on IOE[4] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
if (ret)
goto error;
/* probe TDA18212 */
tmp = 0;
ret = i2c_transfer(&adap->dev->i2c_adap, msg, 2);
if (ret == 2 && tmp == 0xc7)
deb_info("%s: TDA18212 found\n", __func__);
else
tmp = 0;
/* disable tuner on IOE[4] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10);
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 {
/* 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;
/* attach demod */
if (tmp == 0xc7) {
/* TDA18212 config */
adap->fe = dvb_attach(tda10023_attach,
&anysee_tda10023_tda18212_config,
&adap->dev->i2c_adap, 0x48);
} else {
/* PLL config */
adap->fe = dvb_attach(tda10023_attach,
&anysee_tda10023_config,
&adap->dev->i2c_adap, 0x48);
}
}
break;
case ANYSEE_HW_508TC: /* 18 */
/* E7 TC */
/* enable transport stream on IOA[7] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
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 {
/* 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;
/* attach demod */
adap->fe = dvb_attach(tda10023_attach,
&anysee_tda10023_tda18212_config,
&adap->dev->i2c_adap, 0x48);
}
break;
case ANYSEE_HW_508S2: /* 19 */
/* E7 S2 */
/* enable transport stream on IOA[7] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
if (ret)
goto error;
/* enable DVB-S/S2 demod on IOE[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
if (ret)
goto error;
/* attach demod */
adap->fe = dvb_attach(stv0900_attach, &anysee_stv0900_config,
&adap->dev->i2c_adap, 0);
break;
}
/* connect demod on IO port D for TDA10023 & ZL10353 */
ret = anysee_write_reg(adap->dev, 0xb0, 0x25);
if (ret)
return ret;
/* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
&adap->dev->i2c_adap);
if (adap->fe != NULL) {
state->tuner = DVB_PLL_THOMSON_DTT7579;
return 0;
if (!adap->fe) {
/* we have no frontend :-( */
ret = -ENODEV;
err("Unsupported Anysee version. " \
"Please report the <linux-media@vger.kernel.org>.");
}
/* IO port E - E30C rev 0.4 board requires this */
ret = anysee_write_reg(adap->dev, 0xb1, 0xa7);
if (ret)
return ret;
/* Philips TDA10023 DVB-C demod */
adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
&adap->dev->i2c_adap, 0x48);
if (adap->fe != NULL) {
state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
return 0;
}
/* return IO port D to init value for safe */
ret = anysee_write_reg(adap->dev, 0xb0, io_d);
if (ret)
return ret;
err("Unknown Anysee version: %02x %02x %02x. "\
"Please report the <linux-dvb@linuxtv.org>.",
hw_info[0], hw_info[1], hw_info[2]);
return -ENODEV;
error:
return ret;
}
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__);
switch (state->tuner) {
case DVB_PLL_THOMSON_DTT7579:
/* Thomson dtt7579 (not sure) PLL inside of:
Samsung DNOS404ZH102A NIM
Samsung DNOS404ZH103A NIM */
dvb_attach(dvb_pll_attach, adap->fe, 0x61,
NULL, DVB_PLL_THOMSON_DTT7579);
switch (state->hw) {
case ANYSEE_HW_02: /* 2 */
/* E30 */
/* attach tuner */
fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1),
NULL, DVB_PLL_THOMSON_DTT7579);
break;
case DVB_PLL_SAMSUNG_DTOS403IH102A:
/* Unknown PLL inside of Samsung DTOS403IH102A tuner module */
dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
&adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
case ANYSEE_HW_507CD: /* 6 */
/* E30 Plus */
/* attach tuner */
fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1),
&adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579);
break;
case ANYSEE_HW_507DC: /* 10 */
/* E30 C Plus */
/* attach tuner */
fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1),
&adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
break;
case ANYSEE_HW_507SI: /* 11 */
/* E30 S2 Plus */
/* attach LNB controller */
fe = dvb_attach(isl6423_attach, adap->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. */
/* enable tuner on IOE[4] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
if (ret)
goto error;
/* attach tuner */
fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap,
&anysee_tda18212_config);
if (fe)
break;
/* disable tuner on IOE[4] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10);
if (ret)
goto error;
/* attach tuner */
fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1),
&adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
break;
case ANYSEE_HW_508TC: /* 18 */
/* E7 TC */
/* enable tuner on IOE[4] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
if (ret)
goto error;
/* attach tuner */
fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap,
&anysee_tda18212_config);
break;
case ANYSEE_HW_508S2: /* 19 */
/* E7 S2 */
/* attach tuner */
fe = dvb_attach(stv6110_attach, adap->fe,
&anysee_stv6110_config, &adap->dev->i2c_adap);
if (fe) {
/* attach LNB controller */
fe = dvb_attach(isl6423_attach, adap->fe,
&adap->dev->i2c_adap, &anysee_isl6423_config);
}
break;
default:
fe = NULL;
}
return 0;
if (fe)
ret = 0;
else
ret = -ENODEV;
error:
return ret;
}
static int anysee_rc_query(struct dvb_usb_device *d)

View File

@ -57,10 +57,29 @@ enum cmd {
};
struct anysee_state {
u8 tuner;
u8 hw; /* PCB ID */
u8 seq;
};
#define ANYSEE_HW_02 2 /* E30 */
#define ANYSEE_HW_507CD 6 /* E30 Plus */
#define ANYSEE_HW_507DC 10 /* E30 C Plus */
#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */
#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */
#define ANYSEE_HW_508TC 18 /* E7 TC */
#define ANYSEE_HW_508S2 19 /* E7 S2 */
#define REG_IOA 0x80 /* Port A (bit addressable) */
#define REG_IOB 0x90 /* Port B (bit addressable) */
#define REG_IOC 0xa0 /* Port C (bit addressable) */
#define REG_IOD 0xb0 /* Port D (bit addressable) */
#define REG_IOE 0xb1 /* Port E (NOT bit addressable) */
#define REG_OEA 0xb2 /* Port A Output Enable */
#define REG_OEB 0xb3 /* Port B Output Enable */
#define REG_OEC 0xb4 /* Port C Output Enable */
#define REG_OED 0xb5 /* Port D Output Enable */
#define REG_OEE 0xb6 /* Port E Output Enable */
#endif
/***************************************************************************
@ -136,7 +155,7 @@ General reply packet(s) are always used if not own reply defined.
----------------------------------------------------------------------------
| 04 | 0x00
----------------------------------------------------------------------------
| 05 | 0x01
| 05 | data length
----------------------------------------------------------------------------
| 06-59 | don't care
----------------------------------------------------------------------------

View File

@ -33,8 +33,16 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
{
int ret;
u16 index;
u8 usb_buf[6]; /* enough for all known requests,
read returns 5 and write 6 bytes */
u8 *usb_buf;
/*
* allocate enough for all known requests,
* read returns 5 and write 6 bytes
*/
usb_buf = kmalloc(6, GFP_KERNEL);
if (!usb_buf)
return -ENOMEM;
switch (wlen) {
case 1:
index = wbuf[0] << 8;
@ -45,14 +53,15 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
break;
default:
warn("wlen = %x, aborting.", wlen);
return -EINVAL;
ret = -EINVAL;
goto error;
}
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
usb_buf, sizeof(usb_buf), AU6610_USB_TIMEOUT);
usb_buf, 6, AU6610_USB_TIMEOUT);
if (ret < 0)
return ret;
goto error;
switch (operation) {
case AU6610_REQ_I2C_READ:
@ -60,7 +69,8 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
/* requested value is always 5th byte in buffer */
rbuf[0] = usb_buf[4];
}
error:
kfree(usb_buf);
return ret;
}

View File

@ -39,7 +39,7 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
u8 requesttype;
u16 value;
u16 index;
u8 buf[req->data_len];
u8 *buf;
request = req->cmd;
value = req->value;
@ -62,6 +62,12 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
goto error;
}
buf = kmalloc(req->data_len, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto error;
}
if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
/* write */
memcpy(buf, req->data, req->data_len);
@ -74,7 +80,7 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
msleep(1); /* avoid I2C errors */
ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
buf, sizeof(buf), CE6230_USB_TIMEOUT);
buf, req->data_len, CE6230_USB_TIMEOUT);
ce6230_debug_dump(request, requesttype, value, index, buf,
req->data_len, deb_xfer);
@ -88,6 +94,7 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
memcpy(req->data, buf, req->data_len);
kfree(buf);
error:
return ret;
}

View File

@ -46,8 +46,9 @@ struct dib0700_state {
u8 is_dib7000pc;
u8 fw_use_new_i2c_api;
u8 disable_streaming_master_mode;
u32 fw_version;
u32 nb_packet_buffer_size;
u32 fw_version;
u32 nb_packet_buffer_size;
u8 buf[255];
};
extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,

View File

@ -27,19 +27,25 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
u32 *romversion, u32 *ramversion, u32 *fwtype)
{
u8 b[16];
int ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
struct dib0700_state *st = d->priv;
int ret;
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
REQUEST_GET_VERSION,
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
b, sizeof(b), USB_CTRL_GET_TIMEOUT);
st->buf, 16, USB_CTRL_GET_TIMEOUT);
if (hwversion != NULL)
*hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
*hwversion = (st->buf[0] << 24) | (st->buf[1] << 16) |
(st->buf[2] << 8) | st->buf[3];
if (romversion != NULL)
*romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7];
*romversion = (st->buf[4] << 24) | (st->buf[5] << 16) |
(st->buf[6] << 8) | st->buf[7];
if (ramversion != NULL)
*ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11];
*ramversion = (st->buf[8] << 24) | (st->buf[9] << 16) |
(st->buf[10] << 8) | st->buf[11];
if (fwtype != NULL)
*fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15];
*fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) |
(st->buf[14] << 8) | st->buf[15];
return ret;
}
@ -101,24 +107,31 @@ 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)
{
u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) };
return dib0700_ctrl_wr(d, buf, sizeof(buf));
struct dib0700_state *st = d->priv;
s16 ret;
st->buf[0] = REQUEST_SET_GPIO;
st->buf[1] = gpio;
st->buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6);
ret = dib0700_ctrl_wr(d, st->buf, 3);
return ret;
}
static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
{
struct dib0700_state *st = d->priv;
u8 b[3];
int ret;
if (st->fw_version >= 0x10201) {
b[0] = REQUEST_SET_USB_XFER_LEN;
b[1] = (nb_ts_packets >> 8) & 0xff;
b[2] = nb_ts_packets & 0xff;
st->buf[0] = REQUEST_SET_USB_XFER_LEN;
st->buf[1] = (nb_ts_packets >> 8) & 0xff;
st->buf[2] = nb_ts_packets & 0xff;
deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
ret = dib0700_ctrl_wr(d, b, sizeof(b));
ret = dib0700_ctrl_wr(d, st->buf, 3);
} else {
deb_info("this firmware does not allow to change the USB xfer len\n");
ret = -EIO;
@ -137,11 +150,11 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
properly support i2c read calls not preceded by a write */
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct dib0700_state *st = d->priv;
uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */
uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
uint8_t en_start = 0;
uint8_t en_stop = 0;
uint8_t buf[255]; /* TBV: malloc ? */
int result, i;
/* Ensure nobody else hits the i2c bus while we're sending our
@ -195,24 +208,24 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
} else {
/* Write request */
buf[0] = REQUEST_NEW_I2C_WRITE;
buf[1] = msg[i].addr << 1;
buf[2] = (en_start << 7) | (en_stop << 6) |
st->buf[0] = REQUEST_NEW_I2C_WRITE;
st->buf[1] = msg[i].addr << 1;
st->buf[2] = (en_start << 7) | (en_stop << 6) |
(msg[i].len & 0x3F);
/* I2C ctrl + FE bus; */
buf[3] = ((gen_mode << 6) & 0xC0) |
st->buf[3] = ((gen_mode << 6) & 0xC0) |
((bus_mode << 4) & 0x30);
/* The Actual i2c payload */
memcpy(&buf[4], msg[i].buf, msg[i].len);
memcpy(&st->buf[4], msg[i].buf, msg[i].len);
deb_data(">>> ");
debug_dump(buf, msg[i].len + 4, deb_data);
debug_dump(st->buf, msg[i].len + 4, deb_data);
result = usb_control_msg(d->udev,
usb_sndctrlpipe(d->udev, 0),
REQUEST_NEW_I2C_WRITE,
USB_TYPE_VENDOR | USB_DIR_OUT,
0, 0, buf, msg[i].len + 4,
0, 0, st->buf, msg[i].len + 4,
USB_CTRL_GET_TIMEOUT);
if (result < 0) {
deb_info("i2c write error (status = %d)\n", result);
@ -231,27 +244,29 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
struct i2c_msg *msg, int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct dib0700_state *st = d->priv;
int i,len;
u8 buf[255];
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
for (i = 0; i < num; i++) {
/* fill in the address */
buf[1] = msg[i].addr << 1;
st->buf[1] = msg[i].addr << 1;
/* fill the buffer */
memcpy(&buf[2], msg[i].buf, msg[i].len);
memcpy(&st->buf[2], msg[i].buf, msg[i].len);
/* write/read request */
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
buf[0] = REQUEST_I2C_READ;
buf[1] |= 1;
st->buf[0] = REQUEST_I2C_READ;
st->buf[1] |= 1;
/* special thing in the current firmware: when length is zero the read-failed */
if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) {
len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2,
msg[i+1].buf, msg[i+1].len);
if (len <= 0) {
deb_info("I2C read failed on address 0x%02x\n",
msg[i].addr);
msg[i].addr);
break;
}
@ -259,13 +274,13 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
i++;
} else {
buf[0] = REQUEST_I2C_WRITE;
if (dib0700_ctrl_wr(d, buf, msg[i].len + 2) < 0)
st->buf[0] = REQUEST_I2C_WRITE;
if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0)
break;
}
}
mutex_unlock(&d->i2c_mutex);
return i;
}
@ -297,15 +312,23 @@ struct i2c_algorithm dib0700_i2c_algo = {
int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
struct dvb_usb_device_description **desc, int *cold)
{
u8 b[16];
s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
s16 ret;
u8 *b;
b = kmalloc(16, GFP_KERNEL);
if (!b)
return -ENOMEM;
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
deb_info("FW GET_VERSION length: %d\n",ret);
*cold = ret <= 0;
deb_info("cold: %d\n", *cold);
kfree(b);
return 0;
}
@ -313,43 +336,50 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
{
u8 b[10];
b[0] = REQUEST_SET_CLOCK;
b[1] = (en_pll << 7) | (pll_src << 6) | (pll_range << 5) | (clock_gpio3 << 4);
b[2] = (pll_prediv >> 8) & 0xff; // MSB
b[3] = pll_prediv & 0xff; // LSB
b[4] = (pll_loopdiv >> 8) & 0xff; // MSB
b[5] = pll_loopdiv & 0xff; // LSB
b[6] = (free_div >> 8) & 0xff; // MSB
b[7] = free_div & 0xff; // LSB
b[8] = (dsuScaler >> 8) & 0xff; // MSB
b[9] = dsuScaler & 0xff; // LSB
struct dib0700_state *st = d->priv;
s16 ret;
return dib0700_ctrl_wr(d, b, 10);
st->buf[0] = REQUEST_SET_CLOCK;
st->buf[1] = (en_pll << 7) | (pll_src << 6) |
(pll_range << 5) | (clock_gpio3 << 4);
st->buf[2] = (pll_prediv >> 8) & 0xff; /* MSB */
st->buf[3] = pll_prediv & 0xff; /* LSB */
st->buf[4] = (pll_loopdiv >> 8) & 0xff; /* MSB */
st->buf[5] = pll_loopdiv & 0xff; /* LSB */
st->buf[6] = (free_div >> 8) & 0xff; /* MSB */
st->buf[7] = free_div & 0xff; /* LSB */
st->buf[8] = (dsuScaler >> 8) & 0xff; /* MSB */
st->buf[9] = dsuScaler & 0xff; /* LSB */
ret = dib0700_ctrl_wr(d, st->buf, 10);
return ret;
}
int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
{
struct dib0700_state *st = d->priv;
u16 divider;
u8 b[8];
if (scl_kHz == 0)
return -EINVAL;
b[0] = REQUEST_SET_I2C_PARAM;
st->buf[0] = REQUEST_SET_I2C_PARAM;
divider = (u16) (30000 / scl_kHz);
b[2] = (u8) (divider >> 8);
b[3] = (u8) (divider & 0xff);
st->buf[1] = 0;
st->buf[2] = (u8) (divider >> 8);
st->buf[3] = (u8) (divider & 0xff);
divider = (u16) (72000 / scl_kHz);
b[4] = (u8) (divider >> 8);
b[5] = (u8) (divider & 0xff);
st->buf[4] = (u8) (divider >> 8);
st->buf[5] = (u8) (divider & 0xff);
divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */
b[6] = (u8) (divider >> 8);
b[7] = (u8) (divider & 0xff);
st->buf[6] = (u8) (divider >> 8);
st->buf[7] = (u8) (divider & 0xff);
deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
(b[2] << 8) | (b[3]), (b[4] << 8) | b[5], (b[6] << 8) | b[7], scl_kHz);
return dib0700_ctrl_wr(d, b, 8);
(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);
}
@ -364,32 +394,45 @@ int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
static int dib0700_jumpram(struct usb_device *udev, u32 address)
{
int ret, actlen;
u8 buf[8] = { REQUEST_JUMPRAM, 0, 0, 0,
(address >> 24) & 0xff,
(address >> 16) & 0xff,
(address >> 8) & 0xff,
address & 0xff };
int ret = 0, actlen;
u8 *buf;
buf = kmalloc(8, GFP_KERNEL);
if (!buf)
return -ENOMEM;
buf[0] = REQUEST_JUMPRAM;
buf[1] = 0;
buf[2] = 0;
buf[3] = 0;
buf[4] = (address >> 24) & 0xff;
buf[5] = (address >> 16) & 0xff;
buf[6] = (address >> 8) & 0xff;
buf[7] = address & 0xff;
if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
deb_fw("jumpram to 0x%x failed\n",address);
return ret;
goto out;
}
if (actlen != 8) {
deb_fw("jumpram to 0x%x failed\n",address);
return -EIO;
ret = -EIO;
goto out;
}
return 0;
out:
kfree(buf);
return ret;
}
int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
{
struct hexline hx;
int pos = 0, ret, act_len, i, adap_num;
u8 b[16];
u8 *buf;
u32 fw_version;
u8 buf[260];
buf = kmalloc(260, GFP_KERNEL);
if (!buf)
return -ENOMEM;
while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
@ -411,7 +454,7 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
if (ret < 0) {
err("firmware download failed at %d with %d",pos,ret);
return ret;
goto out;
}
}
@ -432,8 +475,8 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
REQUEST_GET_VERSION,
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
b, sizeof(b), USB_CTRL_GET_TIMEOUT);
fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11];
buf, 16, USB_CTRL_GET_TIMEOUT);
fw_version = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11];
/* set the buffer size - DVB-USB is allocating URB buffers
* only after the firwmare download was successful */
@ -451,14 +494,14 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
}
}
}
out:
kfree(buf);
return ret;
}
int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
struct dib0700_state *st = adap->dev->priv;
u8 b[4];
int ret;
if ((onoff != 0) && (st->fw_version >= 0x10201)) {
@ -472,15 +515,17 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
}
}
b[0] = REQUEST_ENABLE_VIDEO;
b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
st->buf[0] = REQUEST_ENABLE_VIDEO;
/* this bit gives a kind of command,
* rather than enabling something or not */
st->buf[1] = (onoff << 4) | 0x00;
if (st->disable_streaming_master_mode == 1)
b[2] = 0x00;
st->buf[2] = 0x00;
else
b[2] = 0x01 << 4; /* Master mode */
st->buf[2] = 0x01 << 4; /* Master mode */
b[3] = 0x00;
st->buf[3] = 0x00;
deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
@ -499,20 +544,23 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
st->channel_state |= 1 << (3-adap->stream.props.endpoint);
}
b[2] |= st->channel_state;
st->buf[2] |= st->channel_state;
deb_info("data for streaming: %x %x\n", b[1], b[2]);
deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
return dib0700_ctrl_wr(adap->dev, b, 4);
return dib0700_ctrl_wr(adap->dev, st->buf, 4);
}
int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
{
struct dvb_usb_device *d = rc->priv;
struct dib0700_state *st = d->priv;
u8 rc_setup[3] = { REQUEST_SET_RC, 0, 0 };
int new_proto, ret;
st->buf[0] = REQUEST_SET_RC;
st->buf[1] = 0;
st->buf[2] = 0;
/* Set the IR mode */
if (rc_type == RC_TYPE_RC5)
new_proto = 1;
@ -526,9 +574,9 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
} else
return -EINVAL;
rc_setup[1] = new_proto;
st->buf[1] = new_proto;
ret = dib0700_ctrl_wr(d, rc_setup, sizeof(rc_setup));
ret = dib0700_ctrl_wr(d, st->buf, 3);
if (ret < 0) {
err("ir protocol setup failed");
return ret;
@ -561,7 +609,6 @@ struct dib0700_rc_response {
static void dib0700_rc_urb_completion(struct urb *purb)
{
struct dvb_usb_device *d = purb->context;
struct dib0700_state *st;
struct dib0700_rc_response *poll_reply;
u32 uninitialized_var(keycode);
u8 toggle;
@ -576,7 +623,6 @@ static void dib0700_rc_urb_completion(struct urb *purb)
return;
}
st = d->priv;
poll_reply = purb->transfer_buffer;
if (purb->status < 0) {

View File

@ -2439,7 +2439,6 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
dib0700_set_i2c_speed(adap->dev, 340);
adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
if (adap->fe == NULL)
return -ENODEV;
@ -2802,6 +2801,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM7090) },
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090PVR) },
{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) },
/* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@ -3411,7 +3411,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
.num_device_descs = 3,
.num_device_descs = 4,
.devices = {
{ "DiBcom STK7770P reference design",
{ &dib0700_usb_id_table[59], NULL },
@ -3427,6 +3427,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[74], NULL },
{ NULL },
},
{ "Medion CTX1921 DVB-T USB",
{ &dib0700_usb_id_table[75], NULL },
{ NULL },
},
},
.rc.core = {

View File

@ -408,7 +408,7 @@ struct rc_map_table rc_map_dibusb_table[] = {
{ 0x8008, KEY_DVD },
{ 0x8009, KEY_AUDIO },
{ 0x800a, KEY_MEDIA }, /* Pictures */
{ 0x800a, KEY_IMAGES }, /* Pictures */
{ 0x800b, KEY_VIDEO },
{ 0x800c, KEY_BACK },

View File

@ -12,7 +12,7 @@
static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
{
struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
int newfeedcount,ret;
int newfeedcount, ret;
if (adap == NULL)
return -ENODEV;
@ -24,9 +24,13 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
deb_ts("stop feeding\n");
usb_urb_kill(&adap->stream);
if (adap->props.streaming_ctrl != NULL)
if ((ret = adap->props.streaming_ctrl(adap,0)))
if (adap->props.streaming_ctrl != NULL) {
ret = adap->props.streaming_ctrl(adap, 0);
if (ret < 0) {
err("error while stopping stream.");
return ret;
}
}
}
adap->feedcount = newfeedcount;
@ -49,17 +53,24 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
deb_ts("controlling pid parser\n");
if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
adap->props.caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
adap->props.pid_filter_ctrl != NULL)
if (adap->props.pid_filter_ctrl(adap,adap->pid_filtering) < 0)
adap->props.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);
if (ret < 0) {
err("could not handle pid_parser");
deb_ts("start feeding\n");
if (adap->props.streaming_ctrl != NULL)
if (adap->props.streaming_ctrl(adap,1)) {
err("error while enabling fifo.");
return -ENODEV;
return ret;
}
}
deb_ts("start feeding\n");
if (adap->props.streaming_ctrl != NULL) {
ret = adap->props.streaming_ctrl(adap, 1);
if (ret < 0) {
err("error while enabling fifo.");
return ret;
}
}
}
return 0;

View File

@ -91,6 +91,7 @@
#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80
#define USB_PID_CONCEPTRONIC_CTVDIGRCU 0xe397
#define USB_PID_CONEXANT_D680_DMB 0x86d6
#define USB_PID_CREATIX_CTX1921 0x1921
#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8

View File

@ -121,12 +121,16 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
u16 index, u8 * data, u16 len, int flags)
{
int ret;
u8 u8buf[len];
u8 *u8buf;
unsigned int pipe = (flags == DW210X_READ_MSG) ?
usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
u8buf = kmalloc(len, GFP_KERNEL);
if (!u8buf)
return -ENOMEM;
if (flags == DW210X_WRITE_MSG)
memcpy(u8buf, data, len);
ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
@ -134,6 +138,8 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
if (flags == DW210X_READ_MSG)
memcpy(data, u8buf, len);
kfree(u8buf);
return ret;
}

View File

@ -36,7 +36,9 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
int ret;
unsigned int pipe;
u8 request, requesttype;
u8 buf[req->size];
u8 *buf;
switch (req->cmd) {
case DOWNLOAD_FIRMWARE:
@ -72,6 +74,12 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
goto error;
}
buf = kmalloc(req->size, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto error;
}
if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
/* write */
memcpy(buf, req->data, req->size);
@ -84,13 +92,13 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
msleep(1); /* avoid I2C errors */
ret = usb_control_msg(udev, pipe, request, requesttype, req->value,
req->index, buf, sizeof(buf), EC168_USB_TIMEOUT);
req->index, buf, req->size, EC168_USB_TIMEOUT);
ec168_debug_dump(request, requesttype, req->value, req->index, buf,
req->size, deb_xfer);
if (ret < 0)
goto error;
goto err_dealloc;
else
ret = 0;
@ -98,7 +106,11 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
memcpy(req->data, buf, req->size);
kfree(buf);
return ret;
err_dealloc:
kfree(buf);
error:
deb_info("%s: failed:%d\n", __func__, ret);
return ret;

View File

@ -142,17 +142,20 @@ static u32 gl861_i2c_func(struct i2c_adapter *adapter)
return I2C_FUNC_I2C;
}
static int friio_ext_ctl(struct dvb_usb_adapter *adap,
u32 sat_color, int lnb_on)
{
int i;
int ret;
struct i2c_msg msg;
u8 buf[2];
u8 *buf;
u32 mask;
u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0;
buf = kmalloc(2, GFP_KERNEL);
if (!buf)
return -ENOMEM;
msg.addr = 0x00;
msg.flags = 0;
msg.len = 2;
@ -189,6 +192,7 @@ static int friio_ext_ctl(struct dvb_usb_adapter *adap,
buf[1] |= FRIIO_CTL_CLK;
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
kfree(buf);
return (ret == 70);
}
@ -219,11 +223,20 @@ static int friio_initialize(struct dvb_usb_device *d)
int ret;
int i;
int retry = 0;
u8 rbuf[2];
u8 wbuf[3];
u8 *rbuf, *wbuf;
deb_info("%s called.\n", __func__);
wbuf = kmalloc(3, GFP_KERNEL);
if (!wbuf)
return -ENOMEM;
rbuf = kmalloc(2, GFP_KERNEL);
if (!rbuf) {
kfree(wbuf);
return -ENOMEM;
}
/* use gl861_i2c_msg instead of gl861_i2c_xfer(), */
/* because the i2c device is not set up yet. */
wbuf[0] = 0x11;
@ -358,6 +371,8 @@ restart:
return 0;
error:
kfree(wbuf);
kfree(rbuf);
deb_info("%s:ret == %d\n", __func__, ret);
return -EIO;
}

View File

@ -62,8 +62,6 @@
* LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system
* with other tuners. After a cold reset streaming will not start.
*
* PID functions have been removed from this driver version due to
* problems with different firmware and application versions.
*/
#define DVB_USB_LOG_PREFIX "LME2510(C)"
#include <linux/usb.h>
@ -104,6 +102,10 @@ static int dvb_usb_lme2510_firmware;
module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644);
MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG");
static int pid_filter;
module_param_named(pid, pid_filter, int, 0644);
MODULE_PARM_DESC(pid, "set default 0=on 1=off");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@ -125,6 +127,7 @@ struct lme2510_state {
u8 i2c_tuner_gate_r;
u8 i2c_tuner_addr;
u8 stream_on;
u8 pid_size;
void *buffer;
struct urb *lme_urb;
void *usb_buffer;
@ -167,14 +170,14 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
}
buff = st->usb_buffer;
/* the read/write capped at 512 */
memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
ret = mutex_lock_interruptible(&d->usb_mutex);
if (ret < 0)
return -EAGAIN;
/* the read/write capped at 512 */
memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
@ -216,6 +219,37 @@ static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u32 keypress)
return 0;
}
static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
{
struct lme2510_state *st = d->priv;
static u8 pid_buff[] = LME_ZERO_PID;
static u8 rbuf[1];
u8 pid_no = index * 2;
u8 pid_len = pid_no + 2;
int ret = 0;
deb_info(1, "PID Setting Pid %04x", pid_out);
if (st->pid_size == 0)
ret |= lme2510_stream_restart(d);
pid_buff[2] = pid_no;
pid_buff[3] = (u8)pid_out & 0xff;
pid_buff[4] = pid_no + 1;
pid_buff[5] = (u8)(pid_out >> 8);
if (pid_len > st->pid_size)
st->pid_size = pid_len;
pid_buff[7] = 0x80 + st->pid_size;
ret |= lme2510_usb_talk(d, pid_buff ,
sizeof(pid_buff) , rbuf, sizeof(rbuf));
if (st->stream_on)
ret |= lme2510_stream_restart(d);
return ret;
}
static void lme2510_int_response(struct urb *lme_urb)
{
struct dvb_usb_adapter *adap = lme_urb->context;
@ -326,16 +360,68 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
return 0;
}
static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
struct lme2510_state *st = adap->dev->priv;
static u8 clear_pid_reg[] = LME_CLEAR_PID;
static u8 rbuf[1];
int ret;
deb_info(1, "PID Clearing Filter");
ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
if (ret < 0)
return -EAGAIN;
if (!onoff)
ret |= lme2510_usb_talk(adap->dev, clear_pid_reg,
sizeof(clear_pid_reg), rbuf, sizeof(rbuf));
st->pid_size = 0;
mutex_unlock(&adap->dev->i2c_mutex);
return 0;
}
static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
int onoff)
{
int ret = 0;
deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__,
pid, index, onoff);
if (onoff)
if (!pid_filter) {
ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
if (ret < 0)
return -EAGAIN;
ret |= lme2510_enable_pid(adap->dev, index, pid);
mutex_unlock(&adap->dev->i2c_mutex);
}
return ret;
}
static int lme2510_return_status(struct usb_device *dev)
{
int ret = 0;
u8 data[10] = {0};
u8 *data;
data = kzalloc(10, GFP_KERNEL);
if (!data)
return -ENOMEM;
ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
info("Firmware Status: %x (%x)", ret , data[2]);
return (ret < 0) ? -ENODEV : data[2];
ret = (ret < 0) ? -ENODEV : data[2];
kfree(data);
return ret;
}
static int lme2510_msg(struct dvb_usb_device *d,
@ -591,9 +677,10 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
else {
deb_info(1, "STM Steam Off");
/* mutex is here only to avoid collision with I2C */
ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
return -EAGAIN;
ret |= lme2510_usb_talk(adap->dev, clear_reg_3,
ret = lme2510_usb_talk(adap->dev, clear_reg_3,
sizeof(clear_reg_3), rbuf, rlen);
st->stream_on = 0;
st->i2c_talk_onoff = 1;
@ -655,7 +742,7 @@ static int lme2510_download_firmware(struct usb_device *dev,
const struct firmware *fw)
{
int ret = 0;
u8 data[512] = {0};
u8 *data;
u16 j, wlen, len_in, start, end;
u8 packet_size, dlen, i;
u8 *fw_data;
@ -663,6 +750,11 @@ static int lme2510_download_firmware(struct usb_device *dev,
packet_size = 0x31;
len_in = 1;
data = kzalloc(512, GFP_KERNEL);
if (!data) {
info("FRM Could not start Firmware Download (Buffer allocation failed)");
return -ENOMEM;
}
info("FRM Starting Firmware Download");
@ -678,15 +770,15 @@ static int lme2510_download_firmware(struct usb_device *dev,
data[0] = i | 0x80;
dlen = (u8)(end - j)-1;
}
data[1] = dlen;
memcpy(&data[2], fw_data, dlen+1);
wlen = (u8) dlen + 4;
data[wlen-1] = check_sum(fw_data, dlen+1);
deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
data[1] = dlen;
memcpy(&data[2], fw_data, dlen+1);
wlen = (u8) dlen + 4;
data[wlen-1] = check_sum(fw_data, dlen+1);
deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
data[dlen+2], data[dlen+3]);
ret |= lme2510_bulk_write(dev, data, wlen, 1);
ret |= lme2510_bulk_read(dev, data, len_in , 1);
ret |= (data[0] == 0x88) ? 0 : -1;
ret |= lme2510_bulk_write(dev, data, wlen, 1);
ret |= lme2510_bulk_read(dev, data, len_in , 1);
ret |= (data[0] == 0x88) ? 0 : -1;
}
}
@ -706,7 +798,7 @@ static int lme2510_download_firmware(struct usb_device *dev,
else
info("FRM Firmware Download Completed - Resetting Device");
kfree(data);
return (ret < 0) ? -ENODEV : 0;
}
@ -747,7 +839,7 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
fw_lme = fw_s0194;
ret = request_firmware(&fw, fw_lme, &udev->dev);
if (ret == 0) {
cold = 0;/*lme2510-s0194 cannot cold reset*/
cold = 0;
break;
}
dvb_usb_lme2510_firmware = TUNER_LG;
@ -769,8 +861,10 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
case TUNER_S7395:
fw_lme = fw_c_s7395;
ret = request_firmware(&fw, fw_lme, &udev->dev);
if (ret == 0)
if (ret == 0) {
cold = 0;
break;
}
dvb_usb_lme2510_firmware = TUNER_LG;
case TUNER_LG:
fw_lme = fw_c_lg;
@ -796,14 +890,14 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
ret = lme2510_download_firmware(udev, fw);
}
release_firmware(fw);
if (cold) {
info("FRM Changing to %s firmware", fw_lme);
lme_coldreset(udev);
return -ENODEV;
}
release_firmware(fw);
return ret;
}
@ -1017,12 +1111,13 @@ static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
static u8 rbuf[1];
int ret, len = 3, rlen = 1;
ret = mutex_lock_interruptible(&d->i2c_mutex);
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
if (onoff)
ret |= lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
else
ret |= lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
st->i2c_talk_onoff = 1;
@ -1086,7 +1181,13 @@ static struct dvb_usb_device_properties lme2510_properties = {
.num_adapters = 1,
.adapter = {
{
.caps = DVB_USB_ADAP_HAS_PID_FILTER|
DVB_USB_ADAP_NEED_PID_FILTERING|
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.streaming_ctrl = lme2510_streaming_ctrl,
.pid_filter_count = 15,
.pid_filter = lme2510_pid_filter,
.pid_filter_ctrl = lme2510_pid_filter_ctrl,
.frontend_attach = dm04_lme2510_frontend_attach,
.tuner_attach = dm04_lme2510_tuner,
/* parameter for the MPEG2-data transfer */
@ -1122,7 +1223,13 @@ static struct dvb_usb_device_properties lme2510c_properties = {
.num_adapters = 1,
.adapter = {
{
.caps = DVB_USB_ADAP_HAS_PID_FILTER|
DVB_USB_ADAP_NEED_PID_FILTERING|
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.streaming_ctrl = lme2510_streaming_ctrl,
.pid_filter_count = 15,
.pid_filter = lme2510_pid_filter,
.pid_filter_ctrl = lme2510_pid_filter_ctrl,
.frontend_attach = dm04_lme2510_frontend_attach,
.tuner_attach = dm04_lme2510_tuner,
/* parameter for the MPEG2-data transfer */
@ -1151,7 +1258,7 @@ static struct dvb_usb_device_properties lme2510c_properties = {
}
};
void *lme2510_exit_int(struct dvb_usb_device *d)
static void *lme2510_exit_int(struct dvb_usb_device *d)
{
struct lme2510_state *st = d->priv;
struct dvb_usb_adapter *adap = &d->adapter[0];
@ -1178,7 +1285,7 @@ void *lme2510_exit_int(struct dvb_usb_device *d)
return buffer;
}
void lme2510_exit(struct usb_interface *intf)
static void lme2510_exit(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
void *usb_buffer;
@ -1220,5 +1327,5 @@ module_exit(lme2510_module_exit);
MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
MODULE_VERSION("1.80");
MODULE_VERSION("1.86");
MODULE_LICENSE("GPL");

View File

@ -40,6 +40,7 @@
*/
#define LME_ST_ON_W {0x06, 0x00}
#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0}
#define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c}
/* LNB Voltage
* 07 XX XX
@ -108,14 +109,14 @@ static u8 s7395_inittab[] = {
0x3d, 0x30,
0x40, 0x63,
0x41, 0x04,
0x42, 0x60,
0x42, 0x20,
0x43, 0x00,
0x44, 0x00,
0x45, 0x00,
0x46, 0x00,
0x47, 0x00,
0x4a, 0x00,
0x50, 0x12,
0x50, 0x10,
0x51, 0x36,
0x52, 0x21,
0x53, 0x94,

View File

@ -134,13 +134,17 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
struct m920x_state *m = d->priv;
int i, ret = 0;
u8 rc_state[2];
u8 *rc_state;
rc_state = kmalloc(2, GFP_KERNEL);
if (!rc_state)
return -ENOMEM;
if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
goto unlock;
goto out;
if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
goto unlock;
goto out;
for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
if (rc5_data(&d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) {
@ -149,7 +153,7 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
switch(rc_state[0]) {
case 0x80:
*state = REMOTE_NO_KEY_PRESSED;
goto unlock;
goto out;
case 0x88: /* framing error or "invalid code" */
case 0x99:
@ -157,7 +161,7 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
case 0xd8:
*state = REMOTE_NO_KEY_PRESSED;
m->rep_count = 0;
goto unlock;
goto out;
case 0x93:
case 0x92:
@ -165,7 +169,7 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
case 0x82:
m->rep_count = 0;
*state = REMOTE_KEY_PRESSED;
goto unlock;
goto out;
case 0x91:
case 0x81: /* pinnacle PCTV310e */
@ -174,12 +178,12 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*state = REMOTE_KEY_REPEAT;
else
*state = REMOTE_NO_KEY_PRESSED;
goto unlock;
goto out;
default:
deb("Unexpected rc state %02x\n", rc_state[0]);
*state = REMOTE_NO_KEY_PRESSED;
goto unlock;
goto out;
}
}
@ -188,8 +192,8 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*state = REMOTE_NO_KEY_PRESSED;
unlock:
out:
kfree(rc_state);
return ret;
}
@ -339,13 +343,19 @@ static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, in
static int m920x_firmware_download(struct usb_device *udev, const struct firmware *fw)
{
u16 value, index, size;
u8 read[4], *buff;
u8 *read, *buff;
int i, pass, ret = 0;
buff = kmalloc(65536, GFP_KERNEL);
if (buff == NULL)
return -ENOMEM;
read = kmalloc(4, GFP_KERNEL);
if (!read) {
kfree(buff);
return -ENOMEM;
}
if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0)
goto done;
deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
@ -396,6 +406,7 @@ static int m920x_firmware_download(struct usb_device *udev, const struct firmwar
deb("firmware uploaded!\n");
done:
kfree(read);
kfree(buff);
return ret;
@ -632,9 +643,9 @@ static struct rc_map_table rc_map_pinnacle310e_table[] = {
{ 0x16, KEY_POWER },
{ 0x17, KEY_FAVORITES },
{ 0x0f, KEY_TEXT },
{ 0x48, KEY_MEDIA }, /* preview */
{ 0x48, KEY_PROGRAM }, /* preview */
{ 0x1c, KEY_EPG },
{ 0x04, KEY_LIST }, /* record list */
{ 0x04, KEY_LIST }, /* record list */
{ 0x03, KEY_1 },
{ 0x01, KEY_2 },
{ 0x06, KEY_3 },
@ -674,14 +685,14 @@ static struct rc_map_table rc_map_pinnacle310e_table[] = {
{ 0x0e, KEY_MUTE },
/* { 0x49, KEY_LR }, */ /* L/R */
{ 0x07, KEY_SLEEP }, /* Hibernate */
{ 0x08, KEY_MEDIA }, /* A/V */
{ 0x0e, KEY_MENU }, /* Recall */
{ 0x08, KEY_VIDEO }, /* A/V */
{ 0x0e, KEY_MENU }, /* Recall */
{ 0x45, KEY_ZOOMIN },
{ 0x46, KEY_ZOOMOUT },
{ 0x18, KEY_TV }, /* Red */
{ 0x53, KEY_VCR }, /* Green */
{ 0x5e, KEY_SAT }, /* Yellow */
{ 0x5f, KEY_PLAYER }, /* Blue */
{ 0x18, KEY_RED }, /* Red */
{ 0x53, KEY_GREEN }, /* Green */
{ 0x5e, KEY_YELLOW }, /* Yellow */
{ 0x5f, KEY_BLUE }, /* Blue */
};
/* DVB USB Driver stuff */

View File

@ -47,7 +47,7 @@ static struct rc_map_table rc_map_haupp_table[] = {
{ 0x1e17, KEY_RIGHT },
{ 0x1e18, KEY_VIDEO },
{ 0x1e19, KEY_AUDIO },
{ 0x1e1a, KEY_MEDIA },
{ 0x1e1a, KEY_IMAGES },
{ 0x1e1b, KEY_EPG },
{ 0x1e1c, KEY_TV },
{ 0x1e1e, KEY_NEXT },

View File

@ -53,27 +53,36 @@ static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
u8 * data, u16 len, int flags)
{
int ret;
u8 r;
u8 u8buf[len];
u8 tmp;
u8 *buf;
unsigned int pipe = (flags == OPERA_READ_MSG) ?
usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0);
u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
buf = kmalloc(len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
if (flags == OPERA_WRITE_MSG)
memcpy(u8buf, data, len);
ret =
usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
value, 0x0, u8buf, len, 2000);
memcpy(buf, data, len);
ret = usb_control_msg(dev, pipe, request,
request_type | USB_TYPE_VENDOR, value, 0x0,
buf, len, 2000);
if (request == OPERA_TUNER_REQ) {
tmp = buf[0];
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
0x01, 0x0, &r, 1, 2000)<1 || r!=0x08)
return 0;
OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
0x01, 0x0, buf, 1, 2000) < 1 || buf[0] != 0x08) {
ret = 0;
goto out;
}
buf[0] = tmp;
}
if (flags == OPERA_READ_MSG)
memcpy(data, u8buf, len);
memcpy(data, buf, len);
out:
kfree(buf);
return ret;
}
@ -189,7 +198,7 @@ static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
static u8 opera1_inittab[] = {
0x00, 0xa1,
0x01, 0x15,
0x02, 0x00,
0x02, 0x30,
0x03, 0x00,
0x04, 0x7d,
0x05, 0x05,

View File

@ -41,14 +41,23 @@ struct vp702x_fe_state {
static int vp702x_fe_refresh_state(struct vp702x_fe_state *st)
{
u8 buf[10];
if (time_after(jiffies,st->next_status_check)) {
vp702x_usb_in_op(st->d,READ_STATUS,0,0,buf,10);
struct vp702x_device_state *dst = st->d->priv;
u8 *buf;
if (time_after(jiffies, st->next_status_check)) {
mutex_lock(&dst->buf_mutex);
buf = dst->buf;
vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10);
st->lock = buf[4];
vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x11,0,&st->snr,1);
vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x15,0,&st->sig,1);
vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1);
st->snr = buf[0];
vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1);
st->sig = buf[0];
mutex_unlock(&dst->buf_mutex);
st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
}
return 0;
@ -130,11 +139,17 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct vp702x_fe_state *st = fe->demodulator_priv;
struct vp702x_device_state *dst = st->d->priv;
u32 freq = fep->frequency/1000;
/*CalFrequency*/
/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */
u64 sr;
u8 cmd[8] = { 0 },ibuf[10];
u8 *cmd;
mutex_lock(&dst->buf_mutex);
cmd = dst->buf;
memset(cmd, 0, 10);
cmd[0] = (freq >> 8) & 0x7f;
cmd[1] = freq & 0xff;
@ -170,13 +185,15 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
st->status_check_interval = 250;
st->next_status_check = jiffies;
vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
if (ibuf[2] == 0 && ibuf[3] == 0)
if (cmd[2] == 0 && cmd[3] == 0)
deb_fe("tuning failed.\n");
else
deb_fe("tuning succeeded.\n");
mutex_unlock(&dst->buf_mutex);
return 0;
}
@ -204,27 +221,32 @@ static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
struct dvb_diseqc_master_cmd *m)
{
u8 *cmd;
struct vp702x_fe_state *st = fe->demodulator_priv;
u8 cmd[8],ibuf[10];
memset(cmd,0,8);
struct vp702x_device_state *dst = st->d->priv;
deb_fe("%s\n",__func__);
if (m->msg_len > 4)
return -EINVAL;
mutex_lock(&dst->buf_mutex);
cmd = dst->buf;
cmd[1] = SET_DISEQC_CMD;
cmd[2] = m->msg_len;
memcpy(&cmd[3], m->msg, m->msg_len);
cmd[7] = vp702x_chksum(cmd,0,7);
cmd[7] = vp702x_chksum(cmd, 0, 7);
vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
if (ibuf[2] == 0 && ibuf[3] == 0)
if (cmd[2] == 0 && cmd[3] == 0)
deb_fe("diseqc cmd failed.\n");
else
deb_fe("diseqc cmd succeeded.\n");
mutex_unlock(&dst->buf_mutex);
return 0;
}
@ -237,7 +259,9 @@ static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd
static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
struct vp702x_fe_state *st = fe->demodulator_priv;
u8 ibuf[10];
struct vp702x_device_state *dst = st->d->priv;
u8 *buf;
deb_fe("%s\n",__func__);
st->tone_mode = tone;
@ -247,14 +271,21 @@ static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
else
st->lnb_buf[2] = 0x00;
st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7);
st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100);
if (ibuf[2] == 0 && ibuf[3] == 0)
mutex_lock(&dst->buf_mutex);
buf = dst->buf;
memcpy(buf, st->lnb_buf, 8);
vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
if (buf[2] == 0 && buf[3] == 0)
deb_fe("set_tone cmd failed.\n");
else
deb_fe("set_tone cmd succeeded.\n");
mutex_unlock(&dst->buf_mutex);
return 0;
}
@ -262,7 +293,8 @@ static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t
voltage)
{
struct vp702x_fe_state *st = fe->demodulator_priv;
u8 ibuf[10];
struct vp702x_device_state *dst = st->d->priv;
u8 *buf;
deb_fe("%s\n",__func__);
st->voltage = voltage;
@ -272,14 +304,20 @@ static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t
else
st->lnb_buf[4] = 0x00;
st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7);
st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100);
if (ibuf[2] == 0 && ibuf[3] == 0)
mutex_lock(&dst->buf_mutex);
buf = dst->buf;
memcpy(buf, st->lnb_buf, 8);
vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
if (buf[2] == 0 && buf[3] == 0)
deb_fe("set_voltage cmd failed.\n");
else
deb_fe("set_voltage cmd succeeded.\n");
mutex_unlock(&dst->buf_mutex);
return 0;
}

View File

@ -15,6 +15,7 @@
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "vp702x.h"
#include <linux/mutex.h>
/* debug */
int dvb_usb_vp702x_debug;
@ -23,27 +24,23 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DV
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct vp702x_state {
struct vp702x_adapter_state {
int pid_filter_count;
int pid_filter_can_bypass;
u8 pid_filter_state;
};
struct vp702x_device_state {
u8 power_state;
};
/* check for mutex FIXME */
int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req,
u16 value, u16 index, u8 *b, int blen)
{
int ret = -1;
int ret;
ret = usb_control_msg(d->udev,
usb_rcvctrlpipe(d->udev,0),
req,
USB_TYPE_VENDOR | USB_DIR_IN,
value,index,b,blen,
2000);
ret = usb_control_msg(d->udev,
usb_rcvctrlpipe(d->udev, 0),
req,
USB_TYPE_VENDOR | USB_DIR_IN,
value, index, b, blen,
2000);
if (ret < 0) {
warn("usb in operation failed. (%d)", ret);
@ -58,8 +55,20 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
return ret;
}
static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
u16 index, u8 *b, int blen)
int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
u16 index, u8 *b, int blen)
{
int ret;
mutex_lock(&d->usb_mutex);
ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen);
mutex_unlock(&d->usb_mutex);
return ret;
}
int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req, u16 value,
u16 index, u8 *b, int blen)
{
int ret;
deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
@ -77,6 +86,18 @@ static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
return 0;
}
int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
u16 index, u8 *b, int blen)
{
int ret;
mutex_lock(&d->usb_mutex);
ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen);
mutex_unlock(&d->usb_mutex);
return ret;
}
int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
{
int ret;
@ -84,50 +105,93 @@ int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int il
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
return ret;
ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen);
ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen);
msleep(msec);
ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen);
mutex_unlock(&d->usb_mutex);
return ret;
}
static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
int olen, u8 *i, int ilen, int msec)
{
u8 bout[olen+2];
u8 bin[ilen+1];
struct vp702x_device_state *st = d->priv;
int ret = 0;
u8 *buf;
int buflen = max(olen + 2, ilen + 1);
bout[0] = 0x00;
bout[1] = cmd;
memcpy(&bout[2],o,olen);
ret = mutex_lock_interruptible(&st->buf_mutex);
if (ret < 0)
return ret;
ret = vp702x_usb_inout_op(d, bout, olen+2, bin, ilen+1,msec);
if (buflen > st->buf_len) {
buf = kmalloc(buflen, GFP_KERNEL);
if (!buf) {
mutex_unlock(&st->buf_mutex);
return -ENOMEM;
}
info("successfully reallocated a bigger buffer");
kfree(st->buf);
st->buf = buf;
st->buf_len = buflen;
} else {
buf = st->buf;
}
buf[0] = 0x00;
buf[1] = cmd;
memcpy(&buf[2], o, olen);
ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec);
if (ret == 0)
memcpy(i,&bin[1],ilen);
memcpy(i, &buf[1], ilen);
mutex_unlock(&st->buf_mutex);
return ret;
}
static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
{
u8 buf[16] = { 0 };
return vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, 0, buf, 16);
int ret;
struct vp702x_device_state *st = adap->dev->priv;
u8 *buf;
mutex_lock(&st->buf_mutex);
buf = st->buf;
memset(buf, 0, 16);
ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e,
0, buf, 16);
mutex_unlock(&st->buf_mutex);
return ret;
}
static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
{
u8 buf[16] = { 0 };
return vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, 0, buf, 16);
int ret;
struct vp702x_device_state *st = adap->dev->priv;
u8 *buf;
mutex_lock(&st->buf_mutex);
buf = st->buf;
memset(buf, 0, 16);
ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f,
0, buf, 16);
mutex_unlock(&st->buf_mutex);
return ret;
}
static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
{
struct vp702x_state *st = adap->priv;
u8 buf[16] = { 0 };
struct vp702x_adapter_state *st = adap->priv;
struct vp702x_device_state *dst = adap->dev->priv;
u8 *buf;
if (onoff)
st->pid_filter_state |= (1 << id);
@ -139,32 +203,45 @@ static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onof
id = 0x10 + id*2;
vp702x_set_pld_state(adap, st->pid_filter_state);
mutex_lock(&dst->buf_mutex);
buf = dst->buf;
memset(buf, 0, 16);
vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16);
mutex_unlock(&dst->buf_mutex);
return 0;
}
static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
{
struct vp702x_state *st = adap->priv;
struct vp702x_adapter_state *st = adap->priv;
struct vp702x_device_state *dst = adap->dev->priv;
int i;
u8 b[10] = { 0 };
u8 *b;
st->pid_filter_count = 8;
st->pid_filter_can_bypass = 1;
st->pid_filter_state = 0x00;
vp702x_set_pld_mode(adap, 1); // bypass
vp702x_set_pld_mode(adap, 1); /* bypass */
for (i = 0; i < st->pid_filter_count; i++)
vp702x_set_pid(adap, 0xffff, i, 1);
mutex_lock(&dst->buf_mutex);
b = dst->buf;
memset(b, 0, 10);
vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
mutex_unlock(&dst->buf_mutex);
/*vp702x_set_pld_mode(d, 0); // filter */
//vp702x_set_pld_mode(d, 0); // filter
return 0;
}
@ -182,18 +259,23 @@ static struct rc_map_table rc_map_vp702x_table[] = {
/* remote control stuff (does not work with my box) */
static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 key[10];
u8 *key;
int i;
/* remove the following return to enabled remote querying */
return 0;
key = kmalloc(10, GFP_KERNEL);
if (!key)
return -ENOMEM;
vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
deb_rc("remote query key: %x %d\n",key[1],key[1]);
if (key[1] == 0x44) {
*state = REMOTE_NO_KEY_PRESSED;
kfree(key);
return 0;
}
@ -203,15 +285,23 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*event = rc_map_vp702x_table[i].keycode;
break;
}
kfree(key);
return 0;
}
static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
{
u8 i;
u8 i, *buf;
struct vp702x_device_state *st = d->priv;
mutex_lock(&st->buf_mutex);
buf = st->buf;
for (i = 6; i < 12; i++)
vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &mac[i - 6], 1);
vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1);
memcpy(mac, buf, 6);
mutex_unlock(&st->buf_mutex);
return 0;
}
@ -221,7 +311,8 @@ static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, buf, 10, 10))
if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
buf, 10, 10))
return -EIO;
buf[9] = '\0';
@ -240,8 +331,38 @@ static struct dvb_usb_device_properties vp702x_properties;
static int vp702x_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return dvb_usb_device_init(intf, &vp702x_properties,
THIS_MODULE, NULL, adapter_nr);
struct dvb_usb_device *d;
struct vp702x_device_state *st;
int ret;
ret = dvb_usb_device_init(intf, &vp702x_properties,
THIS_MODULE, &d, adapter_nr);
if (ret)
goto out;
st = d->priv;
st->buf_len = 16;
st->buf = kmalloc(st->buf_len, GFP_KERNEL);
if (!st->buf) {
ret = -ENOMEM;
dvb_usb_device_exit(intf);
goto out;
}
mutex_init(&st->buf_mutex);
out:
return ret;
}
static void vp702x_usb_disconnect(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
struct vp702x_device_state *st = d->priv;
mutex_lock(&st->buf_mutex);
kfree(st->buf);
mutex_unlock(&st->buf_mutex);
dvb_usb_device_exit(intf);
}
static struct usb_device_id vp702x_usb_table [] = {
@ -278,7 +399,7 @@ static struct dvb_usb_device_properties vp702x_properties = {
}
}
},
.size_of_priv = sizeof(struct vp702x_state),
.size_of_priv = sizeof(struct vp702x_adapter_state),
}
},
.read_mac_address = vp702x_read_mac_addr,
@ -307,9 +428,9 @@ static struct dvb_usb_device_properties vp702x_properties = {
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver vp702x_usb_driver = {
.name = "dvb_usb_vp702x",
.probe = vp702x_usb_probe,
.disconnect = dvb_usb_device_exit,
.id_table = vp702x_usb_table,
.probe = vp702x_usb_probe,
.disconnect = vp702x_usb_disconnect,
.id_table = vp702x_usb_table,
};
/* module stuff */

View File

@ -98,6 +98,13 @@ extern int dvb_usb_vp702x_debug;
#define RESET_TUNER 0xBE
/* IN i: 0, v: 0, no extra buffer */
struct vp702x_device_state {
struct mutex buf_mutex;
int buf_len;
u8 *buf;
};
extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);

View File

@ -28,9 +28,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
{
int ret = 0;
u8 inbuf[12] = { 0 }, outbuf[20] = { 0 };
u8 *buf = d->priv;
outbuf[0] = cmd;
buf[0] = cmd;
if (outlen > 19)
outlen = 19;
@ -38,19 +38,21 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
if (inlen > 11)
inlen = 11;
ret = mutex_lock_interruptible(&d->usb_mutex);
if (ret)
return ret;
if (out != NULL && outlen > 0)
memcpy(&outbuf[1], out, outlen);
memcpy(&buf[1], out, outlen);
deb_xfer("out buffer: ");
debug_dump(outbuf,outlen+1,deb_xfer);
debug_dump(buf, outlen+1, deb_xfer);
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
return ret;
if (usb_control_msg(d->udev,
usb_sndctrlpipe(d->udev,0),
TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
outbuf, 20, 2000) != 20) {
buf, 20, 2000) != 20) {
err("USB control message 'out' went wrong.");
ret = -EIO;
goto unlock;
@ -61,17 +63,17 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
if (usb_control_msg(d->udev,
usb_rcvctrlpipe(d->udev,0),
TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
inbuf, 12, 2000) != 12) {
buf, 12, 2000) != 12) {
err("USB control message 'in' went wrong.");
ret = -EIO;
goto unlock;
}
deb_xfer("in buffer: ");
debug_dump(inbuf,12,deb_xfer);
debug_dump(buf, 12, deb_xfer);
if (in != NULL && inlen > 0)
memcpy(in,&inbuf[1],inlen);
memcpy(in, &buf[1], inlen);
unlock:
mutex_unlock(&d->usb_mutex);
@ -222,8 +224,26 @@ static struct dvb_usb_device_properties vp7045_properties;
static int vp7045_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return dvb_usb_device_init(intf, &vp7045_properties,
THIS_MODULE, NULL, adapter_nr);
struct dvb_usb_device *d;
int ret = dvb_usb_device_init(intf, &vp7045_properties,
THIS_MODULE, &d, adapter_nr);
if (ret)
return ret;
d->priv = kmalloc(20, GFP_KERNEL);
if (!d->priv) {
dvb_usb_device_exit(intf);
return -ENOMEM;
}
return ret;
}
static void vp7045_usb_disconnect(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
kfree(d->priv);
dvb_usb_device_exit(intf);
}
static struct usb_device_id vp7045_usb_table [] = {
@ -238,6 +258,7 @@ MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
static struct dvb_usb_device_properties vp7045_properties = {
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-vp7045-01.fw",
.size_of_priv = sizeof(u8 *),
.num_adapters = 1,
.adapter = {
@ -284,7 +305,7 @@ static struct dvb_usb_device_properties vp7045_properties = {
static struct usb_driver vp7045_usb_driver = {
.name = "dvb_usb_vp7045",
.probe = vp7045_usb_probe,
.disconnect = dvb_usb_device_exit,
.disconnect = vp7045_usb_disconnect,
.id_table = vp7045_usb_table,
};

View File

@ -263,18 +263,16 @@ config DVB_S5H1432
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_DRX397XD
tristate "Micronas DRX3975D/DRX3977D based"
config DVB_DRXD
tristate "Micronas DRXD driver"
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.
TODO:
This driver needs external firmware. Please use the command
"<kerneldir>/Documentation/dvb/get_dvb_firmware drx397xD" to
download/extract them, and then copy them to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
Note: this driver was based on vendor driver reference code (released
under the GPL) as opposed to the existing drx397xd driver, which
was written via reverse engineering.
config DVB_L64781
tristate "LSI L64781"
@ -385,6 +383,13 @@ config DVB_STV0367
help
A DVB-T/C tuner module. Say Y when you want to support this frontend.
config DVB_CXD2820R
tristate "Sony CXD2820R"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
Say Y when you want to support this frontend.
comment "DVB-C (cable) frontends"
depends on DVB_CORE

View File

@ -8,6 +8,8 @@ EXTRA_CFLAGS += -Idrivers/media/common/tuners/
stb0899-objs = stb0899_drv.o stb0899_algo.o
stv0900-objs = stv0900_core.o stv0900_sw.o
au8522-objs = au8522_dig.o au8522_decoder.o
drxd-objs = drxd_firm.o drxd_hard.o
cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
@ -36,7 +38,7 @@ obj-$(CONFIG_DVB_ZL10036) += zl10036.o
obj-$(CONFIG_DVB_ZL10039) += zl10039.o
obj-$(CONFIG_DVB_ZL10353) += zl10353.o
obj-$(CONFIG_DVB_CX22702) += cx22702.o
obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o
obj-$(CONFIG_DVB_DRXD) += drxd.o
obj-$(CONFIG_DVB_TDA10021) += tda10021.o
obj-$(CONFIG_DVB_TDA10023) += tda10023.o
obj-$(CONFIG_DVB_STV0297) += stv0297.o
@ -85,3 +87,5 @@ obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
obj-$(CONFIG_DVB_STV0367) += stv0367.o
obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o

View File

@ -0,0 +1,146 @@
/*
* bsbe1-d01a.h - ALPS BSBE1-D01A tuner support
*
* Copyright (C) 2011 Oliver Endriss <o.endriss@gmx.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
* the project's page is at http://www.linuxtv.org
*/
#ifndef BSBE1_D01A_H
#define BSBE1_D01A_H
#include "stb6000.h"
#include "stv0288.h"
static u8 stv0288_bsbe1_d01a_inittab[] = {
0x01, 0x15,
0x02, 0x20,
0x09, 0x0,
0x0a, 0x4,
0x0b, 0x0,
0x0c, 0x0,
0x0d, 0x0,
0x0e, 0xd4,
0x0f, 0x30,
0x11, 0x80,
0x12, 0x03,
0x13, 0x48,
0x14, 0x84,
0x15, 0x45,
0x16, 0xb7,
0x17, 0x9c,
0x18, 0x0,
0x19, 0xa6,
0x1a, 0x88,
0x1b, 0x8f,
0x1c, 0xf0,
0x20, 0x0b,
0x21, 0x54,
0x22, 0x0,
0x23, 0x0,
0x2b, 0xff,
0x2c, 0xf7,
0x30, 0x0,
0x31, 0x1e,
0x32, 0x14,
0x33, 0x0f,
0x34, 0x09,
0x35, 0x0c,
0x36, 0x05,
0x37, 0x2f,
0x38, 0x16,
0x39, 0xbd,
0x3a, 0x03,
0x3b, 0x13,
0x3c, 0x11,
0x3d, 0x30,
0x40, 0x63,
0x41, 0x04,
0x42, 0x60,
0x43, 0x00,
0x44, 0x00,
0x45, 0x00,
0x46, 0x00,
0x47, 0x00,
0x4a, 0x00,
0x50, 0x10,
0x51, 0x36,
0x52, 0x09,
0x53, 0x94,
0x54, 0x62,
0x55, 0x29,
0x56, 0x64,
0x57, 0x2b,
0x58, 0x54,
0x59, 0x86,
0x5a, 0x0,
0x5b, 0x9b,
0x5c, 0x08,
0x5d, 0x7f,
0x5e, 0x0,
0x5f, 0xff,
0x70, 0x0,
0x71, 0x0,
0x72, 0x0,
0x74, 0x0,
0x75, 0x0,
0x76, 0x0,
0x81, 0x0,
0x82, 0x3f,
0x83, 0x3f,
0x84, 0x0,
0x85, 0x0,
0x88, 0x0,
0x89, 0x0,
0x8a, 0x0,
0x8b, 0x0,
0x8c, 0x0,
0x90, 0x0,
0x91, 0x0,
0x92, 0x0,
0x93, 0x0,
0x94, 0x1c,
0x97, 0x0,
0xa0, 0x48,
0xa1, 0x0,
0xb0, 0xb8,
0xb1, 0x3a,
0xb2, 0x10,
0xb3, 0x82,
0xb4, 0x80,
0xb5, 0x82,
0xb6, 0x82,
0xb7, 0x82,
0xb8, 0x20,
0xb9, 0x0,
0xf0, 0x0,
0xf1, 0x0,
0xf2, 0xc0,
0xff, 0xff,
};
static struct stv0288_config stv0288_bsbe1_d01a_config = {
.demod_address = 0x68,
.min_delay_ms = 100,
.inittab = stv0288_bsbe1_d01a_inittab,
};
#endif

View File

@ -27,7 +27,7 @@
static u8 alps_bsru6_inittab[] = {
0x01, 0x15,
0x02, 0x00,
0x02, 0x30,
0x03, 0x00,
0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */

View File

@ -137,7 +137,7 @@ MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
/* SNR measurements */
static int esno_snr;
module_param(esno_snr, int, 0644);
MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, "\
MODULE_PARM_DESC(esno_snr, "SNR return units, 0=PERCENTAGE 0-100, "\
"1=ESNO(db * 10) (default:0)");
enum cmds {
@ -566,7 +566,7 @@ static int cx24116_load_firmware(struct dvb_frontend *fe,
{
struct cx24116_state *state = fe->demodulator_priv;
struct cx24116_cmd cmd;
int i, ret;
int i, ret, len, max, remaining;
unsigned char vers[4];
dprintk("%s\n", __func__);
@ -603,8 +603,21 @@ static int cx24116_load_firmware(struct dvb_frontend *fe,
cx24116_writereg(state, 0xF5, 0x00);
cx24116_writereg(state, 0xF6, 0x00);
/* write the entire firmware as one transaction */
cx24116_writeregN(state, 0xF7, fw->data, fw->size);
/* Split firmware to the max I2C write len and write.
* Writes whole firmware as one write when i2c_wr_max is set to 0. */
if (state->config->i2c_wr_max)
max = state->config->i2c_wr_max;
else
max = INT_MAX; /* enough for 32k firmware */
for (remaining = fw->size; remaining > 0; remaining -= max - 1) {
len = remaining;
if (len > max - 1)
len = max - 1;
cx24116_writeregN(state, 0xF7, &fw->data[fw->size - remaining],
len);
}
cx24116_writereg(state, 0xF4, 0x10);
cx24116_writereg(state, 0xF0, 0x00);

View File

@ -35,6 +35,9 @@ struct cx24116_config {
/* Need to set MPEG parameters */
u8 mpg_clk_pos_pol:0x02;
/* max bytes I2C provider can write at once */
u16 i2c_wr_max;
};
#if defined(CONFIG_DVB_CX24116) || \

View File

@ -0,0 +1,118 @@
/*
* Sony CXD2820R demodulator driver
*
* Copyright (C) 2010 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.
*/
#ifndef CXD2820R_H
#define CXD2820R_H
#include <linux/dvb/frontend.h>
#define CXD2820R_GPIO_D (0 << 0) /* disable */
#define CXD2820R_GPIO_E (1 << 0) /* enable */
#define CXD2820R_GPIO_O (0 << 1) /* output */
#define CXD2820R_GPIO_I (1 << 1) /* input */
#define CXD2820R_GPIO_L (0 << 2) /* output low */
#define CXD2820R_GPIO_H (1 << 2) /* output high */
#define CXD2820R_TS_SERIAL 0x08
#define CXD2820R_TS_SERIAL_MSB 0x28
#define CXD2820R_TS_PARALLEL 0x30
#define CXD2820R_TS_PARALLEL_MSB 0x70
struct cxd2820r_config {
/* Demodulator I2C address.
* Driver determines DVB-C slave I2C address automatically from master
* address.
* Default: none, must set
* Values: 0x6c, 0x6d
*/
u8 i2c_address;
/* TS output mode.
* Default: none, must set.
* Values:
*/
u8 ts_mode;
/* IF AGC polarity.
* Default: 0
* Values: 0, 1
*/
int if_agc_polarity:1;
/* Spectrum inversion.
* Default: 0
* Values: 0, 1
*/
int spec_inv:1;
/* IFs for all used modes.
* Default: none, must set
* Values: <kHz>
*/
u16 if_dvbt_6;
u16 if_dvbt_7;
u16 if_dvbt_8;
u16 if_dvbt2_5;
u16 if_dvbt2_6;
u16 if_dvbt2_7;
u16 if_dvbt2_8;
u16 if_dvbc;
/* GPIOs for all used modes.
* Default: none, disabled
* Values: <see above>
*/
u8 gpio_dvbt[3];
u8 gpio_dvbt2[3];
u8 gpio_dvbc[3];
};
#if defined(CONFIG_DVB_CXD2820R) || \
(defined(CONFIG_DVB_CXD2820R_MODULE) && defined(MODULE))
extern struct dvb_frontend *cxd2820r_attach(
const struct cxd2820r_config *config,
struct i2c_adapter *i2c,
struct dvb_frontend *fe
);
extern struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(
struct dvb_frontend *fe
);
#else
static inline struct dvb_frontend *cxd2820r_attach(
const struct cxd2820r_config *config,
struct i2c_adapter *i2c,
struct dvb_frontend *fe
)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
static inline struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(
struct dvb_frontend *fe
)
{
return NULL;
}
#endif
#endif /* CXD2820R_H */

View File

@ -0,0 +1,338 @@
/*
* Sony CXD2820R demodulator driver
*
* Copyright (C) 2010 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 "cxd2820r_priv.h"
int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
u8 buf[2];
u16 if_ctl;
u64 num;
struct reg_val_mask tab[] = {
{ 0x00080, 0x01, 0xff },
{ 0x00081, 0x05, 0xff },
{ 0x00085, 0x07, 0xff },
{ 0x00088, 0x01, 0xff },
{ 0x00082, 0x20, 0x60 },
{ 0x1016a, 0x48, 0xff },
{ 0x100a5, 0x00, 0x01 },
{ 0x10020, 0x06, 0x07 },
{ 0x10059, 0x50, 0xff },
{ 0x10087, 0x0c, 0x3c },
{ 0x1008b, 0x07, 0xff },
{ 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 },
{ 0x10070, priv->cfg.ts_mode, 0xff },
};
dbg("%s: RF=%d SR=%d", __func__, c->frequency, c->symbol_rate);
/* update GPIOs */
ret = cxd2820r_gpio(fe);
if (ret)
goto error;
/* program tuner */
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe, params);
if (priv->delivery_system != SYS_DVBC_ANNEX_AC) {
for (i = 0; i < ARRAY_SIZE(tab); i++) {
ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
tab[i].val, tab[i].mask);
if (ret)
goto error;
}
}
priv->delivery_system = SYS_DVBC_ANNEX_AC;
priv->ber_running = 0; /* tune stops BER counter */
num = priv->cfg.if_dvbc;
num *= 0x4000;
if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
buf[0] = (if_ctl >> 8) & 0x3f;
buf[1] = (if_ctl >> 0) & 0xff;
ret = cxd2820r_wr_regs(priv, 0x10042, buf, 2);
if (ret)
goto error;
ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
if (ret)
goto error;
ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
if (ret)
goto error;
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[2];
ret = cxd2820r_rd_regs(priv, 0x1001a, buf, 2);
if (ret)
goto error;
c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]);
ret = cxd2820r_rd_reg(priv, 0x10019, &buf[0]);
if (ret)
goto error;
switch ((buf[0] >> 0) & 0x03) {
case 0:
c->modulation = QAM_16;
break;
case 1:
c->modulation = QAM_32;
break;
case 2:
c->modulation = QAM_64;
break;
case 3:
c->modulation = QAM_128;
break;
case 4:
c->modulation = QAM_256;
break;
}
switch ((buf[0] >> 7) & 0x01) {
case 0:
c->inversion = INVERSION_OFF;
break;
case 1:
c->inversion = INVERSION_ON;
break;
}
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 buf[3], start_ber = 0;
*ber = 0;
if (priv->ber_running) {
ret = cxd2820r_rd_regs(priv, 0x10076, buf, sizeof(buf));
if (ret)
goto error;
if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
*ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
start_ber = 1;
}
} else {
priv->ber_running = 1;
start_ber = 1;
}
if (start_ber) {
/* (re)start BER */
ret = cxd2820r_wr_reg(priv, 0x10079, 0x01);
if (ret)
goto error;
}
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe,
u16 *strength)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 buf[2];
u16 tmp;
ret = cxd2820r_rd_regs(priv, 0x10049, buf, sizeof(buf));
if (ret)
goto error;
tmp = (buf[0] & 0x03) << 8 | buf[1];
tmp = (~tmp & 0x03ff);
if (tmp == 512)
/* ~no signal */
tmp = 0;
else if (tmp > 350)
tmp = 350;
/* scale value to 0x0000-0xffff */
*strength = tmp * 0xffff / (350-0);
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 tmp;
unsigned int A, B;
/* report SNR in dB * 10 */
ret = cxd2820r_rd_reg(priv, 0x10019, &tmp);
if (ret)
goto error;
if (((tmp >> 0) & 0x03) % 2) {
A = 875;
B = 650;
} else {
A = 950;
B = 760;
}
ret = cxd2820r_rd_reg(priv, 0x1004d, &tmp);
if (ret)
goto error;
#define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */
if (tmp)
*snr = A * (intlog2(B / tmp) >> 5) / (CXD2820R_LOG2_E_24 >> 5)
/ 10;
else
*snr = 0;
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks)
{
*ucblocks = 0;
/* no way to read ? */
return 0;
}
int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 buf[2];
*status = 0;
ret = cxd2820r_rd_regs(priv, 0x10088, buf, sizeof(buf));
if (ret)
goto error;
if (((buf[0] >> 0) & 0x01) == 1) {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC;
if (((buf[1] >> 3) & 0x01) == 1) {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
}
}
dbg("%s: lock=%02x %02x", __func__, buf[0], buf[1]);
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_init_c(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
if (ret)
goto error;
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_sleep_c(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret, i;
struct reg_val_mask tab[] = {
{ 0x000ff, 0x1f, 0xff },
{ 0x00085, 0x00, 0xff },
{ 0x00088, 0x01, 0xff },
{ 0x00081, 0x00, 0xff },
{ 0x00080, 0x00, 0xff },
};
dbg("%s", __func__);
priv->delivery_system = SYS_UNDEFINED;
for (i = 0; i < ARRAY_SIZE(tab); i++) {
ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
tab[i].mask);
if (ret)
goto error;
}
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s)
{
s->min_delay_ms = 500;
s->step_size = 0; /* no zigzag */
s->max_drift = 0;
return 0;
}

View File

@ -0,0 +1,915 @@
/*
* Sony CXD2820R demodulator driver
*
* Copyright (C) 2010 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 "cxd2820r_priv.h"
int cxd2820r_debug;
module_param_named(debug, cxd2820r_debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
/* write multiple registers */
static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
u8 *val, int len)
{
int ret;
u8 buf[len+1];
struct i2c_msg msg[1] = {
{
.addr = i2c,
.flags = 0,
.len = sizeof(buf),
.buf = buf,
}
};
buf[0] = reg;
memcpy(&buf[1], val, len);
ret = i2c_transfer(priv->i2c, msg, 1);
if (ret == 1) {
ret = 0;
} else {
warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
/* read multiple registers */
static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
u8 *val, int len)
{
int ret;
u8 buf[len];
struct i2c_msg msg[2] = {
{
.addr = i2c,
.flags = 0,
.len = 1,
.buf = &reg,
}, {
.addr = i2c,
.flags = I2C_M_RD,
.len = sizeof(buf),
.buf = buf,
}
};
ret = i2c_transfer(priv->i2c, msg, 2);
if (ret == 2) {
memcpy(val, buf, len);
ret = 0;
} else {
warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
/* write multiple registers */
int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
int len)
{
int ret;
u8 i2c_addr;
u8 reg = (reginfo >> 0) & 0xff;
u8 bank = (reginfo >> 8) & 0xff;
u8 i2c = (reginfo >> 16) & 0x01;
/* select I2C */
if (i2c)
i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
else
i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
/* switch bank if needed */
if (bank != priv->bank[i2c]) {
ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
if (ret)
return ret;
priv->bank[i2c] = bank;
}
return cxd2820r_wr_regs_i2c(priv, i2c_addr, reg, val, len);
}
/* read multiple registers */
int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
int len)
{
int ret;
u8 i2c_addr;
u8 reg = (reginfo >> 0) & 0xff;
u8 bank = (reginfo >> 8) & 0xff;
u8 i2c = (reginfo >> 16) & 0x01;
/* select I2C */
if (i2c)
i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
else
i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
/* switch bank if needed */
if (bank != priv->bank[i2c]) {
ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
if (ret)
return ret;
priv->bank[i2c] = bank;
}
return cxd2820r_rd_regs_i2c(priv, i2c_addr, reg, val, len);
}
/* write single register */
int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val)
{
return cxd2820r_wr_regs(priv, reg, &val, 1);
}
/* read single register */
int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val)
{
return cxd2820r_rd_regs(priv, reg, val, 1);
}
/* write single register with mask */
int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val,
u8 mask)
{
int ret;
u8 tmp;
/* no need for read if whole reg is written */
if (mask != 0xff) {
ret = cxd2820r_rd_reg(priv, reg, &tmp);
if (ret)
return ret;
val &= mask;
tmp &= ~mask;
val |= tmp;
}
return cxd2820r_wr_reg(priv, reg, val);
}
int cxd2820r_gpio(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret, i;
u8 *gpio, tmp0, tmp1;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBT:
gpio = priv->cfg.gpio_dvbt;
break;
case SYS_DVBT2:
gpio = priv->cfg.gpio_dvbt2;
break;
case SYS_DVBC_ANNEX_AC:
gpio = priv->cfg.gpio_dvbc;
break;
default:
ret = -EINVAL;
goto error;
}
/* update GPIOs only when needed */
if (!memcmp(gpio, priv->gpio, sizeof(priv->gpio)))
return 0;
tmp0 = 0x00;
tmp1 = 0x00;
for (i = 0; i < sizeof(priv->gpio); i++) {
/* enable / disable */
if (gpio[i] & CXD2820R_GPIO_E)
tmp0 |= (2 << 6) >> (2 * i);
else
tmp0 |= (1 << 6) >> (2 * i);
/* input / output */
if (gpio[i] & CXD2820R_GPIO_I)
tmp1 |= (1 << (3 + i));
else
tmp1 |= (0 << (3 + i));
/* high / low */
if (gpio[i] & CXD2820R_GPIO_H)
tmp1 |= (1 << (0 + i));
else
tmp1 |= (0 << (0 + i));
dbg("%s: GPIO i=%d %02x %02x", __func__, i, tmp0, tmp1);
}
dbg("%s: wr gpio=%02x %02x", __func__, tmp0, tmp1);
/* write bits [7:2] */
ret = cxd2820r_wr_reg_mask(priv, 0x00089, tmp0, 0xfc);
if (ret)
goto error;
/* write bits [5:0] */
ret = cxd2820r_wr_reg_mask(priv, 0x0008e, tmp1, 0x3f);
if (ret)
goto error;
memcpy(priv->gpio, gpio, sizeof(priv->gpio));
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
/* lock FE */
static int cxd2820r_lock(struct cxd2820r_priv *priv, int active_fe)
{
int ret = 0;
dbg("%s: active_fe=%d", __func__, active_fe);
mutex_lock(&priv->fe_lock);
/* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
if (priv->active_fe == active_fe)
;
else if (priv->active_fe == -1)
priv->active_fe = active_fe;
else
ret = -EBUSY;
mutex_unlock(&priv->fe_lock);
return ret;
}
/* unlock FE */
static void cxd2820r_unlock(struct cxd2820r_priv *priv, int active_fe)
{
dbg("%s: active_fe=%d", __func__, active_fe);
mutex_lock(&priv->fe_lock);
/* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
if (priv->active_fe == active_fe)
priv->active_fe = -1;
mutex_unlock(&priv->fe_lock);
return;
}
/* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */
u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor)
{
return div_u64(dividend + (divisor / 2), divisor);
}
static int cxd2820r_set_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
if (fe->ops.info.type == FE_OFDM) {
/* DVB-T/T2 */
ret = cxd2820r_lock(priv, 0);
if (ret)
return ret;
switch (priv->delivery_system) {
case SYS_UNDEFINED:
if (c->delivery_system == SYS_DVBT) {
/* SLEEP => DVB-T */
ret = cxd2820r_set_frontend_t(fe, p);
} else {
/* SLEEP => DVB-T2 */
ret = cxd2820r_set_frontend_t2(fe, p);
}
break;
case SYS_DVBT:
if (c->delivery_system == SYS_DVBT) {
/* DVB-T => DVB-T */
ret = cxd2820r_set_frontend_t(fe, p);
} else if (c->delivery_system == SYS_DVBT2) {
/* DVB-T => DVB-T2 */
ret = cxd2820r_sleep_t(fe);
ret = cxd2820r_set_frontend_t2(fe, p);
}
break;
case SYS_DVBT2:
if (c->delivery_system == SYS_DVBT2) {
/* DVB-T2 => DVB-T2 */
ret = cxd2820r_set_frontend_t2(fe, p);
} else if (c->delivery_system == SYS_DVBT) {
/* DVB-T2 => DVB-T */
ret = cxd2820r_sleep_t2(fe);
ret = cxd2820r_set_frontend_t(fe, p);
}
break;
default:
dbg("%s: error state=%d", __func__,
priv->delivery_system);
ret = -EINVAL;
}
} else {
/* DVB-C */
ret = cxd2820r_lock(priv, 1);
if (ret)
return ret;
ret = cxd2820r_set_frontend_c(fe, p);
}
return ret;
}
static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
if (fe->ops.info.type == FE_OFDM) {
/* DVB-T/T2 */
ret = cxd2820r_lock(priv, 0);
if (ret)
return ret;
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBT:
ret = cxd2820r_read_status_t(fe, status);
break;
case SYS_DVBT2:
ret = cxd2820r_read_status_t2(fe, status);
break;
default:
ret = -EINVAL;
}
} else {
/* DVB-C */
ret = cxd2820r_lock(priv, 1);
if (ret)
return ret;
ret = cxd2820r_read_status_c(fe, status);
}
return ret;
}
static int cxd2820r_get_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
if (fe->ops.info.type == FE_OFDM) {
/* DVB-T/T2 */
ret = cxd2820r_lock(priv, 0);
if (ret)
return ret;
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBT:
ret = cxd2820r_get_frontend_t(fe, p);
break;
case SYS_DVBT2:
ret = cxd2820r_get_frontend_t2(fe, p);
break;
default:
ret = -EINVAL;
}
} else {
/* DVB-C */
ret = cxd2820r_lock(priv, 1);
if (ret)
return ret;
ret = cxd2820r_get_frontend_c(fe, p);
}
return ret;
}
static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
if (fe->ops.info.type == FE_OFDM) {
/* DVB-T/T2 */
ret = cxd2820r_lock(priv, 0);
if (ret)
return ret;
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBT:
ret = cxd2820r_read_ber_t(fe, ber);
break;
case SYS_DVBT2:
ret = cxd2820r_read_ber_t2(fe, ber);
break;
default:
ret = -EINVAL;
}
} else {
/* DVB-C */
ret = cxd2820r_lock(priv, 1);
if (ret)
return ret;
ret = cxd2820r_read_ber_c(fe, ber);
}
return ret;
}
static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
if (fe->ops.info.type == FE_OFDM) {
/* DVB-T/T2 */
ret = cxd2820r_lock(priv, 0);
if (ret)
return ret;
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBT:
ret = cxd2820r_read_signal_strength_t(fe, strength);
break;
case SYS_DVBT2:
ret = cxd2820r_read_signal_strength_t2(fe, strength);
break;
default:
ret = -EINVAL;
}
} else {
/* DVB-C */
ret = cxd2820r_lock(priv, 1);
if (ret)
return ret;
ret = cxd2820r_read_signal_strength_c(fe, strength);
}
return ret;
}
static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
if (fe->ops.info.type == FE_OFDM) {
/* DVB-T/T2 */
ret = cxd2820r_lock(priv, 0);
if (ret)
return ret;
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBT:
ret = cxd2820r_read_snr_t(fe, snr);
break;
case SYS_DVBT2:
ret = cxd2820r_read_snr_t2(fe, snr);
break;
default:
ret = -EINVAL;
}
} else {
/* DVB-C */
ret = cxd2820r_lock(priv, 1);
if (ret)
return ret;
ret = cxd2820r_read_snr_c(fe, snr);
}
return ret;
}
static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
if (fe->ops.info.type == FE_OFDM) {
/* DVB-T/T2 */
ret = cxd2820r_lock(priv, 0);
if (ret)
return ret;
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBT:
ret = cxd2820r_read_ucblocks_t(fe, ucblocks);
break;
case SYS_DVBT2:
ret = cxd2820r_read_ucblocks_t2(fe, ucblocks);
break;
default:
ret = -EINVAL;
}
} else {
/* DVB-C */
ret = cxd2820r_lock(priv, 1);
if (ret)
return ret;
ret = cxd2820r_read_ucblocks_c(fe, ucblocks);
}
return ret;
}
static int cxd2820r_init(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
priv->delivery_system = SYS_UNDEFINED;
/* delivery system is unknown at that (init) phase */
if (fe->ops.info.type == FE_OFDM) {
/* DVB-T/T2 */
ret = cxd2820r_lock(priv, 0);
if (ret)
return ret;
ret = cxd2820r_init_t(fe);
} else {
/* DVB-C */
ret = cxd2820r_lock(priv, 1);
if (ret)
return ret;
ret = cxd2820r_init_c(fe);
}
return ret;
}
static int cxd2820r_sleep(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
if (fe->ops.info.type == FE_OFDM) {
/* DVB-T/T2 */
ret = cxd2820r_lock(priv, 0);
if (ret)
return ret;
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBT:
ret = cxd2820r_sleep_t(fe);
break;
case SYS_DVBT2:
ret = cxd2820r_sleep_t2(fe);
break;
default:
ret = -EINVAL;
}
cxd2820r_unlock(priv, 0);
} else {
/* DVB-C */
ret = cxd2820r_lock(priv, 1);
if (ret)
return ret;
ret = cxd2820r_sleep_c(fe);
cxd2820r_unlock(priv, 1);
}
return ret;
}
static int cxd2820r_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
if (fe->ops.info.type == FE_OFDM) {
/* DVB-T/T2 */
ret = cxd2820r_lock(priv, 0);
if (ret)
return ret;
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBT:
ret = cxd2820r_get_tune_settings_t(fe, s);
break;
case SYS_DVBT2:
ret = cxd2820r_get_tune_settings_t2(fe, s);
break;
default:
ret = -EINVAL;
}
} else {
/* DVB-C */
ret = cxd2820r_lock(priv, 1);
if (ret)
return ret;
ret = cxd2820r_get_tune_settings_c(fe, s);
}
return ret;
}
static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
fe_status_t status = 0;
dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
/* switch between DVB-T and DVB-T2 when tune fails */
if (priv->last_tune_failed) {
if (priv->delivery_system == SYS_DVBT)
c->delivery_system = SYS_DVBT2;
else
c->delivery_system = SYS_DVBT;
}
/* set frontend */
ret = cxd2820r_set_frontend(fe, p);
if (ret)
goto error;
/* frontend lock wait loop count */
switch (priv->delivery_system) {
case SYS_DVBT:
i = 20;
break;
case SYS_DVBT2:
i = 40;
break;
case SYS_UNDEFINED:
default:
i = 0;
break;
}
/* wait frontend lock */
for (; i > 0; i--) {
dbg("%s: LOOP=%d", __func__, i);
msleep(50);
ret = cxd2820r_read_status(fe, &status);
if (ret)
goto error;
if (status & FE_HAS_SIGNAL)
break;
}
/* check if we have a valid signal */
if (status) {
priv->last_tune_failed = 0;
return DVBFE_ALGO_SEARCH_SUCCESS;
} else {
priv->last_tune_failed = 1;
return DVBFE_ALGO_SEARCH_AGAIN;
}
error:
dbg("%s: failed:%d", __func__, ret);
return DVBFE_ALGO_SEARCH_ERROR;
}
static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe)
{
return DVBFE_ALGO_CUSTOM;
}
static void cxd2820r_release(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
dbg("%s", __func__);
if (fe->ops.info.type == FE_OFDM) {
i2c_del_adapter(&priv->tuner_i2c_adapter);
kfree(priv);
}
return;
}
static u32 cxd2820r_tuner_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C;
}
static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msg[], int num)
{
struct cxd2820r_priv *priv = i2c_get_adapdata(i2c_adap);
u8 obuf[msg[0].len + 2];
struct i2c_msg msg2[2] = {
{
.addr = priv->cfg.i2c_address,
.flags = 0,
.len = sizeof(obuf),
.buf = obuf,
}, {
.addr = priv->cfg.i2c_address,
.flags = I2C_M_RD,
.len = msg[1].len,
.buf = msg[1].buf,
}
};
obuf[0] = 0x09;
obuf[1] = (msg[0].addr << 1);
if (num == 2) { /* I2C read */
obuf[1] = (msg[0].addr << 1) | I2C_M_RD; /* I2C RD flag */
msg2[0].len = sizeof(obuf) - 1; /* maybe HW bug ? */
}
memcpy(&obuf[2], msg[0].buf, msg[0].len);
return i2c_transfer(priv->i2c, msg2, num);
}
static struct i2c_algorithm cxd2820r_tuner_i2c_algo = {
.master_xfer = cxd2820r_tuner_i2c_xfer,
.functionality = cxd2820r_tuner_i2c_func,
};
struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
return &priv->tuner_i2c_adapter;
}
EXPORT_SYMBOL(cxd2820r_get_tuner_i2c_adapter);
static struct dvb_frontend_ops cxd2820r_ops[2];
struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
struct i2c_adapter *i2c, struct dvb_frontend *fe)
{
int ret;
struct cxd2820r_priv *priv = NULL;
u8 tmp;
if (fe == NULL) {
/* FE0 */
/* allocate memory for the internal priv */
priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL);
if (priv == NULL)
goto error;
/* setup the priv */
priv->i2c = i2c;
memcpy(&priv->cfg, cfg, sizeof(struct cxd2820r_config));
mutex_init(&priv->fe_lock);
priv->active_fe = -1; /* NONE */
/* check if the demod is there */
priv->bank[0] = priv->bank[1] = 0xff;
ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp);
dbg("%s: chip id=%02x", __func__, tmp);
if (ret || tmp != 0xe1)
goto error;
/* create frontends */
memcpy(&priv->fe[0].ops, &cxd2820r_ops[0],
sizeof(struct dvb_frontend_ops));
memcpy(&priv->fe[1].ops, &cxd2820r_ops[1],
sizeof(struct dvb_frontend_ops));
priv->fe[0].demodulator_priv = priv;
priv->fe[1].demodulator_priv = priv;
/* create tuner i2c adapter */
strlcpy(priv->tuner_i2c_adapter.name,
"CXD2820R tuner I2C adapter",
sizeof(priv->tuner_i2c_adapter.name));
priv->tuner_i2c_adapter.algo = &cxd2820r_tuner_i2c_algo;
priv->tuner_i2c_adapter.algo_data = NULL;
i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
err("tuner I2C bus could not be initialized");
goto error;
}
return &priv->fe[0];
} else {
/* FE1: FE0 given as pointer, just return FE1 we have
* already created */
priv = fe->demodulator_priv;
return &priv->fe[1];
}
error:
kfree(priv);
return NULL;
}
EXPORT_SYMBOL(cxd2820r_attach);
static struct dvb_frontend_ops cxd2820r_ops[2] = {
{
/* DVB-T/T2 */
.info = {
.name = "Sony CXD2820R (DVB-T/T2)",
.type = FE_OFDM,
.caps =
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_QAM_16 |
FE_CAN_QAM_64 | FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO |
FE_CAN_MUTE_TS |
FE_CAN_2G_MODULATION
},
.release = cxd2820r_release,
.init = cxd2820r_init,
.sleep = cxd2820r_sleep,
.get_tune_settings = cxd2820r_get_tune_settings,
.get_frontend = cxd2820r_get_frontend,
.get_frontend_algo = cxd2820r_get_frontend_algo,
.search = cxd2820r_search,
.read_status = cxd2820r_read_status,
.read_snr = cxd2820r_read_snr,
.read_ber = cxd2820r_read_ber,
.read_ucblocks = cxd2820r_read_ucblocks,
.read_signal_strength = cxd2820r_read_signal_strength,
},
{
/* DVB-C */
.info = {
.name = "Sony CXD2820R (DVB-C)",
.type = FE_QAM,
.caps =
FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
FE_CAN_QAM_128 | FE_CAN_QAM_256 |
FE_CAN_FEC_AUTO
},
.release = cxd2820r_release,
.init = cxd2820r_init,
.sleep = cxd2820r_sleep,
.get_tune_settings = cxd2820r_get_tune_settings,
.set_frontend = cxd2820r_set_frontend,
.get_frontend = cxd2820r_get_frontend,
.read_status = cxd2820r_read_status,
.read_snr = cxd2820r_read_snr,
.read_ber = cxd2820r_read_ber,
.read_ucblocks = cxd2820r_read_ucblocks,
.read_signal_strength = cxd2820r_read_signal_strength,
},
};
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Sony CXD2820R demodulator driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,166 @@
/*
* Sony CXD2820R demodulator driver
*
* Copyright (C) 2010 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.
*/
#ifndef CXD2820R_PRIV_H
#define CXD2820R_PRIV_H
#include <linux/dvb/version.h>
#include "dvb_frontend.h"
#include "dvb_math.h"
#include "cxd2820r.h"
#define LOG_PREFIX "cxd2820r"
#undef dbg
#define dbg(f, arg...) \
if (cxd2820r_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 reg_val_mask {
u32 reg;
u8 val;
u8 mask;
};
struct cxd2820r_priv {
struct i2c_adapter *i2c;
struct dvb_frontend fe[2];
struct cxd2820r_config cfg;
struct i2c_adapter tuner_i2c_adapter;
struct mutex fe_lock; /* FE lock */
int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */
int ber_running:1;
u8 bank[2];
u8 gpio[3];
fe_delivery_system_t delivery_system;
int last_tune_failed:1; /* for switch between T and T2 tune */
};
/* cxd2820r_core.c */
extern int cxd2820r_debug;
int cxd2820r_gpio(struct dvb_frontend *fe);
int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val,
u8 mask);
int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
int len);
u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor);
int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
int len);
int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
int len);
int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val);
int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val);
/* cxd2820r_c.c */
int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p);
int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params);
int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status);
int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber);
int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe, u16 *strength);
int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr);
int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks);
int cxd2820r_init_c(struct dvb_frontend *fe);
int cxd2820r_sleep_c(struct dvb_frontend *fe);
int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s);
/* cxd2820r_t.c */
int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p);
int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params);
int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status);
int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber);
int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe, u16 *strength);
int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr);
int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks);
int cxd2820r_init_t(struct dvb_frontend *fe);
int cxd2820r_sleep_t(struct dvb_frontend *fe);
int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s);
/* cxd2820r_t2.c */
int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p);
int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params);
int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status);
int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber);
int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe, u16 *strength);
int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr);
int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks);
int cxd2820r_init_t2(struct dvb_frontend *fe);
int cxd2820r_sleep_t2(struct dvb_frontend *fe);
int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s);
#endif /* CXD2820R_PRIV_H */

View File

@ -0,0 +1,449 @@
/*
* Sony CXD2820R demodulator driver
*
* Copyright (C) 2010 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 "cxd2820r_priv.h"
int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
u32 if_khz, if_ctl;
u64 num;
u8 buf[3], bw_param;
u8 bw_params1[][5] = {
{ 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
{ 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
{ 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
};
u8 bw_params2[][2] = {
{ 0x1f, 0xdc }, /* 6 MHz */
{ 0x12, 0xf8 }, /* 7 MHz */
{ 0x01, 0xe0 }, /* 8 MHz */
};
struct reg_val_mask tab[] = {
{ 0x00080, 0x00, 0xff },
{ 0x00081, 0x03, 0xff },
{ 0x00085, 0x07, 0xff },
{ 0x00088, 0x01, 0xff },
{ 0x00070, priv->cfg.ts_mode, 0xff },
{ 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 },
{ 0x000a5, 0x00, 0x01 },
{ 0x00082, 0x20, 0x60 },
{ 0x000c2, 0xc3, 0xff },
{ 0x0016a, 0x50, 0xff },
{ 0x00427, 0x41, 0xff },
};
dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
/* update GPIOs */
ret = cxd2820r_gpio(fe);
if (ret)
goto error;
/* program tuner */
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe, p);
if (priv->delivery_system != SYS_DVBT) {
for (i = 0; i < ARRAY_SIZE(tab); i++) {
ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
tab[i].val, tab[i].mask);
if (ret)
goto error;
}
}
priv->delivery_system = SYS_DVBT;
priv->ber_running = 0; /* tune stops BER counter */
switch (c->bandwidth_hz) {
case 6000000:
if_khz = priv->cfg.if_dvbt_6;
i = 0;
bw_param = 2;
break;
case 7000000:
if_khz = priv->cfg.if_dvbt_7;
i = 1;
bw_param = 1;
break;
case 8000000:
if_khz = priv->cfg.if_dvbt_8;
i = 2;
bw_param = 0;
break;
default:
return -EINVAL;
}
num = if_khz;
num *= 0x1000000;
if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
buf[0] = ((if_ctl >> 16) & 0xff);
buf[1] = ((if_ctl >> 8) & 0xff);
buf[2] = ((if_ctl >> 0) & 0xff);
ret = cxd2820r_wr_regs(priv, 0x000b6, buf, 3);
if (ret)
goto error;
ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[i], 5);
if (ret)
goto error;
ret = cxd2820r_wr_reg_mask(priv, 0x000d7, bw_param << 6, 0xc0);
if (ret)
goto error;
ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[i], 2);
if (ret)
goto error;
ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
if (ret)
goto error;
ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
if (ret)
goto error;
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[2];
ret = cxd2820r_rd_regs(priv, 0x0002f, buf, sizeof(buf));
if (ret)
goto error;
switch ((buf[0] >> 6) & 0x03) {
case 0:
c->modulation = QPSK;
break;
case 1:
c->modulation = QAM_16;
break;
case 2:
c->modulation = QAM_64;
break;
}
switch ((buf[1] >> 1) & 0x03) {
case 0:
c->transmission_mode = TRANSMISSION_MODE_2K;
break;
case 1:
c->transmission_mode = TRANSMISSION_MODE_8K;
break;
}
switch ((buf[1] >> 3) & 0x03) {
case 0:
c->guard_interval = GUARD_INTERVAL_1_32;
break;
case 1:
c->guard_interval = GUARD_INTERVAL_1_16;
break;
case 2:
c->guard_interval = GUARD_INTERVAL_1_8;
break;
case 3:
c->guard_interval = GUARD_INTERVAL_1_4;
break;
}
switch ((buf[0] >> 3) & 0x07) {
case 0:
c->hierarchy = HIERARCHY_NONE;
break;
case 1:
c->hierarchy = HIERARCHY_1;
break;
case 2:
c->hierarchy = HIERARCHY_2;
break;
case 3:
c->hierarchy = HIERARCHY_4;
break;
}
switch ((buf[0] >> 0) & 0x07) {
case 0:
c->code_rate_HP = FEC_1_2;
break;
case 1:
c->code_rate_HP = FEC_2_3;
break;
case 2:
c->code_rate_HP = FEC_3_4;
break;
case 3:
c->code_rate_HP = FEC_5_6;
break;
case 4:
c->code_rate_HP = FEC_7_8;
break;
}
switch ((buf[1] >> 5) & 0x07) {
case 0:
c->code_rate_LP = FEC_1_2;
break;
case 1:
c->code_rate_LP = FEC_2_3;
break;
case 2:
c->code_rate_LP = FEC_3_4;
break;
case 3:
c->code_rate_LP = FEC_5_6;
break;
case 4:
c->code_rate_LP = FEC_7_8;
break;
}
ret = cxd2820r_rd_reg(priv, 0x007c6, &buf[0]);
if (ret)
goto error;
switch ((buf[0] >> 0) & 0x01) {
case 0:
c->inversion = INVERSION_OFF;
break;
case 1:
c->inversion = INVERSION_ON;
break;
}
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 buf[3], start_ber = 0;
*ber = 0;
if (priv->ber_running) {
ret = cxd2820r_rd_regs(priv, 0x00076, buf, sizeof(buf));
if (ret)
goto error;
if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
*ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
start_ber = 1;
}
} else {
priv->ber_running = 1;
start_ber = 1;
}
if (start_ber) {
/* (re)start BER */
ret = cxd2820r_wr_reg(priv, 0x00079, 0x01);
if (ret)
goto error;
}
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe,
u16 *strength)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 buf[2];
u16 tmp;
ret = cxd2820r_rd_regs(priv, 0x00026, buf, sizeof(buf));
if (ret)
goto error;
tmp = (buf[0] & 0x0f) << 8 | buf[1];
tmp = ~tmp & 0x0fff;
/* scale value to 0x0000-0xffff from 0x0000-0x0fff */
*strength = tmp * 0xffff / 0x0fff;
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 buf[2];
u16 tmp;
/* report SNR in dB * 10 */
ret = cxd2820r_rd_regs(priv, 0x00028, buf, sizeof(buf));
if (ret)
goto error;
tmp = (buf[0] & 0x1f) << 8 | buf[1];
#define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
if (tmp)
*snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
/ 100);
else
*snr = 0;
dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks)
{
*ucblocks = 0;
/* no way to read ? */
return 0;
}
int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 buf[4];
*status = 0;
ret = cxd2820r_rd_reg(priv, 0x00010, &buf[0]);
if (ret)
goto error;
if ((buf[0] & 0x07) == 6) {
ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]);
if (ret)
goto error;
if (((buf[1] >> 3) & 0x01) == 1) {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
} else {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC;
}
} else {
ret = cxd2820r_rd_reg(priv, 0x00014, &buf[2]);
if (ret)
goto error;
if ((buf[2] & 0x0f) >= 4) {
ret = cxd2820r_rd_reg(priv, 0x00a14, &buf[3]);
if (ret)
goto error;
if (((buf[3] >> 4) & 0x01) == 1)
*status |= FE_HAS_SIGNAL;
}
}
dbg("%s: lock=%02x %02x %02x %02x", __func__,
buf[0], buf[1], buf[2], buf[3]);
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_init_t(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
if (ret)
goto error;
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_sleep_t(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret, i;
struct reg_val_mask tab[] = {
{ 0x000ff, 0x1f, 0xff },
{ 0x00085, 0x00, 0xff },
{ 0x00088, 0x01, 0xff },
{ 0x00081, 0x00, 0xff },
{ 0x00080, 0x00, 0xff },
};
dbg("%s", __func__);
priv->delivery_system = SYS_UNDEFINED;
for (i = 0; i < ARRAY_SIZE(tab); i++) {
ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
tab[i].mask);
if (ret)
goto error;
}
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s)
{
s->min_delay_ms = 500;
s->step_size = fe->ops.info.frequency_stepsize * 2;
s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
return 0;
}

View File

@ -0,0 +1,423 @@
/*
* Sony CXD2820R demodulator driver
*
* Copyright (C) 2010 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 "cxd2820r_priv.h"
int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
u32 if_khz, if_ctl;
u64 num;
u8 buf[3], bw_param;
u8 bw_params1[][5] = {
{ 0x1c, 0xb3, 0x33, 0x33, 0x33 }, /* 5 MHz */
{ 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
{ 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
{ 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
};
struct reg_val_mask tab[] = {
{ 0x00080, 0x02, 0xff },
{ 0x00081, 0x20, 0xff },
{ 0x00085, 0x07, 0xff },
{ 0x00088, 0x01, 0xff },
{ 0x02069, 0x01, 0xff },
{ 0x0207f, 0x2a, 0xff },
{ 0x02082, 0x0a, 0xff },
{ 0x02083, 0x0a, 0xff },
{ 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 },
{ 0x02070, priv->cfg.ts_mode, 0xff },
{ 0x020b5, priv->cfg.spec_inv << 4, 0x10 },
{ 0x02567, 0x07, 0x0f },
{ 0x02569, 0x03, 0x03 },
{ 0x02595, 0x1a, 0xff },
{ 0x02596, 0x50, 0xff },
{ 0x02a8c, 0x00, 0xff },
{ 0x02a8d, 0x34, 0xff },
{ 0x02a45, 0x06, 0x07 },
{ 0x03f10, 0x0d, 0xff },
{ 0x03f11, 0x02, 0xff },
{ 0x03f12, 0x01, 0xff },
{ 0x03f23, 0x2c, 0xff },
{ 0x03f51, 0x13, 0xff },
{ 0x03f52, 0x01, 0xff },
{ 0x03f53, 0x00, 0xff },
{ 0x027e6, 0x14, 0xff },
{ 0x02786, 0x02, 0x07 },
{ 0x02787, 0x40, 0xe0 },
{ 0x027ef, 0x10, 0x18 },
};
dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
/* update GPIOs */
ret = cxd2820r_gpio(fe);
if (ret)
goto error;
/* program tuner */
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe, params);
if (priv->delivery_system != SYS_DVBT2) {
for (i = 0; i < ARRAY_SIZE(tab); i++) {
ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
tab[i].val, tab[i].mask);
if (ret)
goto error;
}
}
priv->delivery_system = SYS_DVBT2;
switch (c->bandwidth_hz) {
case 5000000:
if_khz = priv->cfg.if_dvbt2_5;
i = 0;
bw_param = 3;
break;
case 6000000:
if_khz = priv->cfg.if_dvbt2_6;
i = 1;
bw_param = 2;
break;
case 7000000:
if_khz = priv->cfg.if_dvbt2_7;
i = 2;
bw_param = 1;
break;
case 8000000:
if_khz = priv->cfg.if_dvbt2_8;
i = 3;
bw_param = 0;
break;
default:
return -EINVAL;
}
num = if_khz;
num *= 0x1000000;
if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
buf[0] = ((if_ctl >> 16) & 0xff);
buf[1] = ((if_ctl >> 8) & 0xff);
buf[2] = ((if_ctl >> 0) & 0xff);
ret = cxd2820r_wr_regs(priv, 0x020b6, buf, 3);
if (ret)
goto error;
ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[i], 5);
if (ret)
goto error;
ret = cxd2820r_wr_reg_mask(priv, 0x020d7, bw_param << 6, 0xc0);
if (ret)
goto error;
ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
if (ret)
goto error;
ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
if (ret)
goto error;
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[2];
ret = cxd2820r_rd_regs(priv, 0x0205c, buf, 2);
if (ret)
goto error;
switch ((buf[0] >> 0) & 0x07) {
case 0:
c->transmission_mode = TRANSMISSION_MODE_2K;
break;
case 1:
c->transmission_mode = TRANSMISSION_MODE_8K;
break;
case 2:
c->transmission_mode = TRANSMISSION_MODE_4K;
break;
case 3:
c->transmission_mode = TRANSMISSION_MODE_1K;
break;
case 4:
c->transmission_mode = TRANSMISSION_MODE_16K;
break;
case 5:
c->transmission_mode = TRANSMISSION_MODE_32K;
break;
}
switch ((buf[1] >> 4) & 0x07) {
case 0:
c->guard_interval = GUARD_INTERVAL_1_32;
break;
case 1:
c->guard_interval = GUARD_INTERVAL_1_16;
break;
case 2:
c->guard_interval = GUARD_INTERVAL_1_8;
break;
case 3:
c->guard_interval = GUARD_INTERVAL_1_4;
break;
case 4:
c->guard_interval = GUARD_INTERVAL_1_128;
break;
case 5:
c->guard_interval = GUARD_INTERVAL_19_128;
break;
case 6:
c->guard_interval = GUARD_INTERVAL_19_256;
break;
}
ret = cxd2820r_rd_regs(priv, 0x0225b, buf, 2);
if (ret)
goto error;
switch ((buf[0] >> 0) & 0x07) {
case 0:
c->fec_inner = FEC_1_2;
break;
case 1:
c->fec_inner = FEC_3_5;
break;
case 2:
c->fec_inner = FEC_2_3;
break;
case 3:
c->fec_inner = FEC_3_4;
break;
case 4:
c->fec_inner = FEC_4_5;
break;
case 5:
c->fec_inner = FEC_5_6;
break;
}
switch ((buf[1] >> 0) & 0x07) {
case 0:
c->modulation = QPSK;
break;
case 1:
c->modulation = QAM_16;
break;
case 2:
c->modulation = QAM_64;
break;
case 3:
c->modulation = QAM_256;
break;
}
ret = cxd2820r_rd_reg(priv, 0x020b5, &buf[0]);
if (ret)
goto error;
switch ((buf[0] >> 4) & 0x01) {
case 0:
c->inversion = INVERSION_OFF;
break;
case 1:
c->inversion = INVERSION_ON;
break;
}
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 buf[1];
*status = 0;
ret = cxd2820r_rd_reg(priv, 0x02010 , &buf[0]);
if (ret)
goto error;
if ((buf[0] & 0x07) == 6) {
if (((buf[0] >> 5) & 0x01) == 1) {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
} else {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC;
}
}
dbg("%s: lock=%02x", __func__, buf[0]);
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 buf[4];
unsigned int errbits;
*ber = 0;
/* FIXME: correct calculation */
ret = cxd2820r_rd_regs(priv, 0x02039, buf, sizeof(buf));
if (ret)
goto error;
if ((buf[0] >> 4) & 0x01) {
errbits = (buf[0] & 0x0f) << 24 | buf[1] << 16 |
buf[2] << 8 | buf[3];
if (errbits)
*ber = errbits * 64 / 16588800;
}
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe,
u16 *strength)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 buf[2];
u16 tmp;
ret = cxd2820r_rd_regs(priv, 0x02026, buf, sizeof(buf));
if (ret)
goto error;
tmp = (buf[0] & 0x0f) << 8 | buf[1];
tmp = ~tmp & 0x0fff;
/* scale value to 0x0000-0xffff from 0x0000-0x0fff */
*strength = tmp * 0xffff / 0x0fff;
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
u8 buf[2];
u16 tmp;
/* report SNR in dB * 10 */
ret = cxd2820r_rd_regs(priv, 0x02028, buf, sizeof(buf));
if (ret)
goto error;
tmp = (buf[0] & 0x0f) << 8 | buf[1];
#define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
if (tmp)
*snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
/ 100);
else
*snr = 0;
dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks)
{
*ucblocks = 0;
/* no way to read ? */
return 0;
}
int cxd2820r_sleep_t2(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret, i;
struct reg_val_mask tab[] = {
{ 0x000ff, 0x1f, 0xff },
{ 0x00085, 0x00, 0xff },
{ 0x00088, 0x01, 0xff },
{ 0x02069, 0x00, 0xff },
{ 0x00081, 0x00, 0xff },
{ 0x00080, 0x00, 0xff },
};
dbg("%s", __func__);
for (i = 0; i < ARRAY_SIZE(tab); i++) {
ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
tab[i].mask);
if (ret)
goto error;
}
priv->delivery_system = SYS_UNDEFINED;
return ret;
error:
dbg("%s: failed:%d", __func__, ret);
return ret;
}
int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s)
{
s->min_delay_ms = 1500;
s->step_size = fe->ops.info.frequency_stepsize * 2;
s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
return 0;
}

View File

@ -73,27 +73,47 @@ struct dib0070_state {
u8 wbd_gain_current;
u16 wbd_offset_3_3[2];
/* for the I2C transfer */
struct i2c_msg msg[2];
u8 i2c_write_buffer[3];
u8 i2c_read_buffer[2];
};
static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
{
u8 b[2];
struct i2c_msg msg[2] = {
{ .addr = state->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
{ .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 },
};
if (i2c_transfer(state->i2c, msg, 2) != 2) {
state->i2c_write_buffer[0] = reg;
memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
state->msg[0].addr = state->cfg->i2c_address;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = 1;
state->msg[1].addr = state->cfg->i2c_address;
state->msg[1].flags = I2C_M_RD;
state->msg[1].buf = state->i2c_read_buffer;
state->msg[1].len = 2;
if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
printk(KERN_WARNING "DiB0070 I2C read failed\n");
return 0;
}
return (b[0] << 8) | b[1];
return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
{
u8 b[3] = { reg, val >> 8, val & 0xff };
struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
state->i2c_write_buffer[0] = reg;
state->i2c_write_buffer[1] = val >> 8;
state->i2c_write_buffer[2] = val & 0xff;
memset(state->msg, 0, sizeof(struct i2c_msg));
state->msg[0].addr = state->cfg->i2c_address;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = 3;
if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0070 I2C write failed\n");
return -EREMOTEIO;
}

View File

@ -191,6 +191,11 @@ struct dib0090_state {
u8 wbd_calibration_gain;
const struct dib0090_wbd_slope *current_wbd_table;
u16 wbdmux;
/* for the I2C transfer */
struct i2c_msg msg[2];
u8 i2c_write_buffer[3];
u8 i2c_read_buffer[2];
};
struct dib0090_fw_state {
@ -198,27 +203,48 @@ struct dib0090_fw_state {
struct dvb_frontend *fe;
struct dib0090_identity identity;
const struct dib0090_config *config;
/* for the I2C transfer */
struct i2c_msg msg;
u8 i2c_write_buffer[2];
u8 i2c_read_buffer[2];
};
static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
{
u8 b[2];
struct i2c_msg msg[2] = {
{.addr = state->config->i2c_address, .flags = 0, .buf = &reg, .len = 1},
{.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2},
};
if (i2c_transfer(state->i2c, msg, 2) != 2) {
state->i2c_write_buffer[0] = reg;
memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
state->msg[0].addr = state->config->i2c_address;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = 1;
state->msg[1].addr = state->config->i2c_address;
state->msg[1].flags = I2C_M_RD;
state->msg[1].buf = state->i2c_read_buffer;
state->msg[1].len = 2;
if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
printk(KERN_WARNING "DiB0090 I2C read failed\n");
return 0;
}
return (b[0] << 8) | b[1];
return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
{
u8 b[3] = { reg & 0xff, val >> 8, val & 0xff };
struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 };
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
state->i2c_write_buffer[0] = reg & 0xff;
state->i2c_write_buffer[1] = val >> 8;
state->i2c_write_buffer[2] = val & 0xff;
memset(state->msg, 0, sizeof(struct i2c_msg));
state->msg[0].addr = state->config->i2c_address;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = 3;
if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0090 I2C write failed\n");
return -EREMOTEIO;
}
@ -227,20 +253,31 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
{
u8 b[2];
struct i2c_msg msg = {.addr = reg, .flags = I2C_M_RD, .buf = b, .len = 2 };
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
state->i2c_write_buffer[0] = reg;
memset(&state->msg, 0, sizeof(struct i2c_msg));
state->msg.addr = reg;
state->msg.flags = I2C_M_RD;
state->msg.buf = state->i2c_read_buffer;
state->msg.len = 2;
if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0090 I2C read failed\n");
return 0;
}
return (b[0] << 8) | b[1];
return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
{
u8 b[2] = { val >> 8, val & 0xff };
struct i2c_msg msg = {.addr = reg, .flags = 0, .buf = b, .len = 2 };
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
state->i2c_write_buffer[0] = val >> 8;
state->i2c_write_buffer[1] = val & 0xff;
memset(&state->msg, 0, sizeof(struct i2c_msg));
state->msg.addr = reg;
state->msg.flags = 0;
state->msg.buf = state->i2c_write_buffer;
state->msg.len = 2;
if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0090 I2C write failed\n");
return -EREMOTEIO;
}

View File

@ -50,6 +50,11 @@ struct dib7000m_state {
u16 revision;
u8 agc_state;
/* for the I2C transfer */
struct i2c_msg msg[2];
u8 i2c_write_buffer[4];
u8 i2c_read_buffer[2];
};
enum dib7000m_power_mode {
@ -64,29 +69,39 @@ enum dib7000m_power_mode {
static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
{
u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
u8 rb[2];
struct i2c_msg msg[2] = {
{ .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 },
{ .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
};
state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
state->i2c_write_buffer[1] = reg & 0xff;
if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
state->msg[0].addr = state->i2c_addr >> 1;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = 2;
state->msg[1].addr = state->i2c_addr >> 1;
state->msg[1].flags = I2C_M_RD;
state->msg[1].buf = state->i2c_read_buffer;
state->msg[1].len = 2;
if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
dprintk("i2c read error on %d",reg);
return (rb[0] << 8) | rb[1];
return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
{
u8 b[4] = {
(reg >> 8) & 0xff, reg & 0xff,
(val >> 8) & 0xff, val & 0xff,
};
struct i2c_msg msg = {
.addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
};
return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
state->i2c_write_buffer[1] = reg & 0xff;
state->i2c_write_buffer[2] = (val >> 8) & 0xff;
state->i2c_write_buffer[3] = val & 0xff;
memset(&state->msg[0], 0, sizeof(struct i2c_msg));
state->msg[0].addr = state->i2c_addr >> 1;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = 4;
return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
}
static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
{

View File

@ -63,6 +63,11 @@ struct dib7000p_state {
u16 tuner_enable;
struct i2c_adapter dib7090_tuner_adap;
/* for the I2C transfer */
struct i2c_msg msg[2];
u8 i2c_write_buffer[4];
u8 i2c_read_buffer[2];
};
enum dib7000p_power_mode {
@ -76,29 +81,39 @@ static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
{
u8 wb[2] = { reg >> 8, reg & 0xff };
u8 rb[2];
struct i2c_msg msg[2] = {
{.addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
{.addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2},
};
state->i2c_write_buffer[0] = reg >> 8;
state->i2c_write_buffer[1] = reg & 0xff;
if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
state->msg[0].addr = state->i2c_addr >> 1;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = 2;
state->msg[1].addr = state->i2c_addr >> 1;
state->msg[1].flags = I2C_M_RD;
state->msg[1].buf = state->i2c_read_buffer;
state->msg[1].len = 2;
if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
dprintk("i2c read error on %d", reg);
return (rb[0] << 8) | rb[1];
return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
{
u8 b[4] = {
(reg >> 8) & 0xff, reg & 0xff,
(val >> 8) & 0xff, val & 0xff,
};
struct i2c_msg msg = {
.addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
};
return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
state->i2c_write_buffer[1] = reg & 0xff;
state->i2c_write_buffer[2] = (val >> 8) & 0xff;
state->i2c_write_buffer[3] = val & 0xff;
memset(&state->msg[0], 0, sizeof(struct i2c_msg));
state->msg[0].addr = state->i2c_addr >> 1;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = 4;
return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
}
static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
@ -1550,11 +1565,24 @@ static void dib7000p_release(struct dvb_frontend *demod)
int dib7000pc_detection(struct i2c_adapter *i2c_adap)
{
u8 tx[2], rx[2];
u8 *tx, *rx;
struct i2c_msg msg[2] = {
{.addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2},
{.addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2},
{.addr = 18 >> 1, .flags = 0, .len = 2},
{.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
};
int ret = 0;
tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
if (!tx)
return -ENOMEM;
rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
if (!rx) {
goto rx_memory_error;
ret = -ENOMEM;
}
msg[0].buf = tx;
msg[1].buf = rx;
tx[0] = 0x03;
tx[1] = 0x00;
@ -1574,7 +1602,11 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
}
dprintk("-D- DiB7000PC not detected");
return 0;
kfree(rx);
rx_memory_error:
kfree(tx);
return ret;
}
EXPORT_SYMBOL(dib7000pc_detection);

View File

@ -35,6 +35,8 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
struct i2c_device {
struct i2c_adapter *adap;
u8 addr;
u8 *i2c_write_buffer;
u8 *i2c_read_buffer;
};
struct dib8000_state {
@ -70,6 +72,11 @@ struct dib8000_state {
u32 status;
struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
/* for the I2C transfer */
struct i2c_msg msg[2];
u8 i2c_write_buffer[4];
u8 i2c_read_buffer[2];
};
enum dib8000_power_mode {
@ -79,22 +86,41 @@ enum dib8000_power_mode {
static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
{
u8 wb[2] = { reg >> 8, reg & 0xff };
u8 rb[2];
struct i2c_msg msg[2] = {
{.addr = i2c->addr >> 1,.flags = 0,.buf = wb,.len = 2},
{.addr = i2c->addr >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2},
{.addr = i2c->addr >> 1, .flags = 0,
.buf = i2c->i2c_write_buffer, .len = 2},
{.addr = i2c->addr >> 1, .flags = I2C_M_RD,
.buf = i2c->i2c_read_buffer, .len = 2},
};
msg[0].buf[0] = reg >> 8;
msg[0].buf[1] = reg & 0xff;
if (i2c_transfer(i2c->adap, msg, 2) != 2)
dprintk("i2c read error on %d", reg);
return (rb[0] << 8) | rb[1];
return (msg[1].buf[0] << 8) | msg[1].buf[1];
}
static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
{
return dib8000_i2c_read16(&state->i2c, reg);
state->i2c_write_buffer[0] = reg >> 8;
state->i2c_write_buffer[1] = reg & 0xff;
memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
state->msg[0].addr = state->i2c.addr >> 1;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = 2;
state->msg[1].addr = state->i2c.addr >> 1;
state->msg[1].flags = I2C_M_RD;
state->msg[1].buf = state->i2c_read_buffer;
state->msg[1].len = 2;
if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
dprintk("i2c read error on %d", reg);
return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
@ -109,19 +135,34 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
{
u8 b[4] = {
(reg >> 8) & 0xff, reg & 0xff,
(val >> 8) & 0xff, val & 0xff,
};
struct i2c_msg msg = {
.addr = i2c->addr >> 1,.flags = 0,.buf = b,.len = 4
};
return i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0,
.buf = i2c->i2c_write_buffer, .len = 4};
int ret = 0;
msg.buf[0] = (reg >> 8) & 0xff;
msg.buf[1] = reg & 0xff;
msg.buf[2] = (val >> 8) & 0xff;
msg.buf[3] = val & 0xff;
ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
return ret;
}
static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
{
return dib8000_i2c_write16(&state->i2c, reg, val);
state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
state->i2c_write_buffer[1] = reg & 0xff;
state->i2c_write_buffer[2] = (val >> 8) & 0xff;
state->i2c_write_buffer[3] = val & 0xff;
memset(&state->msg[0], 0, sizeof(struct i2c_msg));
state->msg[0].addr = state->i2c.addr >> 1;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = 4;
return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
}
static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
@ -980,30 +1021,31 @@ static void dib8000_update_timf(struct dib8000_state *state)
dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
}
static const u16 adc_target_16dB[11] = {
(1 << 13) - 825 - 117,
(1 << 13) - 837 - 117,
(1 << 13) - 811 - 117,
(1 << 13) - 766 - 117,
(1 << 13) - 737 - 117,
(1 << 13) - 693 - 117,
(1 << 13) - 648 - 117,
(1 << 13) - 619 - 117,
(1 << 13) - 575 - 117,
(1 << 13) - 531 - 117,
(1 << 13) - 501 - 117
};
static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
{
u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
u8 guard, crate, constellation, timeI;
u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled
const s16 *ncoeff = NULL, *ana_fe;
u16 tmcc_pow = 0;
u16 coff_pow = 0x2800;
u16 init_prbs = 0xfff;
u16 ana_gain = 0;
u16 adc_target_16dB[11] = {
(1 << 13) - 825 - 117,
(1 << 13) - 837 - 117,
(1 << 13) - 811 - 117,
(1 << 13) - 766 - 117,
(1 << 13) - 737 - 117,
(1 << 13) - 693 - 117,
(1 << 13) - 648 - 117,
(1 << 13) - 619 - 117,
(1 << 13) - 575 - 117,
(1 << 13) - 531 - 117,
(1 << 13) - 501 - 117
};
if (state->ber_monitored_layer != LAYER_ALL)
dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
@ -2379,10 +2421,22 @@ EXPORT_SYMBOL(dib8000_get_slave_frontend);
int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
{
int k = 0;
int k = 0, ret = 0;
u8 new_addr = 0;
struct i2c_device client = {.adap = host };
client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
if (!client.i2c_write_buffer) {
dprintk("%s: not enough memory", __func__);
return -ENOMEM;
}
client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
if (!client.i2c_read_buffer) {
dprintk("%s: not enough memory", __func__);
ret = -ENOMEM;
goto error_memory;
}
for (k = no_of_demods - 1; k >= 0; k--) {
/* designated i2c address */
new_addr = first_addr + (k << 1);
@ -2394,7 +2448,8 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
client.addr = default_addr;
if (dib8000_identify(&client) == 0) {
dprintk("#%d: not identified", k);
return -EINVAL;
ret = -EINVAL;
goto error;
}
}
@ -2420,7 +2475,12 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
dib8000_i2c_write16(&client, 1286, 0);
}
return 0;
error:
kfree(client.i2c_read_buffer);
error_memory:
kfree(client.i2c_write_buffer);
return ret;
}
EXPORT_SYMBOL(dib8000_i2c_enumeration);
@ -2519,6 +2579,8 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s
memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
state->i2c.adap = i2c_adap;
state->i2c.addr = i2c_addr;
state->i2c.i2c_write_buffer = state->i2c_write_buffer;
state->i2c.i2c_read_buffer = state->i2c_read_buffer;
state->gpio_val = cfg->gpio_val;
state->gpio_dir = cfg->gpio_dir;

View File

@ -27,6 +27,8 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
struct i2c_device {
struct i2c_adapter *i2c_adap;
u8 i2c_addr;
u8 *i2c_read_buffer;
u8 *i2c_write_buffer;
};
/* lock */
@ -92,11 +94,16 @@ struct dib9000_state {
struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
u16 component_bus_speed;
/* for the I2C transfer */
struct i2c_msg msg[2];
u8 i2c_write_buffer[255];
u8 i2c_read_buffer[255];
};
u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0
};
enum dib9000_power_mode {
@ -217,25 +224,33 @@ static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32
u32 chunk_size = 126;
u32 l;
int ret;
u8 wb[2] = { reg >> 8, reg & 0xff };
struct i2c_msg msg[2] = {
{.addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
{.addr = state->i2c.i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = len},
};
if (state->platform.risc.fw_is_running && (reg < 1024))
return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len);
memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
state->msg[0].addr = state->i2c.i2c_addr >> 1;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = 2;
state->msg[1].addr = state->i2c.i2c_addr >> 1;
state->msg[1].flags = I2C_M_RD;
state->msg[1].buf = b;
state->msg[1].len = len;
state->i2c_write_buffer[0] = reg >> 8;
state->i2c_write_buffer[1] = reg & 0xff;
if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
wb[0] |= (1 << 5);
state->i2c_write_buffer[0] |= (1 << 5);
if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
wb[0] |= (1 << 4);
state->i2c_write_buffer[0] |= (1 << 4);
do {
l = len < chunk_size ? len : chunk_size;
msg[1].len = l;
msg[1].buf = b;
ret = i2c_transfer(state->i2c.i2c_adap, msg, 2) != 2 ? -EREMOTEIO : 0;
state->msg[1].len = l;
state->msg[1].buf = b;
ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0;
if (ret != 0) {
dprintk("i2c read error on %d", reg);
return -EREMOTEIO;
@ -253,50 +268,47 @@ static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32
static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg)
{
u8 b[2];
u8 wb[2] = { reg >> 8, reg & 0xff };
struct i2c_msg msg[2] = {
{.addr = i2c->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
{.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = 2},
{.addr = i2c->i2c_addr >> 1, .flags = 0,
.buf = i2c->i2c_write_buffer, .len = 2},
{.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD,
.buf = i2c->i2c_read_buffer, .len = 2},
};
i2c->i2c_write_buffer[0] = reg >> 8;
i2c->i2c_write_buffer[1] = reg & 0xff;
if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) {
dprintk("read register %x error", reg);
return 0;
}
return (b[0] << 8) | b[1];
return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1];
}
static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg)
{
u8 b[2];
if (dib9000_read16_attr(state, reg, b, 2, 0) != 0)
if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0)
return 0;
return (b[0] << 8 | b[1]);
return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute)
{
u8 b[2];
if (dib9000_read16_attr(state, reg, b, 2, attribute) != 0)
if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2,
attribute) != 0)
return 0;
return (b[0] << 8 | b[1]);
return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
#define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute)
{
u8 b[255];
u32 chunk_size = 126;
u32 l;
int ret;
struct i2c_msg msg = {
.addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = b, .len = len + 2
};
if (state->platform.risc.fw_is_running && (reg < 1024)) {
if (dib9000_risc_apb_access_write
(state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0)
@ -304,20 +316,26 @@ static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 *
return 0;
}
b[0] = (reg >> 8) & 0xff;
b[1] = (reg) & 0xff;
memset(&state->msg[0], 0, sizeof(struct i2c_msg));
state->msg[0].addr = state->i2c.i2c_addr >> 1;
state->msg[0].flags = 0;
state->msg[0].buf = state->i2c_write_buffer;
state->msg[0].len = len + 2;
state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
state->i2c_write_buffer[1] = (reg) & 0xff;
if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
b[0] |= (1 << 5);
state->i2c_write_buffer[0] |= (1 << 5);
if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
b[0] |= (1 << 4);
state->i2c_write_buffer[0] |= (1 << 4);
do {
l = len < chunk_size ? len : chunk_size;
msg.len = l + 2;
memcpy(&b[2], buf, l);
state->msg[0].len = l + 2;
memcpy(&state->i2c_write_buffer[2], buf, l);
ret = i2c_transfer(state->i2c.i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
buf += l;
len -= l;
@ -331,11 +349,16 @@ static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 *
static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
{
u8 b[4] = { (reg >> 8) & 0xff, reg & 0xff, (val >> 8) & 0xff, val & 0xff };
struct i2c_msg msg = {
.addr = i2c->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
.addr = i2c->i2c_addr >> 1, .flags = 0,
.buf = i2c->i2c_write_buffer, .len = 4
};
i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff;
i2c->i2c_write_buffer[1] = reg & 0xff;
i2c->i2c_write_buffer[2] = (val >> 8) & 0xff;
i2c->i2c_write_buffer[3] = val & 0xff;
return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}
@ -1015,8 +1038,8 @@ static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i)
return 0;
dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i);
do {
dib9000_risc_mem_read(state, FE_MM_RW_SYNC, &i, 1);
} while (i && index_loop--);
dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1);
} while (state->i2c_read_buffer[0] && index_loop--);
if (index_loop > 0)
return 0;
@ -1139,7 +1162,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
s8 intlv_native;
};
struct dibDVBTChannel ch;
struct dibDVBTChannel *ch;
int ret = 0;
DibAcquireLock(&state->platform.risc.mem_mbx_lock);
@ -1148,9 +1171,12 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
ret = -EIO;
}
dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, (u8 *) &ch, sizeof(struct dibDVBTChannel));
dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION,
state->i2c_read_buffer, sizeof(struct dibDVBTChannel));
ch = (struct dibDVBTChannel *)state->i2c_read_buffer;
switch (ch.spectrum_inversion & 0x7) {
switch (ch->spectrum_inversion & 0x7) {
case 1:
state->fe[0]->dtv_property_cache.inversion = INVERSION_ON;
break;
@ -1162,7 +1188,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO;
break;
}
switch (ch.nfft) {
switch (ch->nfft) {
case 0:
state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
break;
@ -1177,7 +1203,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
break;
}
switch (ch.guard) {
switch (ch->guard) {
case 0:
state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
break;
@ -1195,7 +1221,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
break;
}
switch (ch.constellation) {
switch (ch->constellation) {
case 2:
state->fe[0]->dtv_property_cache.modulation = QAM_64;
break;
@ -1210,7 +1236,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.modulation = QAM_AUTO;
break;
}
switch (ch.hrch) {
switch (ch->hrch) {
case 0:
state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE;
break;
@ -1222,7 +1248,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
break;
}
switch (ch.code_rate_hp) {
switch (ch->code_rate_hp) {
case 1:
state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2;
break;
@ -1243,7 +1269,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO;
break;
}
switch (ch.code_rate_lp) {
switch (ch->code_rate_lp) {
case 1:
state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2;
break;
@ -1439,9 +1465,10 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete
break;
case CT_DEMOD_STEP_1:
if (search)
dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, (u8 *) &i, 1);
dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1);
else
dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, (u8 *) &i, 1);
dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1);
i = (s8)state->i2c_read_buffer[0];
switch (i) { /* something happened */
case 0:
break;
@ -2038,14 +2065,17 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
{
struct dib9000_state *state = fe->demodulator_priv;
u16 c[16];
u16 *c;
DibAcquireLock(&state->platform.risc.mem_mbx_lock);
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
return -EIO;
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
state->i2c_read_buffer, 16 * 2);
DibReleaseLock(&state->platform.risc.mem_mbx_lock);
c = (u16 *)state->i2c_read_buffer;
*ber = c[10] << 16 | c[11];
return 0;
}
@ -2054,7 +2084,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
{
struct dib9000_state *state = fe->demodulator_priv;
u8 index_frontend;
u16 c[16];
u16 *c = (u16 *)state->i2c_read_buffer;
u16 val;
*strength = 0;
@ -2069,7 +2099,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
DibAcquireLock(&state->platform.risc.mem_mbx_lock);
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
return -EIO;
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
DibReleaseLock(&state->platform.risc.mem_mbx_lock);
val = 65535 - c[4];
@ -2083,14 +2113,14 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
static u32 dib9000_get_snr(struct dvb_frontend *fe)
{
struct dib9000_state *state = fe->demodulator_priv;
u16 c[16];
u16 *c = (u16 *)state->i2c_read_buffer;
u32 n, s, exp;
u16 val;
DibAcquireLock(&state->platform.risc.mem_mbx_lock);
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
return -EIO;
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
DibReleaseLock(&state->platform.risc.mem_mbx_lock);
val = c[7];
@ -2137,12 +2167,12 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
{
struct dib9000_state *state = fe->demodulator_priv;
u16 c[16];
u16 *c = (u16 *)state->i2c_read_buffer;
DibAcquireLock(&state->platform.risc.mem_mbx_lock);
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
return -EIO;
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
DibReleaseLock(&state->platform.risc.mem_mbx_lock);
*unc = c[12];
@ -2151,10 +2181,22 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
{
int k = 0;
int k = 0, ret = 0;
u8 new_addr = 0;
struct i2c_device client = {.i2c_adap = i2c };
client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
if (!client.i2c_write_buffer) {
dprintk("%s: not enough memory", __func__);
return -ENOMEM;
}
client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
if (!client.i2c_read_buffer) {
dprintk("%s: not enough memory", __func__);
ret = -ENOMEM;
goto error_memory;
}
client.i2c_addr = default_addr + 16;
dib9000_i2c_write16(&client, 1796, 0x0);
@ -2178,7 +2220,8 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul
client.i2c_addr = default_addr;
if (dib9000_identify(&client) == 0) {
dprintk("DiB9000 #%d: not identified", k);
return -EIO;
ret = -EIO;
goto error;
}
}
@ -2196,7 +2239,12 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul
dib9000_i2c_write16(&client, 1795, 0);
}
return 0;
error:
kfree(client.i2c_read_buffer);
error_memory:
kfree(client.i2c_write_buffer);
return ret;
}
EXPORT_SYMBOL(dib9000_i2c_enumeration);
@ -2255,12 +2303,16 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c
if (st == NULL)
return NULL;
fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
if (fe == NULL)
if (fe == NULL) {
kfree(st);
return NULL;
}
memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config));
st->i2c.i2c_adap = i2c_adap;
st->i2c.i2c_addr = i2c_addr;
st->i2c.i2c_write_buffer = st->i2c_write_buffer;
st->i2c.i2c_read_buffer = st->i2c_read_buffer;
st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS;
st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES;

View File

@ -10,30 +10,39 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
{
u8 b[4] = {
(reg >> 8) & 0xff, reg & 0xff,
(val >> 8) & 0xff, val & 0xff,
};
struct i2c_msg msg = {
.addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4
};
mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
mst->i2c_write_buffer[1] = reg & 0xff;
mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
mst->i2c_write_buffer[3] = val & 0xff;
return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
memset(mst->msg, 0, sizeof(struct i2c_msg));
mst->msg[0].addr = mst->i2c_addr;
mst->msg[0].flags = 0;
mst->msg[0].buf = mst->i2c_write_buffer;
mst->msg[0].len = 4;
return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
}
static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
{
u8 wb[2] = { reg >> 8, reg & 0xff };
u8 rb[2];
struct i2c_msg msg[2] = {
{.addr = mst->i2c_addr, .flags = 0, .buf = wb, .len = 2},
{.addr = mst->i2c_addr, .flags = I2C_M_RD, .buf = rb, .len = 2},
};
mst->i2c_write_buffer[0] = reg >> 8;
mst->i2c_write_buffer[1] = reg & 0xff;
if (i2c_transfer(mst->i2c_adap, msg, 2) != 2)
memset(mst->msg, 0, 2 * sizeof(struct i2c_msg));
mst->msg[0].addr = mst->i2c_addr;
mst->msg[0].flags = 0;
mst->msg[0].buf = mst->i2c_write_buffer;
mst->msg[0].len = 2;
mst->msg[1].addr = mst->i2c_addr;
mst->msg[1].flags = I2C_M_RD;
mst->msg[1].buf = mst->i2c_read_buffer;
mst->msg[1].len = 2;
if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
dprintk("i2c read error on %d", reg);
return (rb[0] << 8) | rb[1];
return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
}
static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
@ -248,26 +257,32 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msg[], int num)
{
struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
struct i2c_msg m[2 + num];
u8 tx_open[4], tx_close[4];
memset(m, 0, sizeof(struct i2c_msg) * (2 + num));
if (num > 32) {
dprintk("%s: too much I2C message to be transmitted (%i).\
Maximum is 32", __func__, num);
return -ENOMEM;
}
memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
m[0].addr = mst->i2c_addr;
m[0].buf = tx_open;
m[0].len = 4;
/* open the gate */
dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
mst->msg[0].addr = mst->i2c_addr;
mst->msg[0].buf = &mst->i2c_write_buffer[0];
mst->msg[0].len = 4;
memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
m[num + 1].addr = mst->i2c_addr;
m[num + 1].buf = tx_close;
m[num + 1].len = 4;
/* close the gate */
dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
mst->msg[num + 1].addr = mst->i2c_addr;
mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
mst->msg[num + 1].len = 4;
return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO;
return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
}
static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
@ -279,26 +294,32 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msg[], int num)
{
struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
struct i2c_msg m[2 + num];
u8 tx_open[4], tx_close[4];
memset(m, 0, sizeof(struct i2c_msg) * (2 + num));
if (num > 32) {
dprintk("%s: too much I2C message to be transmitted (%i).\
Maximum is 32", __func__, num);
return -ENOMEM;
}
memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
m[0].addr = mst->i2c_addr;
m[0].buf = tx_open;
m[0].len = 4;
/* open the gate */
dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
mst->msg[0].addr = mst->i2c_addr;
mst->msg[0].buf = &mst->i2c_write_buffer[0];
mst->msg[0].len = 4;
memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
m[num + 1].addr = mst->i2c_addr;
m[num + 1].buf = tx_close;
m[num + 1].len = 4;
/* close the gate */
dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
mst->msg[num + 1].addr = mst->i2c_addr;
mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
mst->msg[num + 1].len = 4;
return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO;
return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
}
static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {

View File

@ -28,6 +28,11 @@ struct dibx000_i2c_master {
u8 i2c_addr;
u16 base_reg;
/* for the I2C transfer */
struct i2c_msg msg[34];
u8 i2c_write_buffer[8];
u8 i2c_read_buffer[2];
};
extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,

File diff suppressed because it is too large Load Diff

View File

@ -1,130 +0,0 @@
/*
* Driver for Micronas DVB-T drx397xD demodulator
*
* Copyright (C) 2007 Henk vergonet <Henk.Vergonet@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
*/
#ifndef _DRX397XD_H_INCLUDED
#define _DRX397XD_H_INCLUDED
#include <linux/dvb/frontend.h>
#define DRX_F_STEPSIZE 166667
#define DRX_F_OFFSET 36000000
#define I2C_ADR_C0(x) \
( cpu_to_le32( \
(u32)( \
(((u32)(x) & (u32)0x000000ffUL) ) | \
(((u32)(x) & (u32)0x0000ff00UL) << 16) | \
(((u32)(x) & (u32)0x0fff0000UL) >> 8) | \
( (u32)0x00c00000UL) \
)) \
)
#define I2C_ADR_E0(x) \
( cpu_to_le32( \
(u32)( \
(((u32)(x) & (u32)0x000000ffUL) ) | \
(((u32)(x) & (u32)0x0000ff00UL) << 16) | \
(((u32)(x) & (u32)0x0fff0000UL) >> 8) | \
( (u32)0x00e00000UL) \
)) \
)
struct drx397xD_CfgRfAgc /* 0x7c */
{
int d00; /* 2 */
u16 w04;
u16 w06;
};
struct drx397xD_CfgIfAgc /* 0x68 */
{
int d00; /* 0 */
u16 w04; /* 0 */
u16 w06;
u16 w08;
u16 w0A;
u16 w0C;
};
struct drx397xD_s20 {
int d04;
u32 d18;
u32 d1C;
u32 d20;
u32 d14;
u32 d24;
u32 d0C;
u32 d08;
};
struct drx397xD_config
{
/* demodulator's I2C address */
u8 demod_address; /* 0x0f */
struct drx397xD_CfgIfAgc ifagc; /* 0x68 */
struct drx397xD_CfgRfAgc rfagc; /* 0x7c */
u32 s20d24;
/* HI_CfgCommand parameters */
u16 w50, w52, /* w54, */ w56;
int d5C;
int d60;
int d48;
int d28;
u32 f_if; /* d14: intermediate frequency [Hz] */
/* 36000000 on Cinergy 2400i DT */
/* 42800000 on Pinnacle Hybrid PRO 330e */
u16 f_osc; /* s66: 48000 oscillator frequency [kHz] */
u16 w92; /* 20000 */
u16 wA0;
u16 w98;
u16 w9A;
u16 w9C; /* 0xe0 */
u16 w9E; /* 0x00 */
/* used for signal strength calculations in
drx397x_read_signal_strength
*/
u16 ss78; // 2200
u16 ss7A; // 150
u16 ss76; // 820
};
#if defined(CONFIG_DVB_DRX397XD) || (defined(CONFIG_DVB_DRX397XD_MODULE) && defined(MODULE))
extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif /* CONFIG_DVB_DRX397XD */
#endif /* _DRX397XD_H_INCLUDED */

View File

@ -1,40 +0,0 @@
/*
* Firmware definitions for Micronas drx397xD
*
* Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef _FW_ENTRY
_FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0, DRXD_FW_A2 ),
_FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1, DRXD_FW_B1 ),
#undef _FW_ENTRY
#endif /* _FW_ENTRY */
#ifdef _BLOB_ENTRY
_BLOB_ENTRY("InitAtomicRead", DRXD_InitAtomicRead = 0 ),
_BLOB_ENTRY("InitCE", DRXD_InitCE ),
_BLOB_ENTRY("InitCP", DRXD_InitCP ),
_BLOB_ENTRY("InitEC", DRXD_InitEC ),
_BLOB_ENTRY("InitEQ", DRXD_InitEQ ),
_BLOB_ENTRY("InitFE_1", DRXD_InitFE_1 ),
_BLOB_ENTRY("InitFE_2", DRXD_InitFE_2 ),
_BLOB_ENTRY("InitFT", DRXD_InitFT ),
_BLOB_ENTRY("InitSC", DRXD_InitSC ),
_BLOB_ENTRY("ResetCEFR", DRXD_ResetCEFR ),
_BLOB_ENTRY("ResetECRAM", DRXD_ResetECRAM ),
_BLOB_ENTRY("microcode", DRXD_microcode ),
#undef _BLOB_ENTRY
#endif /* _BLOB_ENTRY */

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