mirror of
https://github.com/DigitalDevices/dddvb.git
synced 2025-03-01 10:35:23 +00:00
Compare commits
264 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce99c601f8 | ||
|
|
43ab548777 | ||
|
|
2808cf0d50 | ||
|
|
186ba6d414 | ||
|
|
f570b2e071 | ||
|
|
32f46389be | ||
|
|
4b68bcad91 | ||
|
|
1ad4dfacd1 | ||
|
|
f7772c7a88 | ||
|
|
6219e19ece | ||
|
|
192a4ad20d | ||
|
|
e13cec82e4 | ||
|
|
d13416157c | ||
|
|
755f502602 | ||
|
|
a05d1852a3 | ||
|
|
1e15f5474d | ||
|
|
9c1fc648dc | ||
|
|
2e5056c4a1 | ||
|
|
1b89edb4b1 | ||
|
|
875a768266 | ||
|
|
09c068c74c | ||
|
|
c471123f17 | ||
|
|
8dbd33fd82 | ||
|
|
a978e9455f | ||
|
|
9d8c7d4a63 | ||
|
|
81ed8fed9d | ||
|
|
f24a329f2f | ||
|
|
5d7f4fcbe8 | ||
|
|
6243397d99 | ||
|
|
5b86ac7627 | ||
|
|
c831ccfc9e | ||
|
|
cad161f939 | ||
|
|
67257ce132 | ||
|
|
bdea58c1b2 | ||
|
|
29eda9be8e | ||
|
|
2c3c9bdf08 | ||
|
|
2693c181bc | ||
|
|
53464162de | ||
|
|
8cbb835de0 | ||
|
|
d0f7b9be1f | ||
|
|
6b0feea253 | ||
|
|
bed4be534a | ||
|
|
1d7d8bc413 | ||
|
|
70778b818e | ||
|
|
e0fdedbef3 | ||
|
|
9acbf467ec | ||
|
|
3db30defab | ||
|
|
5bf9edba06 | ||
|
|
8f0365e36a | ||
|
|
08a161ba04 | ||
|
|
efbc108939 | ||
|
|
033432cf2f | ||
|
|
948c6c4fe7 | ||
|
|
dedb5bd387 | ||
|
|
991393950b | ||
|
|
ae9644d934 | ||
|
|
9cc6942c07 | ||
|
|
67e36cdef0 | ||
|
|
4f622ec27c | ||
|
|
e7d9457ef8 | ||
|
|
00a3e78f69 | ||
|
|
fc335de763 | ||
|
|
62e491c2cd | ||
|
|
402a822751 | ||
|
|
e19f29dbfa | ||
|
|
caa1dbecce | ||
|
|
642a010be6 | ||
|
|
94dfd16461 | ||
|
|
a6b6e3be29 | ||
|
|
4f136e5659 | ||
|
|
bda6c538ae | ||
|
|
2eb3b3e723 | ||
|
|
2e1c7b62a9 | ||
|
|
6001c5baf5 | ||
|
|
02b292987b | ||
|
|
4ebb3ca938 | ||
|
|
c5b45cdbac | ||
|
|
23826d9981 | ||
|
|
da3539c994 | ||
|
|
db463d0839 | ||
|
|
c07e4bebbd | ||
|
|
dfff0f5953 | ||
|
|
d87246de12 | ||
|
|
b54e6ed689 | ||
|
|
3b44e78bd0 | ||
|
|
f7fbeed21e | ||
|
|
a14cbc0eff | ||
|
|
2d41161cb4 | ||
|
|
c75a7892d9 | ||
|
|
d5bbd3a025 | ||
|
|
096bf9d5a9 | ||
|
|
3806b4d2da | ||
|
|
b42358eaa2 | ||
|
|
04fc90e4d6 | ||
|
|
50cf06cbb8 | ||
|
|
d398909c1d | ||
|
|
b814026565 | ||
|
|
611065f572 | ||
|
|
eabde4ab5a | ||
|
|
efd5070f76 | ||
|
|
ea09ce3b7b | ||
|
|
de27043d42 | ||
|
|
f7e8b25e02 | ||
|
|
c56e156176 | ||
|
|
6f164f38d8 | ||
|
|
ca3c26808f | ||
|
|
9e5576c562 | ||
|
|
021eae2eac | ||
|
|
b7c9038f51 | ||
|
|
a385bcb70c | ||
|
|
7bb6cf99e2 | ||
|
|
7e6f9d6e9d | ||
|
|
e239a6d772 | ||
|
|
3a2e87eefe | ||
|
|
0f05b1988a | ||
|
|
4a93f79093 | ||
|
|
8fa925317c | ||
|
|
0f4beb4e64 | ||
|
|
6ca3e2f2b3 | ||
|
|
249b1e0b40 | ||
|
|
4a137b3d1a | ||
|
|
20d4867869 | ||
|
|
8a1f27c3d2 | ||
|
|
3778a64de5 | ||
|
|
6bdfe43958 | ||
|
|
83000cd73a | ||
|
|
b5ae7ac76f | ||
|
|
872f99fbbe | ||
|
|
1c22a07eaa | ||
|
|
f84d196a1e | ||
|
|
41897e48c8 | ||
|
|
4765eac57a | ||
|
|
7756a09420 | ||
|
|
92b64711ec | ||
|
|
e817b91860 | ||
|
|
b814cf09e4 | ||
|
|
0dd0997133 | ||
|
|
983949f4dd | ||
|
|
fe5f6b737c | ||
|
|
3e67af1b5b | ||
|
|
e4acb524a7 | ||
|
|
aa2762747f | ||
|
|
117d9a065d | ||
|
|
17b3e1ed26 | ||
|
|
07f7720145 | ||
|
|
b2ca06e639 | ||
|
|
2b6babfdc0 | ||
|
|
5074e28e10 | ||
|
|
df4f23384b | ||
|
|
838eb620ba | ||
|
|
e55dcd2fd2 | ||
|
|
27601b4769 | ||
|
|
5751c3fb1a | ||
|
|
5c032058b9 | ||
|
|
a44dbc889b | ||
|
|
3d5fae7dd8 | ||
|
|
7602ecf3e5 | ||
|
|
bf0315bcc0 | ||
|
|
dcddb3437d | ||
|
|
665b5ef857 | ||
|
|
c063cffa63 | ||
|
|
640c15f4a7 | ||
|
|
d3ca949ec5 | ||
|
|
fd41904378 | ||
|
|
eb81f006e4 | ||
|
|
af554da865 | ||
|
|
d6f56c1807 | ||
|
|
31f22ef4de | ||
|
|
d4d0a9b84e | ||
|
|
24503d35ad | ||
|
|
3556d6464b | ||
|
|
862c7bfc60 | ||
|
|
fd21584ecc | ||
|
|
6814a8fa23 | ||
|
|
49d4bd0da8 | ||
|
|
6d1cfd4cd2 | ||
|
|
e68ce2ef62 | ||
|
|
023ae44411 | ||
|
|
7222bd58b3 | ||
|
|
f404b3fb6d | ||
|
|
de34e2ebbd | ||
|
|
774e92bd44 | ||
|
|
8c46d9a86a | ||
|
|
452771913e | ||
|
|
3285b6ade0 | ||
|
|
e6dd33deec | ||
|
|
93e42deeaa | ||
|
|
e415b6e203 | ||
|
|
1354b9021f | ||
|
|
4d17f2f5f0 | ||
|
|
5fa08eb288 | ||
|
|
933779aa24 | ||
|
|
01d35aad26 | ||
|
|
40c32767ec | ||
|
|
8704ceaf94 | ||
|
|
12b792ef3f | ||
|
|
3063b8e88b | ||
|
|
7d73553b61 | ||
|
|
5d4259f6f6 | ||
|
|
04294ab5ef | ||
|
|
4699a19bfb | ||
|
|
f44a9dfcbd | ||
|
|
b3b7a0ef2e | ||
|
|
8a98bd88cd | ||
|
|
bfd1f1979d | ||
|
|
8931ae4d9e | ||
|
|
4070713556 | ||
|
|
bba5fa5683 | ||
|
|
ae37a1e4e9 | ||
|
|
2aee51e447 | ||
|
|
264f08fbad | ||
|
|
6830f4df08 | ||
|
|
785d7c5126 | ||
|
|
52b81cfd8e | ||
|
|
263d593bcf | ||
|
|
f56ec446ae | ||
|
|
fa36763d43 | ||
|
|
08a6d78da7 | ||
|
|
b3806c61ce | ||
|
|
eb6652f18f | ||
|
|
21c69918d3 | ||
|
|
326e928f66 | ||
|
|
0e09153b1f | ||
|
|
adf4e40256 | ||
|
|
9dcd81fe42 | ||
|
|
a7ce2ef8da | ||
|
|
285d7aed49 | ||
|
|
9eb5458eeb | ||
|
|
d51a9db022 | ||
|
|
532afaa97c | ||
|
|
1984377f72 | ||
|
|
37de742aad | ||
|
|
4bfdb11762 | ||
|
|
1e99122d52 | ||
|
|
cd5de95023 | ||
|
|
c56f593a4c | ||
|
|
3a3a48654e | ||
|
|
1a80437b98 | ||
|
|
28a2aaa653 | ||
|
|
f6c7586815 | ||
|
|
d069dc051f | ||
|
|
9392ccec22 | ||
|
|
4c276fbc75 | ||
|
|
7cc9107597 | ||
|
|
1f77192d62 | ||
|
|
fc4a807b4e | ||
|
|
b6d5976e14 | ||
|
|
101289c77e | ||
|
|
26eedb3d26 | ||
|
|
d1387078f1 | ||
|
|
6bf258b54c | ||
|
|
4435efeab5 | ||
|
|
633797e05f | ||
|
|
4ee27ff317 | ||
|
|
7d7da35fb5 | ||
|
|
a3b517391a | ||
|
|
1171b345df | ||
|
|
7f746f0219 | ||
|
|
49a05e75af | ||
|
|
c546918e79 | ||
|
|
570a565f37 | ||
|
|
85b1447059 | ||
|
|
a4c275895d | ||
|
|
7a8d3f80c4 |
@@ -1,3 +1,7 @@
|
||||
0.9.29 compiles with most kernels up to 4.11.1
|
||||
|
||||
see git commit messages for newer changes
|
||||
|
||||
0.9.24 2016.08.03
|
||||
- suport new V2 modulator cards
|
||||
|
||||
|
||||
339
COPYING.GPLv2
Normal file
339
COPYING.GPLv2
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
8
Makefile
8
Makefile
@@ -1,7 +1,9 @@
|
||||
KDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
kernelver ?= $(shell uname -r)
|
||||
KDIR ?= /lib/modules/$(kernelver)/build
|
||||
PWD := $(shell pwd)
|
||||
|
||||
MODDEFS := CONFIG_DVB_CORE=m CONFIG_DVB_DDBRIDGE=m CONFIG_DVB_DRXK=m CONFIG_DVB_TDA18271C2DD=m CONFIG_DVB_CXD2099=m CONFIG_DVB_LNBP21=m CONFIG_DVB_STV090x=m CONFIG_DVB_STV6110x=m CONFIG_DVB_STV0367=m CONFIG_DVB_TDA18212=m CONFIG_DVB_STV0367DD=m CONFIG_DVB_TDA18212DD=m CONFIG_DVB_OCTONET=m CONFIG_DVB_CXD2843=m CONFIG_DVB_STV0910=m CONFIG_DVB_STV6111=m CONFIG_DVB_LNBH25=m CONFIG_DVB_MXL5XX=m
|
||||
MODDEFS := CONFIG_DVB_CORE=m CONFIG_DVB_DDBRIDGE=m CONFIG_DVB_DRXK=m CONFIG_DVB_TDA18271C2DD=m CONFIG_DVB_CXD2099=m CONFIG_DVB_LNBP21=m CONFIG_DVB_STV090x=m CONFIG_DVB_STV6110x=m CONFIG_DVB_STV0367=m CONFIG_DVB_TDA18212=m CONFIG_DVB_STV0367DD=m CONFIG_DVB_TDA18212DD=m CONFIG_DVB_OCTONET=m CONFIG_DVB_CXD2843=m CONFIG_DVB_STV0910=m CONFIG_DVB_STV6111=m CONFIG_DVB_LNBH25=m CONFIG_DVB_MXL5XX=m CONFIG_DVB_NET=m
|
||||
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) $(MODDEFS) modules
|
||||
@@ -14,6 +16,6 @@ install: all
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules_install
|
||||
|
||||
clean:
|
||||
rm -rf */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules*
|
||||
rm -rf */.*.o.d */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules*
|
||||
|
||||
|
||||
|
||||
10
README.md
10
README.md
@@ -1,10 +1,16 @@
|
||||
# DDBridge Driver
|
||||
|
||||
###Prepare for Building
|
||||
### Patches
|
||||
We can only accept patches which don't break compilation for older kernels (as far back as 2.6.37).
|
||||
|
||||
Due to this and other changes not approved by us the kernel version of the ddbridge driver might contain
|
||||
incompatiblities to this driver package.
|
||||
|
||||
### Prepare for Building
|
||||
|
||||
TBD
|
||||
|
||||
###Building
|
||||
### Building
|
||||
|
||||
TBD
|
||||
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
all: cit citin flashprog modt ddtest setmod ddflash
|
||||
all: cit citin flashprog modt ddtest setmod ddflash setmod2 pls setmod3
|
||||
|
||||
cit: cit.c
|
||||
gcc -o cit cit.c -lpthread
|
||||
$(CC) -o cit cit.c -lpthread
|
||||
|
||||
modt: modt.c
|
||||
gcc -o modt modt.c -lpthread
|
||||
$(CC) -o modt modt.c -lpthread
|
||||
|
||||
setmod: setmod.c
|
||||
gcc -o setmod setmod.c -I../include/
|
||||
$(CC) -o setmod setmod.c -I../include/
|
||||
|
||||
flashprog: flashprog.c
|
||||
gcc -o flashprog flashprog.c
|
||||
setmod2: setmod2.c
|
||||
$(CC) -o setmod2 setmod2.c -I../include/
|
||||
|
||||
ddtest: ddtest.c
|
||||
gcc -o ddtest ddtest.c
|
||||
setmod3: setmod3.c
|
||||
$(CC) -o setmod3 setmod3.c -I../include/
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
ddflash: ddflash.c
|
||||
gcc -o ddflash ddflash.c
|
||||
|
||||
17
apps/cit.c
17
apps/cit.c
@@ -91,8 +91,13 @@ void *get_ts(void *a)
|
||||
if (!buf)
|
||||
return NULL;
|
||||
sprintf(fname, "/dev/dvb/adapter%u/ci%u", adapter, device);
|
||||
printf("using %s for reading\n", fname);
|
||||
fdi = open(fname, O_RDONLY);
|
||||
|
||||
if (fdi == -1) {
|
||||
printf("Failed to open %s for read: %m\n", fname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
memset(buf, 0, 188*rnum);
|
||||
len=read(fdi, buf, 188*rnum);
|
||||
@@ -122,7 +127,12 @@ int send(void)
|
||||
if (!buf)
|
||||
return -1;
|
||||
sprintf(fname, "/dev/dvb/adapter%u/ci%u", adapter, device);
|
||||
printf("using %s for writing\n", fname);
|
||||
fdo=open(fname, O_WRONLY);
|
||||
if (fdo == -1) {
|
||||
printf("Failed to open %s to write: %m\n", fname);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
for (i=0; i<snum; i++) {
|
||||
@@ -146,7 +156,7 @@ int send(void)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pthread_t th;
|
||||
|
||||
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
int c;
|
||||
@@ -178,6 +188,8 @@ int main(int argc, char **argv)
|
||||
rnum = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 'h':
|
||||
printf("cit -a<adapter> -d<device>\n");
|
||||
exit(-1);
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -186,6 +198,7 @@ int main(int argc, char **argv)
|
||||
if (optind < argc) {
|
||||
printf("Warning: unused arguments\n");
|
||||
}
|
||||
printf("adapter %d, device: %d\n", adapter, device);
|
||||
memset(ts+8, 180, 0x5a);
|
||||
pthread_create(&th, NULL, get_ts, NULL);
|
||||
usleep(10000);
|
||||
|
||||
1
apps/flash.c
Symbolic link
1
apps/flash.c
Symbolic link
@@ -0,0 +1 @@
|
||||
./octonet/flash.c
|
||||
503
apps/flashprog.c
503
apps/flashprog.c
@@ -33,379 +33,7 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define DDB_MAGIC 'd'
|
||||
|
||||
static uint32_t linknr = 0;
|
||||
|
||||
struct ddb_id {
|
||||
__u16 vendor;
|
||||
__u16 device;
|
||||
__u16 subvendor;
|
||||
__u16 subdevice;
|
||||
__u32 hw;
|
||||
__u32 regmap;
|
||||
};
|
||||
|
||||
struct ddb_flashio {
|
||||
__u8 *write_buf;
|
||||
__u32 write_len;
|
||||
__u8 *read_buf;
|
||||
__u32 read_len;
|
||||
__u32 link;
|
||||
};
|
||||
|
||||
#define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio)
|
||||
#define IOCTL_DDB_ID _IOR(DDB_MAGIC, 0x03, struct ddb_id)
|
||||
|
||||
|
||||
int flashio(int ddb, uint8_t *wbuf, uint32_t wlen, uint8_t *rbuf, uint32_t rlen)
|
||||
{
|
||||
struct ddb_flashio fio = {
|
||||
.write_buf=wbuf,
|
||||
.write_len=wlen,
|
||||
.read_buf=rbuf,
|
||||
.read_len=rlen,
|
||||
.link=linknr,
|
||||
};
|
||||
|
||||
return ioctl(ddb, IOCTL_DDB_FLASHIO, &fio);
|
||||
}
|
||||
|
||||
enum {
|
||||
UNKNOWN_FLASH = 0,
|
||||
ATMEL_AT45DB642D = 1,
|
||||
SSTI_SST25VF016B = 2,
|
||||
SSTI_SST25VF032B = 3,
|
||||
SSTI_SST25VF064C = 4,
|
||||
SPANSION_S25FL116K = 5,
|
||||
};
|
||||
|
||||
|
||||
int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
uint8_t cmd[4]= {0x03, (addr >> 16) & 0xff,
|
||||
(addr >> 8) & 0xff, addr & 0xff};
|
||||
|
||||
return flashio(ddb, cmd, 4, buf, len);
|
||||
}
|
||||
|
||||
int flashdump(int ddb, uint32_t addr, uint32_t len)
|
||||
{
|
||||
int i, j;
|
||||
uint8_t buf[32];
|
||||
int bl = sizeof(buf);
|
||||
|
||||
for (j=0; j<len; j+=bl, addr+=bl) {
|
||||
flashread(ddb, buf, addr, bl);
|
||||
for (i=0; i<bl; i++) {
|
||||
printf("%02x ", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int FlashDetect(int dev)
|
||||
{
|
||||
uint8_t Cmd = 0x9F;
|
||||
uint8_t Id[3];
|
||||
|
||||
int r = flashio(dev, &Cmd,1,Id,3);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x41 )
|
||||
r = SSTI_SST25VF016B;
|
||||
else if( Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x4A )
|
||||
r = SSTI_SST25VF032B;
|
||||
else if( Id[0] == 0x1F && Id[1] == 0x28 )
|
||||
r = ATMEL_AT45DB642D;
|
||||
else if( Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x4B )
|
||||
r = SSTI_SST25VF064C;
|
||||
else if( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x15 )
|
||||
r = SPANSION_S25FL116K;
|
||||
else
|
||||
r = UNKNOWN_FLASH;
|
||||
|
||||
switch(r) {
|
||||
case UNKNOWN_FLASH:
|
||||
printf("Unknown Flash Flash ID = %02x %02x %02x\n",Id[0],Id[1],Id[2]);
|
||||
break;
|
||||
case ATMEL_AT45DB642D:
|
||||
printf("Flash: Atmel AT45DB642D 64 MBit\n");
|
||||
break;
|
||||
case SSTI_SST25VF016B:
|
||||
printf("Flash: SSTI SST25VF016B 16 MBit\n");
|
||||
break;
|
||||
case SSTI_SST25VF032B:
|
||||
printf("Flash: SSTI SST25VF032B 32 MBit\n"); break;
|
||||
case SSTI_SST25VF064C:
|
||||
printf("Flash: SSTI SST25VF064C 64 MBit\n"); break;
|
||||
case SPANSION_S25FL116K:
|
||||
printf("Flash: SPANSION S25FL116K 16 MBit\n"); break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int FlashWriteAtmel(int dev,uint32_t FlashOffset, uint8_t *Buffer,int BufferSize)
|
||||
{
|
||||
int err = 0;
|
||||
int BlockErase = BufferSize >= 8192;
|
||||
int i;
|
||||
|
||||
if (BlockErase) {
|
||||
for(i = 0; i < BufferSize; i += 8192 ) {
|
||||
uint8_t Cmd[4];
|
||||
if( (i & 0xFFFF) == 0 )
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
Cmd[0] = 0x50; // Block Erase
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
err = flashio(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
Cmd[0] = 0xD7; // Read Status register
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x80) == 0x80 ) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < BufferSize; i += 1024 )
|
||||
{
|
||||
uint8_t Cmd[4 + 1024];
|
||||
if( (i & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Program %08x\n",FlashOffset + i);
|
||||
}
|
||||
Cmd[0] = 0x84; // Buffer 1
|
||||
Cmd[1] = 0x00;
|
||||
Cmd[2] = 0x00;
|
||||
Cmd[3] = 0x00;
|
||||
memcpy(&Cmd[4],&Buffer[i],1024);
|
||||
|
||||
err = flashio(dev,Cmd,4 + 1024,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = BlockErase ? 0x88 : 0x83; // Buffer to Main Memory (with Erase)
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
|
||||
err = flashio(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
Cmd[0] = 0xD7; // Read Status register
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x80) == 0x80 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int FlashWritePageMode(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSize, uint8_t LockBits)
|
||||
{
|
||||
int err = 0, i, j;
|
||||
uint8_t Cmd[260];
|
||||
|
||||
if( (BufferSize % 4096) != 0 )
|
||||
return -1; // Must be multiple of sector size
|
||||
|
||||
do {
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev, Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = 0x00; // BPx = 0, Unlock all blocks
|
||||
err = flashio(dev, Cmd,2,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
for(i = 0; i < BufferSize; i += 4096 ) {
|
||||
if( (i & 0xFFFF) == 0 ) {
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
}
|
||||
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev, Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x20; // Sector erase ( 4Kb)
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
err = flashio(dev, Cmd,4,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while(1)
|
||||
{
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev, Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
|
||||
for (j = BufferSize - 256; j >= 0; j -= 256 )
|
||||
{
|
||||
if( (j & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Programm %08x\n",FlashOffset + j);
|
||||
}
|
||||
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev, Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x02; // PP
|
||||
Cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
memcpy(&Cmd[4],&Buffer[j],256);
|
||||
err = flashio(dev, Cmd,260,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while(1)
|
||||
{
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev, Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev, Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = LockBits; // BPx = 0, Lock all blocks
|
||||
err = flashio(dev, Cmd,2,NULL,0);
|
||||
|
||||
} while(0);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int FlashWriteSSTI_B(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSize)
|
||||
{
|
||||
int err = 0;
|
||||
uint8_t Cmd[6];
|
||||
int i, j;
|
||||
|
||||
// Must be multiple of sector size
|
||||
if( (BufferSize % 4096) != 0 )
|
||||
return -1;
|
||||
|
||||
do {
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = 0x00; // BPx = 0, Unlock all blocks
|
||||
err = flashio(dev,Cmd,2,NULL,0);
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
for(i = 0; i < BufferSize; i += 4096 ) {
|
||||
if( (i & 0xFFFF) == 0 )
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
Cmd[0] = 0x20; // Sector erase ( 4Kb)
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
err = flashio(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
while(1) {
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
}
|
||||
if( err < 0 )
|
||||
break;
|
||||
for(j = BufferSize - 4096; j >= 0; j -= 4096 ) {
|
||||
if( (j & 0xFFFF) == 0 )
|
||||
printf(" Program %08x\n",FlashOffset + j);
|
||||
|
||||
for(i = 0; i < 4096; i += 2 ) {
|
||||
if( i == 0 ) {
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
Cmd[0] = 0xAD; // AAI
|
||||
Cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
Cmd[4] = Buffer[j+i];
|
||||
Cmd[5] = Buffer[j+i+1];
|
||||
err = flashio(dev,Cmd,6,NULL,0);
|
||||
} else {
|
||||
Cmd[0] = 0xAD; // AAI
|
||||
Cmd[1] = Buffer[j+i];
|
||||
Cmd[2] = Buffer[j+i+1];
|
||||
err = flashio(dev,Cmd,3,NULL,0);
|
||||
}
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
while(1) {
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x04; // WDIS
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = 0x1C; // BPx = 0, Lock all blocks
|
||||
err = flashio(dev,Cmd,2,NULL,0);
|
||||
} while(0);
|
||||
return err;
|
||||
}
|
||||
#include "flash.h"
|
||||
|
||||
void get_id(int ddb, struct ddb_id *ddbid) {
|
||||
uint8_t id[4];
|
||||
@@ -450,8 +78,8 @@ int main(int argc, char **argv)
|
||||
uint32_t FlashOffset = 0x10000;
|
||||
int ddb;
|
||||
int i, err;
|
||||
int SectorSize=0;
|
||||
int FlashSize=0;
|
||||
uint32_t SectorSize=0;
|
||||
uint32_t FlashSize=0;
|
||||
int Flash;
|
||||
|
||||
uint32_t svid=0, jump=0, dump=0;
|
||||
@@ -459,6 +87,7 @@ int main(int argc, char **argv)
|
||||
|
||||
int ddbnum = 0;
|
||||
int force = 0;
|
||||
char *fname = NULL;
|
||||
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
@@ -470,12 +99,15 @@ int main(int argc, char **argv)
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
c = getopt_long(argc, argv,
|
||||
"d:n:s:o:l:dfhj",
|
||||
"d:n:s:o:l:dfhjb:",
|
||||
long_options, &option_index);
|
||||
if (c==-1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'b':
|
||||
fname = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
dump = strtoul(optarg, NULL, 16);
|
||||
break;
|
||||
@@ -513,32 +145,7 @@ int main(int argc, char **argv)
|
||||
printf("Could not open device\n");
|
||||
return -1;
|
||||
}
|
||||
Flash=FlashDetect(ddb);
|
||||
|
||||
switch(Flash) {
|
||||
case ATMEL_AT45DB642D:
|
||||
SectorSize = 1024;
|
||||
FlashSize = 0x800000;
|
||||
break;
|
||||
case SSTI_SST25VF016B:
|
||||
SectorSize = 4096;
|
||||
FlashSize = 0x200000;
|
||||
break;
|
||||
case SSTI_SST25VF032B:
|
||||
SectorSize = 4096;
|
||||
FlashSize = 0x400000;
|
||||
break;
|
||||
case SSTI_SST25VF064C:
|
||||
SectorSize = 4096;
|
||||
FlashSize = 0x800000;
|
||||
break;
|
||||
case SPANSION_S25FL116K:
|
||||
SectorSize = 4096;
|
||||
FlashSize = 0x200000;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
Flash = flashdetect(ddb, &SectorSize, &FlashSize);
|
||||
|
||||
get_id(ddb, &ddbid);
|
||||
#if 1
|
||||
@@ -553,27 +160,6 @@ int main(int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ddbid.device == 0x0011)
|
||||
type = 1;
|
||||
if (ddbid.device == 0x0201)
|
||||
type = 2;
|
||||
if (ddbid.device == 0x02)
|
||||
type = 3;
|
||||
if (ddbid.device == 0x03)
|
||||
type = 0;
|
||||
if (ddbid.device == 0x07)
|
||||
type = 4;
|
||||
if (ddbid.device == 0x320)
|
||||
type = 5;
|
||||
if (ddbid.device == 0x13)
|
||||
type = 6;
|
||||
if (ddbid.device == 0x12)
|
||||
type = 7;
|
||||
if (ddbid.device == 0x08)
|
||||
type = 8;
|
||||
if (ddbid.device == 0x210)
|
||||
type = 9;
|
||||
|
||||
if (!SectorSize)
|
||||
return 0;
|
||||
|
||||
@@ -616,52 +202,76 @@ int main(int argc, char **argv)
|
||||
} else {
|
||||
int fh, i;
|
||||
int fsize;
|
||||
char *fname;
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
fname="DVBBridgeV1B_DVBBridgeV1B.bit";
|
||||
printf("Octopus\n");
|
||||
break;
|
||||
case 1:
|
||||
fname="CIBridgeV1B_CIBridgeV1B.bit";
|
||||
printf("Octopus CI\n");
|
||||
break;
|
||||
case 2:
|
||||
fname="DVBModulatorV1B_DVBModulatorV1B.bit";
|
||||
printf("Modulator\n");
|
||||
break;
|
||||
case 3:
|
||||
if (!fname)
|
||||
switch (ddbid.device) {
|
||||
case 0x0002:
|
||||
fname="DVBBridgeV1A_DVBBridgeV1A.bit";
|
||||
printf("Octopus 35\n");
|
||||
break;
|
||||
case 4:
|
||||
case 0x0003:
|
||||
fname="DVBBridgeV1B_DVBBridgeV1B.fpga";
|
||||
printf("Octopus\n");
|
||||
break;
|
||||
case 0x0005:
|
||||
fname="DVBBridgeV2A_DD01_0005_STD.fpga";
|
||||
printf("Octopus Classic\n");
|
||||
break;
|
||||
case 0x0006:
|
||||
fname="DVBBridgeV2A_DD01_0006_STD.fpga";
|
||||
printf("CineS2 V7\n");
|
||||
break;
|
||||
case 0x0007:
|
||||
fname="DVBBridgeV2A_DD01_0007_MXL.fpga";
|
||||
printf("Octopus 4/8\n");
|
||||
break;
|
||||
case 8:
|
||||
case 0x0008:
|
||||
fname="DVBBridgeV2A_DD01_0008_CXD.fpga";
|
||||
printf("Octopus 4/8\n");
|
||||
break;
|
||||
case 6:
|
||||
fname="DVBBridgeV2B_DD01_0013_PRO.fpga";
|
||||
printf("Octopus PRO\n");
|
||||
case 0x0009:
|
||||
fname="DVBBridgeV2A_DD01_0009_SX8.fpga";
|
||||
printf("Octopus MAXSX8\n");
|
||||
break;
|
||||
case 7:
|
||||
case 0x000a:
|
||||
fname="DVBBridgeV2A_DD01_000A_M4.fpga";
|
||||
printf("Octopus MAXSX8\n");
|
||||
break;
|
||||
case 0x0011:
|
||||
fname="CIBridgeV1B_CIBridgeV1B.fpga";
|
||||
printf("Octopus CI\n");
|
||||
break;
|
||||
case 0x0012:
|
||||
fname="DVBBridgeV2B_DD01_0012_STD.fpga";
|
||||
printf("Octopus CI\n");
|
||||
break;
|
||||
case 9:
|
||||
case 0x0013:
|
||||
fname="DVBBridgeV2B_DD01_0013_PRO.fpga";
|
||||
printf("Octopus PRO\n");
|
||||
break;
|
||||
case 0x0201:
|
||||
fname="DVBModulatorV1B_DVBModulatorV1B.bit";
|
||||
printf("Modulator\n");
|
||||
break;
|
||||
case 0x0203:
|
||||
fname="DVBModulatorV1B_DD01_0203.fpga";
|
||||
printf("Modulator Test\n");
|
||||
break;
|
||||
case 0x0210:
|
||||
fname="DVBModulatorV2A_DD01_0210.fpga";
|
||||
printf("Modulator V2\n");
|
||||
break;
|
||||
case 0x0220:
|
||||
fname="SDRModulatorV1A_DD01_0220.fpga";
|
||||
printf("SDRModulator\n");
|
||||
break;
|
||||
default:
|
||||
printf("UNKNOWN\n");
|
||||
break;
|
||||
}
|
||||
fh = open(fname, O_RDONLY);
|
||||
if (fh < 0 ) {
|
||||
printf("File not found \n");
|
||||
printf("File %s not found \n", fname);
|
||||
return 0;
|
||||
}
|
||||
printf("Using bitstream %s\n", fname);
|
||||
@@ -720,6 +330,7 @@ int main(int argc, char **argv)
|
||||
err = FlashWritePageMode(ddb,FlashOffset,buffer,BufferSize,0x3C);
|
||||
break;
|
||||
case SPANSION_S25FL116K:
|
||||
case SPANSION_S25FL164K:
|
||||
err = FlashWritePageMode(ddb,FlashOffset,buffer,BufferSize,0x1C);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,6 @@ static int reboot(uint32_t off)
|
||||
struct ddflash {
|
||||
int fd;
|
||||
struct ddb_id id;
|
||||
uint32_t type;
|
||||
uint32_t version;
|
||||
|
||||
uint32_t flash_type;
|
||||
@@ -68,74 +67,9 @@ struct ddflash {
|
||||
uint32_t bufsize;
|
||||
uint32_t block_erase;
|
||||
|
||||
uint8_t * buffer;
|
||||
uint8_t *buffer;
|
||||
};
|
||||
|
||||
int flashio(int ddb, uint8_t *wbuf, uint32_t wlen, uint8_t *rbuf, uint32_t rlen)
|
||||
{
|
||||
struct ddb_flashio fio = {
|
||||
.write_buf=wbuf,
|
||||
.write_len=wlen,
|
||||
.read_buf=rbuf,
|
||||
.read_len=rlen,
|
||||
.link=0,
|
||||
};
|
||||
|
||||
return ioctl(ddb, IOCTL_DDB_FLASHIO, &fio);
|
||||
}
|
||||
|
||||
enum {
|
||||
UNKNOWN_FLASH = 0,
|
||||
ATMEL_AT45DB642D = 1,
|
||||
SSTI_SST25VF016B = 2,
|
||||
SSTI_SST25VF032B = 3,
|
||||
SSTI_SST25VF064C = 4,
|
||||
SPANSION_S25FL116K = 5,
|
||||
SPANSION_S25FL132K = 6,
|
||||
SPANSION_S25FL164K = 7,
|
||||
};
|
||||
|
||||
static int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
uint8_t cmd[4]= {0x03, (addr >> 16) & 0xff,
|
||||
(addr >> 8) & 0xff, addr & 0xff};
|
||||
|
||||
return flashio(ddb, cmd, 4, buf, len);
|
||||
}
|
||||
|
||||
static int flashdump(struct ddflash *ddf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
int i, j;
|
||||
uint8_t buf[32];
|
||||
int bl = sizeof(buf);
|
||||
|
||||
for (j = 0; j < len; j += bl, addr += bl) {
|
||||
flashread(ddf->fd, buf, addr, bl);
|
||||
for (i = 0; i < bl; i++) {
|
||||
printf("%02x ", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void dump(const uint8_t *b, int l)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (j = 0; j < l; j += 16, b += 16) {
|
||||
for (i = 0; i < 16; i++)
|
||||
if (i + j < l)
|
||||
printf("%02x ", b[i]);
|
||||
else
|
||||
printf(" ");
|
||||
printf(" | ");
|
||||
for (i = 0; i < 16; i++)
|
||||
if (i + j < l)
|
||||
putchar((b[i] > 31 && b[i] < 127) ? b[i] : '.');
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int flashwrite_pagemode(struct ddflash *ddf, int dev, uint32_t FlashOffset,
|
||||
uint8_t LockBits, uint32_t fw_off)
|
||||
{
|
||||
@@ -492,7 +426,7 @@ static int flash_detect(struct ddflash *ddf)
|
||||
}
|
||||
if (ddf->sector_size) {
|
||||
ddf->buffer = malloc(ddf->sector_size);
|
||||
printf("allocated buffer %08x@%08x\n", ddf->sector_size, (uint32_t) ddf->buffer);
|
||||
//printf("allocated buffer %08x@%08x\n", ddf->sector_size, (uint32_t) ddf->buffer);
|
||||
if (!ddf->buffer)
|
||||
return -1;
|
||||
}
|
||||
@@ -500,172 +434,6 @@ static int flash_detect(struct ddflash *ddf)
|
||||
}
|
||||
|
||||
|
||||
int FlashWriteAtmel(int dev,uint32_t FlashOffset, uint8_t *Buffer,int BufferSize)
|
||||
{
|
||||
int err = 0;
|
||||
int BlockErase = BufferSize >= 8192;
|
||||
int i;
|
||||
|
||||
if (BlockErase) {
|
||||
for (i = 0; i < BufferSize; i += 8192 ) {
|
||||
uint8_t cmd[4];
|
||||
if ((i & 0xFFFF) == 0 )
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
cmd[0] = 0x50; // Block Erase
|
||||
cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
cmd[3] = 0x00;
|
||||
err = flashio(dev,cmd,4,NULL,0);
|
||||
if (err < 0 ) break;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
cmd[0] = 0xD7; // Read Status register
|
||||
err = flashio(dev,cmd,1,&cmd[0],1);
|
||||
if (err < 0 ) break;
|
||||
if ((cmd[0] & 0x80) == 0x80 ) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < BufferSize; i += 1024) {
|
||||
uint8_t cmd[4 + 1024];
|
||||
if ((i & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Program %08x\n",FlashOffset + i);
|
||||
}
|
||||
cmd[0] = 0x84; // Buffer 1
|
||||
cmd[1] = 0x00;
|
||||
cmd[2] = 0x00;
|
||||
cmd[3] = 0x00;
|
||||
memcpy(&cmd[4],&Buffer[i],1024);
|
||||
|
||||
err = flashio(dev,cmd,4 + 1024,NULL,0);
|
||||
if (err < 0 ) break;
|
||||
|
||||
cmd[0] = BlockErase ? 0x88 : 0x83; // Buffer to Main Memory (with Erase)
|
||||
cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
cmd[3] = 0x00;
|
||||
|
||||
err = flashio(dev,cmd,4,NULL,0);
|
||||
if (err < 0 ) break;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
cmd[0] = 0xD7; // Read Status register
|
||||
err = flashio(dev,cmd,1,&cmd[0],1);
|
||||
if (err < 0 ) break;
|
||||
if ((cmd[0] & 0x80) == 0x80 ) break;
|
||||
}
|
||||
if (err < 0 ) break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int FlashWriteSSTI(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSize)
|
||||
{
|
||||
int err = 0;
|
||||
uint8_t cmd[6];
|
||||
int i, j;
|
||||
|
||||
// Must be multiple of sector size
|
||||
if ((BufferSize % 4096) != 0 )
|
||||
return -1;
|
||||
|
||||
do {
|
||||
cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev,cmd,1,NULL,0);
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
cmd[0] = 0x01; // WRSR
|
||||
cmd[1] = 0x00; // BPx = 0, Unlock all blocks
|
||||
err = flashio(dev,cmd,2,NULL,0);
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
for (i = 0; i < BufferSize; i += 4096 ) {
|
||||
if ((i & 0xFFFF) == 0 )
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev,cmd,1,NULL,0);
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
cmd[0] = 0x20; // Sector erase ( 4Kb)
|
||||
cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
cmd[3] = 0x00;
|
||||
err = flashio(dev,cmd,4,NULL,0);
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
while(1) {
|
||||
cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev,cmd,1,&cmd[0],1);
|
||||
if (err < 0 ) break;
|
||||
if ((cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if (err < 0 ) break;
|
||||
}
|
||||
if (err < 0 )
|
||||
break;
|
||||
for (j = BufferSize - 4096; j >= 0; j -= 4096 ) {
|
||||
if ((j & 0xFFFF) == 0 )
|
||||
printf(" Program %08x\n",FlashOffset + j);
|
||||
|
||||
for (i = 0; i < 4096; i += 2 ) {
|
||||
if (i == 0 ) {
|
||||
cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev,cmd,1,NULL,0);
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
cmd[0] = 0xAD; // AAI
|
||||
cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF );
|
||||
cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF );
|
||||
cmd[3] = 0x00;
|
||||
cmd[4] = Buffer[j+i];
|
||||
cmd[5] = Buffer[j+i+1];
|
||||
err = flashio(dev,cmd,6,NULL,0);
|
||||
} else {
|
||||
cmd[0] = 0xAD; // AAI
|
||||
cmd[1] = Buffer[j+i];
|
||||
cmd[2] = Buffer[j+i+1];
|
||||
err = flashio(dev,cmd,3,NULL,0);
|
||||
}
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
while(1) {
|
||||
cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev,cmd,1,&cmd[0],1);
|
||||
if (err < 0 ) break;
|
||||
if ((cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if (err < 0 ) break;
|
||||
}
|
||||
if (err < 0 ) break;
|
||||
|
||||
cmd[0] = 0x04; // WDIS
|
||||
err = flashio(dev,cmd,1,NULL,0);
|
||||
if (err < 0 ) break;
|
||||
|
||||
}
|
||||
if (err < 0 ) break;
|
||||
|
||||
cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev,cmd,1,NULL,0);
|
||||
if (err < 0 ) break;
|
||||
|
||||
cmd[0] = 0x01; // WRSR
|
||||
cmd[1] = 0x1C; // BPx = 0, Lock all blocks
|
||||
err = flashio(dev,cmd,2,NULL,0);
|
||||
} while(0);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int get_id(struct ddflash *ddf) {
|
||||
uint8_t id[4];
|
||||
|
||||
@@ -677,19 +445,6 @@ static int get_id(struct ddflash *ddf) {
|
||||
ddf->id.subvendor, ddf->id.subdevice,
|
||||
ddf->id.hw, ddf->id.regmap);
|
||||
#endif
|
||||
if (ddf->id.device == 0x0011)
|
||||
ddf->type = 1;
|
||||
if (ddf->id.device == 0x0201)
|
||||
ddf->type = 2;
|
||||
if (ddf->id.device == 0x02)
|
||||
ddf->type = 3;
|
||||
if (ddf->id.device == 0x03)
|
||||
ddf->type = 0;
|
||||
if (ddf->id.device == 0x0300)
|
||||
ddf->type = 4;
|
||||
if (ddf->id.device == 0x0320)
|
||||
ddf->type = 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -755,7 +510,12 @@ static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off)
|
||||
goto out;
|
||||
}
|
||||
} else if (!strcasecmp(key, "Version")) {
|
||||
sscanf(val, "%x", &version);
|
||||
if (strchr(val,'.')) {
|
||||
int major = 0, minor = 0;
|
||||
sscanf(val,"%d.%d",&major,&minor);
|
||||
version = (major << 16) + minor;
|
||||
} else
|
||||
sscanf(val, "%x", &version);
|
||||
} else if (!strcasecmp(key, "Length")) {
|
||||
sscanf(val, "%u", &length);
|
||||
}
|
||||
@@ -810,8 +570,13 @@ static int update_image(struct ddflash *ddf, char *fn,
|
||||
if (res < 0)
|
||||
goto out;
|
||||
res = flashwrite(ddf, fs, adr, len, fw_off);
|
||||
if (res == 0)
|
||||
res = 1;
|
||||
if (res == 0) {
|
||||
res = flashcmp(ddf, fs, adr, len, fw_off);
|
||||
if (res == -2) {
|
||||
res = 1;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
close(fs);
|
||||
return res;
|
||||
@@ -852,18 +617,40 @@ static int update_flash(struct ddflash *ddf)
|
||||
if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 0)) == 1)
|
||||
stat |= 1;
|
||||
} else {
|
||||
if ((res = update_image(ddf, "/config/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1)
|
||||
stat |= 1;
|
||||
if (res == -1)
|
||||
if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1)
|
||||
stat |= 1;
|
||||
if (res == -1)
|
||||
if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1)
|
||||
stat |= 1;
|
||||
if (res == -1)
|
||||
if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1)
|
||||
if (ddf->id.device == 0x0307) {
|
||||
if (res == -1)
|
||||
if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1)
|
||||
stat |= 1;
|
||||
if (res == -1)
|
||||
if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1)
|
||||
stat |= 1;
|
||||
} else {
|
||||
if ((res = update_image(ddf, "/config/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1)
|
||||
stat |= 1;
|
||||
if (res == -1)
|
||||
if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1)
|
||||
stat |= 1;
|
||||
}
|
||||
}
|
||||
#if 1
|
||||
if ( (stat&1) && (ddf->id.hw & 0xffffff) <= 0x010001) {
|
||||
if (ddf->id.device == 0x0307) {
|
||||
if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x160000, 0x80000, 1, 0)) == 1)
|
||||
stat |= 1;
|
||||
if (res == -1)
|
||||
if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x160000, 0x80000, 1, 0)) == 1)
|
||||
stat |= 1;
|
||||
} else {
|
||||
if ((res = update_image(ddf, "/config/fpga.img", 0x160000, 0x80000, 1, 0)) == 1)
|
||||
stat |= 1;
|
||||
if (res == -1)
|
||||
if ((res = update_image(ddf, "/boot/fpga.img", 0x160000, 0x80000, 1, 0)) == 1)
|
||||
stat |= 1;
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
case 0x320:
|
||||
//fname="/boot/DVBNetV1A_DD01_0300.bit";
|
||||
@@ -872,6 +659,13 @@ static int update_flash(struct ddflash *ddf)
|
||||
stat |= 1;
|
||||
return stat;
|
||||
break;
|
||||
case 0x322:
|
||||
//fname="/boot/DVBNetV1A_DD01_0300.bit";
|
||||
fname="/boot/fpga.img";
|
||||
if ((res = update_image(ddf, fname, 0x10000, 0x100000, 1, 0)) == 1)
|
||||
stat |= 1;
|
||||
return stat;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@@ -12,8 +13,6 @@
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
static uint32_t linknr = 0;
|
||||
|
||||
typedef int (*COMMAND_FUNCTION)(int dev, int argc, char* argv[], uint32_t Flags);
|
||||
|
||||
enum {
|
||||
@@ -21,17 +20,6 @@ enum {
|
||||
SILENT_FLAG = 0x00000002,
|
||||
};
|
||||
|
||||
enum {
|
||||
UNKNOWN_FLASH = 0,
|
||||
ATMEL_AT45DB642D = 1,
|
||||
SSTI_SST25VF016B = 2,
|
||||
SSTI_SST25VF032B = 3,
|
||||
SSTI_SST25VF064C = 4,
|
||||
SPANSION_S25FL116K = 5,
|
||||
SPANSION_S25FL132K = 6,
|
||||
SPANSION_S25FL164K = 7,
|
||||
};
|
||||
|
||||
struct SCommand
|
||||
{
|
||||
char* Name;
|
||||
@@ -42,94 +30,25 @@ struct SCommand
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
void Dump(const uint8_t *b, uint32_t start, int l)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (j = 0; j < l; j += 16, b += 16) {
|
||||
printf("%08x: ", start + j);
|
||||
for (i = 0; i < 16; i++)
|
||||
if (i + j < l)
|
||||
printf("%02x ", b[i]);
|
||||
else
|
||||
printf(" ");
|
||||
printf(" |");
|
||||
for (i = 0; i < 16; i++)
|
||||
if (i + j < l)
|
||||
putchar((b[i] > 31 && b[i] < 127) ? b[i] : '.');
|
||||
printf("|\n");
|
||||
}
|
||||
}
|
||||
|
||||
int readreg(int dev, uint32_t RegAddress, uint32_t *pRegValue)
|
||||
{
|
||||
struct ddb_reg reg = { .reg = RegAddress };
|
||||
int ret;
|
||||
|
||||
ret = ioctl(dev, IOCTL_DDB_READ_REG, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (pRegValue)
|
||||
*pRegValue = reg.val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int writereg(int dev, uint32_t RegAddress, uint32_t RegValue)
|
||||
{
|
||||
struct ddb_reg reg = { .reg = RegAddress, .val = RegValue};
|
||||
|
||||
return ioctl(dev, IOCTL_DDB_WRITE_REG, ®);
|
||||
}
|
||||
|
||||
int FlashIO(int ddb, uint8_t *wbuf, uint32_t wlen, uint8_t *rbuf, uint32_t rlen)
|
||||
{
|
||||
struct ddb_flashio fio = {
|
||||
.write_buf=wbuf,
|
||||
.write_len=wlen,
|
||||
.read_buf=rbuf,
|
||||
.read_len=rlen,
|
||||
.link=linknr,
|
||||
};
|
||||
|
||||
return ioctl(ddb, IOCTL_DDB_FLASHIO, &fio);
|
||||
}
|
||||
|
||||
int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
int ret;
|
||||
uint8_t cmd[4];
|
||||
uint32_t l;
|
||||
|
||||
while (len) {
|
||||
cmd[0] = 3;
|
||||
cmd[1] = (addr >> 16) & 0xff;
|
||||
cmd[2] = (addr >> 8) & 0xff;
|
||||
cmd[3] = addr & 0xff;
|
||||
|
||||
if (len > 1024)
|
||||
l = 1024;
|
||||
else
|
||||
l = len;
|
||||
ret = FlashIO(ddb, cmd, 4, buf, l);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
addr += l;
|
||||
buf += l;
|
||||
len -= l;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ReadFlash(int ddb, int argc, char *argv[], uint32_t Flags)
|
||||
{
|
||||
uint32_t Start;
|
||||
uint32_t Len;
|
||||
uint8_t *Buffer;
|
||||
int fd;
|
||||
|
||||
if (argc < 2 )
|
||||
return -1;
|
||||
Start = strtoul(argv[0],NULL,16);
|
||||
Len = strtoul(argv[1],NULL,16);
|
||||
if (argc == 3) {
|
||||
fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC);
|
||||
if (fd < 0) {
|
||||
printf("Could not open file %s\n", argv[2]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Buffer = malloc(Len);
|
||||
if (flashread(ddb, Buffer, Start, Len) < 0) {
|
||||
@@ -138,68 +57,43 @@ int ReadFlash(int ddb, int argc, char *argv[], uint32_t Flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Dump(Buffer,Start,Len);
|
||||
if (argc == 3) {
|
||||
write(fd, Buffer, Len);
|
||||
close(fd);
|
||||
} else
|
||||
Dump(Buffer,Start,Len);
|
||||
|
||||
free(Buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int FlashDetect(int dev)
|
||||
int ReadSave(int ddb, int argc, char *argv[], uint32_t Flags)
|
||||
{
|
||||
uint8_t Cmd = 0x9F;
|
||||
uint8_t Id[3];
|
||||
|
||||
int r = FlashIO(dev, &Cmd, 1, Id, 3);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x41)
|
||||
r = SSTI_SST25VF016B;
|
||||
else if (Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x4A)
|
||||
r = SSTI_SST25VF032B;
|
||||
else if ( Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x4B )
|
||||
r = SSTI_SST25VF064C;
|
||||
else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x15 )
|
||||
r = SPANSION_S25FL116K;
|
||||
else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x16 )
|
||||
r = SPANSION_S25FL132K;
|
||||
else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x17 )
|
||||
r = SPANSION_S25FL164K;
|
||||
else if ( Id[0] == 0x1F && Id[1] == 0x28)
|
||||
r = ATMEL_AT45DB642D;
|
||||
else
|
||||
r = UNKNOWN_FLASH;
|
||||
|
||||
switch(r) {
|
||||
case UNKNOWN_FLASH :
|
||||
printf("Unknown Flash Flash ID = %02x %02x %02x\n",Id[0],Id[1],Id[2]);
|
||||
break;
|
||||
case ATMEL_AT45DB642D :
|
||||
printf("Flash: Atmel AT45DB642D 64 MBit\n");
|
||||
break;
|
||||
case SSTI_SST25VF016B :
|
||||
printf("Flash: SSTI SST25VF016B 16 MBit\n");
|
||||
break;
|
||||
case SSTI_SST25VF032B :
|
||||
printf("Flash: SSTI SST25VF032B 32 MBit\n");
|
||||
break;
|
||||
case SSTI_SST25VF064C :
|
||||
printf("Flash: SSTI SST25VF064C 64 MBit\n");
|
||||
break;
|
||||
case SPANSION_S25FL116K :
|
||||
printf("Flash: SPANSION S25FL116K 16 MBit\n");
|
||||
break;
|
||||
case SPANSION_S25FL132K :
|
||||
printf("Flash: SPANSION S25FL132K 32 MBit\n");
|
||||
break;
|
||||
case SPANSION_S25FL164K :
|
||||
printf("Flash: SPANSION S25FL164K 64 MBit\n");
|
||||
break;
|
||||
uint32_t Start;
|
||||
uint32_t Len;
|
||||
uint8_t *Buffer;
|
||||
int fd;
|
||||
|
||||
if (argc < 3 )
|
||||
return -1;
|
||||
Start = strtoul(argv[0],NULL,16);
|
||||
Len = strtoul(argv[1],NULL,16);
|
||||
|
||||
Buffer = malloc(Len);
|
||||
if (flashread(ddb, Buffer, Start, Len) < 0) {
|
||||
printf("flashread error\n");
|
||||
free(Buffer);
|
||||
return 0;
|
||||
}
|
||||
return r;
|
||||
|
||||
|
||||
|
||||
free(Buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int FlashChipEraseAtmel(int dev)
|
||||
{
|
||||
int err = 0;
|
||||
@@ -214,12 +108,12 @@ int FlashChipEraseAtmel(int dev)
|
||||
Cmd[1] = ( (( i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
err = FlashIO(dev,Cmd,4,NULL,0);
|
||||
err = flashio(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 )
|
||||
break;
|
||||
while (1) {
|
||||
Cmd[0] = 0xD7; // Read Status register
|
||||
err = FlashIO(dev,Cmd,1,&Cmd[0],1);
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x80) == 0x80 ) break;
|
||||
}
|
||||
@@ -237,25 +131,25 @@ int FlashChipEraseSSTI(int dev)
|
||||
|
||||
do {
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = 0x00; // BPx = 0, Unlock all blocks
|
||||
err = FlashIO(dev,Cmd,2,NULL,0);
|
||||
err = flashio(dev,Cmd,2,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x60; // CHIP Erase
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while(1) {
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = FlashIO(dev,Cmd,1,&Cmd[0],1);
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
@@ -263,12 +157,12 @@ int FlashChipEraseSSTI(int dev)
|
||||
break;
|
||||
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = 0x1C; // BPx = 0, Lock all blocks
|
||||
err = FlashIO(dev,Cmd,2,NULL,0);
|
||||
err = flashio(dev,Cmd,2,NULL,0);
|
||||
}
|
||||
while(0);
|
||||
|
||||
@@ -278,286 +172,6 @@ int FlashChipEraseSSTI(int dev)
|
||||
}
|
||||
|
||||
|
||||
int FlashWriteAtmel(int dev,uint32_t FlashOffset,uint8_t * Buffer,int BufferSize)
|
||||
{
|
||||
int err = 0, i;
|
||||
int BlockErase = BufferSize >= 8192;
|
||||
uint8_t Cmd[4];
|
||||
|
||||
if( BlockErase ) {
|
||||
for(i = 0; i < BufferSize; i += 8192 ) {
|
||||
if( (i & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
}
|
||||
Cmd[0] = 0x50; // Block Erase
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
err = FlashIO(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while(1) {
|
||||
Cmd[0] = 0xD7; // Read Status register
|
||||
err = FlashIO(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x80) == 0x80 ) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < BufferSize; i += 1024 )
|
||||
{
|
||||
if( (i & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Programm %08x\n",FlashOffset + i);
|
||||
}
|
||||
uint8_t Cmd[4 + 1024];
|
||||
Cmd[0] = 0x84; // Buffer 1
|
||||
Cmd[1] = 0x00;
|
||||
Cmd[2] = 0x00;
|
||||
Cmd[3] = 0x00;
|
||||
memcpy(&Cmd[4],&Buffer[i],1024);
|
||||
|
||||
err = FlashIO(dev,Cmd,4 + 1024,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = BlockErase ? 0x88 : 0x83; // Buffer to Main Memory (with Erase)
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
|
||||
err = FlashIO(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while(1)
|
||||
{
|
||||
Cmd[0] = 0xD7; // Read Status register
|
||||
err = FlashIO(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x80) == 0x80 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// **************************************************************************************
|
||||
// BUG: Erasing and writing an incomplete image will result in an failure to boot golden image.
|
||||
// FIX: Write the new image from high to low addresses
|
||||
|
||||
int FlashWriteSSTI(int dev,uint32_t FlashOffset,uint8_t * Buffer,int BufferSize)
|
||||
{
|
||||
int err = 0, i, j;
|
||||
uint8_t Cmd[6];
|
||||
|
||||
if( (BufferSize % 4096) != 0 ) return -1; // Must be multiple of sector size
|
||||
|
||||
do
|
||||
{
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = 0x00; // BPx = 0, Unlock all blocks
|
||||
err = FlashIO(dev,Cmd,2,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
for (i = 0; i < BufferSize; i += 4096 )
|
||||
{
|
||||
if( (i & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
}
|
||||
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x20; // Sector erase ( 4Kb)
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
err = FlashIO(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while(1)
|
||||
{
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = FlashIO(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
|
||||
for (j = BufferSize - 4096; j >= 0; j -= 4096 )
|
||||
{
|
||||
if( (j & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Programm %08x\n",FlashOffset + j);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4096; i += 2 )
|
||||
{
|
||||
|
||||
if( i == 0 )
|
||||
{
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0xAD; // AAI
|
||||
Cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
Cmd[4] = Buffer[j+i];
|
||||
Cmd[5] = Buffer[j+i+1];
|
||||
err = FlashIO(dev,Cmd,6,NULL,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cmd[0] = 0xAD; // AAI
|
||||
Cmd[1] = Buffer[j+i];
|
||||
Cmd[2] = Buffer[j+i+1];
|
||||
err = FlashIO(dev,Cmd,3,NULL,0);
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
while(1)
|
||||
{
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = FlashIO(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x04; // WDIS
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = 0x1C; // BPx = 0, Lock all blocks
|
||||
err = FlashIO(dev,Cmd,2,NULL,0);
|
||||
|
||||
}
|
||||
while(0);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int FlashWritePageMode(int dev, uint32_t FlashOffset,
|
||||
uint8_t *Buffer,int BufferSize,uint8_t LockBits)
|
||||
{
|
||||
int err = 0;
|
||||
uint8_t Cmd[260];
|
||||
int i, j;
|
||||
|
||||
if( (BufferSize % 4096) != 0 ) return -1; // Must be multiple of sector size
|
||||
|
||||
do
|
||||
{
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = 0x00; // BPx = 0, Unlock all blocks
|
||||
err = FlashIO(dev,Cmd,2,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
for(i = 0; i < BufferSize; i += 4096 )
|
||||
{
|
||||
if( (i & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
}
|
||||
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x20; // Sector erase ( 4Kb)
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
err = FlashIO(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while(1)
|
||||
{
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = FlashIO(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
|
||||
for(j = BufferSize - 256; j >= 0; j -= 256 )
|
||||
{
|
||||
if( (j & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Programm %08x\n",FlashOffset + j);
|
||||
}
|
||||
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x02; // PP
|
||||
Cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
memcpy(&Cmd[4],&Buffer[j],256);
|
||||
err = FlashIO(dev,Cmd,260,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while(1)
|
||||
{
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = FlashIO(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = FlashIO(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = LockBits; // BPx = 0, Lock all blocks
|
||||
err = FlashIO(dev,Cmd,2,NULL,0);
|
||||
|
||||
}
|
||||
while(0);
|
||||
return err;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
int ReadDeviceMemory(int dev,int argc, char* argv[],uint32_t Flags)
|
||||
{
|
||||
@@ -693,7 +307,7 @@ int GetSetRegister(int dev,int argc, char* argv[],uint32_t Flags)
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
int FlashIOC(int dev,int argc, char* argv[],uint32_t Flags)
|
||||
int flashioc(int dev,int argc, char* argv[],uint32_t Flags)
|
||||
{
|
||||
uint8_t *Buffer;
|
||||
uint32_t tmp = 0, i;
|
||||
@@ -718,7 +332,7 @@ int FlashIOC(int dev,int argc, char* argv[],uint32_t Flags)
|
||||
Buffer[i] = (uint8_t) tmp;
|
||||
}
|
||||
|
||||
if( FlashIO(dev,Buffer,WriteLen,Buffer,ReadLen) < 0 )
|
||||
if( flashio(dev,Buffer,WriteLen,Buffer,ReadLen) < 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -1108,9 +722,10 @@ int mdio(int dev, int argc, char* argv[], uint32_t Flags)
|
||||
adr = strtoul(argv[0], NULL, 16);
|
||||
reg = strtoul(argv[1], NULL, 16);
|
||||
|
||||
#if 0
|
||||
writereg(dev, 0x24, adr);
|
||||
writereg(dev, 0x28, reg);
|
||||
if(argc > 2) {
|
||||
if (argc > 2) {
|
||||
val = strtoul(argv[2], NULL, 16);
|
||||
writereg(dev, 0x2c, val);
|
||||
writereg(dev, 0x20, 0x03);
|
||||
@@ -1125,6 +740,23 @@ int mdio(int dev, int argc, char* argv[], uint32_t Flags)
|
||||
readreg(dev, 0x2c, &val);
|
||||
printf("%04x\n", val);
|
||||
}
|
||||
#else
|
||||
{
|
||||
struct ddb_mdio mdio = {
|
||||
.adr = adr,
|
||||
.reg = reg,
|
||||
};
|
||||
|
||||
if(argc > 2) {
|
||||
mdio.val = strtoul(argv[2], NULL, 16);
|
||||
return ioctl(dev, IOCTL_DDB_WRITE_MDIO, &mdio);
|
||||
} else {
|
||||
if (ioctl(dev, IOCTL_DDB_READ_MDIO, &mdio) < 0)
|
||||
return -1;
|
||||
printf("%04x\n", mdio.val);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1655,7 +1287,7 @@ static int read_sfpd(int dev, uint8_t adr, uint8_t *val)
|
||||
uint8_t cmd[5] = { 0x5a, 0, 0, adr, 00 };
|
||||
int r;
|
||||
|
||||
r = FlashIO(dev, cmd, 5, val, 1);
|
||||
r = flashio(dev, cmd, 5, val, 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return 0;
|
||||
@@ -1667,7 +1299,7 @@ static int read_sst_id(int dev, uint8_t *id)
|
||||
uint8_t buf[9];
|
||||
int r;
|
||||
|
||||
r = FlashIO(dev, cmd, 2, buf, 9);
|
||||
r = flashio(dev, cmd, 2, buf, 9);
|
||||
if (r < 0)
|
||||
return r;
|
||||
memcpy(id, buf + 1, 8);
|
||||
@@ -1696,15 +1328,129 @@ int read_id(int dev, int argc, char* argv[], uint32_t Flags)
|
||||
break;
|
||||
default:
|
||||
printf("Unsupported Flash\n");
|
||||
break;
|
||||
return -1;
|
||||
}
|
||||
printf("ID: ");
|
||||
for (i = 0; i < 8; i++)
|
||||
for (i = 0; i < len; i++)
|
||||
printf("%02x ", Id[i]);
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
|
||||
int i2cread(int dev, int argc, char* argv[], uint32_t Flags)
|
||||
{
|
||||
uint8_t BusNumber = 0;
|
||||
uint8_t DeviceAddress = 0;
|
||||
int i;
|
||||
uint32_t tmp;
|
||||
char *p;
|
||||
uint32_t BufferLength;
|
||||
uint32_t ReadLen;
|
||||
uint8_t *Buffer;
|
||||
int Repeat = (Flags & REPEAT_FLAG) != 0;
|
||||
int Silent = (Flags & SILENT_FLAG) != 0;
|
||||
|
||||
if (argc < 2)
|
||||
return -1;
|
||||
|
||||
tmp = strtoul(argv[0],&p,16);
|
||||
if (tmp > 255)
|
||||
return -1;
|
||||
|
||||
if (*p == ':') {
|
||||
BusNumber = (uint8_t) (tmp - 1);
|
||||
tmp = strtoul(&p[1],NULL,16);
|
||||
}
|
||||
if (tmp > 255 || BusNumber > 3)
|
||||
return -1;
|
||||
|
||||
DeviceAddress = (uint8_t) tmp;
|
||||
BufferLength = (argc-2);
|
||||
ReadLen = strtoul(argv[argc-1],NULL,0);
|
||||
if (ReadLen > BufferLength)
|
||||
BufferLength = ReadLen ;
|
||||
|
||||
printf(" BufferLength = %d tmp = %d\n", BufferLength, ReadLen);
|
||||
Buffer = malloc(BufferLength);
|
||||
|
||||
for (i = 1; i < (argc-1); i += 1 ) {
|
||||
tmp = strtoul(argv[i],NULL,16);
|
||||
if (tmp > 255) {
|
||||
free(Buffer);
|
||||
return -1;
|
||||
}
|
||||
Buffer[i-1] = (uint8_t) tmp;
|
||||
}
|
||||
|
||||
do {
|
||||
int hr = i2c_read(dev, BusNumber, DeviceAddress, Buffer, argc-2, Buffer, ReadLen);
|
||||
if (hr < 0) {
|
||||
printf("ioctl error\n");
|
||||
free(Buffer);
|
||||
return 0;
|
||||
}
|
||||
if (!Silent) {
|
||||
printf("OK\n");
|
||||
Dump(&Buffer[0],0,ReadLen);
|
||||
}
|
||||
} while (Repeat);
|
||||
free(Buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2cwrite(int dev, int argc, char* argv[], uint32_t Flags)
|
||||
{
|
||||
uint8_t BusNumber = 0;
|
||||
uint8_t DeviceAddress = 0;
|
||||
uint32_t tmp;
|
||||
char *p;
|
||||
uint8_t *Buffer;
|
||||
int i;
|
||||
int Repeat = (Flags & REPEAT_FLAG) != 0;
|
||||
int Silent = (Flags & SILENT_FLAG) != 0;
|
||||
|
||||
|
||||
if( argc < 1 )
|
||||
return -1;
|
||||
tmp = strtoul(argv[0],&p,16);
|
||||
if( tmp > 255 )
|
||||
return -1;
|
||||
|
||||
if (*p == ':') {
|
||||
BusNumber = (uint8_t) (tmp - 1);
|
||||
tmp = strtoul(&p[1],NULL,16);
|
||||
}
|
||||
if( tmp > 255 || BusNumber > 3)
|
||||
return -1;
|
||||
|
||||
DeviceAddress = (uint8_t) tmp;
|
||||
Buffer = malloc(argc - 1);
|
||||
|
||||
for (i = 1; i < argc; i += 1) {
|
||||
tmp = strtoul(argv[i],NULL,16);
|
||||
if (tmp > 255 ) {
|
||||
free(Buffer);
|
||||
return -1;
|
||||
}
|
||||
Buffer[i-1] = (uint8_t) tmp;
|
||||
}
|
||||
|
||||
do {
|
||||
int hr =i2c_write(dev, BusNumber,DeviceAddress,NULL,0,Buffer,argc-1);
|
||||
if (hr < 0) {
|
||||
printf("ioctl error\n");
|
||||
free(Buffer);
|
||||
return 0;
|
||||
}
|
||||
if( !Silent )
|
||||
printf("OK\n");
|
||||
} while( Repeat );
|
||||
|
||||
free(Buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct SCommand CommandTable[] =
|
||||
{
|
||||
{ "memread", ReadDeviceMemory, 1, "Read Device Memory : memread <start> <count>" },
|
||||
@@ -1712,13 +1458,13 @@ struct SCommand CommandTable[] =
|
||||
{ "memwrite", WriteDeviceMemory, 1, "Write Device Memory : memwrite <start> <values(8)> .." },
|
||||
{ "register", GetSetRegister, 1, "Get/Set Register : reg <regname>|<[0x]regnum> [[0x]value(32)]" },
|
||||
|
||||
{ "flashread", ReadFlash, 1, "Read Flash : flashread <start> <count>" },
|
||||
{ "flashio", FlashIOC, 1, "Flash IO : flashio <write data>.. <read count>" },
|
||||
{ "flashread", ReadFlash, 1, "Read Flash : flashread <start> <count> [<Filename>]" },
|
||||
{ "flashio", flashioc, 1, "Flash IO : flashio <write data>.. <read count>" },
|
||||
{ "flashprog", FlashProg, 1, "Flash Programming : flashprog <FileName> [<address>]" },
|
||||
{ "flashprog", FlashProg, 1, "Flash Programming : flashprog -SubVendorID <id>" },
|
||||
{ "flashprog", FlashProg, 1, "Flash Programming : flashprog -Jump <address>" },
|
||||
{ "flashverify", FlashVerify, 1, "Flash Verify : flashverify <FileName> [<address>]" },
|
||||
{ "flasherase", FlashErase, 1, "FlashErase : flasherase" },
|
||||
//{ "flasherase", FlashErase, 1, "FlashErase : flasherase" },
|
||||
//{ "flashtest", FlashTest, 1, "FlashTest : flashtest" },
|
||||
|
||||
|
||||
@@ -1729,6 +1475,8 @@ struct SCommand CommandTable[] =
|
||||
{ "licexport", lic_export, 1, "License Export : licexport" },
|
||||
{ "licerase", lic_erase, 1, "License Erase : licerase" },
|
||||
{ "read_id", read_id, 1, "Read Unique ID : read_id" },
|
||||
{ "i2cread", i2cread, 1, "I2C Read : I2CRead <[BusNumber:]DeviceAddress> [<write data>..] <read count>" },
|
||||
{ "i2write", i2cwrite, 1, "I2C Write : I2CWrite <[BusNumber:]DeviceAddress> [<write data>..]"},
|
||||
{ NULL,NULL,0 }
|
||||
};
|
||||
|
||||
|
||||
614
apps/octonet/flash.c
Normal file
614
apps/octonet/flash.c
Normal file
@@ -0,0 +1,614 @@
|
||||
enum {
|
||||
UNKNOWN_FLASH = 0,
|
||||
ATMEL_AT45DB642D = 1,
|
||||
SSTI_SST25VF016B = 2,
|
||||
SSTI_SST25VF032B = 3,
|
||||
SSTI_SST25VF064C = 4,
|
||||
SPANSION_S25FL116K = 5,
|
||||
SPANSION_S25FL132K = 6,
|
||||
SPANSION_S25FL164K = 7,
|
||||
};
|
||||
|
||||
static uint32_t linknr = 0;
|
||||
|
||||
int flashio(int ddb, uint8_t *wbuf, uint32_t wlen, uint8_t *rbuf, uint32_t rlen)
|
||||
{
|
||||
struct ddb_flashio fio = {
|
||||
.write_buf=wbuf,
|
||||
.write_len=wlen,
|
||||
.read_buf=rbuf,
|
||||
.read_len=rlen,
|
||||
.link=linknr,
|
||||
};
|
||||
|
||||
return ioctl(ddb, IOCTL_DDB_FLASHIO, &fio);
|
||||
}
|
||||
|
||||
int FlashDetect(int dev)
|
||||
{
|
||||
uint8_t Cmd = 0x9F;
|
||||
uint8_t Id[3];
|
||||
|
||||
int r = flashio(dev, &Cmd, 1, Id, 3);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x41)
|
||||
r = SSTI_SST25VF016B;
|
||||
else if (Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x4A)
|
||||
r = SSTI_SST25VF032B;
|
||||
else if ( Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x4B )
|
||||
r = SSTI_SST25VF064C;
|
||||
else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x15 )
|
||||
r = SPANSION_S25FL116K;
|
||||
else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x16 )
|
||||
r = SPANSION_S25FL132K;
|
||||
else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x17 )
|
||||
r = SPANSION_S25FL164K;
|
||||
else if ( Id[0] == 0x1F && Id[1] == 0x28)
|
||||
r = ATMEL_AT45DB642D;
|
||||
else
|
||||
r = UNKNOWN_FLASH;
|
||||
|
||||
switch(r) {
|
||||
case UNKNOWN_FLASH :
|
||||
printf("Unknown Flash Flash ID = %02x %02x %02x\n",Id[0],Id[1],Id[2]);
|
||||
break;
|
||||
case ATMEL_AT45DB642D :
|
||||
printf("Flash: Atmel AT45DB642D 64 MBit\n");
|
||||
break;
|
||||
case SSTI_SST25VF016B :
|
||||
printf("Flash: SSTI SST25VF016B 16 MBit\n");
|
||||
break;
|
||||
case SSTI_SST25VF032B :
|
||||
printf("Flash: SSTI SST25VF032B 32 MBit\n");
|
||||
break;
|
||||
case SSTI_SST25VF064C :
|
||||
printf("Flash: SSTI SST25VF064C 64 MBit\n");
|
||||
break;
|
||||
case SPANSION_S25FL116K :
|
||||
printf("Flash: SPANSION S25FL116K 16 MBit\n");
|
||||
break;
|
||||
case SPANSION_S25FL132K :
|
||||
printf("Flash: SPANSION S25FL132K 32 MBit\n");
|
||||
break;
|
||||
case SPANSION_S25FL164K :
|
||||
printf("Flash: SPANSION S25FL164K 64 MBit\n");
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static int flashdetect(int fd, uint32_t *sector_size, uint32_t *flash_size)
|
||||
{
|
||||
uint8_t cmd = 0x9F;
|
||||
uint8_t id[3];
|
||||
int flash_type;
|
||||
|
||||
int r = flashio(fd, &cmd, 1, id, 3);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x41) {
|
||||
flash_type = SSTI_SST25VF016B;
|
||||
printf("Flash: SSTI SST25VF016B 16 MBit\n");
|
||||
*sector_size = 4096;
|
||||
*flash_size = 0x200000;
|
||||
} else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4A) {
|
||||
flash_type = SSTI_SST25VF032B;
|
||||
printf("Flash: SSTI SST25VF032B 32 MBit\n");
|
||||
*sector_size = 4096;
|
||||
*flash_size = 0x400000;
|
||||
} else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4B) {
|
||||
flash_type = SSTI_SST25VF064C;
|
||||
printf("Flash: SSTI SST25VF064C 64 MBit\n");
|
||||
*sector_size = 4096;
|
||||
*flash_size = 0x800000;
|
||||
} else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x15) {
|
||||
flash_type = SPANSION_S25FL116K;
|
||||
printf("Flash: SPANSION S25FL116K 16 MBit\n");
|
||||
*sector_size = 4096;
|
||||
*flash_size = 0x200000;
|
||||
} else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x16) {
|
||||
flash_type = SPANSION_S25FL132K;
|
||||
printf("Flash: SPANSION S25FL132K 32 MBit\n");
|
||||
*sector_size = 4096;
|
||||
*flash_size = 0x400000;
|
||||
} else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x17) {
|
||||
flash_type = SPANSION_S25FL164K;
|
||||
printf("Flash: SPANSION S25FL164K 64 MBit\n");
|
||||
*sector_size = 4096;
|
||||
*flash_size = 0x800000;
|
||||
} else if (id[0] == 0x1F && id[1] == 0x28) {
|
||||
flash_type = ATMEL_AT45DB642D;
|
||||
printf("Flash: Atmel AT45DB642D 64 MBit\n");
|
||||
*sector_size = 1024;
|
||||
*flash_size = 0x800000;
|
||||
} else {
|
||||
printf("Unknown Flash Flash ID = %02x %02x %02x\n", id[0], id[1], id[2]);
|
||||
return -1;
|
||||
}
|
||||
return flash_type;
|
||||
}
|
||||
|
||||
|
||||
#if 1
|
||||
int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
int ret;
|
||||
uint8_t cmd[4];
|
||||
uint32_t l;
|
||||
|
||||
while (len) {
|
||||
cmd[0] = 3;
|
||||
cmd[1] = (addr >> 16) & 0xff;
|
||||
cmd[2] = (addr >> 8) & 0xff;
|
||||
cmd[3] = addr & 0xff;
|
||||
|
||||
if (len > 1024)
|
||||
l = 1024;
|
||||
else
|
||||
l = len;
|
||||
ret = flashio(ddb, cmd, 4, buf, l);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
addr += l;
|
||||
buf += l;
|
||||
len -= l;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
uint8_t cmd[4]= {0x03, (addr >> 16) & 0xff,
|
||||
(addr >> 8) & 0xff, addr & 0xff};
|
||||
|
||||
return flashio(ddb, cmd, 4, buf, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
int flashdump(int ddb, uint32_t addr, uint32_t len)
|
||||
{
|
||||
int i, j;
|
||||
uint8_t buf[32];
|
||||
int bl = sizeof(buf);
|
||||
|
||||
for (j=0; j<len; j+=bl, addr+=bl) {
|
||||
flashread(ddb, buf, addr, bl);
|
||||
for (i=0; i<bl; i++) {
|
||||
printf("%02x ", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int readreg(int dev, uint32_t RegAddress, uint32_t *pRegValue)
|
||||
{
|
||||
struct ddb_reg reg = { .reg = RegAddress };
|
||||
int ret;
|
||||
|
||||
ret = ioctl(dev, IOCTL_DDB_READ_REG, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (pRegValue)
|
||||
*pRegValue = reg.val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int writereg(int dev, uint32_t RegAddress, uint32_t RegValue)
|
||||
{
|
||||
struct ddb_reg reg = { .reg = RegAddress, .val = RegValue};
|
||||
|
||||
return ioctl(dev, IOCTL_DDB_WRITE_REG, ®);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void dump(const uint8_t *b, int l)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (j = 0; j < l; j += 16, b += 16) {
|
||||
for (i = 0; i < 16; i++)
|
||||
if (i + j < l)
|
||||
printf("%02x ", b[i]);
|
||||
else
|
||||
printf(" ");
|
||||
printf(" | ");
|
||||
for (i = 0; i < 16; i++)
|
||||
if (i + j < l)
|
||||
putchar((b[i] > 31 && b[i] < 127) ? b[i] : '.');
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Dump(const uint8_t *b, uint32_t start, int l)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (j = 0; j < l; j += 16, b += 16) {
|
||||
printf("%08x: ", start + j);
|
||||
for (i = 0; i < 16; i++)
|
||||
if (i + j < l)
|
||||
printf("%02x ", b[i]);
|
||||
else
|
||||
printf(" ");
|
||||
printf(" |");
|
||||
for (i = 0; i < 16; i++)
|
||||
if (i + j < l)
|
||||
putchar((b[i] > 31 && b[i] < 127) ? b[i] : '.');
|
||||
printf("|\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int FlashWriteAtmel(int dev,uint32_t FlashOffset, uint8_t *Buffer,int BufferSize)
|
||||
{
|
||||
int err = 0;
|
||||
int BlockErase = BufferSize >= 8192;
|
||||
int i;
|
||||
|
||||
if (BlockErase) {
|
||||
for(i = 0; i < BufferSize; i += 8192 ) {
|
||||
uint8_t Cmd[4];
|
||||
if( (i & 0xFFFF) == 0 )
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
Cmd[0] = 0x50; // Block Erase
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
err = flashio(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
Cmd[0] = 0xD7; // Read Status register
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x80) == 0x80 ) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < BufferSize; i += 1024 )
|
||||
{
|
||||
uint8_t Cmd[4 + 1024];
|
||||
if( (i & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Program %08x\n",FlashOffset + i);
|
||||
}
|
||||
Cmd[0] = 0x84; // Buffer 1
|
||||
Cmd[1] = 0x00;
|
||||
Cmd[2] = 0x00;
|
||||
Cmd[3] = 0x00;
|
||||
memcpy(&Cmd[4],&Buffer[i],1024);
|
||||
|
||||
err = flashio(dev,Cmd,4 + 1024,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = BlockErase ? 0x88 : 0x83; // Buffer to Main Memory (with Erase)
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
|
||||
err = flashio(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
Cmd[0] = 0xD7; // Read Status register
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x80) == 0x80 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int FlashWriteSSTI(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSize)
|
||||
{
|
||||
int err = 0;
|
||||
uint8_t cmd[6];
|
||||
int i, j;
|
||||
|
||||
// Must be multiple of sector size
|
||||
if ((BufferSize % 4096) != 0 )
|
||||
return -1;
|
||||
|
||||
do {
|
||||
cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev,cmd,1,NULL,0);
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
cmd[0] = 0x01; // WRSR
|
||||
cmd[1] = 0x00; // BPx = 0, Unlock all blocks
|
||||
err = flashio(dev,cmd,2,NULL,0);
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
for (i = 0; i < BufferSize; i += 4096 ) {
|
||||
if ((i & 0xFFFF) == 0 )
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev,cmd,1,NULL,0);
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
cmd[0] = 0x20; // Sector erase ( 4Kb)
|
||||
cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
cmd[3] = 0x00;
|
||||
err = flashio(dev,cmd,4,NULL,0);
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
while(1) {
|
||||
cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev,cmd,1,&cmd[0],1);
|
||||
if (err < 0 ) break;
|
||||
if ((cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if (err < 0 ) break;
|
||||
}
|
||||
if (err < 0 )
|
||||
break;
|
||||
for (j = BufferSize - 4096; j >= 0; j -= 4096 ) {
|
||||
if ((j & 0xFFFF) == 0 )
|
||||
printf(" Program %08x\n",FlashOffset + j);
|
||||
|
||||
for (i = 0; i < 4096; i += 2 ) {
|
||||
if (i == 0 ) {
|
||||
cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev,cmd,1,NULL,0);
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
cmd[0] = 0xAD; // AAI
|
||||
cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF );
|
||||
cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF );
|
||||
cmd[3] = 0x00;
|
||||
cmd[4] = Buffer[j+i];
|
||||
cmd[5] = Buffer[j+i+1];
|
||||
err = flashio(dev,cmd,6,NULL,0);
|
||||
} else {
|
||||
cmd[0] = 0xAD; // AAI
|
||||
cmd[1] = Buffer[j+i];
|
||||
cmd[2] = Buffer[j+i+1];
|
||||
err = flashio(dev,cmd,3,NULL,0);
|
||||
}
|
||||
if (err < 0 )
|
||||
break;
|
||||
|
||||
while(1) {
|
||||
cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev,cmd,1,&cmd[0],1);
|
||||
if (err < 0 ) break;
|
||||
if ((cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if (err < 0 ) break;
|
||||
}
|
||||
if (err < 0 ) break;
|
||||
|
||||
cmd[0] = 0x04; // WDIS
|
||||
err = flashio(dev,cmd,1,NULL,0);
|
||||
if (err < 0 ) break;
|
||||
|
||||
}
|
||||
if (err < 0 ) break;
|
||||
|
||||
cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev,cmd,1,NULL,0);
|
||||
if (err < 0 ) break;
|
||||
|
||||
cmd[0] = 0x01; // WRSR
|
||||
cmd[1] = 0x1C; // BPx = 0, Lock all blocks
|
||||
err = flashio(dev,cmd,2,NULL,0);
|
||||
} while(0);
|
||||
return err;
|
||||
}
|
||||
|
||||
int FlashWriteSSTI_B(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSize)
|
||||
{
|
||||
int err = 0;
|
||||
uint8_t Cmd[6];
|
||||
int i, j;
|
||||
|
||||
// Must be multiple of sector size
|
||||
if( (BufferSize % 4096) != 0 )
|
||||
return -1;
|
||||
|
||||
do {
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = 0x00; // BPx = 0, Unlock all blocks
|
||||
err = flashio(dev,Cmd,2,NULL,0);
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
for(i = 0; i < BufferSize; i += 4096 ) {
|
||||
if( (i & 0xFFFF) == 0 )
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
Cmd[0] = 0x20; // Sector erase ( 4Kb)
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
err = flashio(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
while(1) {
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
}
|
||||
if( err < 0 )
|
||||
break;
|
||||
for(j = BufferSize - 4096; j >= 0; j -= 4096 ) {
|
||||
if( (j & 0xFFFF) == 0 )
|
||||
printf(" Program %08x\n",FlashOffset + j);
|
||||
|
||||
for(i = 0; i < 4096; i += 2 ) {
|
||||
if( i == 0 ) {
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
Cmd[0] = 0xAD; // AAI
|
||||
Cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
Cmd[4] = Buffer[j+i];
|
||||
Cmd[5] = Buffer[j+i+1];
|
||||
err = flashio(dev,Cmd,6,NULL,0);
|
||||
} else {
|
||||
Cmd[0] = 0xAD; // AAI
|
||||
Cmd[1] = Buffer[j+i];
|
||||
Cmd[2] = Buffer[j+i+1];
|
||||
err = flashio(dev,Cmd,3,NULL,0);
|
||||
}
|
||||
if( err < 0 )
|
||||
break;
|
||||
|
||||
while(1) {
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x04; // WDIS
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = 0x1C; // BPx = 0, Lock all blocks
|
||||
err = flashio(dev,Cmd,2,NULL,0);
|
||||
} while(0);
|
||||
return err;
|
||||
}
|
||||
|
||||
int FlashWritePageMode(int dev, uint32_t FlashOffset,
|
||||
uint8_t *Buffer,int BufferSize,uint8_t LockBits)
|
||||
{
|
||||
int err = 0;
|
||||
uint8_t Cmd[260];
|
||||
int i, j;
|
||||
|
||||
if( (BufferSize % 4096) != 0 ) return -1; // Must be multiple of sector size
|
||||
|
||||
do
|
||||
{
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = 0x00; // BPx = 0, Unlock all blocks
|
||||
err = flashio(dev,Cmd,2,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
for(i = 0; i < BufferSize; i += 4096 )
|
||||
{
|
||||
if( (i & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Erase %08x\n",FlashOffset + i);
|
||||
}
|
||||
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x20; // Sector erase ( 4Kb)
|
||||
Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
err = flashio(dev,Cmd,4,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while(1)
|
||||
{
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
|
||||
for(j = BufferSize - 256; j >= 0; j -= 256 )
|
||||
{
|
||||
if( (j & 0xFFFF) == 0 )
|
||||
{
|
||||
printf(" Programm %08x\n",FlashOffset + j);
|
||||
}
|
||||
|
||||
Cmd[0] = 0x06; // WREN
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x02; // PP
|
||||
Cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF );
|
||||
Cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF );
|
||||
Cmd[3] = 0x00;
|
||||
memcpy(&Cmd[4],&Buffer[j],256);
|
||||
err = flashio(dev,Cmd,260,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
while(1)
|
||||
{
|
||||
Cmd[0] = 0x05; // RDRS
|
||||
err = flashio(dev,Cmd,1,&Cmd[0],1);
|
||||
if( err < 0 ) break;
|
||||
if( (Cmd[0] & 0x01) == 0 ) break;
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
}
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x50; // EWSR
|
||||
err = flashio(dev,Cmd,1,NULL,0);
|
||||
if( err < 0 ) break;
|
||||
|
||||
Cmd[0] = 0x01; // WRSR
|
||||
Cmd[1] = LockBits; // BPx = 0, Lock all blocks
|
||||
err = flashio(dev,Cmd,2,NULL,0);
|
||||
|
||||
}
|
||||
while(0);
|
||||
return err;
|
||||
}
|
||||
@@ -61,3 +61,5 @@ struct ddb_i2c_msg {
|
||||
#define IOCTL_DDB_WRITE_MDIO _IOR(DDB_MAGIC, 0x09, struct ddb_mdio)
|
||||
#define IOCTL_DDB_READ_I2C _IOWR(DDB_MAGIC, 0x0a, struct ddb_i2c_msg)
|
||||
#define IOCTL_DDB_WRITE_I2C _IOR(DDB_MAGIC, 0x0b, struct ddb_i2c_msg)
|
||||
|
||||
#include "flash.c"
|
||||
|
||||
167
apps/pls.c
Normal file
167
apps/pls.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* pls.c: Convert between Gold and Root Codes for DVB-S2 PLS
|
||||
*
|
||||
* Copyright (C) 2017 Marcus Metzler <mocm@metzlerbros.de>
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* According to ETSI EN 302 307 5.5.4 the PLS (Physical Layer
|
||||
Scrambling) for DVB-S2 consists of a complex randomization
|
||||
sequence which is ultimately derived from two recursively
|
||||
defined m-sequences (=MLS or maximum length sequences)
|
||||
x(i) and y(i) of polynomials over GF(2) with m=18
|
||||
(thus their length is 2^18 - 1).
|
||||
These m-sequences with sequence y starting from y(0) and
|
||||
sequence x starting from x(n) are combined to form a set
|
||||
of 2^18 - 1 different Gold code sequences.
|
||||
|
||||
This starting number n of sequence x selects which
|
||||
of those 2^18 - 1 Gold code sequences to use.
|
||||
As a DVB-S2 tuning parameter n is called the scrambling sequence index
|
||||
(cf. ETSI EN 300 468 table 41) or Gold sequence index,
|
||||
commonly also just called "Gold code".
|
||||
The 18 values of the sequence x starting from x(n)
|
||||
(x(n) ... x(n+17)) are also called the "Root code".
|
||||
So, Gold and Root codes are not different ways of PLS, they are
|
||||
just different ways to select the same sequence start point.
|
||||
|
||||
The initial values for x(i), i=0..18 are x(0)=1, x(1)=0, .., x(17)=0 .
|
||||
The polynomial used for the x sequence recursion is 1+x^7+x^18.
|
||||
If the lower 18 bits of a variable "uint32_t X" contain x(n) ... x(n+17),
|
||||
then we can simply calculate x(n+1) ... x(n+18) by doing:
|
||||
X = (((X ^ (X >> 7)) & 1) << 17) | (X >> 1);
|
||||
|
||||
So, if X contained the "Root code" corresponding to "Gold code" n,
|
||||
it will now contain the "Root code" corresponding to "Gold code" (n+1).
|
||||
Note that X=0 and n=2^18 - 1 do not exist (or rather the lattter is the same
|
||||
as n = 0) and for n=0 to 2^18 - 2 and X=1 to 2^18 - 1 there is a
|
||||
one-to-one correspondence (bijection).
|
||||
|
||||
Note that PLS has nothing to do with encryption for DRM purposes. It is used
|
||||
to minimize interference between transponders.
|
||||
|
||||
|
||||
"Combo code":
|
||||
There is no such thing as a combo code. It is the result of a bug in older
|
||||
STV090x drivers which resulted in a crazy race condition between a Gold->Root
|
||||
conversion in the STV and an ongoing I2C write.
|
||||
Better forget about it and determine the proper Root or Gold code.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
static uint32_t gold2root(uint32_t gold)
|
||||
{
|
||||
uint32_t x, g;
|
||||
|
||||
for (g = 0, x = 1; g < gold; g++)
|
||||
x = (((x ^ (x >> 7)) & 1) << 17) | (x >> 1);
|
||||
return x;
|
||||
}
|
||||
|
||||
static uint32_t root2gold(uint32_t root)
|
||||
{
|
||||
uint32_t x, g;
|
||||
|
||||
for (g = 0, x = 1; g < 0x3ffff; g++) {
|
||||
if (root == x)
|
||||
return g;
|
||||
x = (((x ^ (x >> 7)) & 1) << 17) | (x >> 1);
|
||||
}
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
uint32_t gold = 0xffffffff, root = 0xffffffff;
|
||||
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
int c;
|
||||
static struct option long_options[] = {
|
||||
{"gold", required_argument, 0, 'g'},
|
||||
{"root", required_argument, 0, 'r'},
|
||||
{"help", no_argument , 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
c = getopt_long(argc, argv,
|
||||
"r:g:h",
|
||||
long_options, &option_index);
|
||||
if (c==-1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'g':
|
||||
gold = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'r':
|
||||
root = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'h':
|
||||
printf("pls -g gold_code\n");
|
||||
printf("or\n");
|
||||
printf("pls -r root_code\n");
|
||||
exit(-1);
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
if (optind < argc) {
|
||||
printf("Warning: unused arguments\n");
|
||||
}
|
||||
if (gold != 0xffffffff && root != 0xffffffff) {
|
||||
printf("Only specify root or gold code\n");
|
||||
exit(-1);
|
||||
};
|
||||
if (gold != 0xffffffff) {
|
||||
if (gold < 0x3ffff) {
|
||||
root = gold2root(gold);
|
||||
printf("gold = %llu (0x%05x) root = %llu (0x%05x)\n",
|
||||
gold, gold, root, root);
|
||||
} else
|
||||
printf("Invalid gold code specified.\n");
|
||||
exit(0);
|
||||
}
|
||||
if (root != 0xffffffff) {
|
||||
if (root > 0 && root < 0x40000)
|
||||
gold = root2gold(root);
|
||||
if (gold != 0xffffffff)
|
||||
printf("gold = %llu (0x%05x) root = %llu (0x%05x)\n",
|
||||
gold, gold, root, root);
|
||||
else
|
||||
printf("Invalid root code specified.\n");
|
||||
exit(0);
|
||||
}
|
||||
printf("Specify either root or gold code with -r or -g.\n");
|
||||
}
|
||||
47
apps/setmod2.c
Normal file
47
apps/setmod2.c
Normal file
@@ -0,0 +1,47 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <linux/dvb/mod.h>
|
||||
|
||||
static int set_property(int fd, uint32_t cmd, uint32_t data)
|
||||
{
|
||||
struct dtv_property p;
|
||||
struct dtv_properties c;
|
||||
int ret;
|
||||
|
||||
p.cmd = cmd;
|
||||
c.num = 1;
|
||||
c.props = &p;
|
||||
p.u.data = data;
|
||||
ret = ioctl(fd, FE_SET_PROPERTY, &c);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "FE_SET_PROPERTY returned %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int fd;
|
||||
struct dvb_mod_params mp;
|
||||
struct dvb_mod_channel_params mc;
|
||||
|
||||
fd = open("/dev/dvb/adapter0/mod0", O_RDONLY);
|
||||
|
||||
set_property(fd, MODULATOR_MODULATION, QAM_256);
|
||||
set_property(fd, MODULATOR_SYMBOL_RATE, 6900000);
|
||||
set_property(fd, MODULATOR_FREQUENCY, 114000000);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
83
apps/setmod3.c
Normal file
83
apps/setmod3.c
Normal file
@@ -0,0 +1,83 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <linux/dvb/mod.h>
|
||||
|
||||
static int set_property(int fd, uint32_t cmd, uint32_t data)
|
||||
{
|
||||
struct dtv_property p;
|
||||
struct dtv_properties c;
|
||||
int ret;
|
||||
|
||||
p.cmd = cmd;
|
||||
c.num = 1;
|
||||
c.props = &p;
|
||||
p.u.data = data;
|
||||
ret = ioctl(fd, FE_SET_PROPERTY, &c);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "FE_SET_PROPERTY returned %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_property(int fd, uint32_t cmd, uint32_t *data)
|
||||
{
|
||||
struct dtv_property p;
|
||||
struct dtv_properties c;
|
||||
int ret;
|
||||
|
||||
p.cmd = cmd;
|
||||
c.num = 1;
|
||||
c.props = &p;
|
||||
ret = ioctl(fd, FE_GET_PROPERTY, &c);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "FE_GET_PROPERTY returned %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
*data = p.u.data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
int fd;
|
||||
struct dvb_mod_params mp;
|
||||
struct dvb_mod_channel_params mc;
|
||||
uint32_t data;
|
||||
|
||||
fd = open("/dev/dvb/adapter0/mod0", O_RDONLY);
|
||||
|
||||
/* gain 0-255 */
|
||||
get_property(fd, MODULATOR_GAIN, &data);
|
||||
printf("Modulator gain = %u\n", data);
|
||||
set_property(fd, MODULATOR_GAIN, 100);
|
||||
|
||||
get_property(fd, MODULATOR_GAIN, &data);
|
||||
printf("Modulator gain = %u\n", data);
|
||||
|
||||
get_property(fd, MODULATOR_ATTENUATOR, &data);
|
||||
printf("Modulator attenuator = %u\n", data);
|
||||
|
||||
|
||||
get_property(fd, MODULATOR_STATUS, &data);
|
||||
printf("Modulator status = %u\n", data);
|
||||
set_property(fd, MODULATOR_STATUS, 2);
|
||||
|
||||
|
||||
//set_property(fd, MODULATOR_RESET, 0);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2843 -DCONFIG_DVB_LNBP21 -DCONFIG_DVB_STV090x -DCONFIG_DVB_STV6110x -DCONFIG_DVB_DRXK -DCONFIG_DVB_STV0910 -DCONFIG_DVB_STV6111 -DCONFIG_DVB_LNBH25 -DCONFIG_DVB_MXL5XX
|
||||
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2843 -DCONFIG_DVB_LNBP21 -DCONFIG_DVB_STV090x -DCONFIG_DVB_STV6110x -DCONFIG_DVB_DRXK -DCONFIG_DVB_STV0910 -DCONFIG_DVB_STV6111 -DCONFIG_DVB_LNBH25 -DCONFIG_DVB_MXL5XX -DCONFIG_DVB_CXD2099 -DCONFIG_DVB_NET
|
||||
|
||||
ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
|
||||
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
|
||||
|
||||
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
|
||||
obj-$(CONFIG_DVB_OCTONET) += octonet.o
|
||||
|
||||
46
ddbridge/Kconfig
Normal file
46
ddbridge/Kconfig
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
config DVB_DDBRIDGE
|
||||
tristate "Digital Devices bridge support"
|
||||
depends on MEDIA_PCI_SUPPORT && DVB_CORE && PCI && I2C
|
||||
select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA18212DD if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0367DD if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CXD2843 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT
|
||||
---help---
|
||||
Support for cards with the Digital Devices PCI express bridge:
|
||||
- Octopus PCIe Bridge
|
||||
- Octopus mini PCIe Bridge
|
||||
- Octopus LE
|
||||
- DuoFlex S2 Octopus
|
||||
- DuoFlex CT Octopus
|
||||
- cineS2(v6)
|
||||
|
||||
Say Y if you own such a card and want to use it.
|
||||
|
||||
|
||||
config DVB_OCTONET
|
||||
tristate "Digital Devices octonet support"
|
||||
depends on MEDIA_DIGITAL_TV_SUPPORT && DVB_CORE && I2C
|
||||
select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA18212DD if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0367DD if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CXD2843 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0910 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV6111 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT
|
||||
---help---
|
||||
Support for OctopusNet
|
||||
|
||||
Say Y if you own such a card and want to use it.
|
||||
@@ -1,19 +1,14 @@
|
||||
KDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
PWD := $(shell pwd)
|
||||
#
|
||||
# Makefile for the ddbridge device driver
|
||||
#
|
||||
|
||||
MODDEFS := CONFIG_DVB_DDBRIDGE=m
|
||||
ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
|
||||
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) $(MODDEFS) modules
|
||||
$(MAKE) -C apps
|
||||
|
||||
dep:
|
||||
DIR=`pwd`; (cd $(TOPDIR); make SUBDIRS=$$DIR dep)
|
||||
|
||||
install: all
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules_install
|
||||
|
||||
clean:
|
||||
rm -rf */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules*
|
||||
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
|
||||
obj-$(CONFIG_DVB_OCTONET) += octonet.o
|
||||
|
||||
ccflags-y += -Idrivers/media/dvb-core/
|
||||
ccflags-y += -Idrivers/media/dvb-frontends/
|
||||
ccflags-y += -Idrivers/media/tuners/
|
||||
|
||||
|
||||
14
ddbridge/Makefile.kernel
Normal file
14
ddbridge/Makefile.kernel
Normal file
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# Makefile for the ddbridge device driver
|
||||
#
|
||||
|
||||
ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
|
||||
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
|
||||
|
||||
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
|
||||
obj-$(CONFIG_DVB_OCTONET) += octonet.o
|
||||
|
||||
ccflags-y += -Idrivers/media/dvb-core/
|
||||
ccflags-y += -Idrivers/media/dvb-frontends/
|
||||
ccflags-y += -Idrivers/media/tuners/
|
||||
|
||||
345
ddbridge/ddbridge-ci.c
Normal file
345
ddbridge/ddbridge-ci.c
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* ddbridge-ci.c: Digital Devices bridge and DuoFlex CI driver
|
||||
*
|
||||
* Copyright (C) 2010-2017 Digital Devices GmbH
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-io.h"
|
||||
#include "ddbridge-i2c.h"
|
||||
|
||||
/* Octopus CI internal CI interface */
|
||||
|
||||
static int wait_ci_ready(struct ddb_ci *ci)
|
||||
{
|
||||
u32 count = 10;
|
||||
|
||||
ndelay(500);
|
||||
do {
|
||||
if (ddbreadl(ci->port->dev,
|
||||
CI_CONTROL(ci->nr)) & CI_READY)
|
||||
break;
|
||||
usleep_range(1, 2);
|
||||
if ((--count) == 0)
|
||||
return -1;
|
||||
} while (1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_attribute_mem(struct dvb_ca_en50221 *ca,
|
||||
int slot, int address)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
u32 val, off = (address >> 1) & (CI_BUFFER_SIZE - 1);
|
||||
|
||||
if (address > CI_BUFFER_SIZE)
|
||||
return -1;
|
||||
ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address,
|
||||
CI_DO_READ_ATTRIBUTES(ci->nr));
|
||||
wait_ci_ready(ci);
|
||||
val = 0xff & ddbreadl(ci->port->dev, CI_BUFFER(ci->nr) + off);
|
||||
return val;
|
||||
}
|
||||
|
||||
static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
|
||||
int address, u8 value)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
|
||||
ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,
|
||||
CI_DO_ATTRIBUTE_RW(ci->nr));
|
||||
wait_ci_ready(ci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_cam_control(struct dvb_ca_en50221 *ca,
|
||||
int slot, u8 address)
|
||||
{
|
||||
u32 count = 100;
|
||||
struct ddb_ci *ci = ca->data;
|
||||
u32 res;
|
||||
|
||||
ddbwritel(ci->port->dev, CI_READ_CMD | address,
|
||||
CI_DO_IO_RW(ci->nr));
|
||||
ndelay(500);
|
||||
do {
|
||||
res = ddbreadl(ci->port->dev, CI_READDATA(ci->nr));
|
||||
if (res & CI_READY)
|
||||
break;
|
||||
usleep_range(1, 2);
|
||||
if ((--count) == 0)
|
||||
return -1;
|
||||
} while (1);
|
||||
return 0xff & res;
|
||||
}
|
||||
|
||||
static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,
|
||||
u8 address, u8 value)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
|
||||
ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,
|
||||
CI_DO_IO_RW(ci->nr));
|
||||
wait_ci_ready(ci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
|
||||
ddbwritel(ci->port->dev, CI_POWER_ON,
|
||||
CI_CONTROL(ci->nr));
|
||||
msleep(100);
|
||||
ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM,
|
||||
CI_CONTROL(ci->nr));
|
||||
ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM,
|
||||
CI_CONTROL(ci->nr));
|
||||
usleep_range(20, 25);
|
||||
ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON,
|
||||
CI_CONTROL(ci->nr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
|
||||
ddbwritel(ci->port->dev, 0, CI_CONTROL(ci->nr));
|
||||
msleep(300);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr));
|
||||
|
||||
ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE,
|
||||
CI_CONTROL(ci->nr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr));
|
||||
int stat = 0;
|
||||
|
||||
if (val & CI_CAM_DETECT)
|
||||
stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
|
||||
if (val & CI_CAM_READY)
|
||||
stat |= DVB_CA_EN50221_POLL_CAM_READY;
|
||||
return stat;
|
||||
}
|
||||
|
||||
static struct dvb_ca_en50221 en_templ = {
|
||||
.read_attribute_mem = read_attribute_mem,
|
||||
.write_attribute_mem = write_attribute_mem,
|
||||
.read_cam_control = read_cam_control,
|
||||
.write_cam_control = write_cam_control,
|
||||
.slot_reset = slot_reset,
|
||||
.slot_shutdown = slot_shutdown,
|
||||
.slot_ts_enable = slot_ts_enable,
|
||||
.poll_slot_status = poll_slot_status,
|
||||
};
|
||||
|
||||
static void ci_attach(struct ddb_port *port)
|
||||
{
|
||||
struct ddb_ci *ci;
|
||||
|
||||
ci = kzalloc(sizeof(*ci), GFP_KERNEL);
|
||||
if (!ci)
|
||||
return;
|
||||
memcpy(&ci->en, &en_templ, sizeof(en_templ));
|
||||
ci->en.data = ci;
|
||||
port->en = &ci->en;
|
||||
ci->port = port;
|
||||
ci->nr = port->nr - 2;
|
||||
}
|
||||
|
||||
/* DuoFlex Dual CI support */
|
||||
|
||||
static int write_creg(struct ddb_ci *ci, u8 data, u8 mask)
|
||||
{
|
||||
struct i2c_adapter *i2c = &ci->port->i2c->adap;
|
||||
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
|
||||
|
||||
ci->port->creg = (ci->port->creg & ~mask) | data;
|
||||
return i2c_write_reg(i2c, adr, 0x02, ci->port->creg);
|
||||
}
|
||||
|
||||
static int read_attribute_mem_xo2(struct dvb_ca_en50221 *ca,
|
||||
int slot, int address)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
struct i2c_adapter *i2c = &ci->port->i2c->adap;
|
||||
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
|
||||
int res;
|
||||
u8 val;
|
||||
|
||||
res = i2c_read_reg16(i2c, adr, 0x8000 | address, &val);
|
||||
return res ? res : val;
|
||||
}
|
||||
|
||||
static int write_attribute_mem_xo2(struct dvb_ca_en50221 *ca, int slot,
|
||||
int address, u8 value)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
struct i2c_adapter *i2c = &ci->port->i2c->adap;
|
||||
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
|
||||
|
||||
return i2c_write_reg16(i2c, adr, 0x8000 | address, value);
|
||||
}
|
||||
|
||||
static int read_cam_control_xo2(struct dvb_ca_en50221 *ca,
|
||||
int slot, u8 address)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
struct i2c_adapter *i2c = &ci->port->i2c->adap;
|
||||
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
|
||||
u8 val;
|
||||
int res;
|
||||
|
||||
res = i2c_read_reg(i2c, adr, 0x20 | (address & 3), &val);
|
||||
return res ? res : val;
|
||||
}
|
||||
|
||||
static int write_cam_control_xo2(struct dvb_ca_en50221 *ca, int slot,
|
||||
u8 address, u8 value)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
struct i2c_adapter *i2c = &ci->port->i2c->adap;
|
||||
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
|
||||
|
||||
return i2c_write_reg(i2c, adr, 0x20 | (address & 3), value);
|
||||
}
|
||||
|
||||
static int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
|
||||
write_creg(ci, 0x01, 0x01);
|
||||
write_creg(ci, 0x04, 0x04);
|
||||
msleep(20);
|
||||
write_creg(ci, 0x02, 0x02);
|
||||
write_creg(ci, 0x00, 0x04);
|
||||
write_creg(ci, 0x18, 0x18);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slot_shutdown_xo2(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
|
||||
/*i2c_write_reg(i2c, adr, 0x03, 0x60);*/
|
||||
/*i2c_write_reg(i2c, adr, 0x00, 0xc0);*/
|
||||
write_creg(ci, 0x10, 0xff);
|
||||
write_creg(ci, 0x08, 0x08);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slot_ts_enable_xo2(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
|
||||
write_creg(ci, 0x00, 0x10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int poll_slot_status_xo2(struct dvb_ca_en50221 *ca, int slot, int open)
|
||||
{
|
||||
struct ddb_ci *ci = ca->data;
|
||||
struct i2c_adapter *i2c = &ci->port->i2c->adap;
|
||||
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
|
||||
u8 val = 0;
|
||||
int stat = 0;
|
||||
|
||||
i2c_read_reg(i2c, adr, 0x01, &val);
|
||||
|
||||
if (val & 2)
|
||||
stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
|
||||
if (val & 1)
|
||||
stat |= DVB_CA_EN50221_POLL_CAM_READY;
|
||||
return stat;
|
||||
}
|
||||
|
||||
static struct dvb_ca_en50221 en_xo2_templ = {
|
||||
.read_attribute_mem = read_attribute_mem_xo2,
|
||||
.write_attribute_mem = write_attribute_mem_xo2,
|
||||
.read_cam_control = read_cam_control_xo2,
|
||||
.write_cam_control = write_cam_control_xo2,
|
||||
.slot_reset = slot_reset_xo2,
|
||||
.slot_shutdown = slot_shutdown_xo2,
|
||||
.slot_ts_enable = slot_ts_enable_xo2,
|
||||
.poll_slot_status = poll_slot_status_xo2,
|
||||
};
|
||||
|
||||
static void ci_xo2_attach(struct ddb_port *port)
|
||||
{
|
||||
struct ddb_ci *ci;
|
||||
struct i2c_adapter *i2c;
|
||||
|
||||
ci = kzalloc(sizeof(*ci), GFP_KERNEL);
|
||||
if (!ci)
|
||||
return;
|
||||
memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ));
|
||||
ci->en.data = ci;
|
||||
port->en = &ci->en;
|
||||
ci->port = port;
|
||||
ci->nr = port->nr - 2;
|
||||
ci->port->creg = 0;
|
||||
i2c = &ci->port->i2c->adap;
|
||||
write_creg(ci, 0x10, 0xff);
|
||||
write_creg(ci, 0x08, 0x08);
|
||||
}
|
||||
|
||||
static struct cxd2099_cfg cxd_cfg = {
|
||||
.bitrate = 72000,
|
||||
.adr = 0x40,
|
||||
.polarity = 1,
|
||||
.clock_mode = 1,
|
||||
.max_i2c = 512,
|
||||
};
|
||||
|
||||
int ddb_ci_attach(struct ddb_port *port, u32 bitrate)
|
||||
{
|
||||
switch (port->type) {
|
||||
case DDB_CI_EXTERNAL_SONY:
|
||||
cxd_cfg.bitrate = bitrate;
|
||||
port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap);
|
||||
break;
|
||||
|
||||
case DDB_CI_EXTERNAL_XO2:
|
||||
case DDB_CI_EXTERNAL_XO2_B:
|
||||
ci_xo2_attach(port);
|
||||
break;
|
||||
|
||||
case DDB_CI_INTERNAL:
|
||||
ci_attach(port);
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!port->en)
|
||||
return -ENODEV;
|
||||
dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
757
ddbridge/ddbridge-hw.c
Normal file
757
ddbridge/ddbridge-hw.c
Normal file
@@ -0,0 +1,757 @@
|
||||
/*
|
||||
* ddbridge-hw.c: Digital Devices device information tables
|
||||
*
|
||||
* Copyright (C) 2010-2017 Digital Devices GmbH
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include "ddbridge.h"
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
static const struct ddb_regset octopus_mod_odma = {
|
||||
.base = 0x300,
|
||||
.num = 0x0a,
|
||||
.size = 0x10,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_mod_odma_buf = {
|
||||
.base = 0x2000,
|
||||
.num = 0x0a,
|
||||
.size = 0x100,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_mod_channel = {
|
||||
.base = 0x400,
|
||||
.num = 0x0a,
|
||||
.size = 0x40,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static const struct ddb_regset octopus_mod_2_odma = {
|
||||
.base = 0x400,
|
||||
.num = 0x18,
|
||||
.size = 0x10,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_mod_2_odma_buf = {
|
||||
.base = 0x8000,
|
||||
.num = 0x18,
|
||||
.size = 0x100,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_mod_2_channel = {
|
||||
.base = 0x800,
|
||||
.num = 0x18,
|
||||
.size = 0x40,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_sdr_output = {
|
||||
.base = 0x240,
|
||||
.num = 0x14,
|
||||
.size = 0x10,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static const struct ddb_regset octopus_input = {
|
||||
.base = 0x200,
|
||||
.num = 0x08,
|
||||
.size = 0x10,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_output = {
|
||||
.base = 0x280,
|
||||
.num = 0x08,
|
||||
.size = 0x10,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_idma = {
|
||||
.base = 0x300,
|
||||
.num = 0x08,
|
||||
.size = 0x10,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_idma_buf = {
|
||||
.base = 0x2000,
|
||||
.num = 0x08,
|
||||
.size = 0x100,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_odma = {
|
||||
.base = 0x380,
|
||||
.num = 0x04,
|
||||
.size = 0x10,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_odma_buf = {
|
||||
.base = 0x2800,
|
||||
.num = 0x04,
|
||||
.size = 0x100,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_i2c = {
|
||||
.base = 0x80,
|
||||
.num = 0x04,
|
||||
.size = 0x20,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_i2c_buf = {
|
||||
.base = 0x1000,
|
||||
.num = 0x04,
|
||||
.size = 0x200,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static const struct ddb_regset octopro_input = {
|
||||
.base = 0x400,
|
||||
.num = 0x14,
|
||||
.size = 0x10,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopro_output = {
|
||||
.base = 0x600,
|
||||
.num = 0x0a,
|
||||
.size = 0x10,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopro_idma = {
|
||||
.base = 0x800,
|
||||
.num = 0x40,
|
||||
.size = 0x10,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopro_idma_buf = {
|
||||
.base = 0x4000,
|
||||
.num = 0x40,
|
||||
.size = 0x100,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopro_odma = {
|
||||
.base = 0xc00,
|
||||
.num = 0x20,
|
||||
.size = 0x10,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopro_odma_buf = {
|
||||
.base = 0x8000,
|
||||
.num = 0x20,
|
||||
.size = 0x100,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopro_i2c = {
|
||||
.base = 0x200,
|
||||
.num = 0x0a,
|
||||
.size = 0x20,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopro_i2c_buf = {
|
||||
.base = 0x2000,
|
||||
.num = 0x0a,
|
||||
.size = 0x200,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopro_gtl = {
|
||||
.base = 0xe00,
|
||||
.num = 0x03,
|
||||
.size = 0x40,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
static const struct ddb_regmap octopus_map = {
|
||||
.irq_version = 1,
|
||||
.irq_base_i2c = 0,
|
||||
.irq_base_idma = 8,
|
||||
.irq_base_odma = 16,
|
||||
.i2c = &octopus_i2c,
|
||||
.i2c_buf = &octopus_i2c_buf,
|
||||
.idma = &octopus_idma,
|
||||
.idma_buf = &octopus_idma_buf,
|
||||
.odma = &octopus_odma,
|
||||
.odma_buf = &octopus_odma_buf,
|
||||
.input = &octopus_input,
|
||||
.output = &octopus_output,
|
||||
};
|
||||
|
||||
static const struct ddb_regmap octopro_map = {
|
||||
.irq_version = 2,
|
||||
.irq_base_i2c = 32,
|
||||
.irq_base_idma = 64,
|
||||
.irq_base_odma = 128,
|
||||
.irq_base_gtl = 8,
|
||||
.i2c = &octopro_i2c,
|
||||
.i2c_buf = &octopro_i2c_buf,
|
||||
.idma = &octopro_idma,
|
||||
.idma_buf = &octopro_idma_buf,
|
||||
.odma = &octopro_odma,
|
||||
.odma_buf = &octopro_odma_buf,
|
||||
.input = &octopro_input,
|
||||
.output = &octopro_output,
|
||||
.gtl = &octopro_gtl,
|
||||
};
|
||||
|
||||
static const struct ddb_regmap octopro_hdin_map = {
|
||||
.irq_version = 2,
|
||||
.irq_base_i2c = 32,
|
||||
.irq_base_idma = 64,
|
||||
.irq_base_odma = 128,
|
||||
.i2c = &octopro_i2c,
|
||||
.i2c_buf = &octopro_i2c_buf,
|
||||
.idma = &octopro_idma,
|
||||
.idma_buf = &octopro_idma_buf,
|
||||
.odma = &octopro_odma,
|
||||
.odma_buf = &octopro_odma_buf,
|
||||
.input = &octopro_input,
|
||||
.output = &octopro_output,
|
||||
};
|
||||
|
||||
static const struct ddb_regmap octopus_mod_map = {
|
||||
.irq_version = 1,
|
||||
.irq_base_odma = 8,
|
||||
.irq_base_rate = 18,
|
||||
.output = &octopus_output,
|
||||
.odma = &octopus_mod_odma,
|
||||
.odma_buf = &octopus_mod_odma_buf,
|
||||
.channel = &octopus_mod_channel,
|
||||
};
|
||||
|
||||
static const struct ddb_regmap octopus_mod_2_map = {
|
||||
.irq_version = 2,
|
||||
.irq_base_odma = 64,
|
||||
.irq_base_rate = 32,
|
||||
.output = &octopus_output,
|
||||
.odma = &octopus_mod_2_odma,
|
||||
.odma_buf = &octopus_mod_2_odma_buf,
|
||||
.channel = &octopus_mod_2_channel,
|
||||
};
|
||||
|
||||
static const struct ddb_regmap octopus_sdr_map = {
|
||||
.irq_version = 2,
|
||||
.irq_base_odma = 64,
|
||||
.irq_base_rate = 32,
|
||||
.output = &octopus_sdr_output,
|
||||
.odma = &octopus_mod_2_odma,
|
||||
.odma_buf = &octopus_mod_2_odma_buf,
|
||||
.channel = &octopus_mod_2_channel,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
static const struct ddb_info ddb_none = {
|
||||
.type = DDB_NONE,
|
||||
.name = "unknown Digital Devices device, install newer driver",
|
||||
.regmap = &octopus_map,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_octopus = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_octopusv3 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus V3 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_octopus_le = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus LE DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 2,
|
||||
.i2c_mask = 0x03,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_octopus_oem = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus OEM",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.led_num = 1,
|
||||
.fan_num = 1,
|
||||
.temp_num = 1,
|
||||
.temp_bus = 0,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_octopus_mini = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus Mini",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_v6 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine S2 V6 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x07,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_v6_5 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine S2 V6.5 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_v7a = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine S2 V7 Advanced DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 2,
|
||||
.board_control_2 = 4,
|
||||
.ts_quirks = TS_QUIRK_REVERSED,
|
||||
.hw_min = 0x010007,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_v7 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine S2 V7 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 2,
|
||||
.board_control_2 = 4,
|
||||
.ts_quirks = TS_QUIRK_REVERSED,
|
||||
.hw_min = 0x010007,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_ctv7 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine CT V7 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 3,
|
||||
.board_control_2 = 4,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_satixs2v3 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Mystique SaTiX-S2 V3 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x07,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_ci = {
|
||||
.type = DDB_OCTOPUS_CI,
|
||||
.name = "Digital Devices Octopus CI",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x03,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_cis = {
|
||||
.type = DDB_OCTOPUS_CI,
|
||||
.name = "Digital Devices Octopus CI single",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x03,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_ci_s2_pro = {
|
||||
.type = DDB_OCTOPUS_CI,
|
||||
.name = "Digital Devices Octopus CI S2 Pro",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x01,
|
||||
.board_control = 2,
|
||||
.board_control_2 = 4,
|
||||
.hw_min = 0x010007,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_ci_s2_pro_a = {
|
||||
.type = DDB_OCTOPUS_CI,
|
||||
.name = "Digital Devices Octopus CI S2 Pro Advanced",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x01,
|
||||
.board_control = 2,
|
||||
.board_control_2 = 4,
|
||||
.hw_min = 0x010007,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_dvbct = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices DVBCT V6.1 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x07,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static const struct ddb_info ddb_mod = {
|
||||
.type = DDB_MOD,
|
||||
.name = "Digital Devices DVB-C modulator",
|
||||
.regmap = &octopus_mod_map,
|
||||
.port_num = 10,
|
||||
.temp_num = 1,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_mod_4 = {
|
||||
.type = DDB_MOD,
|
||||
.name = "Digital Devices DVB-C modulator",
|
||||
.regmap = &octopus_mod_map,
|
||||
.port_num = 4,
|
||||
.temp_num = 1,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_mod_fsm_24 = {
|
||||
.type = DDB_MOD,
|
||||
.version = 2,
|
||||
.name = "Digital Devices DVB-C modulator FSM-24",
|
||||
.regmap = &octopus_mod_2_map,
|
||||
.port_num = 24,
|
||||
.temp_num = 1,
|
||||
.tempmon_irq = 8,
|
||||
.lostlock_irq = 9,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_mod_fsm_16 = {
|
||||
.type = DDB_MOD,
|
||||
.version = 2,
|
||||
.name = "Digital Devices DVB-C modulator FSM-16",
|
||||
.regmap = &octopus_mod_2_map,
|
||||
.port_num = 16,
|
||||
.temp_num = 1,
|
||||
.tempmon_irq = 8,
|
||||
.lostlock_irq = 9,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_mod_fsm_8 = {
|
||||
.type = DDB_MOD,
|
||||
.name = "Digital Devices DVB-C modulator FSM-8",
|
||||
.version = 2,
|
||||
.regmap = &octopus_mod_2_map,
|
||||
.port_num = 8,
|
||||
.temp_num = 1,
|
||||
.tempmon_irq = 8,
|
||||
.lostlock_irq = 9,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_mod_fsm_4 = {
|
||||
.type = DDB_MOD,
|
||||
.name = "Digital Devices DVB-C modulator FSM-8",
|
||||
.version = 2,
|
||||
.regmap = &octopus_mod_2_map,
|
||||
.port_num = 4,
|
||||
.temp_num = 1,
|
||||
.tempmon_irq = 8,
|
||||
.lostlock_irq = 9,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_sdr = {
|
||||
.type = DDB_MOD,
|
||||
.name = "Digital Devices SDR",
|
||||
.version = 3,
|
||||
.regmap = &octopus_sdr_map,
|
||||
.port_num = 16,
|
||||
.temp_num = 1,
|
||||
.tempmon_irq = 8,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_octopro_hdin = {
|
||||
.type = DDB_OCTOPRO_HDIN,
|
||||
.name = "Digital Devices OctopusNet Pro HDIN",
|
||||
.regmap = &octopro_hdin_map,
|
||||
.port_num = 10,
|
||||
.i2c_mask = 0x3ff,
|
||||
.mdio_base = 0x10020,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_octopro = {
|
||||
.type = DDB_OCTOPRO,
|
||||
.name = "Digital Devices OctopusNet Pro",
|
||||
.regmap = &octopro_map,
|
||||
.port_num = 10,
|
||||
.i2c_mask = 0x3ff,
|
||||
.mdio_base = 0x10020,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_s2_48 = {
|
||||
.type = DDB_OCTOPUS_MAX,
|
||||
.name = "Digital Devices MAX S8 4/8",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x01,
|
||||
.board_control = 1,
|
||||
.tempmon_irq = 24,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_ct2_8 = {
|
||||
.type = DDB_OCTOPUS_MAX_CT,
|
||||
.name = "Digital Devices MAX A8 CT2",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 0x0ff,
|
||||
.board_control_2 = 0xf00,
|
||||
.ts_quirks = TS_QUIRK_SERIAL,
|
||||
.tempmon_irq = 24,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_c2t2_8 = {
|
||||
.type = DDB_OCTOPUS_MAX_CT,
|
||||
.name = "Digital Devices MAX A8 C2T2",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 0x0ff,
|
||||
.board_control_2 = 0xf00,
|
||||
.ts_quirks = TS_QUIRK_SERIAL,
|
||||
.tempmon_irq = 24,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_isdbt_8 = {
|
||||
.type = DDB_OCTOPUS_MAX_CT,
|
||||
.name = "Digital Devices MAX A8 ISDBT",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 0x0ff,
|
||||
.board_control_2 = 0xf00,
|
||||
.ts_quirks = TS_QUIRK_SERIAL,
|
||||
.tempmon_irq = 24,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_c2t2i_v0_8 = {
|
||||
.type = DDB_OCTOPUS_MAX_CT,
|
||||
.name = "Digital Devices MAX A8 C2T2I V0",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 0x0ff,
|
||||
.board_control_2 = 0xf00,
|
||||
.ts_quirks = TS_QUIRK_SERIAL | TS_QUIRK_ALT_OSC,
|
||||
.tempmon_irq = 24,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_c2t2i_8 = {
|
||||
.type = DDB_OCTOPUS_MAX_CT,
|
||||
.name = "Digital Devices MAX A8 C2T2I",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 0x0ff,
|
||||
.board_control_2 = 0xf00,
|
||||
.ts_quirks = TS_QUIRK_SERIAL,
|
||||
.tempmon_irq = 24,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_s2x_48 = {
|
||||
.type = DDB_OCTOPUS_MCI,
|
||||
.name = "Digital Devices MAX SX8",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x00,
|
||||
.tempmon_irq = 24,
|
||||
.mci_ports = 4,
|
||||
.mci_type = 0,
|
||||
.temp_num = 1,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_m4 = {
|
||||
.type = DDB_OCTOPUS_MCI,
|
||||
.name = "Digital Devices MAX M4",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 2,
|
||||
.i2c_mask = 0x00,
|
||||
.tempmon_irq = 24,
|
||||
.mci_ports = 2,
|
||||
.mci_type = 1,
|
||||
.temp_num = 1,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
static const struct ddb_regmap octopus_net_map = {
|
||||
.irq_version = 1,
|
||||
.irq_base_i2c = 0,
|
||||
.i2c = &octopus_i2c,
|
||||
.i2c_buf = &octopus_i2c_buf,
|
||||
.input = &octopus_input,
|
||||
.output = &octopus_output,
|
||||
};
|
||||
|
||||
static const struct ddb_regset octopus_gtl = {
|
||||
.base = 0x180,
|
||||
.num = 0x01,
|
||||
.size = 0x20,
|
||||
};
|
||||
|
||||
static const struct ddb_regmap octopus_net_gtl = {
|
||||
.irq_version = 1,
|
||||
.irq_base_i2c = 0,
|
||||
.irq_base_gtl = 10,
|
||||
.i2c = &octopus_i2c,
|
||||
.i2c_buf = &octopus_i2c_buf,
|
||||
.input = &octopus_input,
|
||||
.output = &octopus_output,
|
||||
.gtl = &octopus_gtl,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_octonet = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet network DVB adapter",
|
||||
.regmap = &octopus_net_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.ns_num = 12,
|
||||
.mdio_base = 0x20,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_octonet_jse = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet network DVB adapter JSE",
|
||||
.regmap = &octopus_net_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.ns_num = 15,
|
||||
.mdio_base = 0x20,
|
||||
};
|
||||
|
||||
static const struct ddb_info ddb_octonet_gtl = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet GTL",
|
||||
.regmap = &octopus_net_gtl,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x05,
|
||||
.ns_num = 12,
|
||||
.mdio_base = 0x20,
|
||||
.con_clock = 1,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
struct ddb_device_id {
|
||||
u16 vendor;
|
||||
u16 device;
|
||||
u16 subvendor;
|
||||
u16 subdevice;
|
||||
const struct ddb_info *info;
|
||||
};
|
||||
|
||||
#define DDB_DEVID(_device, _subdevice, _info) { \
|
||||
.vendor = 0xdd01, \
|
||||
.device = _device, \
|
||||
.subvendor = 0xdd01, \
|
||||
.subdevice = _subdevice, \
|
||||
.info = &(_info) }
|
||||
|
||||
static const struct ddb_device_id ddb_device_ids[] = {
|
||||
/* OctopusNet */
|
||||
DDB_DEVID(0x0300, 0xffff, ddb_octonet),
|
||||
DDB_DEVID(0x0301, 0xffff, ddb_octonet_jse),
|
||||
DDB_DEVID(0x0307, 0xffff, ddb_octonet_gtl),
|
||||
|
||||
/* PCIe devices */
|
||||
|
||||
/* DVB tuners and demodulators */
|
||||
DDB_DEVID(0x0002, 0x0001, ddb_octopus),
|
||||
DDB_DEVID(0x0003, 0x0001, ddb_octopus),
|
||||
DDB_DEVID(0x0005, 0x0004, ddb_octopusv3),
|
||||
DDB_DEVID(0x0003, 0x0002, ddb_octopus_le),
|
||||
DDB_DEVID(0x0003, 0x0003, ddb_octopus_oem),
|
||||
DDB_DEVID(0x0003, 0x0010, ddb_octopus_mini),
|
||||
DDB_DEVID(0x0005, 0x0011, ddb_octopus_mini),
|
||||
DDB_DEVID(0x0003, 0x0020, ddb_v6),
|
||||
DDB_DEVID(0x0003, 0x0021, ddb_v6_5),
|
||||
DDB_DEVID(0x0006, 0x0022, ddb_v7),
|
||||
DDB_DEVID(0x0006, 0x0024, ddb_v7a),
|
||||
DDB_DEVID(0x0003, 0x0030, ddb_dvbct),
|
||||
DDB_DEVID(0x0003, 0xdb03, ddb_satixs2v3),
|
||||
DDB_DEVID(0x0006, 0x0031, ddb_ctv7),
|
||||
DDB_DEVID(0x0006, 0x0032, ddb_ctv7),
|
||||
DDB_DEVID(0x0006, 0x0033, ddb_ctv7),
|
||||
DDB_DEVID(0x0007, 0x0023, ddb_s2_48),
|
||||
DDB_DEVID(0x0008, 0x0034, ddb_ct2_8),
|
||||
DDB_DEVID(0x0008, 0x0035, ddb_c2t2_8),
|
||||
DDB_DEVID(0x0008, 0x0036, ddb_isdbt_8),
|
||||
DDB_DEVID(0x0008, 0x0037, ddb_c2t2i_v0_8),
|
||||
DDB_DEVID(0x0008, 0x0038, ddb_c2t2i_8),
|
||||
DDB_DEVID(0x0009, 0x0025, ddb_s2x_48),
|
||||
DDB_DEVID(0x0006, 0x0039, ddb_ctv7),
|
||||
DDB_DEVID(0x000a, 0x0050, ddb_m4),
|
||||
DDB_DEVID(0x0011, 0x0040, ddb_ci),
|
||||
DDB_DEVID(0x0011, 0x0041, ddb_cis),
|
||||
DDB_DEVID(0x0012, 0x0042, ddb_ci),
|
||||
DDB_DEVID(0x0013, 0x0043, ddb_ci_s2_pro),
|
||||
DDB_DEVID(0x0013, 0x0044, ddb_ci_s2_pro_a),
|
||||
|
||||
/* Modulators */
|
||||
DDB_DEVID(0x0201, 0x0001, ddb_mod),
|
||||
DDB_DEVID(0x0201, 0x0002, ddb_mod),
|
||||
DDB_DEVID(0x0201, 0x0004, ddb_mod_4), /* dummy entry ! */
|
||||
DDB_DEVID(0x0203, 0x0001, ddb_mod),
|
||||
DDB_DEVID(0x0210, 0x0000, ddb_mod_fsm_4), /* dummy entry ! */
|
||||
DDB_DEVID(0x0210, 0x0001, ddb_mod_fsm_24),
|
||||
DDB_DEVID(0x0210, 0x0002, ddb_mod_fsm_16),
|
||||
DDB_DEVID(0x0210, 0x0003, ddb_mod_fsm_8),
|
||||
DDB_DEVID(0x0220, 0x0001, ddb_sdr),
|
||||
|
||||
/* testing on OctopusNet Pro */
|
||||
DDB_DEVID(0x0320, 0xffff, ddb_octopro_hdin),
|
||||
DDB_DEVID(0x0321, 0xffff, ddb_none),
|
||||
DDB_DEVID(0x0322, 0xffff, ddb_octopro),
|
||||
DDB_DEVID(0x0323, 0xffff, ddb_none),
|
||||
DDB_DEVID(0x0328, 0xffff, ddb_none),
|
||||
DDB_DEVID(0x0329, 0xffff, ddb_octopro_hdin),
|
||||
};
|
||||
|
||||
const struct ddb_info *get_ddb_info(u16 vendor, u16 device,
|
||||
u16 subvendor, u16 subdevice)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ddb_device_ids); i++) {
|
||||
const struct ddb_device_id *id = &ddb_device_ids[i];
|
||||
|
||||
if (vendor == id->vendor &&
|
||||
device == id->device &&
|
||||
subvendor == id->subvendor &&
|
||||
(subdevice == id->subdevice ||
|
||||
id->subdevice == 0xffff))
|
||||
return id->info;
|
||||
}
|
||||
return &ddb_none;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ddbridge-i2c.c: Digital Devices bridge i2c driver
|
||||
*
|
||||
* Copyright (C) 2010-2015 Digital Devices GmbH
|
||||
* Copyright (C) 2010-2017 Digital Devices GmbH
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
*
|
||||
@@ -17,93 +17,12 @@
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
static int i2c_io(struct i2c_adapter *adapter, u8 adr,
|
||||
u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
|
||||
{
|
||||
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
|
||||
.buf = wbuf, .len = wlen },
|
||||
{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = rbuf, .len = rlen } };
|
||||
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
|
||||
{
|
||||
struct i2c_msg msg = {.addr = adr, .flags = 0,
|
||||
.buf = data, .len = len};
|
||||
|
||||
return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
|
||||
{
|
||||
struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = val, .len = 1 } };
|
||||
return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int i2c_read_regs(struct i2c_adapter *adapter,
|
||||
u8 adr, u8 reg, u8 *val, u8 len)
|
||||
{
|
||||
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
|
||||
.buf = ®, .len = 1 },
|
||||
{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = val, .len = len } };
|
||||
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int i2c_read_regs16(struct i2c_adapter *adapter,
|
||||
u8 adr, u16 reg, u8 *val, u8 len)
|
||||
{
|
||||
u8 reg16[2] = { reg >> 8, reg };
|
||||
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
|
||||
.buf = reg16, .len = 2 },
|
||||
{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = val, .len = len } };
|
||||
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val)
|
||||
{
|
||||
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
|
||||
.buf = ®, .len = 1},
|
||||
{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = val, .len = 1 } };
|
||||
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
|
||||
u16 reg, u8 *val)
|
||||
{
|
||||
u8 msg[2] = {reg >> 8, reg & 0xff};
|
||||
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
|
||||
.buf = msg, .len = 2},
|
||||
{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = val, .len = 1 } };
|
||||
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int i2c_write_reg16(struct i2c_adapter *adap, u8 adr,
|
||||
u16 reg, u8 val)
|
||||
{
|
||||
u8 msg[3] = {reg >> 8, reg & 0xff, val};
|
||||
|
||||
return i2c_write(adap, adr, msg, 3);
|
||||
}
|
||||
|
||||
static int i2c_write_reg(struct i2c_adapter *adap, u8 adr,
|
||||
u8 reg, u8 val)
|
||||
{
|
||||
u8 msg[2] = {reg, val};
|
||||
|
||||
return i2c_write(adap, adr, msg, 2);
|
||||
}
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-io.h"
|
||||
|
||||
static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
|
||||
{
|
||||
@@ -115,8 +34,8 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
|
||||
stat = wait_for_completion_timeout(&i2c->completion, HZ);
|
||||
val = ddbreadl(dev, i2c->regs + I2C_COMMAND);
|
||||
if (stat == 0) {
|
||||
pr_err("DDBridge I2C timeout, card %d, port %d, link %u\n",
|
||||
dev->nr, i2c->nr, i2c->link);
|
||||
dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n",
|
||||
dev->nr, i2c->nr, i2c->link);
|
||||
#if 1
|
||||
{
|
||||
u32 istat = ddbreadl(dev, INTERRUPT_STATUS);
|
||||
@@ -144,7 +63,10 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
|
||||
#endif
|
||||
return -EIO;
|
||||
}
|
||||
if (val & 0x70000)
|
||||
val &= 0x70000;
|
||||
if (val == 0x20000)
|
||||
dev_err(dev->dev, "I2C bus errorx\n");
|
||||
if (val)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
@@ -152,42 +74,47 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
|
||||
static int ddb_i2c_master_xfer(struct i2c_adapter *adapter,
|
||||
struct i2c_msg msg[], int num)
|
||||
{
|
||||
struct ddb_i2c *i2c = (struct ddb_i2c *) i2c_get_adapdata(adapter);
|
||||
struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter);
|
||||
struct ddb *dev = i2c->dev;
|
||||
u8 addr = 0;
|
||||
|
||||
if (num != 1 && num != 2)
|
||||
return -EIO;
|
||||
addr = msg[0].addr;
|
||||
if (msg[0].len > i2c->bsize)
|
||||
return -EIO;
|
||||
if (num == 2 && msg[1].flags & I2C_M_RD &&
|
||||
!(msg[0].flags & I2C_M_RD)) {
|
||||
if (msg[1].len > i2c->bsize)
|
||||
return -EIO;
|
||||
ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len);
|
||||
ddbwritel(dev, msg[0].len | (msg[1].len << 16),
|
||||
i2c->regs + I2C_TASKLENGTH);
|
||||
if (!ddb_i2c_cmd(i2c, addr, 1)) {
|
||||
ddbcpyfrom(dev, msg[1].buf,
|
||||
i2c->rbuf,
|
||||
msg[1].len);
|
||||
return num;
|
||||
}
|
||||
}
|
||||
if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
|
||||
ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len);
|
||||
ddbwritel(dev, msg[0].len, i2c->regs + I2C_TASKLENGTH);
|
||||
if (!ddb_i2c_cmd(i2c, addr, 2))
|
||||
return num;
|
||||
}
|
||||
if (num == 1 && (msg[0].flags & I2C_M_RD)) {
|
||||
ddbwritel(dev, msg[0].len << 16, i2c->regs + I2C_TASKLENGTH);
|
||||
if (!ddb_i2c_cmd(i2c, addr, 3)) {
|
||||
switch (num) {
|
||||
case 1:
|
||||
if (msg[0].flags & I2C_M_RD) {
|
||||
ddbwritel(dev, msg[0].len << 16,
|
||||
i2c->regs + I2C_TASKLENGTH);
|
||||
if (ddb_i2c_cmd(i2c, addr, 3))
|
||||
break;
|
||||
ddbcpyfrom(dev, msg[0].buf,
|
||||
i2c->rbuf, msg[0].len);
|
||||
return num;
|
||||
}
|
||||
ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len);
|
||||
ddbwritel(dev, msg[0].len, i2c->regs + I2C_TASKLENGTH);
|
||||
if (ddb_i2c_cmd(i2c, addr, 2))
|
||||
break;
|
||||
return num;
|
||||
case 2:
|
||||
if ((msg[0].flags & I2C_M_RD) == I2C_M_RD)
|
||||
break;
|
||||
if ((msg[1].flags & I2C_M_RD) != I2C_M_RD)
|
||||
break;
|
||||
if (msg[1].len > i2c->bsize)
|
||||
break;
|
||||
ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len);
|
||||
ddbwritel(dev, msg[0].len | (msg[1].len << 16),
|
||||
i2c->regs + I2C_TASKLENGTH);
|
||||
if (ddb_i2c_cmd(i2c, addr, 1))
|
||||
break;
|
||||
ddbcpyfrom(dev, msg[1].buf,
|
||||
i2c->rbuf,
|
||||
msg[1].len);
|
||||
return num;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
@@ -202,7 +129,7 @@ struct i2c_algorithm ddb_i2c_algo = {
|
||||
.functionality = ddb_i2c_functionality,
|
||||
};
|
||||
|
||||
static void ddb_i2c_release(struct ddb *dev)
|
||||
void ddb_i2c_release(struct ddb *dev)
|
||||
{
|
||||
int i;
|
||||
struct ddb_i2c *i2c;
|
||||
@@ -213,15 +140,16 @@ static void ddb_i2c_release(struct ddb *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void i2c_handler(unsigned long priv)
|
||||
static void i2c_handler(void *priv)
|
||||
{
|
||||
struct ddb_i2c *i2c = (struct ddb_i2c *) priv;
|
||||
struct ddb_i2c *i2c = (struct ddb_i2c *)priv;
|
||||
|
||||
complete(&i2c->completion);
|
||||
}
|
||||
|
||||
static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c,
|
||||
struct ddb_regmap *regmap, int link, int i, int num)
|
||||
const struct ddb_regmap *regmap,
|
||||
int link, int i, int num)
|
||||
{
|
||||
struct i2c_adapter *adap;
|
||||
|
||||
@@ -241,13 +169,12 @@ static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c,
|
||||
adap = &i2c->adap;
|
||||
i2c_set_adapdata(adap, i2c);
|
||||
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
|
||||
adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG;
|
||||
adap->class = I2C_ADAP_CLASS_TV_DIGITAL | I2C_CLASS_TV_ANALOG;
|
||||
#else
|
||||
#ifdef I2C_CLASS_TV_ANALOG
|
||||
adap->class = I2C_CLASS_TV_ANALOG;
|
||||
#endif
|
||||
#endif
|
||||
/*strcpy(adap->name, "ddbridge");*/
|
||||
snprintf(adap->name, I2C_NAME_SIZE, "ddbridge_%02x.%x.%x",
|
||||
dev->nr, i2c->link, i);
|
||||
adap->algo = &ddb_i2c_algo;
|
||||
@@ -256,13 +183,13 @@ static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c,
|
||||
return i2c_add_adapter(adap);
|
||||
}
|
||||
|
||||
static int ddb_i2c_init(struct ddb *dev)
|
||||
int ddb_i2c_init(struct ddb *dev)
|
||||
{
|
||||
int stat = 0;
|
||||
u32 i, j, num = 0, l, base;
|
||||
struct ddb_i2c *i2c;
|
||||
struct i2c_adapter *adap;
|
||||
struct ddb_regmap *regmap;
|
||||
const struct ddb_regmap *regmap;
|
||||
|
||||
for (l = 0; l < DDB_MAX_LINK; l++) {
|
||||
if (!dev->link[l].info)
|
||||
@@ -275,8 +202,7 @@ static int ddb_i2c_init(struct ddb *dev)
|
||||
if (!(dev->link[l].info->i2c_mask & (1 << i)))
|
||||
continue;
|
||||
i2c = &dev->i2c[num];
|
||||
dev->handler_data[l][i + base] = (unsigned long) i2c;
|
||||
dev->handler[l][i + base] = i2c_handler;
|
||||
ddb_irq_set(dev, l, i + base, i2c_handler, i2c);
|
||||
stat = ddb_i2c_add(dev, i2c, regmap, l, i, num);
|
||||
if (stat)
|
||||
break;
|
||||
@@ -289,8 +215,9 @@ static int ddb_i2c_init(struct ddb *dev)
|
||||
adap = &i2c->adap;
|
||||
i2c_del_adapter(adap);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
dev->i2c_num = num;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ddbridge-i2c.h: Digital Devices bridge i2c driver
|
||||
*
|
||||
* Copyright (C) 2010-2015 Digital Devices GmbH
|
||||
* Copyright (C) 2010-2017 Digital Devices GmbH
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
*
|
||||
@@ -17,10 +17,8 @@
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#ifndef _DDBRIDGE_I2C_H_
|
||||
|
||||
178
ddbridge/ddbridge-io.c
Normal file
178
ddbridge/ddbridge-io.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* ddbridge-io.c: Digital Devices bridge I/O functions
|
||||
*
|
||||
* Copyright (C) 2010-2017 Digital Devices GmbH
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-io.h"
|
||||
|
||||
u32 ddblreadl(struct ddb_link *link, u32 adr)
|
||||
{
|
||||
if (unlikely(link->nr)) {
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddblwritel0(link, adr & 0xfffc, link->regs + 0x14);
|
||||
ddblwritel0(link, 3, link->regs + 0x10);
|
||||
gtlw(link);
|
||||
val = ddblreadl0(link, link->regs + 0x1c);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return val;
|
||||
}
|
||||
return readl(link->dev->regs + adr);
|
||||
}
|
||||
|
||||
void ddblwritel(struct ddb_link *link, u32 val, u32 adr)
|
||||
{
|
||||
if (unlikely(link->nr)) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
|
||||
ddblwritel0(link, val, link->regs + 0x18);
|
||||
ddblwritel0(link, 1, link->regs + 0x10);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return;
|
||||
}
|
||||
writel(val, link->dev->regs + adr);
|
||||
}
|
||||
|
||||
u32 ddbreadl(struct ddb *dev, u32 adr)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000)) {
|
||||
unsigned long flags;
|
||||
u32 val, l = (adr >> DDB_LINK_SHIFT) & 3;
|
||||
struct ddb_link *link = &dev->link[l];
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddblwritel0(link, adr & 0xfffc, link->regs + 0x14);
|
||||
ddblwritel0(link, 3, link->regs + 0x10);
|
||||
gtlw(link);
|
||||
val = ddblreadl0(link, link->regs + 0x1c);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return val;
|
||||
}
|
||||
return readl(dev->regs + adr);
|
||||
}
|
||||
|
||||
void ddbwritel(struct ddb *dev, u32 val, u32 adr)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000)) {
|
||||
unsigned long flags;
|
||||
u32 l = (adr >> DDB_LINK_SHIFT);
|
||||
struct ddb_link *link = &dev->link[l];
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
|
||||
ddblwritel0(link, val, link->regs + 0x18);
|
||||
ddblwritel0(link, 1, link->regs + 0x10);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return;
|
||||
}
|
||||
writel(val, dev->regs + adr);
|
||||
}
|
||||
|
||||
void gtlcpyto(struct ddb *dev, u32 adr, const u8 *buf,
|
||||
unsigned int count)
|
||||
{
|
||||
u32 val = 0, p = adr;
|
||||
u32 aa = p & 3;
|
||||
|
||||
if (aa) {
|
||||
while (p & 3 && count) {
|
||||
val >>= 8;
|
||||
val |= *buf << 24;
|
||||
p++;
|
||||
buf++;
|
||||
count--;
|
||||
}
|
||||
ddbwritel(dev, val, adr);
|
||||
}
|
||||
while (count >= 4) {
|
||||
val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
ddbwritel(dev, val, p);
|
||||
p += 4;
|
||||
buf += 4;
|
||||
count -= 4;
|
||||
}
|
||||
if (count) {
|
||||
val = buf[0];
|
||||
if (count > 1)
|
||||
val |= buf[1] << 8;
|
||||
if (count > 2)
|
||||
val |= buf[2] << 16;
|
||||
ddbwritel(dev, val, p);
|
||||
}
|
||||
}
|
||||
|
||||
void gtlcpyfrom(struct ddb *dev, u8 *buf, u32 adr, long count)
|
||||
{
|
||||
u32 val = 0, p = adr;
|
||||
u32 a = p & 3;
|
||||
|
||||
if (a) {
|
||||
val = ddbreadl(dev, p) >> (8 * a);
|
||||
while (p & 3 && count) {
|
||||
*buf = val & 0xff;
|
||||
val >>= 8;
|
||||
p++;
|
||||
buf++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
while (count >= 4) {
|
||||
val = ddbreadl(dev, p);
|
||||
buf[0] = val & 0xff;
|
||||
buf[1] = (val >> 8) & 0xff;
|
||||
buf[2] = (val >> 16) & 0xff;
|
||||
buf[3] = (val >> 24) & 0xff;
|
||||
p += 4;
|
||||
buf += 4;
|
||||
count -= 4;
|
||||
}
|
||||
if (count) {
|
||||
val = ddbreadl(dev, p);
|
||||
buf[0] = val & 0xff;
|
||||
if (count > 1)
|
||||
buf[1] = (val >> 8) & 0xff;
|
||||
if (count > 2)
|
||||
buf[2] = (val >> 16) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000))
|
||||
return gtlcpyto(dev, adr, src, count);
|
||||
return memcpy_toio(dev->regs + adr, src, count);
|
||||
}
|
||||
|
||||
void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000))
|
||||
return gtlcpyfrom(dev, dst, adr, count);
|
||||
return memcpy_fromio(dst, dev->regs + adr, count);
|
||||
}
|
||||
97
ddbridge/ddbridge-io.h
Normal file
97
ddbridge/ddbridge-io.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* ddbridge-io.h: Digital Devices bridge I/O functions
|
||||
*
|
||||
* Copyright (C) 2010-2017 Digital Devices GmbH
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#ifndef _DDBRIDGE_IO_H_
|
||||
#define _DDBRIDGE_IO_H_
|
||||
|
||||
u32 ddblreadl(struct ddb_link *link, u32 adr);
|
||||
void ddblwritel(struct ddb_link *link, u32 val, u32 adr);
|
||||
u32 ddbreadl(struct ddb *dev, u32 adr);
|
||||
void ddbwritel(struct ddb *dev, u32 val, u32 adr);
|
||||
void gtlcpyto(struct ddb *dev, u32 adr, const u8 *buf,
|
||||
unsigned int count);
|
||||
void gtlcpyfrom(struct ddb *dev, u8 *buf, u32 adr, long count);
|
||||
void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count);
|
||||
void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count);
|
||||
|
||||
static inline void ddbwriteb0(struct ddb *dev, u32 val, u32 adr)
|
||||
{
|
||||
writeb(val, dev->regs + adr);
|
||||
}
|
||||
|
||||
static inline u32 ddbreadb0(struct ddb *dev, u32 adr)
|
||||
{
|
||||
return readb(dev->regs + adr);
|
||||
}
|
||||
|
||||
static inline void ddbwritel0(struct ddb *dev, u32 val, u32 adr)
|
||||
{
|
||||
writel(val, dev->regs + adr);
|
||||
}
|
||||
|
||||
static inline u32 ddbreadl0(struct ddb *dev, u32 adr)
|
||||
{
|
||||
return readl(dev->regs + adr);
|
||||
}
|
||||
|
||||
static inline void ddblwritel0(struct ddb_link *link, u32 val, u32 adr)
|
||||
{
|
||||
writel(val, link->dev->regs + adr);
|
||||
}
|
||||
|
||||
static inline u32 ddblreadl0(struct ddb_link *link, u32 adr)
|
||||
{
|
||||
return readl(link->dev->regs + adr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline void gtlw(struct ddb_link *link)
|
||||
{
|
||||
u32 count = 0;
|
||||
static u32 max;
|
||||
|
||||
while (1 & ddblreadl0(link, link->regs + 0x10)) {
|
||||
if (++count == 1024) {
|
||||
pr_info("LTO\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count > max) {
|
||||
max = count;
|
||||
pr_info("TO=%u\n", max);
|
||||
}
|
||||
if (ddblreadl0(link, link->regs + 0x10) & 0x8000)
|
||||
pr_err("link error\n");
|
||||
}
|
||||
#else
|
||||
static inline void gtlw(struct ddb_link *link)
|
||||
{
|
||||
while (1 & ddblreadl0(link, link->regs + 0x10))
|
||||
;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ddbmemset(_dev, _adr, _val, _count) \
|
||||
memset_io(((_dev)->regs + (_adr)), (_val), (_count))
|
||||
|
||||
#endif
|
||||
449
ddbridge/ddbridge-m4.c
Normal file
449
ddbridge/ddbridge-m4.c
Normal file
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* ddbridge-m4.c: Digital Devices MAX M4 driver
|
||||
*
|
||||
* Copyright (C) 2018 Digital Devices GmbH
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-io.h"
|
||||
#include "ddbridge-i2c.h"
|
||||
#include "ddbridge-mci.h"
|
||||
|
||||
struct m4_base {
|
||||
struct mci_base mci_base;
|
||||
|
||||
};
|
||||
|
||||
struct m4 {
|
||||
struct mci mci;
|
||||
|
||||
int started;
|
||||
int t2_signalling_valid;
|
||||
int iq_constellation_point;
|
||||
int iq_constellation_point_max;
|
||||
int iq_constellation_tap;
|
||||
int first_time_lock;
|
||||
};
|
||||
|
||||
static int stop(struct dvb_frontend *fe)
|
||||
{
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
struct mci_command cmd;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
|
||||
if (!state->started)
|
||||
return -1;
|
||||
state->started = 0;
|
||||
state->t2_signalling_valid = 0;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.command = MCI_CMD_STOP;
|
||||
cmd.demod = state->mci.demod;
|
||||
ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int search_s2(struct dvb_frontend *fe)
|
||||
{
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
struct m4_base *m4_base = (struct m4_base *) mci_base;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
struct mci_command cmd;
|
||||
int stat;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.command = MCI_CMD_SEARCH_DVBS;
|
||||
cmd.dvbs2_search.flags = 3;
|
||||
cmd.dvbs2_search.s2_modulation_mask = 3;
|
||||
cmd.dvbs2_search.retry = 2;
|
||||
cmd.dvbs2_search.frequency = p->frequency * 1000;
|
||||
cmd.dvbs2_search.symbol_rate = p->symbol_rate;
|
||||
cmd.dvbs2_search.scrambling_sequence_index = 0; //p->scrambling_sequence_index;
|
||||
cmd.dvbs2_search.input_stream_id = p->stream_id;
|
||||
cmd.tuner = state->mci.nr;
|
||||
cmd.demod = state->mci.tuner;
|
||||
cmd.output = state->mci.nr;
|
||||
|
||||
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
if (stat)
|
||||
stop(fe);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int search_c(struct dvb_frontend *fe)
|
||||
{
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
struct m4_base *m4_base = (struct m4_base *) mci_base;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
struct mci_command cmd;
|
||||
int stat;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.command = MCI_CMD_SEARCH_DVBC;
|
||||
switch (p->bandwidth_hz) {
|
||||
case 6000000:
|
||||
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_6MHZ;
|
||||
break;
|
||||
case 7000000:
|
||||
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_7MHZ;
|
||||
break;
|
||||
default:
|
||||
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_8MHZ;
|
||||
break;
|
||||
}
|
||||
cmd.dvbc_search.retry = 2;
|
||||
cmd.dvbc_search.frequency = p->frequency;
|
||||
cmd.tuner = state->mci.tuner;
|
||||
cmd.demod = state->mci.demod;
|
||||
cmd.output = state->mci.nr;
|
||||
|
||||
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
if (stat)
|
||||
stop(fe);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int search_t(struct dvb_frontend *fe)
|
||||
{
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
struct m4_base *m4_base = (struct m4_base *) mci_base;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
struct mci_command cmd;
|
||||
int stat;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.command = MCI_CMD_SEARCH_DVBT;
|
||||
switch (p->bandwidth_hz) {
|
||||
case 5000000:
|
||||
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_5MHZ;
|
||||
break;
|
||||
case 6000000:
|
||||
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_6MHZ;
|
||||
break;
|
||||
case 7000000:
|
||||
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_7MHZ;
|
||||
break;
|
||||
default:
|
||||
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_8MHZ;
|
||||
break;
|
||||
}
|
||||
cmd.dvbt_search.retry = 2;
|
||||
cmd.dvbt_search.frequency = p->frequency;
|
||||
cmd.tuner = state->mci.tuner;
|
||||
cmd.demod = state->mci.demod;
|
||||
cmd.output = state->mci.nr;
|
||||
|
||||
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
if (stat)
|
||||
stop(fe);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int search_t2(struct dvb_frontend *fe)
|
||||
{
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
struct m4_base *m4_base = (struct m4_base *) mci_base;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
struct mci_command cmd;
|
||||
int stat;
|
||||
u32 flags = 0;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.command = MCI_CMD_SEARCH_DVBT2;
|
||||
switch (p->bandwidth_hz) {
|
||||
case 1700000:
|
||||
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_1_7MHZ;
|
||||
break;
|
||||
case 5000000:
|
||||
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_5MHZ;
|
||||
break;
|
||||
case 6000000:
|
||||
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_6MHZ;
|
||||
break;
|
||||
case 7000000:
|
||||
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_7MHZ;
|
||||
break;
|
||||
default:
|
||||
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_8MHZ;
|
||||
break;
|
||||
}
|
||||
cmd.dvbt2_search.retry = 2;
|
||||
cmd.dvbt2_search.frequency = p->frequency;
|
||||
if (p->stream_id != NO_STREAM_ID_FILTER) {
|
||||
cmd.dvbt2_search.plp = p->stream_id & 0xff;
|
||||
cmd.dvbt2_search.flags |= 0x80;
|
||||
cmd.dvbt2_search.flags |= (p->stream_id >> 8) & 1;
|
||||
}
|
||||
cmd.tuner = state->mci.tuner;
|
||||
cmd.demod = state->mci.demod;
|
||||
cmd.output = state->mci.nr;
|
||||
|
||||
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
if (stat)
|
||||
stop(fe);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int search_c2(struct dvb_frontend *fe)
|
||||
{
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
struct m4_base *m4_base = (struct m4_base *) mci_base;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
struct mci_command cmd;
|
||||
int stat;
|
||||
u32 flags = 0;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.command = MCI_CMD_SEARCH_DVBC2;
|
||||
switch (p->bandwidth_hz) {
|
||||
case 6000000:
|
||||
cmd.dvbc2_search.bandwidth = MCI_BANDWIDTH_6MHZ;
|
||||
break;
|
||||
default:
|
||||
cmd.dvbc2_search.bandwidth = MCI_BANDWIDTH_8MHZ;
|
||||
break;
|
||||
}
|
||||
cmd.dvbc2_search.retry = 2;
|
||||
cmd.dvbc2_search.frequency = p->frequency;
|
||||
if (p->stream_id != NO_STREAM_ID_FILTER) {
|
||||
cmd.dvbc2_search.plp = p->stream_id & 0xff;
|
||||
cmd.dvbc2_search.data_slice = (p->stream_id >> 8) & 0xff;
|
||||
}
|
||||
cmd.tuner = state->mci.tuner;
|
||||
cmd.demod = state->mci.demod;
|
||||
cmd.output = state->mci.nr;
|
||||
|
||||
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
if (stat)
|
||||
stop(fe);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int search_isdbt(struct dvb_frontend *fe)
|
||||
{
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
struct m4_base *m4_base = (struct m4_base *) mci_base;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
struct mci_command cmd;
|
||||
int stat;
|
||||
u32 flags = 0;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.command = MCI_CMD_SEARCH_ISDBT;
|
||||
switch (p->bandwidth_hz) {
|
||||
case 8000000:
|
||||
cmd.isdbt_search.bandwidth = MCI_BANDWIDTH_8MHZ;
|
||||
break;
|
||||
case 7000000:
|
||||
cmd.isdbt_search.bandwidth = MCI_BANDWIDTH_7MHZ;
|
||||
break;
|
||||
default:
|
||||
cmd.isdbt_search.bandwidth = MCI_BANDWIDTH_6MHZ;
|
||||
break;
|
||||
}
|
||||
cmd.isdbt_search.retry = 2;
|
||||
cmd.isdbt_search.frequency = p->frequency;
|
||||
cmd.tuner = state->mci.tuner;
|
||||
cmd.demod = state->mci.demod;
|
||||
cmd.output = state->mci.nr;
|
||||
|
||||
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
if (stat)
|
||||
stop(fe);
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
||||
static int set_parameters(struct dvb_frontend *fe)
|
||||
{
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
int res;
|
||||
|
||||
stop(fe);
|
||||
|
||||
state->t2_signalling_valid = 0;
|
||||
state->iq_constellation_point = 0;
|
||||
state->iq_constellation_point_max = 0;
|
||||
|
||||
state->iq_constellation_tap = 0;
|
||||
switch (fe->dtv_property_cache.delivery_system) {
|
||||
case SYS_DVBS:
|
||||
case SYS_DVBS2:
|
||||
res = search_s2(fe);
|
||||
break;
|
||||
case SYS_DVBC_ANNEX_A:
|
||||
res = search_c(fe);
|
||||
break;
|
||||
case SYS_DVBT:
|
||||
state->iq_constellation_tap = 5;
|
||||
res = search_t(fe);
|
||||
break;
|
||||
case SYS_DVBT2:
|
||||
res = search_t2(fe);
|
||||
break;
|
||||
case SYS_DVBC2:
|
||||
res = search_c2(fe);
|
||||
break;
|
||||
case SYS_ISDBT:
|
||||
res = search_isdbt(fe);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!res) {
|
||||
state->started = 1;
|
||||
state->first_time_lock = 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
|
||||
{
|
||||
int stat;
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
struct mci_result res;
|
||||
|
||||
stat = ddb_mci_get_status(&state->mci, &res);
|
||||
if (stat)
|
||||
return stat;
|
||||
*status = 0x00;
|
||||
ddb_mci_get_info(&state->mci);
|
||||
ddb_mci_get_strength(fe);
|
||||
if (res.status == M4_DEMOD_WAIT_SIGNAL)
|
||||
*status = 0x01;
|
||||
if (res.status == M4_DEMOD_LOCKED) {
|
||||
*status = 0x1f;
|
||||
ddb_mci_get_snr(fe);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int tune(struct dvb_frontend *fe, bool re_tune,
|
||||
unsigned int mode_flags,
|
||||
unsigned int *delay, enum fe_status *status)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (re_tune) {
|
||||
r = set_parameters(fe);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
r = read_status(fe, status);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (*status & FE_HAS_LOCK)
|
||||
return 0;
|
||||
*delay = HZ / 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
|
||||
if (state->started)
|
||||
stop(fe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
|
||||
mci_base->count--;
|
||||
if (mci_base->count == 0) {
|
||||
list_del(&mci_base->mci_list);
|
||||
kfree(mci_base);
|
||||
}
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static int get_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
return DVBFE_ALGO_HW;
|
||||
}
|
||||
|
||||
static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
|
||||
{
|
||||
struct m4 *state = fe->demodulator_priv;
|
||||
|
||||
ddb_mci_proc_info(&state->mci, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops m4_ops = {
|
||||
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2, SYS_DVBC2, SYS_ISDBT,
|
||||
SYS_DVBS, SYS_DVBS2, },
|
||||
.info = {
|
||||
.name = "M4",
|
||||
.frequency_min = 950000, /* DVB-T: 47125000 */
|
||||
.frequency_max = 865000000, /* DVB-C: 862000000 */
|
||||
.symbol_rate_min = 100000,
|
||||
.symbol_rate_max = 100000000,
|
||||
.frequency_stepsize = 0,
|
||||
.frequency_tolerance = 0,
|
||||
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
|
||||
FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 |
|
||||
FE_CAN_QAM_AUTO |
|
||||
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
|
||||
FE_CAN_FEC_4_5 |
|
||||
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
|
||||
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION
|
||||
},
|
||||
.release = release,
|
||||
.get_frontend_algo = get_algo,
|
||||
.get_frontend = get_frontend,
|
||||
.read_status = read_status,
|
||||
.tune = tune,
|
||||
.sleep = sleep,
|
||||
};
|
||||
|
||||
static int init(struct mci *mci)
|
||||
{
|
||||
//struct m4 *state = (struct m4 *) mci;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int base_init(struct mci_base *mci_base)
|
||||
{
|
||||
//struct m4_base *base = (struct m4_base *) mci_base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mci_cfg ddb_max_m4_cfg = {
|
||||
.type = 0,
|
||||
.fe_ops = &m4_ops,
|
||||
.base_size = sizeof(struct m4_base),
|
||||
.state_size = sizeof(struct m4),
|
||||
.init = init,
|
||||
.base_init = base_init,
|
||||
};
|
||||
471
ddbridge/ddbridge-main.c
Normal file
471
ddbridge/ddbridge-main.c
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* ddbridge.c: Digital Devices PCIe bridge driver
|
||||
*
|
||||
* Copyright (C) 2010-2017 Digital Devices GmbH
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-io.h"
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
static int msi = 1;
|
||||
module_param(msi, int, 0444);
|
||||
MODULE_PARM_DESC(msi,
|
||||
" Control MSI interrupts: 0-disable, 1-enable (default)");
|
||||
#endif
|
||||
|
||||
#if (KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE)
|
||||
#if (KERNEL_VERSION(3, 19, 0) > LINUX_VERSION_CODE)
|
||||
#define msi_desc_to_dev(desc) (&(desc)->dev.dev)
|
||||
#define dev_to_msi_list(dev) (&to_pci_dev((dev))->msi_list)
|
||||
#define first_msi_entry(dev) \
|
||||
list_first_entry(dev_to_msi_list((dev)), struct msi_desc, list)
|
||||
#define for_each_msi_entry(desc, dev) \
|
||||
list_for_each_entry((desc), dev_to_msi_list((dev)), list)
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
#define first_pci_msi_entry(pdev) first_msi_entry(&(pdev)->dev)
|
||||
#define for_each_pci_msi_entry(desc, pdev) \
|
||||
for_each_msi_entry((desc), &(pdev)->dev)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <linux/msi.h>
|
||||
|
||||
int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
|
||||
{
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
if (dev->msix_enabled) {
|
||||
struct msi_desc *entry;
|
||||
int i = 0;
|
||||
|
||||
for_each_pci_msi_entry(entry, dev) {
|
||||
if (i == nr)
|
||||
return entry->irq;
|
||||
i++;
|
||||
}
|
||||
WARN_ON_ONCE(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* This does not work < 3.19 because nvec_used is used differently. */
|
||||
#if (KERNEL_VERSION(3, 19, 0) <= LINUX_VERSION_CODE)
|
||||
if (dev->msi_enabled) {
|
||||
struct msi_desc *entry = first_pci_msi_entry(dev);
|
||||
|
||||
if (WARN_ON_ONCE(nr >= entry->nvec_used))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (WARN_ON_ONCE(nr > 0))
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return dev->irq + nr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
static void __devexit ddb_irq_disable(struct ddb *dev)
|
||||
{
|
||||
if (dev->link[0].info->regmap->irq_version == 2) {
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_CONTROL);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_1);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_2);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_3);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_4);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_5);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_6);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_7);
|
||||
} else {
|
||||
ddbwritel(dev, 0, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0, MSI1_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void __devexit ddb_msi_exit(struct ddb *dev)
|
||||
{
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
if (dev->msi) {
|
||||
#if (KERNEL_VERSION(4, 8, 0) <= LINUX_VERSION_CODE)
|
||||
pci_free_irq_vectors(dev->pdev);
|
||||
#else
|
||||
pci_disable_msi(dev->pdev);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __devexit ddb_irq_exit(struct ddb *dev)
|
||||
{
|
||||
ddb_irq_disable(dev);
|
||||
if (dev->msi == 2)
|
||||
free_irq(pci_irq_vector(dev->pdev, 1), dev);
|
||||
free_irq(pci_irq_vector(dev->pdev, 0), dev);
|
||||
}
|
||||
|
||||
static void __devexit ddb_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct ddb *dev = (struct ddb *)pci_get_drvdata(pdev);
|
||||
|
||||
ddb_device_destroy(dev);
|
||||
ddb_nsd_detach(dev);
|
||||
ddb_ports_detach(dev);
|
||||
ddb_i2c_release(dev);
|
||||
|
||||
if (dev->link[0].info->ns_num)
|
||||
ddbwritel(dev, 0, ETHER_CONTROL);
|
||||
ddb_irq_exit(dev);
|
||||
ddb_msi_exit(dev);
|
||||
ddb_ports_release(dev);
|
||||
ddb_buffers_free(dev);
|
||||
|
||||
ddb_unmap(dev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(3, 8, 0) <= LINUX_VERSION_CODE)
|
||||
#define __devinit
|
||||
#define __devinitdata
|
||||
#endif
|
||||
|
||||
static int __devinit ddb_irq_msi(struct ddb *dev, int nr)
|
||||
{
|
||||
int stat = 0;
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
if (msi && pci_msi_enabled()) {
|
||||
#if (KERNEL_VERSION(3, 15, 0) <= LINUX_VERSION_CODE)
|
||||
#if (KERNEL_VERSION(4, 8, 0) <= LINUX_VERSION_CODE)
|
||||
stat = pci_alloc_irq_vectors(dev->pdev, 1, nr,
|
||||
PCI_IRQ_MSI | PCI_IRQ_MSIX);
|
||||
#else
|
||||
stat = pci_enable_msi_range(dev->pdev, 1, nr);
|
||||
#endif
|
||||
if (stat >= 1) {
|
||||
dev->msi = stat;
|
||||
dev_info(dev->dev, "using %d MSI interrupt(s)\n",
|
||||
dev->msi);
|
||||
} else {
|
||||
dev_info(dev->dev, "MSI not available.\n");
|
||||
}
|
||||
#else
|
||||
stat = pci_enable_msi_block(dev->pdev, nr);
|
||||
if (stat == 0) {
|
||||
dev->msi = nr;
|
||||
dev_info(dev->dev, "using %d MSI interrupts\n", nr);
|
||||
} else if (stat == 1) {
|
||||
stat = pci_enable_msi(dev->pdev);
|
||||
dev->msi = 1;
|
||||
}
|
||||
if (stat < 0)
|
||||
dev_info(dev->dev, "MSI not available.\n");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int __devinit ddb_irq_init2(struct ddb *dev)
|
||||
{
|
||||
int stat;
|
||||
int irq_flag = IRQF_SHARED;
|
||||
|
||||
dev_info(dev->dev, "init type 2 IRQ hardware block\n");
|
||||
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_CONTROL);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_1);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_2);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_3);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_4);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_5);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_6);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_7);
|
||||
|
||||
ddb_irq_msi(dev, 1);
|
||||
if (dev->msi)
|
||||
irq_flag = 0;
|
||||
|
||||
stat = request_irq(pci_irq_vector(dev->pdev, 0), ddb_irq_handler_v2,
|
||||
irq_flag, "ddbridge", (void *)dev);
|
||||
if (stat < 0)
|
||||
return stat;
|
||||
|
||||
ddbwritel(dev, 0x0000ff7f, INTERRUPT_V2_CONTROL);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_1);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_2);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_3);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_4);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_5);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_6);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_7);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int __devinit ddb_irq_init(struct ddb *dev)
|
||||
{
|
||||
int stat;
|
||||
int irq_flag = IRQF_SHARED;
|
||||
|
||||
if (dev->link[0].info->regmap->irq_version == 2)
|
||||
return ddb_irq_init2(dev);
|
||||
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI2_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI3_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI4_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI5_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI6_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI7_ENABLE);
|
||||
|
||||
ddb_irq_msi(dev, 2);
|
||||
|
||||
if (dev->msi)
|
||||
irq_flag = 0;
|
||||
if (dev->msi == 2) {
|
||||
stat = request_irq(pci_irq_vector(dev->pdev, 0), ddb_irq_handler0,
|
||||
irq_flag, "ddbridge", (void *)dev);
|
||||
if (stat < 0)
|
||||
return stat;
|
||||
stat = request_irq(pci_irq_vector(dev->pdev, 1), ddb_irq_handler1,
|
||||
irq_flag, "ddbridge", (void *)dev);
|
||||
if (stat < 0) {
|
||||
free_irq(pci_irq_vector(dev->pdev, 0), dev);
|
||||
return stat;
|
||||
}
|
||||
} else {
|
||||
#ifdef DDB_TEST_THREADED
|
||||
stat = request_threaded_irq(pci_irq_vector(dev->pdev, 0),
|
||||
dev->pdev->irq, ddb_irq_handler,
|
||||
irq_thread,
|
||||
irq_flag,
|
||||
"ddbridge", (void *)dev);
|
||||
#else
|
||||
stat = request_irq(pci_irq_vector(dev->pdev, 0),
|
||||
ddb_irq_handler,
|
||||
irq_flag, "ddbridge", (void *)dev);
|
||||
#endif
|
||||
if (stat < 0)
|
||||
return stat;
|
||||
}
|
||||
/*ddbwritel(dev, 0xffffffff, INTERRUPT_ACK);*/
|
||||
if (dev->msi == 2) {
|
||||
ddbwritel(dev, 0x0fffff00, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0x0000000f, MSI1_ENABLE);
|
||||
} else {
|
||||
ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int __devinit ddb_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct ddb *dev;
|
||||
int stat = 0;
|
||||
|
||||
if (pci_enable_device(pdev) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
|
||||
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
|
||||
return -ENODEV;
|
||||
|
||||
dev = vzalloc(sizeof(*dev));
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&dev->mutex);
|
||||
dev->has_dma = 1;
|
||||
dev->pdev = pdev;
|
||||
dev->dev = &pdev->dev;
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
dev->link[0].ids.vendor = id->vendor;
|
||||
dev->link[0].ids.device = id->device;
|
||||
dev->link[0].ids.subvendor = id->subvendor;
|
||||
dev->link[0].ids.subdevice = pdev->subsystem_device;
|
||||
dev->link[0].ids.devid = (id->device << 16) | id->vendor;
|
||||
|
||||
dev->link[0].dev = dev;
|
||||
dev->link[0].info = get_ddb_info(id->vendor, id->device,
|
||||
id->subvendor, pdev->subsystem_device);
|
||||
dev_info(dev->dev, "device name: %s\n", dev->link[0].info->name);
|
||||
|
||||
dev->regs_len = pci_resource_len(dev->pdev, 0);
|
||||
dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
|
||||
pci_resource_len(dev->pdev, 0));
|
||||
|
||||
if (!dev->regs) {
|
||||
dev_err(dev->dev, "not enough memory for register map\n");
|
||||
stat = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (ddbreadl(dev, 0) == 0xffffffff) {
|
||||
dev_err(dev->dev, "cannot read registers\n");
|
||||
stat = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev->link[0].ids.hwid = ddbreadl(dev, 0);
|
||||
dev->link[0].ids.regmapid = ddbreadl(dev, 4);
|
||||
|
||||
dev_info(dev->dev, "HW %08x REGMAP %08x\n",
|
||||
dev->link[0].ids.hwid, dev->link[0].ids.regmapid);
|
||||
if ((dev->link[0].ids.hwid & 0xffffff) <
|
||||
dev->link[0].info->hw_min) {
|
||||
u32 min = dev->link[0].info->hw_min;
|
||||
|
||||
dev_err(dev->dev, "Update firmware to at least version %u.%u to ensure full functionality!\n",
|
||||
(min & 0xff0000) >> 16, min & 0xffff);
|
||||
}
|
||||
|
||||
if (dev->link[0].info->ns_num) {
|
||||
ddbwritel(dev, 0, ETHER_CONTROL);
|
||||
ddb_reset_ios(dev);
|
||||
}
|
||||
ddbwritel(dev, 0, DMA_BASE_READ);
|
||||
if (dev->link[0].info->type != DDB_MOD)
|
||||
ddbwritel(dev, 0, DMA_BASE_WRITE);
|
||||
|
||||
if (dev->link[0].info->type == DDB_MOD
|
||||
&& dev->link[0].info->version <= 1) {
|
||||
if (ddbreadl(dev, 0x1c) == 4)
|
||||
dev->link[0].info =
|
||||
get_ddb_info(0xdd01, 0x0201, 0xdd01, 0x0004);
|
||||
}
|
||||
if (dev->link[0].info->type == DDB_MOD
|
||||
&& dev->link[0].info->version == 2) {
|
||||
u32 lic = ddbreadl(dev, 0x1c) & 7;
|
||||
|
||||
switch (lic) {
|
||||
case 0:
|
||||
dev->link[0].info =
|
||||
get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0000);
|
||||
break;
|
||||
case 1:
|
||||
dev->link[0].info =
|
||||
get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0003);
|
||||
break;
|
||||
case 3:
|
||||
dev->link[0].info =
|
||||
get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0002);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
stat = ddb_irq_init(dev);
|
||||
if (stat < 0)
|
||||
goto fail0;
|
||||
|
||||
if (ddb_init(dev) == 0)
|
||||
return 0;
|
||||
|
||||
ddb_irq_exit(dev);
|
||||
fail0:
|
||||
dev_err(dev->dev, "fail0\n");
|
||||
ddb_msi_exit(dev);
|
||||
fail:
|
||||
dev_err(dev->dev, "fail\n");
|
||||
|
||||
ddb_unmap(dev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
pci_disable_device(pdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
#define DDB_DEVICE_ANY(_device) \
|
||||
{ PCI_DEVICE_SUB(0xdd01, _device, 0xdd01, PCI_ANY_ID) }
|
||||
|
||||
static const struct pci_device_id ddb_id_table[] __devinitconst = {
|
||||
DDB_DEVICE_ANY(0x0002),
|
||||
DDB_DEVICE_ANY(0x0003),
|
||||
DDB_DEVICE_ANY(0x0005),
|
||||
DDB_DEVICE_ANY(0x0006),
|
||||
DDB_DEVICE_ANY(0x0007),
|
||||
DDB_DEVICE_ANY(0x0008),
|
||||
DDB_DEVICE_ANY(0x0009),
|
||||
DDB_DEVICE_ANY(0x000a),
|
||||
DDB_DEVICE_ANY(0x0011),
|
||||
DDB_DEVICE_ANY(0x0012),
|
||||
DDB_DEVICE_ANY(0x0013),
|
||||
DDB_DEVICE_ANY(0x0201),
|
||||
DDB_DEVICE_ANY(0x0203),
|
||||
DDB_DEVICE_ANY(0x0210),
|
||||
DDB_DEVICE_ANY(0x0220),
|
||||
DDB_DEVICE_ANY(0x0320),
|
||||
DDB_DEVICE_ANY(0x0321),
|
||||
DDB_DEVICE_ANY(0x0322),
|
||||
DDB_DEVICE_ANY(0x0323),
|
||||
DDB_DEVICE_ANY(0x0328),
|
||||
DDB_DEVICE_ANY(0x0329),
|
||||
{0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ddb_id_table);
|
||||
|
||||
static struct pci_driver ddb_pci_driver = {
|
||||
.name = "ddbridge",
|
||||
.id_table = ddb_id_table,
|
||||
.probe = ddb_probe,
|
||||
.remove = ddb_remove,
|
||||
};
|
||||
|
||||
static __init int module_init_ddbridge(void)
|
||||
{
|
||||
int stat;
|
||||
|
||||
pr_info("Digital Devices PCIE bridge driver "
|
||||
DDBRIDGE_VERSION
|
||||
", Copyright (C) 2010-17 Digital Devices GmbH\n");
|
||||
stat = ddb_init_ddbridge();
|
||||
if (stat < 0)
|
||||
return stat;
|
||||
stat = pci_register_driver(&ddb_pci_driver);
|
||||
if (stat < 0)
|
||||
ddb_exit_ddbridge(0, stat);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static __exit void module_exit_ddbridge(void)
|
||||
{
|
||||
pci_unregister_driver(&ddb_pci_driver);
|
||||
ddb_exit_ddbridge(0, 0);
|
||||
}
|
||||
|
||||
module_init(module_init_ddbridge);
|
||||
module_exit(module_exit_ddbridge);
|
||||
|
||||
MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
|
||||
MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_VERSION(DDBRIDGE_VERSION);
|
||||
521
ddbridge/ddbridge-max.c
Normal file
521
ddbridge/ddbridge-max.c
Normal file
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
* ddbridge-max.c: Digital Devices MAX card line support functions
|
||||
*
|
||||
* Copyright (C) 2010-2017 Digital Devices GmbH
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-io.h"
|
||||
#include "ddbridge-i2c.h"
|
||||
|
||||
/* MAX LNB interface related module parameters */
|
||||
|
||||
static int fmode;
|
||||
module_param(fmode, int, 0444);
|
||||
MODULE_PARM_DESC(fmode, "frontend emulation mode");
|
||||
|
||||
static int fmode_sat = -1;
|
||||
module_param(fmode_sat, int, 0444);
|
||||
MODULE_PARM_DESC(fmode_sat, "set frontend emulation mode sat");
|
||||
|
||||
static int old_quattro;
|
||||
module_param(old_quattro, int, 0444);
|
||||
MODULE_PARM_DESC(old_quattro, "old quattro LNB input order ");
|
||||
|
||||
/* MAX LNB interface related functions */
|
||||
|
||||
static int lnb_command(struct ddb *dev, u32 link, u32 lnb, u32 cmd)
|
||||
{
|
||||
u32 c, v = 0, tag = DDB_LINK_TAG(link);
|
||||
|
||||
v = LNB_TONE & (dev->link[link].lnb.tone << (15 - lnb));
|
||||
ddbwritel(dev, cmd | v, tag | LNB_CONTROL(lnb));
|
||||
for (c = 0; c < 10; c++) {
|
||||
v = ddbreadl(dev, tag | LNB_CONTROL(lnb));
|
||||
if ((v & LNB_BUSY) == 0)
|
||||
break;
|
||||
msleep(20);
|
||||
}
|
||||
if (c == 10)
|
||||
dev_info(dev->dev,
|
||||
"%s lnb = %08x cmd = %08x\n",
|
||||
__func__, lnb, cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max_set_input_unlocked(struct dvb_frontend *fe, int in);
|
||||
|
||||
static int max_emulate_switch(struct dvb_frontend *fe,
|
||||
u8 *cmd, u32 len)
|
||||
{
|
||||
int input;
|
||||
|
||||
if (len !=4)
|
||||
return -1;
|
||||
|
||||
if ((cmd[0] != 0xe0) || (cmd[1] != 0x10) || (cmd[2] != 0x39))
|
||||
return -1;
|
||||
|
||||
input = cmd[3] & 3;
|
||||
max_set_input_unlocked(fe, input);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max_send_master_cmd(struct dvb_frontend *fe,
|
||||
struct dvb_diseqc_master_cmd *cmd)
|
||||
{
|
||||
struct ddb_input *input = fe->sec_priv;
|
||||
struct ddb_port *port = input->port;
|
||||
struct ddb *dev = port->dev;
|
||||
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
|
||||
u32 tag = DDB_LINK_TAG(port->lnr);
|
||||
int i;
|
||||
u32 fmode = dev->link[port->lnr].lnb.fmode;
|
||||
|
||||
if (fmode == 2 || fmode == 1)
|
||||
return 0;
|
||||
|
||||
if (fmode == 4)
|
||||
max_emulate_switch(fe, cmd->msg, cmd->msg_len);
|
||||
|
||||
if (dvb->diseqc_send_master_cmd)
|
||||
dvb->diseqc_send_master_cmd(fe, cmd);
|
||||
|
||||
mutex_lock(&dev->link[port->lnr].lnb.lock);
|
||||
ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(dvb->input));
|
||||
for (i = 0; i < cmd->msg_len; i++)
|
||||
ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(dvb->input));
|
||||
lnb_command(dev, port->lnr, dvb->input, LNB_CMD_DISEQC);
|
||||
mutex_unlock(&dev->link[port->lnr].lnb.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lnb_send_diseqc(struct ddb *dev, u32 link, u32 input,
|
||||
struct dvb_diseqc_master_cmd *cmd)
|
||||
{
|
||||
u32 tag = DDB_LINK_TAG(link);
|
||||
int i;
|
||||
|
||||
ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(input));
|
||||
for (i = 0; i < cmd->msg_len; i++)
|
||||
ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(input));
|
||||
lnb_command(dev, link, input, LNB_CMD_DISEQC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lnb_set_sat(struct ddb *dev, u32 link,
|
||||
u32 input, u32 sat, u32 band, u32 hor)
|
||||
{
|
||||
struct dvb_diseqc_master_cmd cmd = {
|
||||
.msg = {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00},
|
||||
.msg_len = 4
|
||||
};
|
||||
cmd.msg[3] = 0xf0 | (((sat << 2) & 0x0c) |
|
||||
(band ? 1 : 0) | (hor ? 2 : 0));
|
||||
return lnb_send_diseqc(dev, link, input, &cmd);
|
||||
}
|
||||
|
||||
static int lnb_set_tone(struct ddb *dev, u32 link, u32 input,
|
||||
enum fe_sec_tone_mode tone)
|
||||
{
|
||||
int s = 0;
|
||||
u32 mask = (1ULL << input);
|
||||
|
||||
switch (tone) {
|
||||
case SEC_TONE_OFF:
|
||||
if (!(dev->link[link].lnb.tone & mask))
|
||||
return 0;
|
||||
dev->link[link].lnb.tone &= ~(1ULL << input);
|
||||
break;
|
||||
case SEC_TONE_ON:
|
||||
if (dev->link[link].lnb.tone & mask)
|
||||
return 0;
|
||||
dev->link[link].lnb.tone |= (1ULL << input);
|
||||
break;
|
||||
default:
|
||||
s = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (!s)
|
||||
s = lnb_command(dev, link, input, LNB_CMD_NOP);
|
||||
return s;
|
||||
}
|
||||
|
||||
static int lnb_set_voltage(struct ddb *dev, u32 link, u32 input,
|
||||
enum fe_sec_voltage voltage)
|
||||
{
|
||||
int s = 0;
|
||||
|
||||
if (dev->link[link].lnb.oldvoltage[input] == voltage)
|
||||
return 0;
|
||||
switch (voltage) {
|
||||
case SEC_VOLTAGE_OFF:
|
||||
if (dev->link[link].lnb.voltage[input])
|
||||
return 0;
|
||||
lnb_command(dev, link, input, LNB_CMD_OFF);
|
||||
break;
|
||||
case SEC_VOLTAGE_13:
|
||||
lnb_command(dev, link, input, LNB_CMD_LOW);
|
||||
break;
|
||||
case SEC_VOLTAGE_18:
|
||||
lnb_command(dev, link, input, LNB_CMD_HIGH);
|
||||
break;
|
||||
default:
|
||||
s = -EINVAL;
|
||||
break;
|
||||
}
|
||||
dev->link[link].lnb.oldvoltage[input] = voltage;
|
||||
return s;
|
||||
}
|
||||
|
||||
static int max_set_input_unlocked(struct dvb_frontend *fe, int in)
|
||||
{
|
||||
struct ddb_input *input = fe->sec_priv;
|
||||
struct ddb_port *port = input->port;
|
||||
struct ddb *dev = port->dev;
|
||||
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
|
||||
int res = 0;
|
||||
|
||||
if (in > 3)
|
||||
return -EINVAL;
|
||||
if (dvb->input != in) {
|
||||
u32 bit = (1ULL << input->nr);
|
||||
u32 obit = dev->link[port->lnr].lnb.voltage[dvb->input] & bit;
|
||||
|
||||
dev->link[port->lnr].lnb.voltage[dvb->input] &= ~bit;
|
||||
dvb->input = in;
|
||||
dev->link[port->lnr].lnb.voltage[dvb->input] |= obit;
|
||||
}
|
||||
if (dvb->set_input)
|
||||
res = dvb->set_input(fe, in);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int max_set_input(struct dvb_frontend *fe, int in)
|
||||
{
|
||||
struct ddb_input *input = fe->sec_priv;
|
||||
struct ddb_port *port = input->port;
|
||||
struct ddb *dev = input->port->dev;
|
||||
int res;
|
||||
|
||||
mutex_lock(&dev->link[port->lnr].lnb.lock);
|
||||
res = max_set_input_unlocked(fe, in);
|
||||
mutex_unlock(&dev->link[port->lnr].lnb.lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int max_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
|
||||
{
|
||||
struct ddb_input *input = fe->sec_priv;
|
||||
struct ddb_port *port = input->port;
|
||||
struct ddb *dev = port->dev;
|
||||
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
|
||||
int tuner = 0;
|
||||
int res = 0;
|
||||
u32 fmode = dev->link[port->lnr].lnb.fmode;
|
||||
|
||||
mutex_lock(&dev->link[port->lnr].lnb.lock);
|
||||
dvb->tone = tone;
|
||||
switch (fmode) {
|
||||
default:
|
||||
case 0:
|
||||
case 3:
|
||||
res = lnb_set_tone(dev, port->lnr, dvb->input, tone);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
if (old_quattro) {
|
||||
if (dvb->tone == SEC_TONE_ON)
|
||||
tuner |= 2;
|
||||
if (dvb->voltage == SEC_VOLTAGE_18)
|
||||
tuner |= 1;
|
||||
} else {
|
||||
if (dvb->tone == SEC_TONE_ON)
|
||||
tuner |= 1;
|
||||
if (dvb->voltage == SEC_VOLTAGE_18)
|
||||
tuner |= 2;
|
||||
}
|
||||
res = max_set_input_unlocked(fe, tuner);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&dev->link[port->lnr].lnb.lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int max_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage)
|
||||
{
|
||||
struct ddb_input *input = fe->sec_priv;
|
||||
struct ddb_port *port = input->port;
|
||||
struct ddb *dev = port->dev;
|
||||
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
|
||||
int tuner = 0;
|
||||
u32 nv, ov = dev->link[port->lnr].lnb.voltages;
|
||||
int res = 0;
|
||||
u32 fmode = dev->link[port->lnr].lnb.fmode;
|
||||
|
||||
mutex_lock(&dev->link[port->lnr].lnb.lock);
|
||||
dvb->voltage = voltage;
|
||||
|
||||
switch (fmode) {
|
||||
case 3:
|
||||
default:
|
||||
case 0:
|
||||
if (fmode == 3)
|
||||
max_set_input_unlocked(fe, 0);
|
||||
if (voltage == SEC_VOLTAGE_OFF)
|
||||
dev->link[port->lnr].lnb.voltage[dvb->input] &=
|
||||
~(1ULL << input->nr);
|
||||
else
|
||||
dev->link[port->lnr].lnb.voltage[dvb->input] |=
|
||||
(1ULL << input->nr);
|
||||
|
||||
res = lnb_set_voltage(dev, port->lnr, dvb->input, voltage);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
if (voltage == SEC_VOLTAGE_OFF)
|
||||
dev->link[port->lnr].lnb.voltages &=
|
||||
~(1ULL << input->nr);
|
||||
else
|
||||
dev->link[port->lnr].lnb.voltages |=
|
||||
(1ULL << input->nr);
|
||||
nv = dev->link[port->lnr].lnb.voltages;
|
||||
|
||||
if (old_quattro) {
|
||||
if (dvb->tone == SEC_TONE_ON)
|
||||
tuner |= 2;
|
||||
if (dvb->voltage == SEC_VOLTAGE_18)
|
||||
tuner |= 1;
|
||||
} else {
|
||||
if (dvb->tone == SEC_TONE_ON)
|
||||
tuner |= 1;
|
||||
if (dvb->voltage == SEC_VOLTAGE_18)
|
||||
tuner |= 2;
|
||||
}
|
||||
res = max_set_input_unlocked(fe, tuner);
|
||||
|
||||
if (nv != ov) {
|
||||
if (nv) {
|
||||
lnb_set_voltage(dev, port->lnr, 0,
|
||||
SEC_VOLTAGE_13);
|
||||
if (fmode == 1) {
|
||||
lnb_set_voltage(dev, port->lnr, 0,
|
||||
SEC_VOLTAGE_13);
|
||||
if (old_quattro) {
|
||||
lnb_set_voltage(dev,
|
||||
port->lnr, 1,
|
||||
SEC_VOLTAGE_18);
|
||||
lnb_set_voltage(dev, port->lnr,
|
||||
2,
|
||||
SEC_VOLTAGE_13);
|
||||
} else {
|
||||
lnb_set_voltage(dev, port->lnr,
|
||||
1,
|
||||
SEC_VOLTAGE_13);
|
||||
lnb_set_voltage(dev, port->lnr,
|
||||
2,
|
||||
SEC_VOLTAGE_18);
|
||||
}
|
||||
lnb_set_voltage(dev, port->lnr, 3,
|
||||
SEC_VOLTAGE_18);
|
||||
}
|
||||
} else {
|
||||
lnb_set_voltage(dev, port->lnr,
|
||||
0, SEC_VOLTAGE_OFF);
|
||||
if (fmode == 1) {
|
||||
lnb_set_voltage(dev, port->lnr, 1,
|
||||
SEC_VOLTAGE_OFF);
|
||||
lnb_set_voltage(dev, port->lnr, 2,
|
||||
SEC_VOLTAGE_OFF);
|
||||
lnb_set_voltage(dev, port->lnr, 3,
|
||||
SEC_VOLTAGE_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&dev->link[port->lnr].lnb.lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int max_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max_send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxl_fw_read(void *priv, u8 *buf, u32 len)
|
||||
{
|
||||
struct ddb_link *link = priv;
|
||||
struct ddb *dev = link->dev;
|
||||
|
||||
dev_info(dev->dev,
|
||||
"Read mxl_fw from link %u\n", link->nr);
|
||||
|
||||
return ddbridge_flashread(dev, link->nr, buf, 0xc0000, len);
|
||||
}
|
||||
|
||||
int ddb_lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm)
|
||||
{
|
||||
u32 l = link->nr;
|
||||
|
||||
if (link->lnb.fmode == fm)
|
||||
return 0;
|
||||
dev_info(dev->dev, "Set fmode link %u = %u\n", l, fm);
|
||||
mutex_lock(&link->lnb.lock);
|
||||
if (fm == 2 || fm == 1) {
|
||||
if (fmode_sat >= 0) {
|
||||
lnb_set_sat(dev, l, 0, fmode_sat, 0, 0);
|
||||
if (old_quattro) {
|
||||
lnb_set_sat(dev, l, 1, fmode_sat, 0, 1);
|
||||
lnb_set_sat(dev, l, 2, fmode_sat, 1, 0);
|
||||
} else {
|
||||
lnb_set_sat(dev, l, 1, fmode_sat, 1, 0);
|
||||
lnb_set_sat(dev, l, 2, fmode_sat, 0, 1);
|
||||
}
|
||||
lnb_set_sat(dev, l, 3, fmode_sat, 1, 1);
|
||||
}
|
||||
lnb_set_tone(dev, l, 0, SEC_TONE_OFF);
|
||||
if (old_quattro) {
|
||||
lnb_set_tone(dev, l, 1, SEC_TONE_OFF);
|
||||
lnb_set_tone(dev, l, 2, SEC_TONE_ON);
|
||||
} else {
|
||||
lnb_set_tone(dev, l, 1, SEC_TONE_ON);
|
||||
lnb_set_tone(dev, l, 2, SEC_TONE_OFF);
|
||||
}
|
||||
lnb_set_tone(dev, l, 3, SEC_TONE_ON);
|
||||
}
|
||||
link->lnb.fmode = fm;
|
||||
mutex_unlock(&link->lnb.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MAXS8 related functions */
|
||||
|
||||
static struct mxl5xx_cfg mxl5xx = {
|
||||
.adr = 0x60,
|
||||
.type = 0x01,
|
||||
.clk = 27000000,
|
||||
.ts_clk = 139,
|
||||
.cap = 12,
|
||||
.fw_read = mxl_fw_read,
|
||||
};
|
||||
|
||||
int ddb_fe_attach_mxl5xx(struct ddb_input *input)
|
||||
{
|
||||
struct ddb *dev = input->port->dev;
|
||||
struct i2c_adapter *i2c = &input->port->i2c->adap;
|
||||
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
|
||||
struct ddb_port *port = input->port;
|
||||
struct ddb_link *link = &dev->link[port->lnr];
|
||||
struct mxl5xx_cfg cfg;
|
||||
int demod, tuner;
|
||||
|
||||
cfg = mxl5xx;
|
||||
cfg.fw_priv = link;
|
||||
if (dev->link[0].info->type == DDB_OCTONET)
|
||||
;/*cfg.ts_clk = 69;*/
|
||||
|
||||
demod = input->nr;
|
||||
tuner = demod & 3;
|
||||
if (fmode >= 3)
|
||||
tuner = 0;
|
||||
dvb->fe = dvb_attach(mxl5xx_attach, i2c, &cfg, demod, tuner);
|
||||
if (!dvb->fe) {
|
||||
dev_err(dev->dev, "No MXL5XX found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (input->nr < 4) {
|
||||
lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT);
|
||||
lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF);
|
||||
}
|
||||
ddb_lnb_init_fmode(dev, link, fmode);
|
||||
|
||||
dvb->fe->ops.set_voltage = max_set_voltage;
|
||||
dvb->fe->ops.enable_high_lnb_voltage = max_enable_high_lnb_voltage;
|
||||
dvb->fe->ops.set_tone = max_set_tone;
|
||||
dvb->diseqc_send_master_cmd = dvb->fe->ops.diseqc_send_master_cmd;
|
||||
dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd;
|
||||
dvb->fe->ops.diseqc_send_burst = max_send_burst;
|
||||
dvb->fe->sec_priv = input;
|
||||
dvb->set_input = dvb->fe->ops.set_input;
|
||||
dvb->fe->ops.set_input = max_set_input;
|
||||
dvb->input = tuner;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MAX MCI related functions */
|
||||
|
||||
extern struct mci_cfg ddb_max_sx8_cfg;
|
||||
extern struct mci_cfg ddb_max_m4_cfg;
|
||||
|
||||
int ddb_fe_attach_mci(struct ddb_input *input, u32 type)
|
||||
{
|
||||
struct ddb *dev = input->port->dev;
|
||||
//struct i2c_adapter *i2c = &input->port->i2c->adap;
|
||||
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
|
||||
struct ddb_port *port = input->port;
|
||||
struct ddb_link *link = &dev->link[port->lnr];
|
||||
int demod, tuner;
|
||||
struct mci_cfg cfg;
|
||||
int fm = fmode;
|
||||
|
||||
demod = input->nr;
|
||||
tuner = demod & 3;
|
||||
switch (type) {
|
||||
case DDB_TUNER_MCI_SX8:
|
||||
cfg = ddb_max_sx8_cfg;
|
||||
if (fm >= 3)
|
||||
tuner = 0;
|
||||
break;
|
||||
case DDB_TUNER_MCI_M4:
|
||||
fm = 0;
|
||||
cfg = ddb_max_m4_cfg;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
dvb->fe = ddb_mci_attach(input, &cfg, demod, tuner);
|
||||
if (!dvb->fe) {
|
||||
dev_err(dev->dev, "No MCI card found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (input->nr < 4) {
|
||||
lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT);
|
||||
lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF);
|
||||
}
|
||||
ddb_lnb_init_fmode(dev, link, fm);
|
||||
|
||||
dvb->fe->ops.set_voltage = max_set_voltage;
|
||||
dvb->fe->ops.enable_high_lnb_voltage = max_enable_high_lnb_voltage;
|
||||
dvb->fe->ops.set_tone = max_set_tone;
|
||||
dvb->diseqc_send_master_cmd = dvb->fe->ops.diseqc_send_master_cmd;
|
||||
dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd;
|
||||
dvb->fe->ops.diseqc_send_burst = max_send_burst;
|
||||
dvb->fe->sec_priv = input;
|
||||
dvb->set_input = dvb->fe->ops.set_input;
|
||||
dvb->fe->ops.set_input = max_set_input;
|
||||
dvb->input = tuner;
|
||||
return 0;
|
||||
}
|
||||
377
ddbridge/ddbridge-mci.c
Normal file
377
ddbridge/ddbridge-mci.c
Normal file
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
* ddbridge-mci.c: Digital Devices microcode interface
|
||||
*
|
||||
* Copyright (C) 2017-2018 Digital Devices GmbH
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-io.h"
|
||||
#include "ddbridge-mci.h"
|
||||
|
||||
static LIST_HEAD(mci_list);
|
||||
|
||||
static int mci_reset(struct mci *state)
|
||||
{
|
||||
struct ddb_link *link = state->base->link;
|
||||
u32 status = 0;
|
||||
u32 timeout = 40;
|
||||
|
||||
ddblwritel(link, MCI_CONTROL_RESET, MCI_CONTROL);
|
||||
ddblwritel(link, 0, MCI_CONTROL + 4); /* 1= no internal init */
|
||||
msleep(300);
|
||||
ddblwritel(link, 0, MCI_CONTROL);
|
||||
|
||||
while(1) {
|
||||
status = ddblreadl(link, MCI_CONTROL);
|
||||
if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY)
|
||||
break;
|
||||
if (--timeout == 0)
|
||||
break;
|
||||
msleep(50);
|
||||
}
|
||||
if ((status & MCI_CONTROL_READY) == 0 )
|
||||
return -1;
|
||||
if (link->ids.device == 0x0009)
|
||||
ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ddb_mci_config(struct mci *state, u32 config)
|
||||
{
|
||||
struct ddb_link *link = state->base->link;
|
||||
|
||||
if (link->ids.device != 0x0009)
|
||||
return -EINVAL;
|
||||
ddblwritel(link, config, SX8_TSCONFIG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ddb_mci_cmd_raw_unlocked(struct mci *state,
|
||||
u32 *cmd, u32 cmd_len,
|
||||
u32 *res, u32 res_len)
|
||||
{
|
||||
struct ddb_link *link = state->base->link;
|
||||
u32 i, val;
|
||||
unsigned long stat;
|
||||
|
||||
val = ddblreadl(link, MCI_CONTROL);
|
||||
if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND))
|
||||
return -EIO;
|
||||
if (cmd && cmd_len)
|
||||
for (i = 0; i < cmd_len; i++)
|
||||
ddblwritel(link, cmd[i], MCI_COMMAND + i * 4);
|
||||
val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT);
|
||||
ddblwritel(link, val, MCI_CONTROL);
|
||||
|
||||
stat = wait_for_completion_timeout(&state->base->completion, HZ);
|
||||
if (stat == 0) {
|
||||
printk("MCI timeout\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (res && res_len)
|
||||
for (i = 0; i < res_len; i++)
|
||||
res[i] = ddblreadl(link, MCI_RESULT + i * 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ddb_mci_cmd_unlocked(struct mci *state,
|
||||
struct mci_command *command,
|
||||
struct mci_result *result)
|
||||
{
|
||||
u32 *cmd = (u32 *) command;
|
||||
u32 *res = (u32 *) result;
|
||||
|
||||
return ddb_mci_cmd_raw_unlocked(state, cmd, sizeof(*command)/sizeof(u32),
|
||||
res, sizeof(*result)/sizeof(u32));
|
||||
}
|
||||
|
||||
int ddb_mci_cmd(struct mci *state,
|
||||
struct mci_command *command,
|
||||
struct mci_result *result)
|
||||
{
|
||||
int stat;
|
||||
|
||||
mutex_lock(&state->base->mci_lock);
|
||||
stat = ddb_mci_cmd_raw_unlocked(state,
|
||||
(u32 *)command, sizeof(*command)/sizeof(u32),
|
||||
(u32 *)result, sizeof(*result)/sizeof(u32));
|
||||
mutex_unlock(&state->base->mci_lock);
|
||||
return stat;
|
||||
}
|
||||
|
||||
int ddb_mci_cmd_raw(struct mci *state,
|
||||
struct mci_command *command, u32 command_len,
|
||||
struct mci_result *result, u32 result_len)
|
||||
{
|
||||
int stat;
|
||||
|
||||
mutex_lock(&state->base->mci_lock);
|
||||
stat = ddb_mci_cmd_raw_unlocked(state,
|
||||
(u32 *)command, command_len,
|
||||
(u32 *)result, result_len);
|
||||
mutex_unlock(&state->base->mci_lock);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int ddb_mci_get_iq(struct mci *mci, u32 demod, s16 *i, s16 *q)
|
||||
{
|
||||
int stat;
|
||||
struct mci_command cmd;
|
||||
struct mci_result res;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
memset(&res, 0, sizeof(res));
|
||||
cmd.command = MCI_CMD_GET_IQSYMBOL;
|
||||
cmd.demod = demod;
|
||||
stat = ddb_mci_cmd(mci, &cmd, &res);
|
||||
if (!stat) {
|
||||
*i = res.iq_symbol.i;
|
||||
*q = res.iq_symbol.q;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
int ddb_mci_get_status(struct mci *mci, struct mci_result *res)
|
||||
{
|
||||
struct mci_command cmd;
|
||||
|
||||
cmd.command = MCI_CMD_GETSTATUS;
|
||||
cmd.demod = mci->demod;
|
||||
return ddb_mci_cmd_raw(mci, &cmd, 1, res, 1);
|
||||
}
|
||||
|
||||
int ddb_mci_get_snr(struct dvb_frontend *fe)
|
||||
{
|
||||
struct mci *mci = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
|
||||
p->cnr.len = 1;
|
||||
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
p->cnr.stat[0].svalue = (s64) mci->
|
||||
signal_info.dvbs2_signal_info.signal_to_noise * 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ddb_mci_get_strength(struct dvb_frontend *fe)
|
||||
{
|
||||
struct mci *mci = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
s32 str;
|
||||
|
||||
str = mci->signal_info.dvbs2_signal_info.channel_power * 10;
|
||||
p->strength.len = 1;
|
||||
p->strength.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
p->strength.stat[0].svalue = str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ddb_mci_get_info(struct mci *mci)
|
||||
{
|
||||
int stat;
|
||||
struct mci_command cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.command = MCI_CMD_GETSIGNALINFO;
|
||||
cmd.demod = mci->demod;
|
||||
stat = ddb_mci_cmd(mci, &cmd, &mci->signal_info);
|
||||
return stat;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p)
|
||||
{
|
||||
const enum fe_modulation modcod2mod[0x20] = {
|
||||
QPSK, QPSK, QPSK, QPSK,
|
||||
QPSK, QPSK, QPSK, QPSK,
|
||||
QPSK, QPSK, QPSK, QPSK,
|
||||
PSK_8, PSK_8, PSK_8, PSK_8,
|
||||
PSK_8, PSK_8, APSK_16, APSK_16,
|
||||
APSK_16, APSK_16, APSK_16, APSK_16,
|
||||
APSK_32, APSK_32, APSK_32, APSK_32,
|
||||
APSK_32,
|
||||
};
|
||||
const enum fe_code_rate modcod2fec[0x20] = {
|
||||
FEC_NONE, FEC_1_4, FEC_1_3, FEC_2_5,
|
||||
FEC_1_2, FEC_3_5, FEC_2_3, FEC_3_4,
|
||||
FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10,
|
||||
FEC_3_5, FEC_2_3, FEC_3_4, FEC_5_6,
|
||||
FEC_8_9, FEC_9_10, FEC_2_3, FEC_3_4,
|
||||
FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10,
|
||||
FEC_3_4, FEC_4_5, FEC_5_6, FEC_8_9,
|
||||
FEC_9_10, FEC_NONE, FEC_NONE, FEC_NONE,
|
||||
};
|
||||
const enum fe_code_rate dvbs_fec_lut[8] = {
|
||||
FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6,
|
||||
FEC_NONE, FEC_7_8, FEC_NONE, FEC_NONE,
|
||||
};
|
||||
const enum fe_rolloff ro_lut[8] = {
|
||||
ROLLOFF_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_10,
|
||||
ROLLOFF_5, ROLLOFF_15, ROLLOFF_35, ROLLOFF_35
|
||||
};
|
||||
|
||||
p->frequency =
|
||||
mci->signal_info.dvbs2_signal_info.frequency;
|
||||
switch (p->delivery_system) {
|
||||
default:
|
||||
case SYS_DVBS:
|
||||
case SYS_DVBS2:
|
||||
{
|
||||
u32 pls_code =
|
||||
mci->signal_info.dvbs2_signal_info.pls_code;
|
||||
|
||||
p->frequency =
|
||||
mci->signal_info.dvbs2_signal_info.frequency / 1000;
|
||||
p->delivery_system =
|
||||
(mci->signal_info.dvbs2_signal_info.standard == 2) ?
|
||||
SYS_DVBS2 : SYS_DVBS;
|
||||
if (mci->signal_info.dvbs2_signal_info.standard == 2) {
|
||||
u32 modcod = (0x7c & pls_code) >> 2;
|
||||
|
||||
p->delivery_system = SYS_DVBS2;
|
||||
p->rolloff =
|
||||
ro_lut[mci->signal_info.
|
||||
dvbs2_signal_info.roll_off & 7];
|
||||
p->pilot = (pls_code & 1) ? PILOT_ON : PILOT_OFF;
|
||||
p->fec_inner = modcod2fec[modcod];
|
||||
p->modulation = modcod2mod[modcod];
|
||||
p->transmission_mode = pls_code;
|
||||
} else {
|
||||
p->delivery_system = SYS_DVBS;
|
||||
p->rolloff = ROLLOFF_35;
|
||||
p->pilot = PILOT_OFF;
|
||||
p->fec_inner = dvbs_fec_lut[pls_code & 7];
|
||||
p->modulation = QPSK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SYS_DVBC_ANNEX_A:
|
||||
break;
|
||||
case SYS_DVBT:
|
||||
break;
|
||||
case SYS_DVBT2:
|
||||
break;
|
||||
case SYS_DVBC2:
|
||||
break;
|
||||
case SYS_ISDBT:
|
||||
break;
|
||||
}
|
||||
p->pre_bit_error.len = 1;
|
||||
p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
|
||||
p->pre_bit_error.stat[0].uvalue =
|
||||
mci->signal_info.dvbs2_signal_info.ber_numerator;
|
||||
|
||||
p->pre_bit_count.len = 1;
|
||||
p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
|
||||
p->pre_bit_count.stat[0].uvalue =
|
||||
mci->signal_info.dvbs2_signal_info.ber_denominator;
|
||||
|
||||
p->block_error.len = 1;
|
||||
p->block_error.stat[0].scale = FE_SCALE_COUNTER;
|
||||
p->block_error.stat[0].uvalue =
|
||||
mci->signal_info.dvbs2_signal_info.packet_errors;
|
||||
p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
||||
|
||||
p->cnr.len = 1;
|
||||
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
p->cnr.stat[0].svalue = (s64) mci->
|
||||
signal_info.dvbs2_signal_info.signal_to_noise * 10;
|
||||
|
||||
p->strength.len = 1;
|
||||
p->strength.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
p->strength.stat[0].svalue =
|
||||
mci->signal_info.dvbs2_signal_info.channel_power * 10;
|
||||
}
|
||||
|
||||
static void mci_handler(void *priv)
|
||||
{
|
||||
struct mci_base *base = (struct mci_base *)priv;
|
||||
|
||||
complete(&base->completion);
|
||||
}
|
||||
|
||||
static struct mci_base *match_base(void *key)
|
||||
{
|
||||
struct mci_base *p;
|
||||
|
||||
list_for_each_entry(p, &mci_list, mci_list)
|
||||
if (p->key == key)
|
||||
return p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int probe(struct mci *state)
|
||||
{
|
||||
mci_reset(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, struct mci_cfg *cfg, int nr, int tuner)
|
||||
{
|
||||
struct ddb_port *port = input->port;
|
||||
struct ddb *dev = port->dev;
|
||||
struct ddb_link *link = &dev->link[port->lnr];
|
||||
struct mci_base *base;
|
||||
struct mci *state;
|
||||
void *key = cfg->type ? (void *) port : (void *) link;
|
||||
|
||||
state = kzalloc(cfg->state_size, GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
base = match_base(key);
|
||||
if (base) {
|
||||
base->count++;
|
||||
state->base = base;
|
||||
} else {
|
||||
base = kzalloc(cfg->base_size, GFP_KERNEL);
|
||||
if (!base)
|
||||
goto fail;
|
||||
base->key = key;
|
||||
base->count = 1;
|
||||
base->link = link;
|
||||
mutex_init(&base->mci_lock);
|
||||
mutex_init(&base->tuner_lock);
|
||||
ddb_irq_set(dev, link->nr, 0, mci_handler, base);
|
||||
init_completion(&base->completion);
|
||||
state->base = base;
|
||||
if (probe(state) < 0) {
|
||||
kfree(base);
|
||||
goto fail;
|
||||
}
|
||||
list_add(&base->mci_list, &mci_list);
|
||||
if (cfg->base_init)
|
||||
cfg->base_init(base);
|
||||
}
|
||||
memcpy(&state->fe.ops, cfg->fe_ops, sizeof(struct dvb_frontend_ops));
|
||||
state->fe.demodulator_priv = state;
|
||||
state->nr = nr;
|
||||
state->demod = nr;
|
||||
state->tuner = tuner;
|
||||
if (cfg->init)
|
||||
cfg->init(state);
|
||||
return &state->fe;
|
||||
fail:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
547
ddbridge/ddbridge-mci.h
Normal file
547
ddbridge/ddbridge-mci.h
Normal file
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* ddbridge-mci.h: Digital Devices micro code interface
|
||||
*
|
||||
* Copyright (C) 2017-2018 Digital Devices GmbH
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#ifndef _DDBRIDGE_MCI_H_
|
||||
#define _DDBRIDGE_MCI_H_
|
||||
|
||||
#define SX8_TSINPUT (0x280)
|
||||
#define MIC_CONTROL (0x500)
|
||||
#define MIC_PROGMEM_OLD (0x4000)
|
||||
#define MIC_PROGMEM_OLD_SIZE (0x4000)
|
||||
|
||||
#define MIC_PROGMEM (0x8000)
|
||||
#define MIC_PROGMEM_SIZE (0x8000)
|
||||
|
||||
#define MIC_DATAMEM (0x8000)
|
||||
#define MIC_DATAMEM_SIZE (0x2000)
|
||||
|
||||
#define MIC_INTERFACE_IN (0x0600)
|
||||
#define MIC_INTERFACE_OUT (0x0680)
|
||||
#define MIC_INTERFACE_VER (0x06F0)
|
||||
|
||||
|
||||
#define MCI_CONTROL (0x500)
|
||||
#define MCI_COMMAND (0x600)
|
||||
#define MCI_RESULT (0x680)
|
||||
|
||||
#define MCI_COMMAND_SIZE (0x80)
|
||||
#define MCI_RESULT_SIZE (0x80)
|
||||
|
||||
#define MCI_CONTROL_START_COMMAND (0x00000001)
|
||||
#define MCI_CONTROL_ENABLE_DONE_INTERRUPT (0x00000002)
|
||||
#define MCI_CONTROL_RESET (0x00008000)
|
||||
#define MCI_CONTROL_READY (0x00010000)
|
||||
|
||||
#define SX8_TSCONFIG (0x280)
|
||||
|
||||
#define SX8_TSCONFIG_MODE_MASK (0x00000003)
|
||||
#define SX8_TSCONFIG_MODE_OFF (0x00000000)
|
||||
#define SX8_TSCONFIG_MODE_NORMAL (0x00000001)
|
||||
#define SX8_TSCONFIG_MODE_IQ (0x00000003)
|
||||
|
||||
/*
|
||||
* IQMode only vailable on MaxSX8 on a single tuner
|
||||
*
|
||||
* IQ_MODE_SAMPLES
|
||||
* sampling rate is 1550/24 MHz (64.583 MHz)
|
||||
* channel agc is frozen, to allow stitching the FFT results together
|
||||
*
|
||||
* IQ_MODE_VTM
|
||||
* sampling rate is the supplied symbolrate
|
||||
* channel agc is active
|
||||
*
|
||||
* in both cases down sampling is done with a RRC Filter (currently fixed to alpha = 0.05)
|
||||
* which causes some (ca 5%) aliasing at the edges from outside the spectrum
|
||||
*/
|
||||
|
||||
|
||||
#define SX8_TSCONFIG_TSHEADER (0x00000004)
|
||||
#define SX8_TSCONFIG_BURST (0x00000008)
|
||||
|
||||
#define SX8_TSCONFIG_BURSTSIZE_MASK (0x00000030)
|
||||
#define SX8_TSCONFIG_BURSTSIZE_2K (0x00000000)
|
||||
#define SX8_TSCONFIG_BURSTSIZE_4K (0x00000010)
|
||||
#define SX8_TSCONFIG_BURSTSIZE_8K (0x00000020)
|
||||
#define SX8_TSCONFIG_BURSTSIZE_16K (0x00000030)
|
||||
|
||||
/* additional TS input control bits on MaxSX8 DD01:0009 */
|
||||
#define TS_INPUT_CONTROL_SIZEMASK (0x00000030)
|
||||
#define TS_INPUT_CONTROL_SIZE188 (0x00000000)
|
||||
#define TS_INPUT_CONTROL_SIZE192 (0x00000010)
|
||||
#define TS_INPUT_CONTROL_SIZE196 (0x00000020)
|
||||
|
||||
|
||||
/********************************************************/
|
||||
|
||||
#define SX8_DEMOD_STOPPED (0)
|
||||
#define SX8_DEMOD_IQ_MODE (1)
|
||||
#define SX8_DEMOD_WAIT_SIGNAL (2)
|
||||
#define SX8_DEMOD_WAIT_MATYPE (3)
|
||||
#define SX8_DEMOD_TIMEOUT (14)
|
||||
#define SX8_DEMOD_LOCKED (15)
|
||||
|
||||
#define M4_DEMOD_STOPPED (0)
|
||||
#define M4_DEMOD_WAIT_SIGNAL (1)
|
||||
#define M4_DEMOD_TIMEOUT (14)
|
||||
#define M4_DEMOD_LOCKED (15)
|
||||
|
||||
#define MCI_CMD_STOP (0x01)
|
||||
#define MCI_CMD_GETSTATUS (0x02)
|
||||
#define MCI_CMD_GETSIGNALINFO (0x03)
|
||||
#define MCI_CMD_RFPOWER (0x04)
|
||||
|
||||
#define MCI_CMD_SEARCH_DVBS (0x10)
|
||||
#define MCI_CMD_SEARCH_DVBC (0x20)
|
||||
#define MCI_CMD_SEARCH_DVBT (0x21)
|
||||
#define MCI_CMD_SEARCH_DVBT2 (0x22)
|
||||
#define MCI_CMD_SEARCH_DVBC2 (0x23)
|
||||
#define MCI_CMD_SEARCH_ISDBT (0x24)
|
||||
|
||||
#define MCI_CMD_GET_IQSYMBOL (0x30)
|
||||
|
||||
#define MCI_BANDWIDTH_UNKNOWN (0)
|
||||
#define MCI_BANDWIDTH_1_7MHZ (1)
|
||||
#define MCI_BANDWIDTH_5MHZ (5)
|
||||
#define MCI_BANDWIDTH_6MHZ (6)
|
||||
#define MCI_BANDWIDTH_7MHZ (7)
|
||||
#define MCI_BANDWIDTH_8MHZ (8)
|
||||
|
||||
#define M4_MODE_DVBSX (2)
|
||||
#define M4_MODE_DVBC (3)
|
||||
#define M4_MODE_DVBT (4)
|
||||
#define M4_MODE_DVBT2 (5)
|
||||
#define M4_MODE_DVBC2 (6)
|
||||
#define M4_MODE_ISDBT (7)
|
||||
|
||||
#define SX8_CMD_INPUT_ENABLE (0x40)
|
||||
#define SX8_CMD_INPUT_DISABLE (0x41)
|
||||
#define SX8_CMD_START_IQ (0x42)
|
||||
#define SX8_CMD_STOP_IQ (0x43)
|
||||
#define SX8_CMD_ENABLE_IQOUTPUT (0x44)
|
||||
#define SX8_CMD_DISABLE_IQOUTPUT (0x45)
|
||||
|
||||
#define M4_CMD_GET_T2_L1INFO (0x50)
|
||||
#define M4_CMD_GET_C2_L1P2 (0x50)
|
||||
#define M4_CMD_GET_IDS (0x51)
|
||||
|
||||
#define MCI_STATUS_OK (0x00)
|
||||
#define MCI_STATUS_UNSUPPORTED (0x80)
|
||||
#define MCI_STATUS_RETRY (0xFD)
|
||||
#define MCI_STATUS_NOT_READY (0xFE)
|
||||
#define MCI_STATUS_ERROR (0xFF)
|
||||
|
||||
#define MCI_SUCCESS(status) ((status & MCI_STATUS_UNSUPPORTED) == 0)
|
||||
|
||||
|
||||
/********************************************************/
|
||||
|
||||
struct mci_command {
|
||||
union {
|
||||
u32 command_word;
|
||||
struct {
|
||||
u8 command;
|
||||
u8 tuner;
|
||||
u8 demod;
|
||||
u8 output;
|
||||
};
|
||||
};
|
||||
union {
|
||||
u32 params[31];
|
||||
struct {
|
||||
u8 flags; /* Bit 0: DVB-S Enabled, 1: DVB-S2 Enabled, 7: InputStreamID*/
|
||||
/* Bit 0 : QPSK, 1: 8PSK/8APSK, 2 : 16APSK, 3: 32APSK, 4: 64APSK, 5: 128APSK, 6: 256APSK */
|
||||
u8 s2_modulation_mask;
|
||||
u8 rsvd1;
|
||||
u8 retry;
|
||||
u32 frequency;
|
||||
u32 symbol_rate;
|
||||
u8 input_stream_id;
|
||||
u8 rsvd2[3];
|
||||
u32 scrambling_sequence_index;
|
||||
u32 frequency_range;
|
||||
} dvbs2_search;
|
||||
|
||||
struct {
|
||||
u8 flags;
|
||||
u8 bandwidth;
|
||||
u8 rsvd1;
|
||||
u8 retry;
|
||||
u32 frequency;
|
||||
} dvbc_search;
|
||||
|
||||
struct {
|
||||
u8 flags; /* Bit 0: LP Stream */
|
||||
u8 bandwidth;
|
||||
u8 rsvd1;
|
||||
u8 retry;
|
||||
u32 frequency;
|
||||
} dvbt_search;
|
||||
|
||||
struct {
|
||||
u8 flags; /* Bit 0: T2 Lite Profile, 7: PLP, */
|
||||
u8 bandwidth;
|
||||
u8 rsvd1;
|
||||
u8 retry;
|
||||
u32 frequency;
|
||||
u32 reserved;
|
||||
u8 plp;
|
||||
u8 rsvd2[3];
|
||||
} dvbt2_search;
|
||||
|
||||
struct {
|
||||
u8 flags;
|
||||
u8 bandwidth;
|
||||
u8 rsvd1;
|
||||
u8 retry;
|
||||
u32 frequency;
|
||||
u32 reserved;
|
||||
u8 plp;
|
||||
u8 data_slice;
|
||||
u8 rsvd2[2];
|
||||
} dvbc2_search;
|
||||
|
||||
struct {
|
||||
u8 flags;
|
||||
u8 bandwidth;
|
||||
u8 rsvd1;
|
||||
u8 retry;
|
||||
u32 frequency;
|
||||
} isdbt_search;
|
||||
|
||||
struct {
|
||||
u8 tap;
|
||||
u8 rsvd;
|
||||
u16 point;
|
||||
} get_iq_symbol;
|
||||
|
||||
struct {
|
||||
u8 flags; /* Bit 0 : 0 = VTM, 1 = SCAN. Bit 1: Set Gain */
|
||||
u8 roll_off;
|
||||
u8 rsvd1;
|
||||
u8 rsvd2;
|
||||
u32 frequency;
|
||||
u32 symbol_rate; /* Only in VTM mode. */
|
||||
u16 gain;
|
||||
} sx8_start_iq;
|
||||
|
||||
struct {
|
||||
/* Bit 1:0 = STVVGLNA Gain. 0 = AGC, 1 = 0dB,
|
||||
2 = Minimum, 3 = Maximum */
|
||||
u8 flags;
|
||||
} sx8_input_enable;
|
||||
|
||||
struct {
|
||||
u8 Offset; // Offset into list, must be multiple of 64
|
||||
u8 Select; // 0 = Slices, 1 = PLPs (C2 Only)
|
||||
u8 DataSlice; // DataSlice to get PLPList (C2 Only)
|
||||
} get_ids;
|
||||
|
||||
struct {
|
||||
u8 select; // 0 = Base, 1 = DataSilce, 2 = PLP, Bit 7: Set new ID
|
||||
u8 id; // DataSliceID, PLPId
|
||||
} get_l1_info;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
struct mci_result {
|
||||
union {
|
||||
u32 status_word;
|
||||
struct {
|
||||
u8 status;
|
||||
u8 mode;
|
||||
u16 time;
|
||||
};
|
||||
};
|
||||
union {
|
||||
u32 result[27];
|
||||
struct {
|
||||
u8 standard; /* 1 = DVB-S, 2 = DVB-S2X */
|
||||
u8 pls_code; /* puncture rate for DVB-S */
|
||||
u8 roll_off; /* 2-0: rolloff */
|
||||
u8 rsvd;
|
||||
u32 frequency; /* actual frequency in Hz */
|
||||
u32 symbol_rate; /* actual symbolrate in Hz */
|
||||
s16 channel_power; /* channel power in dBm x 100 */
|
||||
s16 band_power; /*/ band power in dBm x 100 */
|
||||
s16 signal_to_noise; /* SNR in dB x 100, Note: negativ values are valid in DVB-S2 */
|
||||
s16 rsvd2;
|
||||
u32 packet_errors; /* Counter for packet errors. (set to 0 on Start command) */
|
||||
u32 ber_numerator; /* Bit error rate: PreRS in DVB-S, PreBCH in DVB-S2X */
|
||||
u32 ber_denominator;
|
||||
} dvbs2_signal_info;
|
||||
|
||||
struct {
|
||||
u8 modulation;
|
||||
u8 rsvd1[3];
|
||||
u32 frequency; /* actual frequency in Hz */
|
||||
u32 symbol_rate; /* actual symbolrate in Hz */
|
||||
s16 channel_power; /* channel power in dBm x 100 */
|
||||
s16 band_power; /* band power in dBm x 100 */
|
||||
s16 signal_to_noise; /* SNR in dB x 100, Note: negativ values are valid in DVB-S2 */
|
||||
s16 rsvd2;
|
||||
u32 packet_errors; /* Counter for packet errors. (set to 0 on Start command) */
|
||||
u32 ber_numerator; /* Bit error rate: PreRS */
|
||||
u32 ber_denominator;
|
||||
} dvbc_signal_info;
|
||||
|
||||
struct {
|
||||
u8 tps_25_32; /* Constellation (2), Hierarchy (3), Coderate HP (3) */
|
||||
u8 tps_33_39; /* Coderate LP (3), Guardinterval (2), FFT (2), 0 (1) */
|
||||
u16 tps_cell_id; /* Cell Identifier */
|
||||
u32 frequency; /* actual frequency in Hz */
|
||||
u32 rsvd1;
|
||||
s16 channel_power; /* channel power in dBm x 100 */
|
||||
s16 band_power; /* band power in dBm x 100 */
|
||||
s16 signal_to_noise; /* SNR in dB x 100, Note: negativ values are valid in DVB-S2 */
|
||||
s16 rsvd2;
|
||||
u32 packet_errors; /* Counter for packet errors. (set to 0 on Start command) */
|
||||
u32 ber_numerator; /* Bit error rate: PreRS */
|
||||
u32 ber_denominator;
|
||||
} dvbt_signal_info;
|
||||
|
||||
struct {
|
||||
u32 rsvd0;
|
||||
u32 frequency; /* actual frequency in Hz */
|
||||
u32 rsvd1;
|
||||
s16 channel_power; /* channel power in dBm x 100 */
|
||||
s16 band_power; /* band power in dBm x 100 */
|
||||
s16 signal_to_noise; /* SNR in dB x 100, Note: negativ values are valid in DVB-S2 */
|
||||
s16 rsvd2;
|
||||
u32 packet_errors; /* Counter for packet errors. (set to 0 on Start command) */
|
||||
u32 ber_numerator; /* Bit error rate: PreRS */
|
||||
u32 ber_denominator;
|
||||
} dvbt2_signal_info;
|
||||
|
||||
struct { // Work in Progress
|
||||
u32 rsvd0 ; // Cell Identifier
|
||||
|
||||
u32 frequency; // actual frequency in Hz
|
||||
u32 rsvd1; //
|
||||
s16 channel_power; // channel power in dBm x 100
|
||||
s16 band_power; // band power in dBm x 100
|
||||
s16 signal_to_noise; // SNR in dB x 100, Note: negativ values are valid in DVB-S2
|
||||
s16 rsvd2;
|
||||
u32 packet_errors; // Counter for packet errors. (set to 0 on Start command)
|
||||
u32 ber_numerator; // Bit error rate: PreBCH
|
||||
u32 ber_denominator;
|
||||
} dvbc2_signal_info;
|
||||
|
||||
struct {
|
||||
u32 rsvd0;
|
||||
|
||||
u32 frequency; // actual frequency in Hz
|
||||
u32 rsvd1; //
|
||||
s16 channel_power; // channel power in dBm x 100
|
||||
s16 band_power; // band power in dBm x 100
|
||||
s16 signal_to_noise; // SNR in dB x 100, Note: negativ values are valid in DVB-S2
|
||||
s16 rsvd2;
|
||||
u32 packet_errors; // Counter for packet errors. (set to 0 on Start command)
|
||||
u32 ber_numerator; // Bit error rate: PreRS
|
||||
u32 ber_denominator;
|
||||
|
||||
u8 tmcc_info[13]; // TMCC B20 - B121
|
||||
} isdbt_signal_info;
|
||||
|
||||
struct {
|
||||
s16 i;
|
||||
s16 q;
|
||||
} iq_symbol;
|
||||
|
||||
struct {
|
||||
u8 t2_l1_pre[37];
|
||||
u8 t2_l1_post[15];
|
||||
u8 t2_l1_post_d[19];
|
||||
u8 t2_l1_post_c[19];
|
||||
} dvbt2_l1_info;
|
||||
|
||||
struct {
|
||||
u8 NetworkID[2];
|
||||
u8 C2SystemID[2];
|
||||
u8 StartFrequency[3];
|
||||
u8 C2BandWidth[2];
|
||||
u8 GuardInterval;
|
||||
u8 C2FrameLength[2];
|
||||
u8 L1P2ChangeCounter;
|
||||
u8 NumDataSlices;
|
||||
u8 NumNotches;
|
||||
struct {
|
||||
u8 Start[2];
|
||||
u8 Width[2];
|
||||
u8 Reserved3;
|
||||
} NotchData[15];
|
||||
u8 ReservedTone;
|
||||
u8 Reserved4[2]; // EWS 1 bit, C2_Version 4 bit, Rsvd 11 bit
|
||||
} DVBC2_L1Part2;
|
||||
|
||||
struct {
|
||||
u8 NumIDs;
|
||||
u8 Offset;
|
||||
u8 IDs[64];
|
||||
} DVBC2_IDList;
|
||||
|
||||
struct {
|
||||
u8 SliceID;
|
||||
u8 TunePosition[2];
|
||||
u8 OffsetLeft[2];
|
||||
u8 OffsetRight[2];
|
||||
u8 TIDepth;
|
||||
u8 Type;
|
||||
u8 FECHeaderType;
|
||||
u8 ConstConf;
|
||||
u8 LeftNotch;
|
||||
u8 NumPLP;
|
||||
u8 Reserved2;
|
||||
} DVBC2_SliceInfo;
|
||||
|
||||
struct {
|
||||
u8 PLPID;
|
||||
u8 Bundled;
|
||||
u8 Type;
|
||||
u8 PayloadType;
|
||||
u8 GroupID;
|
||||
u8 Start[2];
|
||||
u8 FEC_Type;
|
||||
u8 Mod;
|
||||
u8 Cod;
|
||||
u8 PSISIReprocessing;
|
||||
u8 TransportstreamID[2];
|
||||
u8 OrginalNetworkID[2];
|
||||
u8 Reserved1;
|
||||
} DVBC2_PLPInfo;
|
||||
};
|
||||
u32 version[4];
|
||||
};
|
||||
|
||||
/* Helper Macros */
|
||||
|
||||
/* DVB-T2 L1-Pre Signalling Data ( ETSI EN 302 755 V1.4.1 Chapter 7.2.2 ) */
|
||||
|
||||
#define L1PRE_TYPE(p) ((p)[0] & 0xFF)
|
||||
#define L1PRE_BWT_EXT(p) ((p)[1] & 0x01)
|
||||
#define L1PRE_S1(p) ((p)[2] & 0x07)
|
||||
#define L1PRE_S2(p) ((p)[3] & 0x0F)
|
||||
#define L1PRE_L1_REPETITION_FLAG(p) ((p)[4] & 0x01)
|
||||
#define L1PRE_GUARD_INTERVAL(p) ((p)[5] & 0x07)
|
||||
#define L1PRE_PAPR(p) ((p)[6] & 0x0F)
|
||||
#define L1PRE_L1_MOD(p) ((p)[7] & 0x0F)
|
||||
#define L1PRE_L1_COD(p) ((p)[8] & 0x03)
|
||||
#define L1PRE_L1_FEC_TYPE(p) ((p)[9] & 0x03)
|
||||
#define L1PRE_L1_POST_SIZE(p) (((u32)((p)[10] & 0x03) << 16) | ((u32)(p)[11] << 8) | (p)[12])
|
||||
#define L1PRE_L1_POST_INFO_SIZE(p) (((u32)((p)[13] & 0x03) << 16) | ((u32)(p)[14] << 8) | (p)[15])
|
||||
#define L1PRE_PILOT_PATTERN(p) ((p)[16] & 0x0F)
|
||||
#define L1PRE_TX_ID_AVAILABILITY(p) ((p)[17] & 0xFF)
|
||||
#define L1PRE_CELL_ID(p) (((u16)(p)[18] << 8) | (p)[19])
|
||||
#define L1PRE_NETWORK_ID(p) (((u16)(p)[20] << 8) | (p)[21])
|
||||
#define L1PRE_T2_SYSTEM_ID(p) (((u16)(p)[22] << 8) | (p)[23])
|
||||
#define L1PRE_NUM_T2_FRAMES(p) ((p)[24] & 0xFF)
|
||||
#define L1PRE_NUM_DATA_SYMBOLS(p) (((u16)((p)[25] & 0x0F) << 8) | (p)[26])
|
||||
#define L1PRE_REGEN_FLAG(p) ((p)[27] & 0x07)
|
||||
#define L1PRE_L1_POST_EXTENSION(p) ((p)[28] & 0x01)
|
||||
#define L1PRE_NUM_RF(p) ((p)[29] & 0x07)
|
||||
#define L1PRE_CURRENT_RF_IDX(p) ((p)[30] & 0x07)
|
||||
#define L1PRE_T2_VERSION(p) ((((p)[31] & 0x03) << 2) | (((p)[32] & 0xC0) >> 6))
|
||||
#define L1PRE_L1_POST_SCRAMBLED(p) (((p)[32] & 0x20) >> 5)
|
||||
#define L1PRE_T2_BASE_LITE(p) (((p)[32] & 0x10) >> 4)
|
||||
|
||||
|
||||
/* DVB-T2 L1-Post Signalling Data ( ETSI EN 302 755 V1.4.1 Chapter 7.2.3 ) */
|
||||
|
||||
#define L1POST_SUB_SLICES_PER_FRAME(p) (((u16)(p)[ 0] & 0x7F) | (p)[ 1])
|
||||
#define L1POST_NUM_PLP(p) ((p)[2] & 0xFF)
|
||||
#define L1POST_NUM_AUX(p) ((p)[3] & 0x0F)
|
||||
#define L1POST_AUX_CONFIG_RFU(p) ((p)[4] & 0xFF)
|
||||
#define L1POST_RF_IDX(p) ((p)[5] & 0x07)
|
||||
#define L1POST_FREQUENCY(p) (((u32)(p)[6] << 24) | ((u32)(p)[7] << 16) | ((u32)(p)[8] << 8) | (p)[9])
|
||||
#define L1POST_FEF_TYPE(p) ((p)[10] & 0x0F)
|
||||
#define L1POST_FEF_LENGTH(p) (((u32)(p)[11] << 16) | ((u32)(p)[12] << 8) | (p)[13])
|
||||
#define L1POST_FEF_INTERVAL(p) ((p)[14] & 0xFF)
|
||||
|
||||
/* Repeated for each PLP, */
|
||||
/* Hardware is restricted to retrieve only values for current data PLP and common PLP */
|
||||
|
||||
#define L1POST_PLP_ID(p) ((p)[0] & 0xFF)
|
||||
#define L1POST_PLP_TYPE(p) ((p)[1] & 0x07)
|
||||
#define L1POST_PLP_PAYLOAD_TYPE(p) ((p)[2] & 0x1F)
|
||||
#define L1POST_FF_FLAG(p) ((p)[3] & 0x01)
|
||||
#define L1POST_FIRST_RF_IDX(p) ((p)[4] & 0x07)
|
||||
#define L1POST_FIRST_FRAME_IDX(p) ((p)[5] & 0xFF)
|
||||
#define L1POST_PLP_GROUP_ID(p) ((p)[6] & 0xFF)
|
||||
#define L1POST_PLP_COD(p) ((p)[7] & 0x07)
|
||||
#define L1POST_PLP_MOD(p) ((p)[8] & 0x07)
|
||||
#define L1POST_PLP_ROTATION(p) ((p)[9] & 0x01)
|
||||
#define L1POST_PLP_FEC_TYPE(p) ((p)[10] & 0x03)
|
||||
#define L1POST_PLP_NUM_BLOCKS_MAX(p) (((u16)((p)[11] & 0x03) << 8) | (p)[12])
|
||||
#define L1POST_FRAME_INTERVAL(p) ((p)[13] & 0xFF)
|
||||
#define L1POST_TIME_IL_LENGTH(p) ((p)[14] & 0xFF)
|
||||
#define L1POST_TIME_IL_TYPE(p) ((p)[15] & 0x01)
|
||||
#define L1POST_IN_BAND_A_FLAG(p) ((p)[16] & 0x01)
|
||||
#define L1POST_IN_BAND_B_FLAG(p) (((p)[17] >> 7) & 0x01)
|
||||
#define L1POST_RESERVED_1(p) (((u16)((p)[17] & 0x7F) << 4) | ((p)[18] & 0xF0) >> 4)
|
||||
#define L1POST_PLP_MODE(p) (((p)[18] >> 2) & 0x03)
|
||||
#define L1POST_STATIC_FLAG(p) (((p)[18] >> 1) & 0x01)
|
||||
#define L1POST_STATIC_PADDING_FLAG(p) (((p)[18] >> 1) & 0x01)
|
||||
|
||||
struct mci_base {
|
||||
struct list_head mci_list;
|
||||
void *key;
|
||||
struct ddb_link *link;
|
||||
struct completion completion;
|
||||
struct i2c_adapter *i2c;
|
||||
struct mutex i2c_lock;
|
||||
struct mutex tuner_lock;
|
||||
struct mutex mci_lock;
|
||||
int count;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct mci {
|
||||
struct mci_base *base;
|
||||
struct dvb_frontend fe;
|
||||
int nr;
|
||||
int demod;
|
||||
int tuner;
|
||||
|
||||
struct mci_result signal_info;
|
||||
};
|
||||
|
||||
struct mci_cfg {
|
||||
int type;
|
||||
struct dvb_frontend_ops *fe_ops;
|
||||
u32 base_size;
|
||||
u32 state_size;
|
||||
int (*init)(struct mci *mci);
|
||||
int (*base_init)(struct mci_base *mci_base);
|
||||
};
|
||||
|
||||
int ddb_mci_cmd(struct mci *state, struct mci_command *command, struct mci_result *result);
|
||||
int ddb_mci_cmd_raw(struct mci *state, struct mci_command *command, u32 command_len,
|
||||
struct mci_result *result, u32 result_len);
|
||||
int ddb_mci_config(struct mci *state, u32 config);
|
||||
int ddb_mci_get_status(struct mci *mci, struct mci_result *res);
|
||||
int ddb_mci_get_snr(struct dvb_frontend *fe);
|
||||
int ddb_mci_get_info(struct mci *mci);
|
||||
int ddb_mci_get_strength(struct dvb_frontend *fe);
|
||||
void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ddbridge-ns.c: Digital Devices PCIe bridge driver net streaming
|
||||
*
|
||||
* Copyright (C) 2010-2015 Marcus Metzler <mocm@metzlerbros.de>
|
||||
* Copyright (C) 2010-2017Marcus Metzler <mocm@metzlerbros.de>
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Digital Devices GmbH
|
||||
*
|
||||
@@ -17,14 +17,12 @@
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
static int ddb_dvb_ns_input_start(struct ddb_input *input);
|
||||
static int ddb_dvb_ns_input_stop(struct ddb_input *input);
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-io.h"
|
||||
|
||||
static u16 calc_pcs(struct dvb_ns_params *p)
|
||||
{
|
||||
@@ -62,7 +60,7 @@ static u16 calc_pcs16(struct dvb_ns_params *p, int ipv)
|
||||
|
||||
static void ns_free(struct dvbnss *nss)
|
||||
{
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
@@ -87,7 +85,6 @@ static int ns_alloc(struct dvbnss *nss)
|
||||
dev->ns[i].fe = input;
|
||||
nss->priv = &dev->ns[i];
|
||||
ret = 0;
|
||||
/*pr_info("%s i=%d fe=%d\n", __func__, i, input->nr); */
|
||||
break;
|
||||
}
|
||||
ddbwritel(dev, 0x03, RTP_MASTER_CONTROL);
|
||||
@@ -100,7 +97,7 @@ static int ns_set_pids(struct dvbnss *nss)
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
|
||||
|
||||
if (dev->link[0].ids.devid == 0x0301dd01) {
|
||||
u32 sys = 0;
|
||||
@@ -118,8 +115,9 @@ static int ns_set_pids(struct dvbnss *nss)
|
||||
/* disable unused pids */
|
||||
for (; j < 5; j++)
|
||||
ddbwritel(dev, 0, PID_FILTER_PID(dns->nr, j));
|
||||
} else
|
||||
} else {
|
||||
ddbcpyto(dev, STREAM_PIDS(dns->nr), nss->pids, 0x400);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -128,7 +126,7 @@ static int ns_set_pid(struct dvbnss *nss, u16 pid)
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
|
||||
u16 byte = (pid & 0x1fff) >> 3;
|
||||
u8 bit = 1 << (pid & 7);
|
||||
u32 off = STREAM_PIDS(dns->nr);
|
||||
@@ -154,12 +152,12 @@ static int ns_set_pid(struct dvbnss *nss, u16 pid)
|
||||
else
|
||||
ddbmemset(dev, off, 0x00, 0x400);
|
||||
} else {
|
||||
u8 val = ddbreadb(dev, off + byte);
|
||||
u8 val = ddbreadb0(dev, off + byte);
|
||||
|
||||
if (pid & 0x8000)
|
||||
ddbwriteb(dev, val | bit, off + byte);
|
||||
ddbwriteb0(dev, val | bit, off + byte);
|
||||
else
|
||||
ddbwriteb(dev, val & ~bit, off + byte);
|
||||
ddbwriteb0(dev, val & ~bit, off + byte);
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -187,7 +185,7 @@ static int ns_set_ci(struct dvbnss *nss, u8 ci)
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
|
||||
int ciport;
|
||||
|
||||
if (ci == 255) {
|
||||
@@ -198,8 +196,8 @@ static int ns_set_ci(struct dvbnss *nss, u8 ci)
|
||||
if (ciport < 0)
|
||||
return -EINVAL;
|
||||
|
||||
pr_info("input %d.%d to ci %d at port %d\n",
|
||||
input->port->lnr, input->nr, ci, ciport);
|
||||
dev_info(dev->dev, "DDBridge: input %d.%d to ci %d at port %d\n",
|
||||
input->port->lnr, input->nr, ci, ciport);
|
||||
ddbwritel(dev, (input->port->lnr << 21) | (input->nr << 16) | 0x1c,
|
||||
TS_CONTROL(dev->port[ciport].output));
|
||||
usleep_range(1, 5);
|
||||
@@ -247,7 +245,7 @@ static int ns_set_rtcp_msg(struct dvbnss *nss, u8 *msg, u32 len)
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
|
||||
u32 off = STREAM_PACKET_ADR(dns->nr);
|
||||
u32 coff = 96;
|
||||
u16 wlen;
|
||||
@@ -371,7 +369,7 @@ static u32 set_nsbuf(struct dvb_ns_params *p, u8 *buf,
|
||||
|
||||
static int ns_set_ts_packets(struct dvbnss *nss, u8 *buf, u32 len)
|
||||
{
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
@@ -388,7 +386,7 @@ static int ns_set_ts_packets(struct dvbnss *nss, u8 *buf, u32 len)
|
||||
|
||||
static int ns_insert_ts_packets(struct dvbnss *nss, u8 count)
|
||||
{
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
@@ -410,7 +408,7 @@ static int ns_set_net(struct dvbnss *nss)
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
struct dvb_ns_params *p = &nss->params;
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
|
||||
u32 off = STREAM_PACKET_ADR(dns->nr);
|
||||
u32 coff = 96;
|
||||
|
||||
@@ -429,7 +427,7 @@ static int ns_set_net(struct dvbnss *nss)
|
||||
|
||||
static int ns_start(struct dvbnss *nss)
|
||||
{
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
@@ -446,8 +444,6 @@ static int ns_start(struct dvbnss *nss)
|
||||
if (dns->fe != input)
|
||||
ddb_dvb_ns_input_start(dns->fe);
|
||||
ddb_dvb_ns_input_start(input);
|
||||
/* printk("ns start ns %u, fe %u link %u\n",
|
||||
dns->nr, dns->fe->nr, dns->fe->port->lnr); */
|
||||
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
|
||||
STREAM_CONTROL(dns->nr));
|
||||
return 0;
|
||||
@@ -455,7 +451,7 @@ static int ns_start(struct dvbnss *nss)
|
||||
|
||||
static int ns_stop(struct dvbnss *nss)
|
||||
{
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
@@ -467,7 +463,7 @@ static int ns_stop(struct dvbnss *nss)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netstream_init(struct ddb_input *input)
|
||||
int netstream_init(struct ddb_input *input)
|
||||
{
|
||||
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
|
||||
struct dvb_adapter *adap = dvb->adap;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ddbridge-regs.h: Digital Devices PCIe bridge driver
|
||||
*
|
||||
* Copyright (C) 2010-2016 Digital Devices GmbH
|
||||
* Copyright (C) 2010-2017 Digital Devices GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -15,19 +15,22 @@
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/* Register Definitions */
|
||||
|
||||
#define CUR_REGISTERMAP_VERSION_V1 0x00010001
|
||||
#define CUR_REGISTERMAP_VERSION_V2 0x00020000
|
||||
#define CUR_REGISTERMAP_VERSION 0x10004
|
||||
#define CUR_REGISTERMAP_VERSION_0007 0x10002
|
||||
#define CUR_REGISTERMAP_VERSION_0008 0x10002
|
||||
#define CUR_REGISTERMAP_VERSION_CI 0x10000
|
||||
#define CUR_REGISTERMAP_VERSION_CI_PRO 0x10000
|
||||
|
||||
#define HARDWARE_VERSION 0x00000000
|
||||
#define REGISTERMAP_VERSION 0x00000004
|
||||
#define HARDWARE_VERSION 0x0000
|
||||
#define REGISTERMAP_VERSION 0x0004
|
||||
#define DEVICE_ID 0x0008
|
||||
#define BOARD_ID 0x000C
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* SPI Controller */
|
||||
@@ -45,10 +48,10 @@
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* MDIO */
|
||||
|
||||
#define MDIO_CTRL 0x20
|
||||
#define MDIO_ADR 0x24
|
||||
#define MDIO_REG 0x28
|
||||
#define MDIO_VAL 0x2C
|
||||
#define MDIO_CTRL_OFF 0x00
|
||||
#define MDIO_ADR_OFF 0x04
|
||||
#define MDIO_REG_OFF 0x08
|
||||
#define MDIO_VAL_OFF 0x0C
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
@@ -57,9 +60,9 @@
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Interrupt controller
|
||||
How many MSI's are available depends on HW (Min 2 max 8)
|
||||
How many are usable also depends on Host platform
|
||||
*/
|
||||
* How many MSI's are available depends on HW (Min 2 max 8)
|
||||
* How many are usable also depends on Host platform
|
||||
*/
|
||||
|
||||
#define INTERRUPT_BASE (0x40)
|
||||
|
||||
@@ -105,7 +108,6 @@
|
||||
#define INTMASK_TSOUTPUT3 (0x00040000)
|
||||
#define INTMASK_TSOUTPUT4 (0x00080000)
|
||||
|
||||
|
||||
#define INTERRUPT_V2_CONTROL (INTERRUPT_BASE + 0x00)
|
||||
#define INTERRUPT_V2_ENABLE_1 (INTERRUPT_BASE + 0x04)
|
||||
#define INTERRUPT_V2_ENABLE_2 (INTERRUPT_BASE + 0x08)
|
||||
@@ -124,9 +126,6 @@
|
||||
#define INTERRUPT_V2_STATUS_6 (INTERRUPT_BASE + 0x38)
|
||||
#define INTERRUPT_V2_STATUS_7 (INTERRUPT_BASE + 0x3c)
|
||||
|
||||
|
||||
|
||||
|
||||
/* Modulator registers */
|
||||
|
||||
/* Clock Generator ( Sil598 @ 0xAA I2c ) */
|
||||
@@ -139,8 +138,8 @@
|
||||
/* DAC ( AD9781/AD9783 SPI ) */
|
||||
#define DAC_BASE (0x090)
|
||||
#define DAC_CONTROL (DAC_BASE)
|
||||
#define DAC_WRITE_DATA (DAC_BASE+4)
|
||||
#define DAC_READ_DATA (DAC_BASE+8)
|
||||
#define DAC_WRITE_DATA (DAC_BASE + 4)
|
||||
#define DAC_READ_DATA (DAC_BASE + 8)
|
||||
|
||||
#define DAC_CONTROL_INSTRUCTION_REG (0xFF)
|
||||
#define DAC_CONTROL_STARTIO (0x100)
|
||||
@@ -153,32 +152,47 @@
|
||||
#define TEMPMON_CONTROL_SCAN (0x00000001)
|
||||
#define TEMPMON_CONTROL_AUTOSCAN (0x00000002)
|
||||
#define TEMPMON_CONTROL_INTENABLE (0x00000004)
|
||||
#define TEMPMON_CONTROL_CLEAR (0x00000008)
|
||||
#define TEMPMON_CONTROL_OVERTEMP (0x00008000)
|
||||
#define TEMPMON_STATUS_SHUTDOWN (0x00008000)
|
||||
|
||||
|
||||
/* SHORT Temperature in <20>C x 256 */
|
||||
/* Temperature in C x 256 */
|
||||
#define TEMPMON_CORE (TEMPMON_BASE + 0x04)
|
||||
#define TEMPMON_SENSOR0 (TEMPMON_BASE + 0x04)
|
||||
#define TEMPMON_SENSOR1 (TEMPMON_BASE + 0x08)
|
||||
#define TEMPMON_SENSOR2 (TEMPMON_BASE + 0x0C)
|
||||
|
||||
#define TEMPMON_FANCONTROL (TEMPMON_BASE + 0x10)
|
||||
#define TEMPMON_FANPWM (0x00000F00) // PWM speed in 10% steps
|
||||
#define TEMPMON_FANTACHO (0x000000FF) // Rotations in 100/min steps
|
||||
#define TEMPMON_FANPWM (0x00000F00) /* PWM speed in 10% steps */
|
||||
#define TEMPMON_FANTACHO (0x000000FF) /* Rotations in 100/min steps */
|
||||
|
||||
// V1 Temperature Monitor
|
||||
// Temperature Monitor TEMPMON_CONTROL & 0x8000 == 0 : ( 2x LM75A @ 0x90,0x92 )
|
||||
// Temperature Monitor TEMPMON_CONTROL & 0x8000 == 1 : ( 1x LM75A @ 0x90, 1x ADM1032 @ 0x9A )
|
||||
#define TEMPMON_INTERRUPT_V1 (24)
|
||||
#define TEMPMON_INTERRUPT_V1_MASK (1<<24)
|
||||
|
||||
#define TEMPMON1_CORE (TEMPMON_SENSOR0) // SHORT Temperature in <20>C x 256 (ADM1032 ext)
|
||||
#define TEMPMON1_SENSOR1 (TEMPMON_BASE + 0x08) // SHORT Temperature in <20>C x 256 (LM75A 0x90)
|
||||
#define TEMPMON1_SENSOR2 (TEMPMON_BASE + 0x0C) // SHORT Temperature in <20>C x 256 (LM75A 0x92 or ADM1032 Int)
|
||||
/* V1 Temperature Monitor
|
||||
* Temperature Monitor TEMPMON_CONTROL & 0x8000 == 0 : ( 2x LM75A @ 0x90,0x92 )
|
||||
* Temperature Monitor TEMPMON_CONTROL & 0x8000 == 1 :
|
||||
* ( 1x LM75A @ 0x90, 1x ADM1032 @ 0x9A )
|
||||
*/
|
||||
|
||||
// V2 Temperature Monitor 2 ADM1032
|
||||
/* Temperature in C x 256 (ADM1032 ext) */
|
||||
#define TEMPMON1_CORE (TEMPMON_SENSOR0)
|
||||
/* Temperature in C x 256 (LM75A 0x90) */
|
||||
#define TEMPMON1_SENSOR1 (TEMPMON_BASE + 0x08)
|
||||
/* Temperature in C x 256 (LM75A 0x92 or ADM1032 Int) */
|
||||
#define TEMPMON1_SENSOR2 (TEMPMON_BASE + 0x0C)
|
||||
|
||||
/* V2 Temperature Monitor 2 ADM1032 */
|
||||
|
||||
/* Temperature in C x 256 (ADM1032 int) */
|
||||
#define TEMPMON2_BOARD (TEMPMON_SENSOR0)
|
||||
/* Temperature in C x 256 (ADM1032 ext) */
|
||||
#define TEMPMON2_FPGACORE (TEMPMON_SENSOR1)
|
||||
/* Temperature in C x 256 (ADM1032 ext) */
|
||||
#define TEMPMON2_QAMCORE (TEMPMON_SENSOR2)
|
||||
/* SHORT Temperature in C x 256 (ADM1032 ext) */
|
||||
#define TEMPMON2_DACCORE (TEMPMON_SENSOR2)
|
||||
|
||||
#define TEMPMON2_BOARD (TEMPMON_SENSOR0) // SHORT Temperature in <20>C x 256 (ADM1032 int)
|
||||
#define TEMPMON2_FPGACORE (TEMPMON_SENSOR1) // SHORT Temperature in <20>C x 256 (ADM1032 ext)
|
||||
#define TEMPMON2_QAMCORE (TEMPMON_SENSOR2) // SHORT Temperature in <20>C x 256 (ADM1032 ext)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* I2C Master Controller */
|
||||
@@ -197,7 +211,6 @@
|
||||
#define I2C_SPEED_77 (0x19181919)
|
||||
#define I2C_SPEED_50 (0x27262727)
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* DMA Controller */
|
||||
|
||||
@@ -217,18 +230,20 @@
|
||||
#define DMA_DIAG_WAITOVERFLOWCOUNTER (0x38)
|
||||
#define DMA_DIAG_WAITCOUNTER (0x3C)
|
||||
|
||||
#define TS_CONTROL(_io) (_io->regs + 0x00)
|
||||
#define TS_CONTROL2(_io) (_io->regs + 0x04)
|
||||
#define TS_CONTROL(_io) ((_io)->regs + 0x00)
|
||||
#define TS_CONTROL2(_io) ((_io)->regs + 0x04)
|
||||
|
||||
#define TS_INPUT_CONTROL_ENABLE (0x00000001)
|
||||
#define TS_INPUT_CONTROL_RESET (0x00000002)
|
||||
#define TS_INPUT_CONTROL_SKIPERROR (0x00000008)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* DMA Buffer */
|
||||
|
||||
#define DMA_BUFFER_CONTROL(_dma) (_dma->regs + 0x00)
|
||||
#define DMA_BUFFER_ACK(_dma) (_dma->regs + 0x04)
|
||||
#define DMA_BUFFER_CURRENT(_dma) (_dma->regs + 0x08)
|
||||
#define DMA_BUFFER_SIZE(_dma) (_dma->regs + 0x0c)
|
||||
|
||||
#define DMA_BUFFER_CONTROL(_dma) ((_dma)->regs + 0x00)
|
||||
#define DMA_BUFFER_ACK(_dma) ((_dma)->regs + 0x04)
|
||||
#define DMA_BUFFER_CURRENT(_dma) ((_dma)->regs + 0x08)
|
||||
#define DMA_BUFFER_SIZE(_dma) ((_dma)->regs + 0x0c)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
@@ -242,10 +257,12 @@
|
||||
#define LNB_CMD_HIGH 4
|
||||
#define LNB_CMD_OFF 5
|
||||
#define LNB_CMD_DISEQC 6
|
||||
#define LNB_CMD_UNI 7
|
||||
#define LNB_CMD_SCIF 7
|
||||
|
||||
#define LNB_BUSY (1ULL << 4)
|
||||
#define LNB_TONE (1ULL << 15)
|
||||
#define LNB_BUSY BIT_ULL(4)
|
||||
#define LNB_TONE BIT_ULL(15)
|
||||
|
||||
#define LNB_INTERRUPT_BASE 4
|
||||
|
||||
#define LNB_STATUS(i) (LNB_BASE + (i) * 0x20 + 0x04)
|
||||
#define LNB_VOLTAGE(i) (LNB_BASE + (i) * 0x20 + 0x08)
|
||||
@@ -253,6 +270,11 @@
|
||||
#define LNB_BUF_LEVEL(i) (LNB_BASE + (i) * 0x20 + 0x10)
|
||||
#define LNB_BUF_WRITE(i) (LNB_BASE + (i) * 0x20 + 0x14)
|
||||
|
||||
#define LNB_SETTING(i) (LNB_BASE + (i) * 0x20 + 0x0c)
|
||||
#define LNB_FIFO_LEVEL(i) (LNB_BASE + (i) * 0x20 + 0x10)
|
||||
#define LNB_RESET_FIFO(i) (LNB_BASE + (i) * 0x20 + 0x10)
|
||||
#define LNB_WRITE_FIFO(i) (LNB_BASE + (i) * 0x20 + 0x14)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* CI Interface (only CI-Bridge) */
|
||||
|
||||
@@ -291,14 +313,14 @@
|
||||
|
||||
#define CI_BUFFER_BASE (0x3000)
|
||||
#define CI_BUFFER_SIZE (0x0800)
|
||||
#define CI_BLOCKIO_BUFFER_SIZE (CI_BUFFER_SIZE/2)
|
||||
#define CI_BLOCKIO_BUFFER_SIZE (CI_BUFFER_SIZE / 2)
|
||||
|
||||
#define CI_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE)
|
||||
#define CI_BLOCKIO_RECEIVE_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE)
|
||||
#define CI_BLOCKIO_SEND_BUFFER(i) \
|
||||
(CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE + CI_BLOCKIO_BUFFER_SIZE)
|
||||
|
||||
// V1
|
||||
/* V1 */
|
||||
|
||||
#define VCO1_BASE (0xC0)
|
||||
#define VCO1_CONTROL (VCO1_BASE + 0x00)
|
||||
@@ -330,16 +352,27 @@
|
||||
/* Muxout from VCO (usually = Lock) */
|
||||
#define VCO3_CONTROL_MUXOUT (0x00000004)
|
||||
|
||||
// V2
|
||||
/* V2 */
|
||||
|
||||
#define MAX2871_BASE (0xC0)
|
||||
#define MAX2871_CONTROL (MAX2871_BASE + 0x00)
|
||||
#define MAX2871_OUTDATA (MAX2871_BASE + 0x04) // 32 Bit
|
||||
#define MAX2871_INDATA (MAX2871_BASE + 0x08) // 32 Bit
|
||||
#define MAX2871_CONTROL_WRITE (0x00000001) // 1 = Trigger write, resets when done
|
||||
#define MAX2871_CONTROL_CE (0x00000002) // 0 = Put VCO into power down
|
||||
#define MAX2871_CONTROL_MUXOUT (0x00000004) // Muxout from VCO
|
||||
#define MAX2871_CONTROL_LOCK (0x00000008) // Lock from VCO
|
||||
#define MAX2871_OUTDATA (MAX2871_BASE + 0x04)
|
||||
#define MAX2871_INDATA (MAX2871_BASE + 0x08)
|
||||
/* 1 = Trigger write, resets when done */
|
||||
#define MAX2871_CONTROL_WRITE (0x00000001)
|
||||
/* 0 = Put VCO into power down */
|
||||
#define MAX2871_CONTROL_CE (0x00000002)
|
||||
/* Muxout from VCO */
|
||||
#define MAX2871_CONTROL_MUXOUT (0x00000004)
|
||||
/* Lock from VCO */
|
||||
#define MAX2871_CONTROL_LOCK (0x00000008)
|
||||
/* Signal the loss of lock event (currently only an interrupt) */
|
||||
#define MAX2871_CONTROL_ENABLE_LOSTLOCK_EVENT (0x00000010)
|
||||
/* Loss of Lock, needs to be cleared by writing a 1
|
||||
* during initial setup this bit can be set.
|
||||
*/
|
||||
#define MAX2871_CONTROL_LOSTLOCK (0x00008000)
|
||||
|
||||
|
||||
#define FSM_BASE (0x200)
|
||||
#define FSM_CONTROL (FSM_BASE + 0x00)
|
||||
@@ -356,11 +389,10 @@
|
||||
#define FSM_STATUS_READY (0x00010000)
|
||||
#define FSM_STATUS_QAMREADY (0x00020000)
|
||||
|
||||
|
||||
#define FSM_CAPACITY (FSM_BASE + 0x04)
|
||||
#define FSM_CAPACITY_MAX (0x3F000000)
|
||||
#define FSM_CAPACITY_CUR (0x003F0000)
|
||||
#define FSM_CAPACITY_INUSE (0x0000003F)
|
||||
#define FSM_CAPACITY_MAX (0x3F000000)
|
||||
#define FSM_CAPACITY_CUR (0x003F0000)
|
||||
#define FSM_CAPACITY_INUSE (0x0000003F)
|
||||
|
||||
#define FSM_GAIN (FSM_BASE + 0x10)
|
||||
#define FSM_GAINMASK (0x000000FF)
|
||||
@@ -373,21 +405,20 @@
|
||||
#define FSM_GAIN_N24 (0x00000029)
|
||||
#define FSM_GAIN_N96 (0x00000011)
|
||||
|
||||
|
||||
// Attenuator/VGA
|
||||
/* Attenuator/VGA */
|
||||
|
||||
#define RF_ATTENUATOR (0xD8)
|
||||
#define RF_ATTENUATOR (0xD8)
|
||||
/* 0x00 = 0 dB
|
||||
0x01 = 1 dB
|
||||
...
|
||||
0x1F = 31 dB
|
||||
*/
|
||||
* 0x01 = 1 dB
|
||||
* ...
|
||||
* 0x1F = 31 dB
|
||||
*/
|
||||
|
||||
#define RF_VGA (0xDC)
|
||||
/* Only V2 */
|
||||
/* 8 bit range 0 - 31.75 dB Gain */
|
||||
|
||||
|
||||
/* VGA Gain for same output level as V1 Modulator */
|
||||
#define RF_VGA_GAIN_N8 (85)
|
||||
#define RF_VGA_GAIN_N16 (117)
|
||||
@@ -395,7 +426,6 @@
|
||||
|
||||
#define RF_VGA_GAIN_MAX (200)
|
||||
|
||||
|
||||
/* V1 only */
|
||||
|
||||
#define RF_POWER (0xE0)
|
||||
@@ -408,10 +438,9 @@
|
||||
#define RF_POWER_CONTROL_VALIDMASK (0x00000700)
|
||||
#define RF_POWER_CONTROL_VALID (0x00000500)
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Output control
|
||||
*/
|
||||
/*
|
||||
* Output control
|
||||
*/
|
||||
|
||||
#define IQOUTPUT_BASE (0x240)
|
||||
#define IQOUTPUT_CONTROL (IQOUTPUT_BASE + 0x00)
|
||||
@@ -440,14 +469,13 @@
|
||||
#define IQOUTPUT_CONTROL_ENABLE_PEAK (0x00000008)
|
||||
#define IQOUTPUT_CONTROL_BYPASS_EQUALIZER (0x00000010)
|
||||
|
||||
|
||||
/* Modulator Base V1 */
|
||||
|
||||
#define MODULATOR_BASE (0x200)
|
||||
#define MODULATOR_CONTROL (MODULATOR_BASE)
|
||||
#define MODULATOR_IQTABLE_END (MODULATOR_BASE+4)
|
||||
#define MODULATOR_IQTABLE_INDEX (MODULATOR_BASE+8)
|
||||
#define MODULATOR_IQTABLE_DATA (MODULATOR_BASE+12)
|
||||
#define MODULATOR_IQTABLE_END (MODULATOR_BASE + 4)
|
||||
#define MODULATOR_IQTABLE_INDEX (MODULATOR_BASE + 8)
|
||||
#define MODULATOR_IQTABLE_DATA (MODULATOR_BASE + 12)
|
||||
|
||||
#define MODULATOR_IQTABLE_INDEX_CHANNEL_MASK (0x000F0000)
|
||||
#define MODULATOR_IQTABLE_INDEX_IQ_MASK (0x00008000)
|
||||
@@ -456,7 +484,6 @@
|
||||
#define MODULATOR_IQTABLE_INDEX_SEL_Q (MODULATOR_IQTABLE_INDEX_IQ_MASK)
|
||||
#define MODULATOR_IQTABLE_SIZE (2048)
|
||||
|
||||
|
||||
/* Modulator Channels */
|
||||
|
||||
#define CHANNEL_BASE dev->link[0].info->regmap->channel->base
|
||||
@@ -508,12 +535,11 @@
|
||||
#define CHANNEL_SETTINGS2_OUTPUT_MASK (0x0000007F)
|
||||
|
||||
#define KFLF_MAX (0x07FFFFFFUL)
|
||||
#define KF_INIT(Symbolrate) (Symbolrate)
|
||||
#define LF_INIT(Symbolrate) (9000000UL)
|
||||
#define KF_INIT(_symbol_rate) (_symbol_rate)
|
||||
#define LF_INIT(_symbol_rate) (9000000UL)
|
||||
#define MIN_SYMBOLRATE (1000000)
|
||||
#define MAX_SYMBOLRATE (7100000)
|
||||
|
||||
|
||||
/* OCTONET */
|
||||
|
||||
#define ETHER_BASE (0x100)
|
||||
@@ -550,5 +576,70 @@
|
||||
#define PID_FILTER_SYSTEM_PIDS(i) (PID_FILTER_BASE + (i) * 0x20)
|
||||
#define PID_FILTER_PID(i, j) (PID_FILTER_BASE + (i) * 0x20 + (j) * 4)
|
||||
|
||||
/* V2 */
|
||||
|
||||
/* MAX2871 same as DVB Modulator V2 */
|
||||
|
||||
#define RFDAC_BASE (0x200)
|
||||
#define RFDAC_CONTROL (RFDAC_BASE + 0x00)
|
||||
|
||||
#define RFDAC_CMD_MASK (0x00000087)
|
||||
#define RFDAC_CMD_STATUS (0x00000080)
|
||||
#define RFDAC_CMD_RESET (0x00000080)
|
||||
#define RFDAC_CMD_POWERDOWN (0x00000081)
|
||||
#define RFDAC_CMD_SETUP (0x00000082)
|
||||
|
||||
#define RFDAC_STATUS (RFDAC_BASE + 0x00)
|
||||
#define RFDAC_STATUS_READY (0x00010000)
|
||||
#define RFDAC_STATUS_DACREADY (0x00020000)
|
||||
|
||||
#define RFDAC_FCW (RFDAC_BASE + 0x10)
|
||||
|
||||
#define JESD204B_BASE (0x280)
|
||||
|
||||
/* Additional Status Bits */
|
||||
|
||||
#define DMA_PCIE_LANES_MASK (0x00070000)
|
||||
|
||||
/* Modulator Channels, partially compatible to DVB Modulator V1 */
|
||||
|
||||
#define SDR_CHANNEL_BASE (0x800)
|
||||
|
||||
#define SDR_CHANNEL_CONTROL(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x00)
|
||||
#define SDR_CHANNEL_CONFIG(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x04)
|
||||
#define SDR_CHANNEL_CFCW(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x08)
|
||||
#define SDR_CHANNEL_ARICW(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x0C)
|
||||
#define SDR_CHANNEL_RGAIN(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x10)
|
||||
#define SDR_CHANNEL_SETFIR(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x14)
|
||||
|
||||
#define SDR_CHANNEL_FMDCW(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x20)
|
||||
#define SDR_CHANNEL_FM1FCW(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x24)
|
||||
#define SDR_CHANNEL_FM2FCW(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x28)
|
||||
#define SDR_CHANNEL_FM1GAIN(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x2C)
|
||||
#define SDR_CHANNEL_FM2GAIN(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x30)
|
||||
|
||||
/* Control and status bits */
|
||||
#define SDR_CONTROL_ENABLE_CHANNEL (0x00000004)
|
||||
#define SDR_CONTROL_ENABLE_DMA (0x00000008)
|
||||
#define SDR_STATUS_DMA_UNDERRUN (0x00010000)
|
||||
|
||||
/* Config */
|
||||
#define SDR_CONFIG_ENABLE_FM1 (0x00000002)
|
||||
#define SDR_CONFIG_ENABLE_FM2 (0x00000004)
|
||||
#define SDR_CONFIG_DISABLE_ARI (0x00000010)
|
||||
#define SDR_CONFIG_DISABLE_VSB (0x00000020)
|
||||
|
||||
/* SET FIR */
|
||||
#define SDR_FIR_COEFF_MASK (0x00000FFF)
|
||||
#define SDR_FIR_TAP_MASK (0x001F0000)
|
||||
#define SDR_FIR_SELECT_MASK (0x00C00000)
|
||||
#define SDR_VSB_LENGTH_MASK (0x01000000)
|
||||
|
||||
#define SDR_SET_FIR(select, tap, coeff, vsblen) \
|
||||
((((select) << 22) & SDR_FIR_SELECT_MASK) | \
|
||||
(((tap) << 16) & SDR_FIR_TAP_MASK) | \
|
||||
((coeff) & SDR_FIR_COEFF_MASK) | \
|
||||
(((vsblen) << 24) & SDR_VSB_LENGTH_MASK) | \
|
||||
0 \
|
||||
)
|
||||
|
||||
|
||||
521
ddbridge/ddbridge-sx8.c
Normal file
521
ddbridge/ddbridge-sx8.c
Normal file
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
* ddbridge-sx8.c: Digital Devices MAX SX8 driver
|
||||
*
|
||||
* Copyright (C) 2018 Digital Devices GmbH
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-io.h"
|
||||
#include "ddbridge-i2c.h"
|
||||
#include "ddbridge-mci.h"
|
||||
|
||||
static const u32 MCLK = (1550000000 / 12);
|
||||
static const u32 MAX_LDPC_BITRATE = (720000000);
|
||||
static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6);
|
||||
|
||||
#define SX8_TUNER_NUM 4
|
||||
#define SX8_DEMOD_NUM 8
|
||||
#define SX8_DEMOD_NONE 0xff
|
||||
|
||||
struct sx8_base {
|
||||
struct mci_base mci_base;
|
||||
|
||||
u8 tuner_use_count[SX8_TUNER_NUM];
|
||||
u32 gain_mode[SX8_TUNER_NUM];
|
||||
|
||||
u32 used_ldpc_bitrate[SX8_DEMOD_NUM];
|
||||
u8 demod_in_use[SX8_DEMOD_NUM];
|
||||
u32 iq_mode;
|
||||
u32 burst_size;
|
||||
u32 direct_mode;
|
||||
};
|
||||
|
||||
struct sx8 {
|
||||
struct mci mci;
|
||||
|
||||
int first_time_lock;
|
||||
int started;
|
||||
|
||||
u32 bb_mode;
|
||||
u32 local_frequency;
|
||||
|
||||
};
|
||||
|
||||
static const u8 dvbs2_bits_per_symbol[] = {
|
||||
0, 0, 0, 0,
|
||||
/* S2 QPSK */
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* S2 8PSK */
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3,
|
||||
/* S2 16APSK */
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4,
|
||||
/* S2 32APSK */
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 5,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
3, 0, 4, 0,
|
||||
2, 2, 2, 2, 2, 2, // S2X QPSK
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // S2X 8PSK
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // S2X 16APSK
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // S2X 32APSK
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // S2X 64APSK
|
||||
7, 7, 7, 7, // S2X 128APSK
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // S2X 256APSK
|
||||
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // S2X QPSK
|
||||
3, 3, 3, 3, 3, 3, 3, 3, // S2X 8PSK
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // S2X 16APSK
|
||||
5, 5, 5, 5, // S2X 32APSK
|
||||
|
||||
3, 4, 5, 6, 8, 10,
|
||||
};
|
||||
|
||||
|
||||
static void release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct sx8 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
|
||||
mci_base->count--;
|
||||
if (mci_base->count == 0) {
|
||||
list_del(&mci_base->mci_list);
|
||||
kfree(mci_base);
|
||||
}
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
|
||||
{
|
||||
int stat;
|
||||
struct sx8 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
struct mci_result res;
|
||||
|
||||
stat = ddb_mci_get_status(&state->mci, &res);
|
||||
if (stat)
|
||||
return stat;
|
||||
*status = 0x00;
|
||||
ddb_mci_get_info(&state->mci);
|
||||
if (res.status == SX8_DEMOD_WAIT_MATYPE)
|
||||
*status = 0x0f;
|
||||
if (res.status == SX8_DEMOD_LOCKED) {
|
||||
*status = 0x1f;
|
||||
if (state->mci.signal_info.dvbs2_signal_info.standard == 2) {
|
||||
sx8_base->used_ldpc_bitrate[state->mci.nr] =
|
||||
p->symbol_rate *
|
||||
dvbs2_bits_per_symbol[
|
||||
state->mci.signal_info.
|
||||
dvbs2_signal_info.pls_code];
|
||||
} else
|
||||
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on)
|
||||
{
|
||||
struct sx8 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
|
||||
struct mci_command cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.tuner = state->mci.tuner;
|
||||
cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE;
|
||||
cmd.sx8_input_enable.flags = sx8_base->gain_mode[state->mci.tuner];
|
||||
return ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
}
|
||||
|
||||
static int stop(struct dvb_frontend *fe)
|
||||
{
|
||||
struct sx8 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
|
||||
struct mci_command cmd;
|
||||
u32 input = state->mci.tuner;
|
||||
|
||||
if (!state->started)
|
||||
return -1;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
if (state->mci.demod != SX8_DEMOD_NONE) {
|
||||
cmd.command = MCI_CMD_STOP;
|
||||
cmd.demod = state->mci.demod;
|
||||
ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
if (sx8_base->iq_mode) {
|
||||
cmd.command = SX8_CMD_DISABLE_IQOUTPUT;
|
||||
cmd.demod = state->mci.demod;
|
||||
cmd.output = 0;
|
||||
ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
ddb_mci_config(&state->mci, SX8_TSCONFIG_MODE_NORMAL);
|
||||
}
|
||||
}
|
||||
mutex_lock(&mci_base->tuner_lock);
|
||||
sx8_base->tuner_use_count[input]--;
|
||||
if (!sx8_base->tuner_use_count[input])
|
||||
mci_set_tuner(fe, input, 0);
|
||||
if (state->mci.demod != SX8_DEMOD_NONE) {
|
||||
sx8_base->demod_in_use[state->mci.demod] = 0;
|
||||
state->mci.demod = SX8_DEMOD_NONE;
|
||||
}
|
||||
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
|
||||
sx8_base->iq_mode = 0;
|
||||
mutex_unlock(&mci_base->tuner_lock);
|
||||
state->started = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
|
||||
{
|
||||
struct sx8 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6);
|
||||
u32 used_ldpc_bitrate = 0, free_ldpc_bitrate;
|
||||
u32 used_demods = 0;
|
||||
struct mci_command cmd;
|
||||
u32 input = state->mci.tuner;
|
||||
u32 bits_per_symbol = 0;
|
||||
int i = -1, stat = 0;
|
||||
|
||||
if (p->symbol_rate >= MCLK / 2)
|
||||
flags &= ~1;
|
||||
if ((flags & 3) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (flags & 2) {
|
||||
u32 tmp = modmask;
|
||||
|
||||
bits_per_symbol = 1;
|
||||
while (tmp & 1) {
|
||||
tmp >>= 1;
|
||||
bits_per_symbol++;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&mci_base->tuner_lock);
|
||||
if (sx8_base->iq_mode) {
|
||||
stat = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (sx8_base->direct_mode) {
|
||||
if (p->symbol_rate >= MCLK / 2) {
|
||||
if (state->mci.nr < 4)
|
||||
i = state->mci.nr;
|
||||
} else {
|
||||
i = state->mci.nr;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < SX8_DEMOD_NUM; i++) {
|
||||
used_ldpc_bitrate += sx8_base->used_ldpc_bitrate[i];
|
||||
if (sx8_base->demod_in_use[i])
|
||||
used_demods++;
|
||||
}
|
||||
printk("used_ldpc_bitrate = %u\n", used_ldpc_bitrate);
|
||||
if ((used_ldpc_bitrate >= MAX_LDPC_BITRATE) ||
|
||||
((ts_config & SX8_TSCONFIG_MODE_MASK) >
|
||||
SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) {
|
||||
stat = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate;
|
||||
if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE)
|
||||
free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE;
|
||||
|
||||
while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate)
|
||||
bits_per_symbol--;
|
||||
if (bits_per_symbol < 2) {
|
||||
stat = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
modmask &= ((1 << (bits_per_symbol - 1)) - 1);
|
||||
if( ((flags & 0x02) != 0) && (modmask == 0)) {
|
||||
stat = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
i = (p->symbol_rate > MCLK / 2) ? 3 : 7;
|
||||
while (i >= 0 && sx8_base->demod_in_use[i])
|
||||
i--;
|
||||
}
|
||||
if (i < 0) {
|
||||
stat = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
sx8_base->demod_in_use[i] = 1;
|
||||
sx8_base->used_ldpc_bitrate[state->mci.nr] = p->symbol_rate * bits_per_symbol;
|
||||
state->mci.demod = i;
|
||||
|
||||
if (!sx8_base->tuner_use_count[input])
|
||||
mci_set_tuner(fe, input, 1);
|
||||
sx8_base->tuner_use_count[input]++;
|
||||
sx8_base->iq_mode = (ts_config > 1);
|
||||
unlock:
|
||||
mutex_unlock(&mci_base->tuner_lock);
|
||||
if (stat)
|
||||
return stat;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
if (sx8_base->iq_mode) {
|
||||
cmd.command = SX8_CMD_ENABLE_IQOUTPUT;
|
||||
cmd.demod = state->mci.demod;
|
||||
cmd.output = 0;
|
||||
ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
ddb_mci_config(&state->mci, ts_config);
|
||||
}
|
||||
if (p->stream_id != NO_STREAM_ID_FILTER && p->stream_id != 0x80000000)
|
||||
flags |= 0x80;
|
||||
printk("frontend %u: tuner=%u demod=%u\n", state->mci.nr, state->mci.tuner, state->mci.demod);
|
||||
cmd.command = MCI_CMD_SEARCH_DVBS;
|
||||
cmd.dvbs2_search.flags = flags;
|
||||
cmd.dvbs2_search.s2_modulation_mask = modmask;
|
||||
cmd.dvbs2_search.retry = 2;
|
||||
cmd.dvbs2_search.frequency = p->frequency * 1000;
|
||||
cmd.dvbs2_search.symbol_rate = p->symbol_rate;
|
||||
cmd.dvbs2_search.scrambling_sequence_index =
|
||||
p->scrambling_sequence_index | 0x80000000;
|
||||
cmd.dvbs2_search.input_stream_id = p->stream_id;
|
||||
cmd.tuner = state->mci.tuner;
|
||||
cmd.demod = state->mci.demod;
|
||||
cmd.output = state->mci.nr;
|
||||
if (p->stream_id == 0x80000000)
|
||||
cmd.output |= 0x80;
|
||||
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
if (stat)
|
||||
stop(fe);
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
||||
static int start_iq(struct dvb_frontend *fe, u32 flags,
|
||||
u32 roll_off, u32 ts_config)
|
||||
{
|
||||
struct sx8 *state = fe->demodulator_priv;
|
||||
struct mci_base *mci_base = state->mci.base;
|
||||
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
u32 used_demods = 0;
|
||||
struct mci_command cmd;
|
||||
u32 input = state->mci.tuner;
|
||||
int i, stat = 0;
|
||||
|
||||
mutex_lock(&mci_base->tuner_lock);
|
||||
if (sx8_base->iq_mode) {
|
||||
stat = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
for (i = 0; i < SX8_DEMOD_NUM; i++)
|
||||
if (sx8_base->demod_in_use[i])
|
||||
used_demods++;
|
||||
if (used_demods > 0) {
|
||||
stat = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
state->mci.demod = 0;
|
||||
if (!sx8_base->tuner_use_count[input])
|
||||
mci_set_tuner(fe, input, 1);
|
||||
sx8_base->tuner_use_count[input]++;
|
||||
sx8_base->iq_mode = (ts_config > 1);
|
||||
unlock:
|
||||
mutex_unlock(&mci_base->tuner_lock);
|
||||
if (stat)
|
||||
return stat;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.command = SX8_CMD_START_IQ;
|
||||
cmd.sx8_start_iq.flags = flags;
|
||||
cmd.sx8_start_iq.roll_off = roll_off;
|
||||
cmd.sx8_start_iq.frequency = p->frequency * 1000;
|
||||
cmd.sx8_start_iq.symbol_rate = p->symbol_rate;
|
||||
cmd.tuner = state->mci.tuner;
|
||||
cmd.demod = state->mci.demod;
|
||||
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
|
||||
if (stat)
|
||||
stop(fe);
|
||||
ddb_mci_config(&state->mci, ts_config);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int set_parameters(struct dvb_frontend *fe)
|
||||
{
|
||||
int stat = 0;
|
||||
struct sx8 *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
u32 ts_config = SX8_TSCONFIG_MODE_NORMAL, iq_mode = 0, isi;
|
||||
|
||||
stop(fe);
|
||||
isi = p->stream_id;
|
||||
if (isi != NO_STREAM_ID_FILTER) {
|
||||
iq_mode = (isi & 0x30000000) >> 28;
|
||||
}
|
||||
if (iq_mode)
|
||||
ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
|
||||
if (iq_mode < 2) {
|
||||
u32 mask;
|
||||
|
||||
switch (p->modulation) {
|
||||
case APSK_256:
|
||||
mask = 0x7f;
|
||||
break;
|
||||
case APSK_128:
|
||||
mask = 0x3f;
|
||||
break;
|
||||
case APSK_64:
|
||||
mask = 0x1f;
|
||||
break;
|
||||
case APSK_32:
|
||||
mask = 0x0f;
|
||||
break;
|
||||
case APSK_16:
|
||||
mask = 0x07;
|
||||
break;
|
||||
default:
|
||||
mask = 0x03;
|
||||
break;
|
||||
}
|
||||
stat = start(fe, 3, mask, ts_config);
|
||||
} else {
|
||||
stat = start_iq(fe, iq_mode & 1, 4, ts_config);
|
||||
}
|
||||
if (!stat) {
|
||||
state->started = 1;
|
||||
state->first_time_lock = 1;
|
||||
state->mci.signal_info.status = SX8_DEMOD_WAIT_SIGNAL;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int tune(struct dvb_frontend *fe, bool re_tune,
|
||||
unsigned int mode_flags,
|
||||
unsigned int *delay, enum fe_status *status)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (re_tune) {
|
||||
r = set_parameters(fe);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
r = read_status(fe, status);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (*status & FE_HAS_LOCK)
|
||||
return 0;
|
||||
*delay = HZ / 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
return DVBFE_ALGO_HW;
|
||||
}
|
||||
|
||||
static int set_input(struct dvb_frontend *fe, int input)
|
||||
{
|
||||
struct sx8 *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
|
||||
printk("fe %u, set input = %u\n", state->mci.nr, input);
|
||||
if (input >= SX8_TUNER_NUM)
|
||||
return -EINVAL;
|
||||
if (state->mci.tuner == input)
|
||||
return 0;
|
||||
stop(fe);
|
||||
state->mci.tuner = p->input = input;
|
||||
printk("fe %u, input = %u\n", state->mci.nr, input);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
stop(fe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
|
||||
{
|
||||
struct sx8 *state = fe->demodulator_priv;
|
||||
|
||||
ddb_mci_proc_info(&state->mci, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops sx8_ops = {
|
||||
.delsys = { SYS_DVBS, SYS_DVBS2 },
|
||||
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
|
||||
.info = {
|
||||
.name = "DVB-S/S2X",
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = 0,
|
||||
.frequency_tolerance = 0,
|
||||
.symbol_rate_min = 100000,
|
||||
.symbol_rate_max = 100000000,
|
||||
.caps = FE_CAN_INVERSION_AUTO |
|
||||
FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QPSK |
|
||||
FE_CAN_2G_MODULATION |
|
||||
FE_CAN_MULTISTREAM,
|
||||
},
|
||||
.get_frontend_algo = get_algo,
|
||||
.get_frontend = get_frontend,
|
||||
.tune = tune,
|
||||
.release = release,
|
||||
.read_status = read_status,
|
||||
.set_input = set_input,
|
||||
.sleep = sleep,
|
||||
};
|
||||
|
||||
static int init(struct mci *mci)
|
||||
{
|
||||
struct sx8 *state = (struct sx8 *) mci;
|
||||
|
||||
state->mci.demod = SX8_DEMOD_NONE;
|
||||
mci->fe.ops.xbar[1] = mci->nr;
|
||||
mci->fe.dtv_property_cache.input = mci->tuner;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int base_init(struct mci_base *mci_base)
|
||||
{
|
||||
//struct sx8_base *base = (struct sx8_base *) mci_base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mci_cfg ddb_max_sx8_cfg = {
|
||||
.type = 0,
|
||||
.fe_ops = &sx8_ops,
|
||||
.base_size = sizeof(struct sx8_base),
|
||||
.state_size = sizeof(struct sx8),
|
||||
.init = init,
|
||||
.base_init = base_init,
|
||||
};
|
||||
@@ -1,626 +0,0 @@
|
||||
/*
|
||||
* ddbridge.c: Digital Devices PCIe bridge driver
|
||||
*
|
||||
* Copyright (C) 2010-2015 Digital Devices GmbH
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#define DDB_USE_WORK
|
||||
/*#define DDB_TEST_THREADED*/
|
||||
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-regs.h"
|
||||
|
||||
static struct workqueue_struct *ddb_wq;
|
||||
|
||||
static int adapter_alloc;
|
||||
module_param(adapter_alloc, int, 0444);
|
||||
MODULE_PARM_DESC(adapter_alloc,
|
||||
"0-one adapter per io, 1-one per tab with io, 2-one per tab, 3-one for all");
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
static int msi = 1;
|
||||
module_param(msi, int, 0444);
|
||||
MODULE_PARM_DESC(msi,
|
||||
" Control MSI interrupts: 0-disable, 1-enable (default)");
|
||||
#endif
|
||||
|
||||
#include "ddbridge-core.c"
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
static void ddb_unmap(struct ddb *dev)
|
||||
{
|
||||
if (dev->regs)
|
||||
iounmap(dev->regs);
|
||||
vfree(dev);
|
||||
}
|
||||
|
||||
static void __devexit ddb_irq_disable(struct ddb *dev)
|
||||
{
|
||||
if (dev->link[0].info->regmap->irq_version == 2) {
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_CONTROL);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_1);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_2);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_3);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_4);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_5);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_6);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_7);
|
||||
} else {
|
||||
ddbwritel(dev, 0, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0, MSI1_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void __devexit ddb_irq_exit(struct ddb *dev)
|
||||
{
|
||||
ddb_irq_disable(dev);
|
||||
if (dev->msi == 2)
|
||||
free_irq(dev->pdev->irq + 1, dev);
|
||||
free_irq(dev->pdev->irq, dev);
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
if (dev->msi)
|
||||
pci_disable_msi(dev->pdev);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __devexit ddb_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev);
|
||||
|
||||
ddb_device_destroy(dev);
|
||||
ddb_nsd_detach(dev);
|
||||
ddb_ports_detach(dev);
|
||||
ddb_i2c_release(dev);
|
||||
|
||||
if (dev->link[0].info->ns_num)
|
||||
ddbwritel(dev, 0, ETHER_CONTROL);
|
||||
ddb_irq_exit(dev);
|
||||
ddb_ports_release(dev);
|
||||
ddb_buffers_free(dev);
|
||||
|
||||
ddb_unmap(dev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
|
||||
#define __devinit
|
||||
#define __devinitdata
|
||||
#endif
|
||||
|
||||
static int __devinit ddb_irq_msi(struct ddb *dev, int nr)
|
||||
{
|
||||
int stat;
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
if (msi && pci_msi_enabled()) {
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
|
||||
stat = pci_enable_msi_range(dev->pdev, 1, nr);
|
||||
if (stat >= 1) {
|
||||
dev->msi = stat;
|
||||
pr_info("DDBridge: using %d MSI interrupt(s)\n",
|
||||
dev->msi);
|
||||
} else
|
||||
pr_info("DDBridge: MSI not available.\n");
|
||||
|
||||
#else
|
||||
stat = pci_enable_msi_block(dev->pdev, nr);
|
||||
if (stat == 0) {
|
||||
dev->msi = nr;
|
||||
pr_info("DDBridge: using %d MSI interrupts\n", nr);
|
||||
} else if (stat == 1) {
|
||||
stat = pci_enable_msi(dev->pdev);
|
||||
dev->msi = 1;
|
||||
}
|
||||
if (stat < 0)
|
||||
pr_info("DDBridge: MSI not available.\n");
|
||||
#endif
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int __devinit ddb_irq_init2(struct ddb *dev)
|
||||
{
|
||||
int stat;
|
||||
int irq_flag = IRQF_SHARED;
|
||||
|
||||
pr_info("init type 2 IRQ hardware block\n");
|
||||
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_CONTROL);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_1);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_2);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_3);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_4);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_5);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_6);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_7);
|
||||
|
||||
ddb_irq_msi(dev, 1);
|
||||
if (dev->msi)
|
||||
irq_flag = 0;
|
||||
|
||||
stat = request_irq(dev->pdev->irq, irq_handler_v2,
|
||||
irq_flag, "ddbridge", (void *) dev);
|
||||
if (stat < 0)
|
||||
return stat;
|
||||
|
||||
ddbwritel(dev, 0x0000ff7f, INTERRUPT_V2_CONTROL);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_1);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_2);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_3);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_4);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_5);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_6);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_7);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int __devinit ddb_irq_init(struct ddb *dev)
|
||||
{
|
||||
int stat;
|
||||
int irq_flag = IRQF_SHARED;
|
||||
|
||||
if (dev->link[0].info->regmap->irq_version == 2)
|
||||
return ddb_irq_init2(dev);
|
||||
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI2_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI3_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI4_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI5_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI6_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI7_ENABLE);
|
||||
|
||||
ddb_irq_msi(dev, 2);
|
||||
|
||||
if (dev->msi)
|
||||
irq_flag = 0;
|
||||
if (dev->msi == 2) {
|
||||
stat = request_irq(dev->pdev->irq, irq_handler0,
|
||||
irq_flag, "ddbridge", (void *) dev);
|
||||
if (stat < 0)
|
||||
return stat;
|
||||
stat = request_irq(dev->pdev->irq + 1, irq_handler1,
|
||||
irq_flag, "ddbridge", (void *) dev);
|
||||
if (stat < 0) {
|
||||
free_irq(dev->pdev->irq, dev);
|
||||
return stat;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
#ifdef DDB_TEST_THREADED
|
||||
stat = request_threaded_irq(dev->pdev->irq, irq_handler,
|
||||
irq_thread,
|
||||
irq_flag,
|
||||
"ddbridge", (void *) dev);
|
||||
#else
|
||||
stat = request_irq(dev->pdev->irq, irq_handler,
|
||||
irq_flag, "ddbridge", (void *) dev);
|
||||
#endif
|
||||
if (stat < 0)
|
||||
return stat;
|
||||
}
|
||||
/*ddbwritel(dev, 0xffffffff, INTERRUPT_ACK);*/
|
||||
if (dev->msi == 2) {
|
||||
ddbwritel(dev, 0x0fffff00, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0x0000000f, MSI1_ENABLE);
|
||||
} else {
|
||||
ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int __devinit ddb_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct ddb *dev;
|
||||
int stat = 0;
|
||||
|
||||
if (pci_enable_device(pdev) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
|
||||
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
|
||||
return -ENODEV;
|
||||
|
||||
dev = vzalloc(sizeof(struct ddb));
|
||||
if (dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&dev->mutex);
|
||||
dev->has_dma = 1;
|
||||
dev->pdev = pdev;
|
||||
dev->dev = &pdev->dev;
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
dev->link[0].ids.vendor = id->vendor;
|
||||
dev->link[0].ids.device = id->device;
|
||||
dev->link[0].ids.subvendor = id->subvendor;
|
||||
dev->link[0].ids.subdevice = id->subdevice;
|
||||
|
||||
dev->link[0].dev = dev;
|
||||
dev->link[0].info = (struct ddb_info *) id->driver_data;
|
||||
pr_info("DDBridge driver detected: %s\n", dev->link[0].info->name);
|
||||
|
||||
dev->regs_len = pci_resource_len(dev->pdev, 0);
|
||||
dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
|
||||
pci_resource_len(dev->pdev, 0));
|
||||
|
||||
if (!dev->regs) {
|
||||
pr_err("DDBridge: not enough memory for register map\n");
|
||||
stat = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (ddbreadl(dev, 0) == 0xffffffff) {
|
||||
pr_err("DDBridge: cannot read registers\n");
|
||||
stat = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev->link[0].ids.hwid = ddbreadl(dev, 0);
|
||||
dev->link[0].ids.regmapid = ddbreadl(dev, 4);
|
||||
|
||||
pr_info("DDBridge: HW %08x REGMAP %08x\n",
|
||||
dev->link[0].ids.hwid, dev->link[0].ids.regmapid);
|
||||
|
||||
if (dev->link[0].info->ns_num) {
|
||||
ddbwritel(dev, 0, ETHER_CONTROL);
|
||||
ddb_reset_ios(dev);
|
||||
}
|
||||
ddbwritel(dev, 0, DMA_BASE_READ);
|
||||
if (dev->link[0].info->type != DDB_MOD)
|
||||
ddbwritel(dev, 0, DMA_BASE_WRITE);
|
||||
|
||||
if (dev->link[0].info->type == DDB_MOD) {
|
||||
if (ddbreadl(dev, 0x1c) == 4)
|
||||
dev->link[0].info->port_num = 4;
|
||||
}
|
||||
|
||||
stat = ddb_irq_init(dev);
|
||||
if (stat < 0)
|
||||
goto fail0;
|
||||
|
||||
if (ddb_init(dev) == 0)
|
||||
return 0;
|
||||
|
||||
ddb_irq_disable(dev);
|
||||
fail0:
|
||||
pr_err("fail0\n");
|
||||
if (dev->msi)
|
||||
pci_disable_msi(dev->pdev);
|
||||
fail:
|
||||
pr_err("fail\n");
|
||||
|
||||
ddb_unmap(dev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
pci_disable_device(pdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
static struct ddb_info ddb_none = {
|
||||
.type = DDB_NONE,
|
||||
.name = "unknown Digital Devices PCIe card, install newer driver",
|
||||
.regmap = &octopus_map,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopus = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopusv3 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus V3 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopus_le = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus LE DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 2,
|
||||
.i2c_mask = 0x03,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopus_oem = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus OEM",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.led_num = 1,
|
||||
.fan_num = 1,
|
||||
.temp_num = 1,
|
||||
.temp_bus = 0,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopus_mini = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus Mini",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_v6 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine S2 V6 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x07,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_v6_5 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine S2 V6.5 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_v7 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine S2 V7 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 2,
|
||||
.board_control_2 = 4,
|
||||
.ts_quirks = TS_QUIRK_REVERSED,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_ctv7 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine CT V7 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 3,
|
||||
.board_control_2 = 4,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_satixS2v3 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Mystique SaTiX-S2 V3 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x07,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_ci = {
|
||||
.type = DDB_OCTOPUS_CI,
|
||||
.name = "Digital Devices Octopus CI",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x03,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_cis = {
|
||||
.type = DDB_OCTOPUS_CI,
|
||||
.name = "Digital Devices Octopus CI single",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x03,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_ci_s2_pro = {
|
||||
.type = DDB_OCTOPUS_CI,
|
||||
.name = "Digital Devices Octopus CI S2 Pro",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x01,
|
||||
.board_control = 2,
|
||||
.board_control_2 = 4,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_dvbct = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices DVBCT V6.1 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x07,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static struct ddb_info ddb_mod = {
|
||||
.type = DDB_MOD,
|
||||
.name = "Digital Devices DVB-C modulator",
|
||||
.regmap = &octopus_mod_map,
|
||||
.port_num = 10,
|
||||
.temp_num = 1,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_mod_fsm_24 = {
|
||||
.type = DDB_MOD,
|
||||
.version = 2,
|
||||
.name = "Digital Devices DVB-C modulator FSM-24",
|
||||
.regmap = &octopus_mod_2_map,
|
||||
.port_num = 24,
|
||||
.temp_num = 1,
|
||||
.tempmon_irq = 8,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_mod_fsm_16 = {
|
||||
.type = DDB_MOD,
|
||||
.version = 2,
|
||||
.name = "Digital Devices DVB-C modulator FSM-16",
|
||||
.regmap = &octopus_mod_2_map,
|
||||
.port_num = 16,
|
||||
.temp_num = 1,
|
||||
.tempmon_irq = 8,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_mod_fsm_8 = {
|
||||
.type = DDB_MOD,
|
||||
.name = "Digital Devices DVB-C modulator FSM-8",
|
||||
.version = 2,
|
||||
.regmap = &octopus_mod_2_map,
|
||||
.port_num = 8,
|
||||
.temp_num = 1,
|
||||
.tempmon_irq = 8,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopro_hdin = {
|
||||
.type = DDB_OCTOPRO_HDIN,
|
||||
.name = "Digital Devices OctopusNet Pro HDIN",
|
||||
.regmap = &octopro_hdin_map,
|
||||
.port_num = 10,
|
||||
.i2c_mask = 0x3ff,
|
||||
.mdio_num = 1,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopro = {
|
||||
.type = DDB_OCTOPRO,
|
||||
.name = "Digital Devices OctopusNet Pro",
|
||||
.regmap = &octopro_map,
|
||||
.port_num = 10,
|
||||
.i2c_mask = 0x3ff,
|
||||
.mdio_num = 1,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
#define DDVID 0xdd01 /* Digital Devices Vendor ID */
|
||||
|
||||
#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \
|
||||
.vendor = _vend, .device = _dev, \
|
||||
.subvendor = _subvend, .subdevice = _subdev, \
|
||||
.driver_data = (unsigned long)&_driverdata }
|
||||
|
||||
static const struct pci_device_id ddb_id_tbl[] __devinitconst = {
|
||||
DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus),
|
||||
DDB_ID(DDVID, 0x0005, DDVID, 0x0004, ddb_octopusv3),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0003, ddb_octopus_oem),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus_mini),
|
||||
DDB_ID(DDVID, 0x0005, DDVID, 0x0011, ddb_octopus_mini),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0021, ddb_v6_5),
|
||||
DDB_ID(DDVID, 0x0006, DDVID, 0x0022, ddb_v7),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0030, ddb_dvbct),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0xdb03, ddb_satixS2v3),
|
||||
DDB_ID(DDVID, 0x0006, DDVID, 0x0031, ddb_ctv7),
|
||||
DDB_ID(DDVID, 0x0006, DDVID, 0x0032, ddb_ctv7),
|
||||
DDB_ID(DDVID, 0x0006, DDVID, 0x0033, ddb_ctv7),
|
||||
DDB_ID(DDVID, 0x0007, DDVID, 0x0023, ddb_s2_48),
|
||||
DDB_ID(DDVID, 0x0008, DDVID, 0x0034, ddb_ct2_8),
|
||||
DDB_ID(DDVID, 0x0008, DDVID, 0x0035, ddb_c2t2_8),
|
||||
DDB_ID(DDVID, 0x0008, DDVID, 0x0036, ddb_isdbt_8),
|
||||
DDB_ID(DDVID, 0x0008, DDVID, 0x0037, ddb_c2t2i_v0_8),
|
||||
DDB_ID(DDVID, 0x0008, DDVID, 0x0038, ddb_c2t2i_8),
|
||||
DDB_ID(DDVID, 0x0011, DDVID, 0x0040, ddb_ci),
|
||||
DDB_ID(DDVID, 0x0011, DDVID, 0x0041, ddb_cis),
|
||||
DDB_ID(DDVID, 0x0012, DDVID, 0x0042, ddb_ci),
|
||||
DDB_ID(DDVID, 0x0013, DDVID, 0x0043, ddb_ci_s2_pro),
|
||||
DDB_ID(DDVID, 0x0201, DDVID, 0x0001, ddb_mod),
|
||||
DDB_ID(DDVID, 0x0201, DDVID, 0x0002, ddb_mod),
|
||||
DDB_ID(DDVID, 0x0203, DDVID, 0x0001, ddb_mod),
|
||||
DDB_ID(DDVID, 0x0210, DDVID, 0x0001, ddb_mod_fsm_24),
|
||||
DDB_ID(DDVID, 0x0210, DDVID, 0x0002, ddb_mod_fsm_16),
|
||||
DDB_ID(DDVID, 0x0210, DDVID, 0x0003, ddb_mod_fsm_8),
|
||||
/* testing on OctopusNet Pro */
|
||||
DDB_ID(DDVID, 0x0320, PCI_ANY_ID, PCI_ANY_ID, ddb_octopro_hdin),
|
||||
DDB_ID(DDVID, 0x0321, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0322, PCI_ANY_ID, PCI_ANY_ID, ddb_octopro),
|
||||
DDB_ID(DDVID, 0x0323, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0328, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0329, PCI_ANY_ID, PCI_ANY_ID, ddb_octopro_hdin),
|
||||
/* in case sub-ids got deleted in flash */
|
||||
DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0005, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0006, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0007, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0008, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0011, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0013, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0201, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0320, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
{0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ddb_id_tbl);
|
||||
|
||||
static struct pci_driver ddb_pci_driver = {
|
||||
.name = "ddbridge",
|
||||
.id_table = ddb_id_tbl,
|
||||
.probe = ddb_probe,
|
||||
.remove = ddb_remove,
|
||||
};
|
||||
|
||||
static __init int module_init_ddbridge(void)
|
||||
{
|
||||
int stat = -1;
|
||||
|
||||
pr_info("Digital Devices PCIE bridge driver "
|
||||
DDBRIDGE_VERSION
|
||||
", Copyright (C) 2010-16 Digital Devices GmbH\n");
|
||||
if (ddb_class_create() < 0)
|
||||
return -1;
|
||||
ddb_wq = create_workqueue("ddbridge");
|
||||
if (ddb_wq == NULL)
|
||||
goto exit1;
|
||||
stat = pci_register_driver(&ddb_pci_driver);
|
||||
if (stat < 0)
|
||||
goto exit2;
|
||||
return stat;
|
||||
exit2:
|
||||
destroy_workqueue(ddb_wq);
|
||||
exit1:
|
||||
ddb_class_destroy();
|
||||
return stat;
|
||||
}
|
||||
|
||||
static __exit void module_exit_ddbridge(void)
|
||||
{
|
||||
pci_unregister_driver(&ddb_pci_driver);
|
||||
destroy_workqueue(ddb_wq);
|
||||
ddb_class_destroy();
|
||||
}
|
||||
|
||||
module_init(module_init_ddbridge);
|
||||
module_exit(module_exit_ddbridge);
|
||||
|
||||
MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
|
||||
MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DDBRIDGE_VERSION);
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ddbridge.h: Digital Devices PCIe bridge driver
|
||||
*
|
||||
* Copyright (C) 2010-2015 Digital Devices GmbH
|
||||
* Copyright (C) 2010-2017 Digital Devices GmbH
|
||||
* Ralph Metzler <rmetzler@digitaldevices.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -16,18 +16,19 @@
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#ifndef _DDBRIDGE_H_
|
||||
#define _DDBRIDGE_H_
|
||||
|
||||
#define DDB_USE_WORK
|
||||
/*#define DDB_TEST_THREADED*/
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
|
||||
#if (KERNEL_VERSION(3, 8, 0) <= LINUX_VERSION_CODE)
|
||||
#define __devexit
|
||||
#define __devinit
|
||||
#define __devinitconst
|
||||
@@ -55,7 +56,6 @@
|
||||
#include <linux/completion.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/dma.h>
|
||||
@@ -91,6 +91,9 @@
|
||||
#include "lnbh25.h"
|
||||
#include "mxl5xx.h"
|
||||
|
||||
#include "ddbridge-regs.h"
|
||||
#include "ddbridge-mci.h"
|
||||
|
||||
#define DDB_MAX_I2C 32
|
||||
#define DDB_MAX_PORT 32
|
||||
#define DDB_MAX_INPUT 64
|
||||
@@ -98,7 +101,7 @@
|
||||
#define DDB_MAX_LINK 4
|
||||
#define DDB_LINK_SHIFT 28
|
||||
|
||||
#define DDB_LINK_TAG(_x) (_x << DDB_LINK_SHIFT)
|
||||
#define DDB_LINK_TAG(_x) ((_x) << DDB_LINK_SHIFT)
|
||||
|
||||
struct ddb_regset {
|
||||
u32 base;
|
||||
@@ -114,22 +117,18 @@ struct ddb_regmap {
|
||||
u32 irq_base_gtl;
|
||||
u32 irq_base_rate;
|
||||
|
||||
struct ddb_regset *i2c;
|
||||
struct ddb_regset *i2c_buf;
|
||||
struct ddb_regset *idma;
|
||||
struct ddb_regset *idma_buf;
|
||||
struct ddb_regset *odma;
|
||||
struct ddb_regset *odma_buf;
|
||||
const struct ddb_regset *i2c;
|
||||
const struct ddb_regset *i2c_buf;
|
||||
const struct ddb_regset *idma;
|
||||
const struct ddb_regset *idma_buf;
|
||||
const struct ddb_regset *odma;
|
||||
const struct ddb_regset *odma_buf;
|
||||
|
||||
struct ddb_regset *input;
|
||||
struct ddb_regset *output;
|
||||
|
||||
struct ddb_regset *channel;
|
||||
//struct ddb_regset *ci;
|
||||
//struct ddb_regset *pid_filter;
|
||||
//struct ddb_regset *ns;
|
||||
struct ddb_regset *gtl;
|
||||
//struct ddb_regset *mdio;
|
||||
const struct ddb_regset *input;
|
||||
const struct ddb_regset *output;
|
||||
|
||||
const struct ddb_regset *channel;
|
||||
const struct ddb_regset *gtl;
|
||||
};
|
||||
|
||||
struct ddb_ids {
|
||||
@@ -146,58 +145,47 @@ struct ddb_ids {
|
||||
|
||||
struct ddb_info {
|
||||
u32 type;
|
||||
#define DDB_NONE 0
|
||||
#define DDB_OCTOPUS 1
|
||||
#define DDB_OCTOPUS_CI 2
|
||||
#define DDB_MOD 3
|
||||
#define DDB_OCTONET 4
|
||||
#define DDB_OCTOPUS_MAX 5
|
||||
#define DDB_OCTOPUS_MAX_CT 6
|
||||
#define DDB_OCTOPRO 7
|
||||
#define DDB_OCTOPRO_HDIN 8
|
||||
#define DDB_NONE 0
|
||||
#define DDB_OCTOPUS 1
|
||||
#define DDB_OCTOPUS_CI 2
|
||||
#define DDB_MOD 3
|
||||
#define DDB_OCTONET 4
|
||||
#define DDB_OCTOPUS_MAX 5
|
||||
#define DDB_OCTOPUS_MAX_CT 6
|
||||
#define DDB_OCTOPRO 7
|
||||
#define DDB_OCTOPRO_HDIN 8
|
||||
#define DDB_OCTOPUS_MCI 9
|
||||
u32 version;
|
||||
char *name;
|
||||
u32 i2c_mask;
|
||||
u32 board_control;
|
||||
u32 board_control_2;
|
||||
|
||||
u8 port_num;
|
||||
u8 led_num;
|
||||
u8 fan_num;
|
||||
u8 temp_num;
|
||||
u8 temp_bus;
|
||||
u32 board_control;
|
||||
u32 board_control_2;
|
||||
u8 ns_num;
|
||||
u8 mdio_num;
|
||||
u8 con_clock; /* use a continuous clock */
|
||||
u8 ts_quirks;
|
||||
#define TS_QUIRK_SERIAL 1
|
||||
#define TS_QUIRK_REVERSED 2
|
||||
#define TS_QUIRK_NO_OUTPUT 4
|
||||
u32 tempmon_irq;
|
||||
struct ddb_regmap *regmap;
|
||||
#define TS_QUIRK_ALT_OSC 8
|
||||
u8 mci_ports;
|
||||
u8 mci_type;
|
||||
|
||||
u32 tempmon_irq;
|
||||
u32 lostlock_irq;
|
||||
u32 mdio_base;
|
||||
u32 hw_min;
|
||||
const struct ddb_regmap *regmap;
|
||||
};
|
||||
|
||||
/* DMA_SIZE MUST be smaller than 256k and
|
||||
MUST be divisible by 188 and 128 !!! */
|
||||
|
||||
#define DMA_MAX_BUFS 32 /* hardware table limit */
|
||||
|
||||
#ifdef SMALL_DMA_BUFS
|
||||
#define INPUT_DMA_BUFS 32
|
||||
#define INPUT_DMA_SIZE (32*47*21)
|
||||
#define INPUT_DMA_IRQ_DIV 1
|
||||
|
||||
#define OUTPUT_DMA_BUFS 32
|
||||
#define OUTPUT_DMA_SIZE (32*47*21)
|
||||
#define OUTPUT_DMA_IRQ_DIV 1
|
||||
#else
|
||||
#define INPUT_DMA_BUFS 8
|
||||
#define INPUT_DMA_SIZE (128*47*21)
|
||||
#define INPUT_DMA_IRQ_DIV 1
|
||||
|
||||
#define OUTPUT_DMA_BUFS 8
|
||||
#define OUTPUT_DMA_SIZE (128*47*21)
|
||||
#define OUTPUT_DMA_IRQ_DIV 1
|
||||
#endif
|
||||
#define OUTPUT_DMA_BUFS_SDR 32
|
||||
#define OUTPUT_DMA_SIZE_SDR (256 * 1024)
|
||||
|
||||
struct ddb;
|
||||
struct ddb_port;
|
||||
@@ -219,7 +207,7 @@ struct ddb_dma {
|
||||
#else
|
||||
struct tasklet_struct tasklet;
|
||||
#endif
|
||||
spinlock_t lock;
|
||||
spinlock_t lock; /* DMA lock */
|
||||
wait_queue_head_t wq;
|
||||
int running;
|
||||
u32 stat;
|
||||
@@ -244,11 +232,12 @@ struct ddb_dvb {
|
||||
u32 attached;
|
||||
u8 input;
|
||||
|
||||
fe_sec_tone_mode_t tone;
|
||||
fe_sec_voltage_t voltage;
|
||||
enum fe_sec_tone_mode tone;
|
||||
enum fe_sec_voltage voltage;
|
||||
|
||||
int (*i2c_gate_ctrl)(struct dvb_frontend *, int);
|
||||
int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
|
||||
int (*set_voltage)(struct dvb_frontend *fe,
|
||||
enum fe_sec_voltage voltage);
|
||||
int (*set_input)(struct dvb_frontend *fe, int input);
|
||||
int (*diseqc_send_master_cmd)(struct dvb_frontend *fe,
|
||||
struct dvb_diseqc_master_cmd *cmd);
|
||||
@@ -258,7 +247,6 @@ struct ddb_ci {
|
||||
struct dvb_ca_en50221 en;
|
||||
struct ddb_port *port;
|
||||
u32 nr;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
struct ddb_io {
|
||||
@@ -292,7 +280,7 @@ struct ddb_port {
|
||||
u32 regs;
|
||||
u32 lnr;
|
||||
struct ddb_i2c *i2c;
|
||||
struct mutex i2c_gate_lock;
|
||||
struct mutex i2c_gate_lock; /* I2C access lock */
|
||||
u32 class;
|
||||
#define DDB_PORT_NONE 0
|
||||
#define DDB_PORT_CI 1
|
||||
@@ -302,6 +290,7 @@ struct ddb_port {
|
||||
char *name;
|
||||
char *type_name;
|
||||
u32 type;
|
||||
#define DDB_TUNER_DUMMY 0xffffffff
|
||||
#define DDB_TUNER_NONE 0
|
||||
#define DDB_TUNER_DVBS_ST 1
|
||||
#define DDB_TUNER_DVBS_ST_AA 2
|
||||
@@ -317,6 +306,7 @@ struct ddb_port {
|
||||
#define DDB_CI_EXTERNAL_XO2 12
|
||||
#define DDB_CI_EXTERNAL_XO2_B 13
|
||||
#define DDB_TUNER_DVBS_STV0910_PR 14
|
||||
#define DDB_TUNER_DVBC2T2I_SONY_P 15
|
||||
|
||||
#define DDB_TUNER_XO2 32
|
||||
#define DDB_TUNER_DVBS_STV0910 (DDB_TUNER_XO2 + 0)
|
||||
@@ -324,7 +314,11 @@ struct ddb_port {
|
||||
#define DDB_TUNER_ISDBT_SONY (DDB_TUNER_XO2 + 2)
|
||||
#define DDB_TUNER_DVBC2T2_SONY (DDB_TUNER_XO2 + 3)
|
||||
#define DDB_TUNER_ATSC_ST (DDB_TUNER_XO2 + 4)
|
||||
#define DDB_TUNER_DVBC2T2_ST (DDB_TUNER_XO2 + 5)
|
||||
#define DDB_TUNER_DVBC2T2I_SONY (DDB_TUNER_XO2 + 5)
|
||||
|
||||
#define DDB_TUNER_MCI 48
|
||||
#define DDB_TUNER_MCI_SX8 (DDB_TUNER_MCI + 0)
|
||||
#define DDB_TUNER_MCI_M4 (DDB_TUNER_MCI + 1)
|
||||
|
||||
struct ddb_input *input[2];
|
||||
struct ddb_output *output;
|
||||
@@ -343,13 +337,11 @@ struct mod_base {
|
||||
|
||||
struct ddb_mod {
|
||||
struct ddb_port *port;
|
||||
u32 nr;
|
||||
u32 regs;
|
||||
|
||||
|
||||
u32 frequency;
|
||||
u32 modulation;
|
||||
u32 symbolrate;
|
||||
|
||||
|
||||
u64 obitrate;
|
||||
u64 ibitrate;
|
||||
u32 pcr_correction;
|
||||
@@ -403,28 +395,34 @@ struct ddb_ns {
|
||||
};
|
||||
|
||||
struct ddb_lnb {
|
||||
struct mutex lock;
|
||||
struct mutex lock; /* lock lnb access */
|
||||
u32 tone;
|
||||
fe_sec_voltage_t oldvoltage[4];
|
||||
enum fe_sec_voltage oldvoltage[4];
|
||||
u32 voltage[4];
|
||||
u32 voltages;
|
||||
u32 fmode;
|
||||
};
|
||||
|
||||
struct ddb_irq {
|
||||
void (*handler)(void *);
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct ddb_link {
|
||||
struct ddb *dev;
|
||||
struct ddb_info *info;
|
||||
const struct ddb_info *info;
|
||||
u32 nr;
|
||||
u32 regs;
|
||||
spinlock_t lock;
|
||||
struct mutex flash_mutex;
|
||||
spinlock_t lock; /* lock link access */
|
||||
struct mutex flash_mutex; /* lock flash access */
|
||||
struct ddb_lnb lnb;
|
||||
struct tasklet_struct tasklet;
|
||||
struct ddb_ids ids;
|
||||
|
||||
spinlock_t temp_lock;
|
||||
int OverTemperatureError;
|
||||
spinlock_t temp_lock; /* lock temp chip access */
|
||||
int over_temperature_error;
|
||||
u8 temp_tab[11];
|
||||
struct ddb_irq irq[256];
|
||||
};
|
||||
|
||||
struct ddb {
|
||||
@@ -450,9 +448,6 @@ struct ddb {
|
||||
struct ddb_dma idma[DDB_MAX_INPUT];
|
||||
struct ddb_dma odma[DDB_MAX_OUTPUT];
|
||||
|
||||
void (*handler[4][256])(unsigned long);
|
||||
unsigned long handler_data[4][256];
|
||||
|
||||
struct device *ddb_dev;
|
||||
u32 ddb_dev_users;
|
||||
u32 nr;
|
||||
@@ -465,230 +460,16 @@ struct ddb {
|
||||
int ns_num;
|
||||
struct ddb_ns ns[DDB_NS_MAX];
|
||||
int vlan;
|
||||
struct mutex mutex;
|
||||
struct mutex mutex; /* lock accces to global ddb array */
|
||||
|
||||
struct dvb_device *nsd_dev;
|
||||
u8 tsbuf[TS_CAPTURE_LEN];
|
||||
|
||||
struct mod_base mod_base;
|
||||
struct ddb_mod mod[24];
|
||||
|
||||
struct mutex ioctl_mutex; /* lock extra ioctls */
|
||||
};
|
||||
|
||||
static inline void ddbwriteb(struct ddb *dev, u32 val, u32 adr)
|
||||
{
|
||||
writeb(val, (char *) (dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static inline u32 ddbreadb(struct ddb *dev, u32 adr)
|
||||
{
|
||||
return readb((char *) (dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static inline void ddbwritel0(struct ddb_link *link, u32 val, u32 adr)
|
||||
{
|
||||
writel(val, (char *) (link->dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static inline u32 ddbreadl0(struct ddb_link *link, u32 adr)
|
||||
{
|
||||
return readl((char *) (link->dev->regs + (adr)));
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline void gtlw(struct ddb_link *link)
|
||||
{
|
||||
u32 count = 0;
|
||||
static u32 max;
|
||||
|
||||
while (1 & ddbreadl0(link, link->regs + 0x10)) {
|
||||
if (++count == 1024) {
|
||||
pr_info("LTO\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count > max) {
|
||||
max = count;
|
||||
pr_info("TO=%u\n", max);
|
||||
}
|
||||
if (ddbreadl0(link, link->regs + 0x10) & 0x8000)
|
||||
pr_err("link error\n");
|
||||
}
|
||||
#else
|
||||
static inline void gtlw(struct ddb_link *link)
|
||||
{
|
||||
while (1 & ddbreadl0(link, link->regs + 0x10))
|
||||
;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static u32 ddblreadl(struct ddb_link *link, u32 adr)
|
||||
{
|
||||
if (unlikely(link->nr)) {
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddbwritel0(link, adr & 0xfffc, link->regs + 0x14);
|
||||
ddbwritel0(link, 3, link->regs + 0x10);
|
||||
gtlw(link);
|
||||
val = ddbreadl0(link, link->regs + 0x1c);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return val;
|
||||
}
|
||||
return readl((char *) (link->dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static void ddblwritel(struct ddb_link *link, u32 val, u32 adr)
|
||||
{
|
||||
if (unlikely(link->nr)) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddbwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
|
||||
ddbwritel0(link, val, link->regs + 0x18);
|
||||
ddbwritel0(link, 1, link->regs + 0x10);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return;
|
||||
}
|
||||
writel(val, (char *) (link->dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static u32 ddbreadl(struct ddb *dev, u32 adr)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000)) {
|
||||
unsigned long flags;
|
||||
u32 val, l = (adr >> DDB_LINK_SHIFT);
|
||||
struct ddb_link *link = &dev->link[l];
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddbwritel0(link, adr & 0xfffc, link->regs + 0x14);
|
||||
ddbwritel0(link, 3, link->regs + 0x10);
|
||||
gtlw(link);
|
||||
val = ddbreadl0(link, link->regs + 0x1c);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return val;
|
||||
}
|
||||
return readl((char *) (dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static void ddbwritel(struct ddb *dev, u32 val, u32 adr)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000)) {
|
||||
unsigned long flags;
|
||||
u32 l = (adr >> DDB_LINK_SHIFT);
|
||||
struct ddb_link *link = &dev->link[l];
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddbwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
|
||||
ddbwritel0(link, val, link->regs + 0x18);
|
||||
ddbwritel0(link, 1, link->regs + 0x10);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return;
|
||||
}
|
||||
writel(val, (char *) (dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static void gtlcpyto(struct ddb *dev, u32 adr, const u8 *buf,
|
||||
unsigned int count)
|
||||
{
|
||||
u32 val = 0, p = adr;
|
||||
u32 aa = p & 3;
|
||||
|
||||
if (aa) {
|
||||
while (p & 3 && count) {
|
||||
val >>= 8;
|
||||
val |= *buf << 24;
|
||||
p++;
|
||||
buf++;
|
||||
count--;
|
||||
}
|
||||
ddbwritel(dev, val, adr);
|
||||
}
|
||||
while (count >= 4) {
|
||||
val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
ddbwritel(dev, val, p);
|
||||
p += 4;
|
||||
buf += 4;
|
||||
count -= 4;
|
||||
}
|
||||
if (count) {
|
||||
val = buf[0];
|
||||
if (count > 1)
|
||||
val |= buf[1] << 8;
|
||||
if (count > 2)
|
||||
val |= buf[2] << 16;
|
||||
ddbwritel(dev, val, p);
|
||||
}
|
||||
}
|
||||
|
||||
static void gtlcpyfrom(struct ddb *dev, u8 *buf, u32 adr, long count)
|
||||
{
|
||||
u32 val = 0, p = adr;
|
||||
u32 a = p & 3;
|
||||
|
||||
if (a) {
|
||||
val = ddbreadl(dev, p) >> (8 * a);
|
||||
while (p & 3 && count) {
|
||||
*buf = val & 0xff;
|
||||
val >>= 8;
|
||||
p++;
|
||||
buf++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
while (count >= 4) {
|
||||
val = ddbreadl(dev, p);
|
||||
buf[0] = val & 0xff;
|
||||
buf[1] = (val >> 8) & 0xff;
|
||||
buf[2] = (val >> 16) & 0xff;
|
||||
buf[3] = (val >> 24) & 0xff;
|
||||
p += 4;
|
||||
buf += 4;
|
||||
count -= 4;
|
||||
}
|
||||
if (count) {
|
||||
val = ddbreadl(dev, p);
|
||||
buf[0] = val & 0xff;
|
||||
if (count > 1)
|
||||
buf[1] = (val >> 8) & 0xff;
|
||||
if (count > 2)
|
||||
buf[2] = (val >> 16) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000))
|
||||
return gtlcpyto(dev, adr, src, count);
|
||||
return memcpy_toio((char *) (dev->regs + adr), src, count);
|
||||
}
|
||||
|
||||
static void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000))
|
||||
return gtlcpyfrom(dev, dst, adr, count);
|
||||
return memcpy_fromio(dst, (char *) (dev->regs + adr), count);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
#define ddbcpyto(_dev, _adr, _src, _count) \
|
||||
memcpy_toio((char *) (_dev->regs + (_adr)), (_src), (_count))
|
||||
|
||||
#define ddbcpyfrom(_dev, _dst, _adr, _count) \
|
||||
memcpy_fromio((_dst), (char *) (_dev->regs + (_adr)), (_count))
|
||||
#endif
|
||||
|
||||
#define ddbmemset(_dev, _adr, _val, _count) \
|
||||
memset_io((char *) (_dev->regs + (_adr)), (_val), (_count))
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
@@ -741,16 +522,51 @@ struct DDMOD_FLASH {
|
||||
|
||||
#define DDMOD_FLASH_MAGIC 0x5F564d5F
|
||||
|
||||
int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
|
||||
|
||||
#define DDBRIDGE_VERSION "0.9.34"
|
||||
|
||||
/* linked function prototypes */
|
||||
|
||||
const struct ddb_info *get_ddb_info(u16 vendor, u16 device,
|
||||
u16 subvendor, u16 subdevice);
|
||||
int netstream_init(struct ddb_input *input);
|
||||
int ddb_dvb_ns_input_start(struct ddb_input *input);
|
||||
int ddb_dvb_ns_input_stop(struct ddb_input *input);
|
||||
|
||||
int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg);
|
||||
int ddbridge_mod_init(struct ddb *dev);
|
||||
void ddbridge_mod_output_stop(struct ddb_output *output);
|
||||
int ddbridge_mod_output_start(struct ddb_output *output);
|
||||
void ddbridge_mod_rate_handler(unsigned long data);
|
||||
void ddbridge_mod_rate_handler(void *);
|
||||
|
||||
void ddb_device_destroy(struct ddb *dev);
|
||||
void ddb_nsd_detach(struct ddb *dev);
|
||||
void ddb_ports_detach(struct ddb *dev);
|
||||
void ddb_ports_release(struct ddb *dev);
|
||||
void ddb_buffers_free(struct ddb *dev);
|
||||
void ddb_unmap(struct ddb *dev);
|
||||
irqreturn_t ddb_irq_handler0(int irq, void *dev_id);
|
||||
irqreturn_t ddb_irq_handler1(int irq, void *dev_id);
|
||||
irqreturn_t ddb_irq_handler(int irq, void *dev_id);
|
||||
irqreturn_t ddb_irq_handler_v2(int irq, void *dev_id);
|
||||
void ddb_reset_ios(struct ddb *dev);
|
||||
int ddb_init(struct ddb *dev);
|
||||
int ddb_exit_ddbridge(int stage, int error);
|
||||
int ddb_init_ddbridge(void);
|
||||
|
||||
int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
|
||||
int ddb_i2c_init(struct ddb *dev);
|
||||
void ddb_i2c_release(struct ddb *dev);
|
||||
|
||||
#define DDBRIDGE_VERSION "0.9.25"
|
||||
int ddb_ci_attach(struct ddb_port *port, u32 bitrate);
|
||||
|
||||
int ddb_fe_attach_mxl5xx(struct ddb_input *input);
|
||||
int ddb_fe_attach_mci(struct ddb_input *input, u32 type);
|
||||
int ddb_lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm);
|
||||
|
||||
struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr,
|
||||
void (*handler)(void *), void *data);
|
||||
|
||||
struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, struct mci_cfg *cfg, int nr, int tuner);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* octonet.c: Digital Devices network tuner driver
|
||||
*
|
||||
* Copyright (C) 2012-16 Digital Devices GmbH
|
||||
* Copyright (C) 2012-17 Digital Devices GmbH
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
*
|
||||
@@ -17,96 +17,12 @@
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
* along with this program; if not, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-regs.h"
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0))
|
||||
#include <asm-generic/pci-dma-compat.h>
|
||||
#else
|
||||
#include <linux/pci-dma-compat.h>
|
||||
#endif
|
||||
|
||||
static int adapter_alloc = 3;
|
||||
module_param(adapter_alloc, int, 0444);
|
||||
MODULE_PARM_DESC(adapter_alloc,
|
||||
"0-one adapter per io, 1-one per tab with io, 2-one per tab, 3-one for all");
|
||||
|
||||
#include "ddbridge-core.c"
|
||||
|
||||
static struct ddb_regmap octopus_net_map = {
|
||||
.irq_version = 1,
|
||||
.irq_base_i2c = 0,
|
||||
.i2c = &octopus_i2c,
|
||||
.i2c_buf = &octopus_i2c_buf,
|
||||
.input = &octopus_input,
|
||||
.output = &octopus_output,
|
||||
};
|
||||
|
||||
static struct ddb_regset octopus_gtl = {
|
||||
.base = 0x180,
|
||||
.num = 0x01,
|
||||
.size = 0x20,
|
||||
};
|
||||
|
||||
static struct ddb_regmap octopus_net_gtl = {
|
||||
.irq_version = 1,
|
||||
.irq_base_i2c = 0,
|
||||
.irq_base_gtl = 10,
|
||||
.i2c = &octopus_i2c,
|
||||
.i2c_buf = &octopus_i2c_buf,
|
||||
.input = &octopus_input,
|
||||
.output = &octopus_output,
|
||||
.gtl = &octopus_gtl,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octonet = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet network DVB adapter",
|
||||
.regmap = &octopus_net_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.ns_num = 12,
|
||||
.mdio_num = 1,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octonet_jse = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet network DVB adapter JSE",
|
||||
.regmap = &octopus_net_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.ns_num = 15,
|
||||
.mdio_num = 1,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octonet_gtl = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet GTL",
|
||||
.regmap = &octopus_net_gtl,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x05,
|
||||
.ns_num = 12,
|
||||
.mdio_num = 1,
|
||||
.con_clock = 1,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octonet_tbd = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet",
|
||||
.regmap = &octopus_net_map,
|
||||
};
|
||||
|
||||
static void octonet_unmap(struct ddb *dev)
|
||||
{
|
||||
if (dev->regs)
|
||||
iounmap(dev->regs);
|
||||
vfree(dev);
|
||||
}
|
||||
#include "ddbridge-io.h"
|
||||
|
||||
static int __exit octonet_remove(struct platform_device *pdev)
|
||||
{
|
||||
@@ -125,7 +41,7 @@ static int __exit octonet_remove(struct platform_device *pdev)
|
||||
|
||||
free_irq(platform_get_irq(dev->pfdev, 0), dev);
|
||||
ddb_ports_release(dev);
|
||||
octonet_unmap(dev);
|
||||
ddb_unmap(dev);
|
||||
platform_set_drvdata(pdev, 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -136,7 +52,7 @@ static int __init octonet_probe(struct platform_device *pdev)
|
||||
struct resource *regs;
|
||||
int irq;
|
||||
|
||||
dev = vzalloc(sizeof(struct ddb));
|
||||
dev = vzalloc(sizeof(*dev));
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
@@ -149,7 +65,7 @@ static int __init octonet_probe(struct platform_device *pdev)
|
||||
return -ENXIO;
|
||||
dev->regs_len = (regs->end - regs->start) + 1;
|
||||
dev_info(dev->dev, "regs_start=%08x regs_len=%08x\n",
|
||||
(u32) regs->start, (u32) dev->regs_len);
|
||||
(u32)regs->start, (u32)dev->regs_len);
|
||||
dev->regs = ioremap(regs->start, dev->regs_len);
|
||||
|
||||
if (!dev->regs) {
|
||||
@@ -168,19 +84,13 @@ static int __init octonet_probe(struct platform_device *pdev)
|
||||
dev->link[0].ids.subdevice = dev->link[0].ids.devid >> 16;
|
||||
|
||||
dev->link[0].dev = dev;
|
||||
if (dev->link[0].ids.devid == 0x0300dd01)
|
||||
dev->link[0].info = &ddb_octonet;
|
||||
else if (dev->link[0].ids.devid == 0x0301dd01)
|
||||
dev->link[0].info = &ddb_octonet_jse;
|
||||
else if (dev->link[0].ids.devid == 0x0307dd01)
|
||||
dev->link[0].info = &ddb_octonet_gtl;
|
||||
else
|
||||
dev->link[0].info = &ddb_octonet_tbd;
|
||||
|
||||
pr_info("HW %08x REGMAP %08x\n",
|
||||
dev->link[0].ids.hwid, dev->link[0].ids.regmapid);
|
||||
pr_info("MAC %08x DEVID %08x\n",
|
||||
dev->link[0].ids.mac, dev->link[0].ids.devid);
|
||||
dev->link[0].info = get_ddb_info(dev->link[0].ids.vendor,
|
||||
dev->link[0].ids.device,
|
||||
0xdd01, 0xffff);
|
||||
dev_info(dev->dev, "DDBridge: HW %08x REGMAP %08x\n",
|
||||
dev->link[0].ids.hwid, dev->link[0].ids.regmapid);
|
||||
dev_info(dev->dev, "DDBridge: MAC %08x DEVID %08x\n",
|
||||
dev->link[0].ids.mac, dev->link[0].ids.devid);
|
||||
|
||||
ddbwritel(dev, 0, ETHER_CONTROL);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE);
|
||||
@@ -190,9 +100,9 @@ static int __init octonet_probe(struct platform_device *pdev)
|
||||
irq = platform_get_irq(dev->pfdev, 0);
|
||||
if (irq < 0)
|
||||
goto fail;
|
||||
if (request_irq(irq, irq_handler,
|
||||
if (request_irq(irq, ddb_irq_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
"octonet-dvb", (void *) dev) < 0)
|
||||
"octonet-dvb", (void *)dev) < 0)
|
||||
goto fail;
|
||||
ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE);
|
||||
|
||||
@@ -203,7 +113,7 @@ fail:
|
||||
dev_err(dev->dev, "fail\n");
|
||||
ddbwritel(dev, 0, ETHER_CONTROL);
|
||||
ddbwritel(dev, 0, INTERRUPT_ENABLE);
|
||||
octonet_unmap(dev);
|
||||
ddb_unmap(dev);
|
||||
platform_set_drvdata(pdev, 0);
|
||||
return -1;
|
||||
}
|
||||
@@ -217,7 +127,7 @@ static const struct of_device_id octonet_dt_ids[] = {
|
||||
MODULE_DEVICE_TABLE(of, octonet_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver octonet_driver = {
|
||||
static struct platform_driver octonet_driver __refdata = {
|
||||
.remove = __exit_p(octonet_remove),
|
||||
.probe = octonet_probe,
|
||||
.driver = {
|
||||
@@ -231,25 +141,23 @@ static struct platform_driver octonet_driver = {
|
||||
|
||||
static __init int init_octonet(void)
|
||||
{
|
||||
int res;
|
||||
int stat;
|
||||
|
||||
pr_info("Digital Devices OctopusNet driver " DDBRIDGE_VERSION
|
||||
", Copyright (C) 2010-16 Digital Devices GmbH\n");
|
||||
res = ddb_class_create();
|
||||
if (res)
|
||||
return res;
|
||||
res = platform_driver_probe(&octonet_driver, octonet_probe);
|
||||
if (res) {
|
||||
ddb_class_destroy();
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
pr_info("DDBridge: Digital Devices OctopusNet driver " DDBRIDGE_VERSION
|
||||
", Copyright (C) 2010-17 Digital Devices GmbH\n");
|
||||
stat = ddb_init_ddbridge();
|
||||
if (stat < 0)
|
||||
return stat;
|
||||
stat = platform_driver_probe(&octonet_driver, octonet_probe);
|
||||
if (stat < 0)
|
||||
ddb_exit_ddbridge(0, stat);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static __exit void exit_octonet(void)
|
||||
{
|
||||
platform_driver_unregister(&octonet_driver);
|
||||
ddb_class_destroy();
|
||||
ddb_exit_ddbridge(0, 0);
|
||||
}
|
||||
|
||||
module_init(init_octonet);
|
||||
@@ -257,5 +165,5 @@ module_exit(exit_octonet);
|
||||
|
||||
MODULE_DESCRIPTION("GPL");
|
||||
MODULE_AUTHOR("Marcus and Ralph Metzler, Metzler Brothers Systementwicklung GbR");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("0.6");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_VERSION(DDBRIDGE_VERSION);
|
||||
104
docs/bbframes
Normal file
104
docs/bbframes
Normal file
@@ -0,0 +1,104 @@
|
||||
To allow the transport of DVB-S2 baseband frames (BBFrame) across existing hard- and software
|
||||
interfaces, we have added the ability to embed the BBFrame data into
|
||||
an MPEG2 transport stream.
|
||||
|
||||
This feature is available on supported cards as firmware update and
|
||||
is currently considered experimental.
|
||||
|
||||
Supported hardware:
|
||||
|
||||
Cine V7A (>=1.7 FW)
|
||||
OctopusCI S2 Pro Advanced (>=1.7 FW)
|
||||
Duoflex S2 v4 Advanced (TBA)
|
||||
MaxSX8 (NOT the MAXS8!)
|
||||
|
||||
The following cards are based on the broadcast version of the
|
||||
DVB-S2 demodulator. The BBFrame output is working but
|
||||
not documented. We therefore can not guarantee the
|
||||
feature will work under all conditions.
|
||||
|
||||
cineS2 V7 (>=1.7 FW)
|
||||
OctopusCI S2 Pro (>=1.7 FW)
|
||||
Duoflex S2 v4 (TBA)
|
||||
|
||||
|
||||
Current FPGA images (including FW 1.7 for the above mentioned cards)
|
||||
can be found here:
|
||||
|
||||
http://download.digital-devices.de/download/firmware/html/firmwareupdate.html
|
||||
|
||||
|
||||
|
||||
Packet format:
|
||||
|
||||
The BBFrames are packetized into MPEG2 private sections (0x80), one section per transport stream
|
||||
packet. The PID is fixed at 0x010E.
|
||||
|
||||
|
||||
Header packet of frame:
|
||||
|
||||
0x47 0x41 0x0E 0x1X 0x00 0x80 0x00 L 0xB8 BBHeader (169 * Data)
|
||||
|
||||
L: Section Length, always 180 (0xB4)
|
||||
BBHeader: 10 Bytes BBFrame header (see DVB-S2, EN-302307)
|
||||
Data: 169 Bytes of BBFrame payload
|
||||
|
||||
|
||||
Payload packets:
|
||||
|
||||
0x47 0x41 0x0E 0x1X 0x00 0x80 0x00 L N (179 * Data)
|
||||
|
||||
L: Section Length, always 180 (0xB4)
|
||||
N: Packet counter, starting with 0x01 after header packet
|
||||
Data: 179 Bytes of BBFrame payload
|
||||
|
||||
|
||||
Last packet:
|
||||
0x47 0x41 0x0E 0x1X 0x00 0x80 0x00 L N ((L-1) * Data) ((180 – L) * 0xFF)
|
||||
|
||||
L: Section Length, remaining Data – 1, (0x01 .. 0xB4)
|
||||
N: Packet counter
|
||||
Data: L-1 Bytes of BBFrame payload
|
||||
|
||||
|
||||
|
||||
Automatic detection of input format:
|
||||
|
||||
The bridge firmware allows automatic detection of the incoming data.
|
||||
To receive regular transport streams in this formats it is still required to setup
|
||||
the DVB-S2 demodulator to output BBFrames instead of regular TS Packets.
|
||||
When enabled the embedding mode is automatically turned on or off depending on incoming data
|
||||
from the DVB-S2/S2X frontend. The decision depends currently only on the first byte of a packet.
|
||||
If it is 0x47 it switches to transport stream mode else it switches to embedding mode.
|
||||
|
||||
Note that 0x47 can currently not occur in the first byte of a BBFrame header if all reserved
|
||||
values of DVB-S2 and -S2X are observed.
|
||||
|
||||
|
||||
|
||||
|
||||
API:
|
||||
|
||||
Currently DTV_STREAM_ID is misused.
|
||||
Set it to 0x80000000 to enable frame mode in the demod.
|
||||
|
||||
|
||||
|
||||
Because there were some questions why we use this data format,
|
||||
here are some examples for why using this format this makes handling BBFrames easier:
|
||||
|
||||
- The start of a frame is easily found because a new set of sections is
|
||||
started.
|
||||
|
||||
- Existing software layers like the Linux kernel DVB demuxer can be used unchanged.
|
||||
|
||||
- Existing hardware like the OctopusNet SAT>IP server which can only handle TS packets can
|
||||
stream BBFrames via SAT>IP with this method.
|
||||
|
||||
- There is at least one demodulator (e.g. on the MaxSX8) which supports this format in hardware.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
103
docs/modulator
103
docs/modulator
@@ -26,4 +26,105 @@ talks to the CI to decrypt the desired services.
|
||||
For testing one can use a standard application that
|
||||
supports decryption. Additionally to seeing the
|
||||
decoded service on the PC it will then also be streamed
|
||||
into cable by the modulator.
|
||||
into cable by the modulator.
|
||||
|
||||
|
||||
|
||||
The modulator device can be controlled with the
|
||||
following properties:
|
||||
|
||||
MODULATOR_FREQUENCY:
|
||||
|
||||
Set the frequency on Version 2 (FSM) cards
|
||||
units - Hz
|
||||
range - 114000000-874000000
|
||||
allowed values - 114 + 8000000*X
|
||||
|
||||
For older cards you have to use the
|
||||
DVB_MOD_SET ioctl.
|
||||
|
||||
|
||||
|
||||
MODULATOR_SYMBOLRATE:
|
||||
|
||||
Set the symbol rate
|
||||
units - Hz
|
||||
range - Version 1 cards: only 6900000
|
||||
Version 2 cards(FSM): X-7100000
|
||||
|
||||
|
||||
MODULATOR_MODULATION:
|
||||
|
||||
Set the modulation type
|
||||
range: QAM_16 .. QAM_256
|
||||
|
||||
|
||||
|
||||
MODULATOR_ATTENUATION:
|
||||
|
||||
range - 0-31
|
||||
unit - 1 dB
|
||||
|
||||
|
||||
MODULATOR_GAIN:
|
||||
|
||||
range - 0-255
|
||||
unit - 0.125 dB
|
||||
|
||||
|
||||
The MODULATOR_ATTENUATOR is based on a switched resistor network,
|
||||
also it is backward compatible to our old modulator.
|
||||
the MODULATOR_GAIN is based on a variable gain amplifier, so it is less
|
||||
accurate then the attenuator.
|
||||
High gain values will drive the output amplifier into clipping. The
|
||||
limit depends on # of channels active.
|
||||
|
||||
|
||||
|
||||
|
||||
MODULATOR_INPUT_BITRATE:
|
||||
|
||||
The modulator will ALWAY insert null packets if it
|
||||
does not get enough data.
|
||||
If you specify the input bitrate it will insert additional
|
||||
null packets according to the difference between input
|
||||
and output bit rate.
|
||||
The latter is determined by symbol rte and modulation.
|
||||
So, this property should be set last.
|
||||
|
||||
unit - 2^-32 Hz
|
||||
|
||||
|
||||
|
||||
Debugging features:
|
||||
|
||||
MODULATOR_STATUS and MODULATOR_RESET have been added to debug
|
||||
possible problems with too high temperatures (overtemperature)
|
||||
or PLL lock loss on FSM type cards.
|
||||
|
||||
The MODULATOR_STATUS property returns a __u32 with the following status bits:
|
||||
|
||||
- bit 0 : Lock status 1=lock OK, 0 = lock lost
|
||||
|
||||
- bit 1 : Sticky lock lost indicator
|
||||
0 = no PLL lock loss since last status read
|
||||
1 = lock has been lost since last status read
|
||||
|
||||
- bit 2 : 0 = no overtemperature
|
||||
1 = overtemperature detected
|
||||
|
||||
- bit 4 : 0 = PCIe link OK
|
||||
1 = PCIe link lost
|
||||
|
||||
In case of overtemperratur or PCIe link loss you will have to reboot the PC.
|
||||
|
||||
|
||||
Putting a MODULATOR_STATUS property with value 2 will enable the lost lock
|
||||
interrupt. This will set the gain to 0 and the attenuation to 31 in case
|
||||
of a lost PLL lock.
|
||||
|
||||
|
||||
The MODULATOR_RESET property can be used to reset the modulator without
|
||||
needing to reload the driver or rebooting in case of PLL lock loss.
|
||||
All channels should be stopped before using it and restarted after using it.
|
||||
Otherwise, results are unpredictable.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
- NAND flash
|
||||
|
||||
0x00000000 - 0x0025ffff U-boot
|
||||
0x00260000 - 0x0027ffff ENV
|
||||
0x00300000 - 0x00ffffff Linux image
|
||||
|
||||
0x01000000 - 0x01ffffff Linux recovery
|
||||
0x02000000 - 0x1fffffff Linux UBI
|
||||
0x00000000 - 0x0007ffff spl 512K
|
||||
0x00080000 - 0x0047ffff uboot 4M
|
||||
0x00480000 - 0x004fffff env 512K
|
||||
0x00500000 - 0x00ffffff spare 11M
|
||||
0x01000000 - 0x01ffffff recovery 16M
|
||||
0x02000000 - 0x1fffffff ubi -
|
||||
|
||||
|
||||
42
dvb-core/Kconfig
Normal file
42
dvb-core/Kconfig
Normal file
@@ -0,0 +1,42 @@
|
||||
#
|
||||
# DVB device configuration
|
||||
#
|
||||
|
||||
config DVB_MAX_ADAPTERS
|
||||
int "maximum number of DVB/ATSC adapters"
|
||||
depends on DVB_CORE
|
||||
default 16
|
||||
range 1 255
|
||||
help
|
||||
Maximum number of DVB/ATSC adapters. Increasing this number
|
||||
increases the memory consumption of the DVB subsystem even
|
||||
if a much lower number of DVB/ATSC adapters is present.
|
||||
Only values in the range 4-32 are tested.
|
||||
|
||||
If you are unsure about this, use the default value 16
|
||||
|
||||
config DVB_DYNAMIC_MINORS
|
||||
bool "Dynamic DVB minor allocation"
|
||||
depends on DVB_CORE
|
||||
default n
|
||||
help
|
||||
If you say Y here, the DVB subsystem will use dynamic minor
|
||||
allocation for any device that uses the DVB major number.
|
||||
This means that you can have more than 4 of a single type
|
||||
of device (like demuxes and frontends) per adapter, but udev
|
||||
will be required to manage the device nodes.
|
||||
|
||||
If you are unsure about this, say N here.
|
||||
|
||||
config DVB_DEMUX_SECTION_LOSS_LOG
|
||||
bool "Enable DVB demux section packet loss log"
|
||||
depends on DVB_CORE
|
||||
default n
|
||||
help
|
||||
Enable extra log messages meant to detect packet loss
|
||||
inside the Kernel.
|
||||
|
||||
Should not be enabled on normal cases, as logs can
|
||||
be very verbose.
|
||||
|
||||
If you are unsure about this, say N here.
|
||||
12
dvb-core/Makefile.kernel
Normal file
12
dvb-core/Makefile.kernel
Normal file
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# Makefile for the kernel DVB device drivers.
|
||||
#
|
||||
|
||||
dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
|
||||
|
||||
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
|
||||
dvb_ca_en50221.o dvb_frontend.o \
|
||||
$(dvb-net-y) dvb_ringbuffer.o dvb_math.o \
|
||||
dvb_netstream.o
|
||||
|
||||
obj-$(CONFIG_DVB_CORE) += dvb-core.o
|
||||
634
dvb-core/demux.h
634
dvb-core/demux.h
@@ -1,6 +1,10 @@
|
||||
/*
|
||||
* demux.h
|
||||
*
|
||||
* The Kernel Digital TV Demux kABI defines a driver-internal interface for
|
||||
* registering low-level, hardware specific driver to a hardware independent
|
||||
* demux layer.
|
||||
*
|
||||
* Copyright (c) 2002 Convergence GmbH
|
||||
*
|
||||
* based on code:
|
||||
@@ -17,10 +21,6 @@
|
||||
* 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 Lesser 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DEMUX_H
|
||||
@@ -32,9 +32,9 @@
|
||||
#include <linux/time.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Common definitions */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Common definitions
|
||||
*/
|
||||
|
||||
/*
|
||||
* DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
|
||||
@@ -45,7 +45,8 @@
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
|
||||
* DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed
|
||||
* filter.
|
||||
*/
|
||||
|
||||
#ifndef DMX_MAX_SECTION_SIZE
|
||||
@@ -55,187 +56,534 @@
|
||||
#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* enum dmx_success: Success codes for the Demux Callback API.
|
||||
* TS packet reception
|
||||
*/
|
||||
|
||||
enum dmx_success {
|
||||
DMX_OK = 0, /* Received Ok */
|
||||
DMX_LENGTH_ERROR, /* Incorrect length */
|
||||
DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
|
||||
DMX_CRC_ERROR, /* Incorrect CRC */
|
||||
DMX_FRAME_ERROR, /* Frame alignment error */
|
||||
DMX_FIFO_ERROR, /* Receiver FIFO overrun */
|
||||
DMX_MISSED_ERROR /* Receiver missed packet */
|
||||
} ;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* TS packet reception */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/* TS filter type for set() */
|
||||
|
||||
#define TS_PACKET 1 /* send TS packets (188 bytes) to callback (default) */
|
||||
#define TS_PAYLOAD_ONLY 2 /* in case TS_PACKET is set, only send the TS
|
||||
payload (<=184 bytes per packet) to callback */
|
||||
#define TS_DECODER 4 /* send stream to built-in decoder (if present) */
|
||||
#define TS_DEMUX 8 /* in case TS_PACKET is set, send the TS to
|
||||
the demux device, not to the dvr device */
|
||||
/**
|
||||
* enum ts_filter_type - filter type bitmap for dmx_ts_feed.set\(\)
|
||||
*
|
||||
* @TS_PACKET: Send TS packets (188 bytes) to callback (default).
|
||||
* @TS_PAYLOAD_ONLY: In case TS_PACKET is set, only send the TS payload
|
||||
* (<=184 bytes per packet) to callback
|
||||
* @TS_DECODER: Send stream to built-in decoder (if present).
|
||||
* @TS_DEMUX: In case TS_PACKET is set, send the TS to the demux
|
||||
* device, not to the dvr device
|
||||
*/
|
||||
enum ts_filter_type {
|
||||
TS_PACKET = 1,
|
||||
TS_PAYLOAD_ONLY = 2,
|
||||
TS_DECODER = 4,
|
||||
TS_DEMUX = 8,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dmx_ts_feed - Structure that contains a TS feed filter
|
||||
*
|
||||
* @is_filtering: Set to non-zero when filtering in progress
|
||||
* @parent: pointer to struct dmx_demux
|
||||
* @priv: pointer to private data of the API client
|
||||
* @set: sets the TS filter
|
||||
* @start_filtering: starts TS filtering
|
||||
* @stop_filtering: stops TS filtering
|
||||
*
|
||||
* A TS feed is typically mapped to a hardware PID filter on the demux chip.
|
||||
* Using this API, the client can set the filtering properties to start/stop
|
||||
* filtering TS packets on a particular TS feed.
|
||||
*/
|
||||
struct dmx_ts_feed {
|
||||
int is_filtering; /* Set to non-zero when filtering in progress */
|
||||
struct dmx_demux *parent; /* Back-pointer */
|
||||
void *priv; /* Pointer to private data of the API client */
|
||||
int (*set) (struct dmx_ts_feed *feed,
|
||||
u16 pid,
|
||||
int type,
|
||||
enum dmx_ts_pes pes_type,
|
||||
size_t circular_buffer_size,
|
||||
struct timespec timeout);
|
||||
int (*start_filtering) (struct dmx_ts_feed* feed);
|
||||
int (*stop_filtering) (struct dmx_ts_feed* feed);
|
||||
int is_filtering;
|
||||
struct dmx_demux *parent;
|
||||
void *priv;
|
||||
int (*set)(struct dmx_ts_feed *feed,
|
||||
u16 pid,
|
||||
int type,
|
||||
enum dmx_ts_pes pes_type,
|
||||
ktime_t timeout);
|
||||
int (*start_filtering)(struct dmx_ts_feed *feed);
|
||||
int (*stop_filtering)(struct dmx_ts_feed *feed);
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Section reception */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Section reception
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct dmx_section_filter - Structure that describes a section filter
|
||||
*
|
||||
* @filter_value: Contains up to 16 bytes (128 bits) of the TS section header
|
||||
* that will be matched by the section filter
|
||||
* @filter_mask: Contains a 16 bytes (128 bits) filter mask with the bits
|
||||
* specified by @filter_value that will be used on the filter
|
||||
* match logic.
|
||||
* @filter_mode: Contains a 16 bytes (128 bits) filter mode.
|
||||
* @parent: Pointer to struct dmx_section_feed.
|
||||
* @priv: Pointer to private data of the API client.
|
||||
*
|
||||
*
|
||||
* The @filter_mask controls which bits of @filter_value are compared with
|
||||
* the section headers/payload. On a binary value of 1 in filter_mask, the
|
||||
* corresponding bits are compared. The filter only accepts sections that are
|
||||
* equal to filter_value in all the tested bit positions.
|
||||
*/
|
||||
struct dmx_section_filter {
|
||||
u8 filter_value [DMX_MAX_FILTER_SIZE];
|
||||
u8 filter_mask [DMX_MAX_FILTER_SIZE];
|
||||
u8 filter_mode [DMX_MAX_FILTER_SIZE];
|
||||
struct dmx_section_feed* parent; /* Back-pointer */
|
||||
void* priv; /* Pointer to private data of the API client */
|
||||
u8 filter_value[DMX_MAX_FILTER_SIZE];
|
||||
u8 filter_mask[DMX_MAX_FILTER_SIZE];
|
||||
u8 filter_mode[DMX_MAX_FILTER_SIZE];
|
||||
struct dmx_section_feed *parent; /* Back-pointer */
|
||||
void *priv; /* Pointer to private data of the API client */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dmx_section_feed - Structure that contains a section feed filter
|
||||
*
|
||||
* @is_filtering: Set to non-zero when filtering in progress
|
||||
* @parent: pointer to struct dmx_demux
|
||||
* @priv: pointer to private data of the API client
|
||||
* @check_crc: If non-zero, check the CRC values of filtered sections.
|
||||
* @set: sets the section filter
|
||||
* @allocate_filter: This function is used to allocate a section filter on
|
||||
* the demux. It should only be called when no filtering
|
||||
* is in progress on this section feed. If a filter cannot
|
||||
* be allocated, the function fails with -ENOSPC.
|
||||
* @release_filter: This function releases all the resources of a
|
||||
* previously allocated section filter. The function
|
||||
* should not be called while filtering is in progress
|
||||
* on this section feed. After calling this function,
|
||||
* the caller should not try to dereference the filter
|
||||
* pointer.
|
||||
* @start_filtering: starts section filtering
|
||||
* @stop_filtering: stops section filtering
|
||||
*
|
||||
* A TS feed is typically mapped to a hardware PID filter on the demux chip.
|
||||
* Using this API, the client can set the filtering properties to start/stop
|
||||
* filtering TS packets on a particular TS feed.
|
||||
*/
|
||||
struct dmx_section_feed {
|
||||
int is_filtering; /* Set to non-zero when filtering in progress */
|
||||
struct dmx_demux* parent; /* Back-pointer */
|
||||
void* priv; /* Pointer to private data of the API client */
|
||||
int is_filtering;
|
||||
struct dmx_demux *parent;
|
||||
void *priv;
|
||||
|
||||
int check_crc;
|
||||
|
||||
/* private: Used internally at dvb_demux.c */
|
||||
u32 crc_val;
|
||||
|
||||
u8 *secbuf;
|
||||
u8 secbuf_base[DMX_MAX_SECFEED_SIZE];
|
||||
u16 secbufp, seclen, tsfeedp;
|
||||
|
||||
int (*set) (struct dmx_section_feed* feed,
|
||||
u16 pid,
|
||||
size_t circular_buffer_size,
|
||||
int check_crc);
|
||||
int (*allocate_filter) (struct dmx_section_feed* feed,
|
||||
struct dmx_section_filter** filter);
|
||||
int (*release_filter) (struct dmx_section_feed* feed,
|
||||
struct dmx_section_filter* filter);
|
||||
int (*start_filtering) (struct dmx_section_feed* feed);
|
||||
int (*stop_filtering) (struct dmx_section_feed* feed);
|
||||
/* public: */
|
||||
int (*set)(struct dmx_section_feed *feed,
|
||||
u16 pid,
|
||||
int check_crc);
|
||||
int (*allocate_filter)(struct dmx_section_feed *feed,
|
||||
struct dmx_section_filter **filter);
|
||||
int (*release_filter)(struct dmx_section_feed *feed,
|
||||
struct dmx_section_filter *filter);
|
||||
int (*start_filtering)(struct dmx_section_feed *feed);
|
||||
int (*stop_filtering)(struct dmx_section_feed *feed);
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Callback functions */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/**
|
||||
* typedef dmx_ts_cb - DVB demux TS filter callback function prototype
|
||||
*
|
||||
* @buffer1: Pointer to the start of the filtered TS packets.
|
||||
* @buffer1_length: Length of the TS data in buffer1.
|
||||
* @buffer2: Pointer to the tail of the filtered TS packets, or NULL.
|
||||
* @buffer2_length: Length of the TS data in buffer2.
|
||||
* @source: Indicates which TS feed is the source of the callback.
|
||||
*
|
||||
* This function callback prototype, provided by the client of the demux API,
|
||||
* is called from the demux code. The function is only called when filtering
|
||||
* on a TS feed has been enabled using the start_filtering\(\) function at
|
||||
* the &dmx_demux.
|
||||
* Any TS packets that match the filter settings are copied to a circular
|
||||
* buffer. The filtered TS packets are delivered to the client using this
|
||||
* callback function.
|
||||
* It is expected that the @buffer1 and @buffer2 callback parameters point to
|
||||
* addresses within the circular buffer, but other implementations are also
|
||||
* possible. Note that the called party should not try to free the memory
|
||||
* the @buffer1 and @buffer2 parameters point to.
|
||||
*
|
||||
* When this function is called, the @buffer1 parameter typically points to
|
||||
* the start of the first undelivered TS packet within a circular buffer.
|
||||
* The @buffer2 buffer parameter is normally NULL, except when the received
|
||||
* TS packets have crossed the last address of the circular buffer and
|
||||
* "wrapped" to the beginning of the buffer. In the latter case the @buffer1
|
||||
* parameter would contain an address within the circular buffer, while the
|
||||
* @buffer2 parameter would contain the first address of the circular buffer.
|
||||
* The number of bytes delivered with this function (i.e. @buffer1_length +
|
||||
* @buffer2_length) is usually equal to the value of callback_length parameter
|
||||
* given in the set() function, with one exception: if a timeout occurs before
|
||||
* receiving callback_length bytes of TS data, any undelivered packets are
|
||||
* immediately delivered to the client by calling this function. The timeout
|
||||
* duration is controlled by the set() function in the TS Feed API.
|
||||
*
|
||||
* If a TS packet is received with errors that could not be fixed by the
|
||||
* TS-level forward error correction (FEC), the Transport_error_indicator
|
||||
* flag of the TS packet header should be set. The TS packet should not be
|
||||
* discarded, as the error can possibly be corrected by a higher layer
|
||||
* protocol. If the called party is slow in processing the callback, it
|
||||
* is possible that the circular buffer eventually fills up. If this happens,
|
||||
* the demux driver should discard any TS packets received while the buffer
|
||||
* is full and return -EOVERFLOW.
|
||||
*
|
||||
* The type of data returned to the callback can be selected by the
|
||||
* &dmx_ts_feed.@set function. The type parameter decides if the raw
|
||||
* TS packet (TS_PACKET) or just the payload (TS_PACKET|TS_PAYLOAD_ONLY)
|
||||
* should be returned. If additionally the TS_DECODER bit is set the stream
|
||||
* will also be sent to the hardware MPEG decoder.
|
||||
*
|
||||
* Return:
|
||||
*
|
||||
* - 0, on success;
|
||||
*
|
||||
* - -EOVERFLOW, on buffer overflow.
|
||||
*/
|
||||
typedef int (*dmx_ts_cb)(const u8 *buffer1,
|
||||
size_t buffer1_length,
|
||||
const u8 *buffer2,
|
||||
size_t buffer2_length,
|
||||
struct dmx_ts_feed *source);
|
||||
|
||||
typedef int (*dmx_ts_cb) ( const u8 * buffer1,
|
||||
size_t buffer1_length,
|
||||
const u8 * buffer2,
|
||||
size_t buffer2_length,
|
||||
struct dmx_ts_feed* source,
|
||||
enum dmx_success success);
|
||||
/**
|
||||
* typedef dmx_section_cb - DVB demux TS filter callback function prototype
|
||||
*
|
||||
* @buffer1: Pointer to the start of the filtered section, e.g.
|
||||
* within the circular buffer of the demux driver.
|
||||
* @buffer1_len: Length of the filtered section data in @buffer1,
|
||||
* including headers and CRC.
|
||||
* @buffer2: Pointer to the tail of the filtered section data,
|
||||
* or NULL. Useful to handle the wrapping of a
|
||||
* circular buffer.
|
||||
* @buffer2_len: Length of the filtered section data in @buffer2,
|
||||
* including headers and CRC.
|
||||
* @source: Indicates which section feed is the source of the
|
||||
* callback.
|
||||
*
|
||||
* This function callback prototype, provided by the client of the demux API,
|
||||
* is called from the demux code. The function is only called when
|
||||
* filtering of sections has been enabled using the function
|
||||
* &dmx_ts_feed.@start_filtering. When the demux driver has received a
|
||||
* complete section that matches at least one section filter, the client
|
||||
* is notified via this callback function. Normally this function is called
|
||||
* for each received section; however, it is also possible to deliver
|
||||
* multiple sections with one callback, for example when the system load
|
||||
* is high. If an error occurs while receiving a section, this
|
||||
* function should be called with the corresponding error type set in the
|
||||
* success field, whether or not there is data to deliver. The Section Feed
|
||||
* implementation should maintain a circular buffer for received sections.
|
||||
* However, this is not necessary if the Section Feed API is implemented as
|
||||
* a client of the TS Feed API, because the TS Feed implementation then
|
||||
* buffers the received data. The size of the circular buffer can be
|
||||
* configured using the &dmx_ts_feed.@set function in the Section Feed API.
|
||||
* If there is no room in the circular buffer when a new section is received,
|
||||
* the section must be discarded. If this happens, the value of the success
|
||||
* parameter should be DMX_OVERRUN_ERROR on the next callback.
|
||||
*/
|
||||
typedef int (*dmx_section_cb)(const u8 *buffer1,
|
||||
size_t buffer1_len,
|
||||
const u8 *buffer2,
|
||||
size_t buffer2_len,
|
||||
struct dmx_section_filter *source);
|
||||
|
||||
typedef int (*dmx_section_cb) ( const u8 * buffer1,
|
||||
size_t buffer1_len,
|
||||
const u8 * buffer2,
|
||||
size_t buffer2_len,
|
||||
struct dmx_section_filter * source,
|
||||
enum dmx_success success);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* DVB Front-End */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/*
|
||||
* DVB Front-End
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum dmx_frontend_source - Used to identify the type of frontend
|
||||
*
|
||||
* @DMX_MEMORY_FE: The source of the demux is memory. It means that
|
||||
* the MPEG-TS to be filtered comes from userspace,
|
||||
* via write() syscall.
|
||||
*
|
||||
* @DMX_FRONTEND_0: The source of the demux is a frontend connected
|
||||
* to the demux.
|
||||
*/
|
||||
enum dmx_frontend_source {
|
||||
DMX_MEMORY_FE,
|
||||
DMX_FRONTEND_0,
|
||||
DMX_FRONTEND_1,
|
||||
DMX_FRONTEND_2,
|
||||
DMX_FRONTEND_3,
|
||||
DMX_STREAM_0, /* external stream input, e.g. LVDS */
|
||||
DMX_STREAM_1,
|
||||
DMX_STREAM_2,
|
||||
DMX_STREAM_3
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dmx_frontend - Structure that lists the frontends associated with
|
||||
* a demux
|
||||
*
|
||||
* @connectivity_list: List of front-ends that can be connected to a
|
||||
* particular demux;
|
||||
* @source: Type of the frontend.
|
||||
*
|
||||
* FIXME: this structure should likely be replaced soon by some
|
||||
* media-controller based logic.
|
||||
*/
|
||||
struct dmx_frontend {
|
||||
struct list_head connectivity_list; /* List of front-ends that can
|
||||
be connected to a particular
|
||||
demux */
|
||||
struct list_head connectivity_list;
|
||||
enum dmx_frontend_source source;
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* MPEG-2 TS Demux */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Flags OR'ed in the capabilities field of struct dmx_demux.
|
||||
* MPEG-2 TS Demux
|
||||
*/
|
||||
|
||||
#define DMX_TS_FILTERING 1
|
||||
#define DMX_PES_FILTERING 2
|
||||
#define DMX_SECTION_FILTERING 4
|
||||
#define DMX_MEMORY_BASED_FILTERING 8 /* write() available */
|
||||
#define DMX_CRC_CHECKING 16
|
||||
#define DMX_TS_DESCRAMBLING 32
|
||||
/**
|
||||
* enum dmx_demux_caps - MPEG-2 TS Demux capabilities bitmap
|
||||
*
|
||||
* @DMX_TS_FILTERING: set if TS filtering is supported;
|
||||
* @DMX_SECTION_FILTERING: set if section filtering is supported;
|
||||
* @DMX_MEMORY_BASED_FILTERING: set if write() available.
|
||||
*
|
||||
* Those flags are OR'ed in the &dmx_demux.capabilities field
|
||||
*/
|
||||
enum dmx_demux_caps {
|
||||
DMX_TS_FILTERING = 1,
|
||||
DMX_SECTION_FILTERING = 4,
|
||||
DMX_MEMORY_BASED_FILTERING = 8,
|
||||
};
|
||||
|
||||
/*
|
||||
* Demux resource type identifier.
|
||||
*/
|
||||
*/
|
||||
|
||||
/*
|
||||
* DMX_FE_ENTRY(): Casts elements in the list of registered
|
||||
* front-ends from the generic type struct list_head
|
||||
* to the type * struct dmx_frontend
|
||||
*.
|
||||
*/
|
||||
|
||||
#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list)
|
||||
/**
|
||||
* DMX_FE_ENTRY - Casts elements in the list of registered
|
||||
* front-ends from the generic type struct list_head
|
||||
* to the type * struct dmx_frontend
|
||||
*
|
||||
* @list: list of struct dmx_frontend
|
||||
*/
|
||||
#define DMX_FE_ENTRY(list) \
|
||||
list_entry(list, struct dmx_frontend, connectivity_list)
|
||||
|
||||
/**
|
||||
* struct dmx_demux - Structure that contains the demux capabilities and
|
||||
* callbacks.
|
||||
*
|
||||
* @capabilities: Bitfield of capability flags.
|
||||
*
|
||||
* @frontend: Front-end connected to the demux
|
||||
*
|
||||
* @priv: Pointer to private data of the API client
|
||||
*
|
||||
* @open: This function reserves the demux for use by the caller and, if
|
||||
* necessary, initializes the demux. When the demux is no longer needed,
|
||||
* the function @close should be called. It should be possible for
|
||||
* multiple clients to access the demux at the same time. Thus, the
|
||||
* function implementation should increment the demux usage count when
|
||||
* @open is called and decrement it when @close is called.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -EUSERS, if maximum usage count was reached;
|
||||
* -EINVAL, on bad parameter.
|
||||
*
|
||||
* @close: This function reserves the demux for use by the caller and, if
|
||||
* necessary, initializes the demux. When the demux is no longer needed,
|
||||
* the function @close should be called. It should be possible for
|
||||
* multiple clients to access the demux at the same time. Thus, the
|
||||
* function implementation should increment the demux usage count when
|
||||
* @open is called and decrement it when @close is called.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -ENODEV, if demux was not in use (e. g. no users);
|
||||
* -EINVAL, on bad parameter.
|
||||
*
|
||||
* @write: This function provides the demux driver with a memory buffer
|
||||
* containing TS packets. Instead of receiving TS packets from the DVB
|
||||
* front-end, the demux driver software will read packets from memory.
|
||||
* Any clients of this demux with active TS, PES or Section filters will
|
||||
* receive filtered data via the Demux callback API (see 0). The function
|
||||
* returns when all the data in the buffer has been consumed by the demux.
|
||||
* Demux hardware typically cannot read TS from memory. If this is the
|
||||
* case, memory-based filtering has to be implemented entirely in software.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* The @buf function parameter contains a pointer to the TS data in
|
||||
* kernel-space memory.
|
||||
* The @count function parameter contains the length of the TS data.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -ERESTARTSYS, if mutex lock was interrupted;
|
||||
* -EINTR, if a signal handling is pending;
|
||||
* -ENODEV, if demux was removed;
|
||||
* -EINVAL, on bad parameter.
|
||||
*
|
||||
* @allocate_ts_feed: Allocates a new TS feed, which is used to filter the TS
|
||||
* packets carrying a certain PID. The TS feed normally corresponds to a
|
||||
* hardware PID filter on the demux chip.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* The @feed function parameter contains a pointer to the TS feed API and
|
||||
* instance data.
|
||||
* The @callback function parameter contains a pointer to the callback
|
||||
* function for passing received TS packet.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -ERESTARTSYS, if mutex lock was interrupted;
|
||||
* -EBUSY, if no more TS feeds is available;
|
||||
* -EINVAL, on bad parameter.
|
||||
*
|
||||
* @release_ts_feed: Releases the resources allocated with @allocate_ts_feed.
|
||||
* Any filtering in progress on the TS feed should be stopped before
|
||||
* calling this function.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* The @feed function parameter contains a pointer to the TS feed API and
|
||||
* instance data.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -EINVAL on bad parameter.
|
||||
*
|
||||
* @allocate_section_feed: Allocates a new section feed, i.e. a demux resource
|
||||
* for filtering and receiving sections. On platforms with hardware
|
||||
* support for section filtering, a section feed is directly mapped to
|
||||
* the demux HW. On other platforms, TS packets are first PID filtered in
|
||||
* hardware and a hardware section filter then emulated in software. The
|
||||
* caller obtains an API pointer of type dmx_section_feed_t as an out
|
||||
* parameter. Using this API the caller can set filtering parameters and
|
||||
* start receiving sections.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* The @feed function parameter contains a pointer to the TS feed API and
|
||||
* instance data.
|
||||
* The @callback function parameter contains a pointer to the callback
|
||||
* function for passing received TS packet.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -EBUSY, if no more TS feeds is available;
|
||||
* -EINVAL, on bad parameter.
|
||||
*
|
||||
* @release_section_feed: Releases the resources allocated with
|
||||
* @allocate_section_feed, including allocated filters. Any filtering in
|
||||
* progress on the section feed should be stopped before calling this
|
||||
* function.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* The @feed function parameter contains a pointer to the TS feed API and
|
||||
* instance data.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -EINVAL, on bad parameter.
|
||||
*
|
||||
* @add_frontend: Registers a connectivity between a demux and a front-end,
|
||||
* i.e., indicates that the demux can be connected via a call to
|
||||
* @connect_frontend to use the given front-end as a TS source. The
|
||||
* client of this function has to allocate dynamic or static memory for
|
||||
* the frontend structure and initialize its fields before calling this
|
||||
* function. This function is normally called during the driver
|
||||
* initialization. The caller must not free the memory of the frontend
|
||||
* struct before successfully calling @remove_frontend.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* The @frontend function parameter contains a pointer to the front-end
|
||||
* instance data.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -EINVAL, on bad parameter.
|
||||
*
|
||||
* @remove_frontend: Indicates that the given front-end, registered by a call
|
||||
* to @add_frontend, can no longer be connected as a TS source by this
|
||||
* demux. The function should be called when a front-end driver or a demux
|
||||
* driver is removed from the system. If the front-end is in use, the
|
||||
* function fails with the return value of -EBUSY. After successfully
|
||||
* calling this function, the caller can free the memory of the frontend
|
||||
* struct if it was dynamically allocated before the @add_frontend
|
||||
* operation.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* The @frontend function parameter contains a pointer to the front-end
|
||||
* instance data.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -ENODEV, if the front-end was not found,
|
||||
* -EINVAL, on bad parameter.
|
||||
*
|
||||
* @get_frontends: Provides the APIs of the front-ends that have been
|
||||
* registered for this demux. Any of the front-ends obtained with this
|
||||
* call can be used as a parameter for @connect_frontend. The include
|
||||
* file demux.h contains the macro DMX_FE_ENTRY() for converting an
|
||||
* element of the generic type struct &list_head * to the type
|
||||
* struct &dmx_frontend *. The caller must not free the memory of any of
|
||||
* the elements obtained via this function call.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* It returns a struct list_head pointer to the list of front-end
|
||||
* interfaces, or NULL in the case of an empty list.
|
||||
*
|
||||
* @connect_frontend: Connects the TS output of the front-end to the input of
|
||||
* the demux. A demux can only be connected to a front-end registered to
|
||||
* the demux with the function @add_frontend. It may or may not be
|
||||
* possible to connect multiple demuxes to the same front-end, depending
|
||||
* on the capabilities of the HW platform. When not used, the front-end
|
||||
* should be released by calling @disconnect_frontend.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* The @frontend function parameter contains a pointer to the front-end
|
||||
* instance data.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -EINVAL, on bad parameter.
|
||||
*
|
||||
* @disconnect_frontend: Disconnects the demux and a front-end previously
|
||||
* connected by a @connect_frontend call.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -EINVAL on bad parameter.
|
||||
*
|
||||
* @get_pes_pids: Get the PIDs for DMX_PES_AUDIO0, DMX_PES_VIDEO0,
|
||||
* DMX_PES_TELETEXT0, DMX_PES_SUBTITLE0 and DMX_PES_PCR0.
|
||||
* The @demux function parameter contains a pointer to the demux API and
|
||||
* instance data.
|
||||
* The @pids function parameter contains an array with five u16 elements
|
||||
* where the PIDs will be stored.
|
||||
* It returns:
|
||||
* 0 on success;
|
||||
* -EINVAL on bad parameter.
|
||||
*/
|
||||
struct dmx_demux {
|
||||
u32 capabilities; /* Bitfield of capability flags */
|
||||
struct dmx_frontend* frontend; /* Front-end connected to the demux */
|
||||
void* priv; /* Pointer to private data of the API client */
|
||||
int (*open) (struct dmx_demux* demux);
|
||||
int (*close) (struct dmx_demux* demux);
|
||||
int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
|
||||
int (*allocate_ts_feed) (struct dmx_demux* demux,
|
||||
struct dmx_ts_feed** feed,
|
||||
dmx_ts_cb callback);
|
||||
int (*release_ts_feed) (struct dmx_demux* demux,
|
||||
struct dmx_ts_feed* feed);
|
||||
int (*allocate_section_feed) (struct dmx_demux* demux,
|
||||
struct dmx_section_feed** feed,
|
||||
dmx_section_cb callback);
|
||||
int (*release_section_feed) (struct dmx_demux* demux,
|
||||
struct dmx_section_feed* feed);
|
||||
int (*add_frontend) (struct dmx_demux* demux,
|
||||
struct dmx_frontend* frontend);
|
||||
int (*remove_frontend) (struct dmx_demux* demux,
|
||||
struct dmx_frontend* frontend);
|
||||
struct list_head* (*get_frontends) (struct dmx_demux* demux);
|
||||
int (*connect_frontend) (struct dmx_demux* demux,
|
||||
struct dmx_frontend* frontend);
|
||||
int (*disconnect_frontend) (struct dmx_demux* demux);
|
||||
enum dmx_demux_caps capabilities;
|
||||
struct dmx_frontend *frontend;
|
||||
void *priv;
|
||||
int (*open)(struct dmx_demux *demux);
|
||||
int (*close)(struct dmx_demux *demux);
|
||||
int (*write)(struct dmx_demux *demux, const char __user *buf,
|
||||
size_t count);
|
||||
int (*allocate_ts_feed)(struct dmx_demux *demux,
|
||||
struct dmx_ts_feed **feed,
|
||||
dmx_ts_cb callback);
|
||||
int (*release_ts_feed)(struct dmx_demux *demux,
|
||||
struct dmx_ts_feed *feed);
|
||||
int (*allocate_section_feed)(struct dmx_demux *demux,
|
||||
struct dmx_section_feed **feed,
|
||||
dmx_section_cb callback);
|
||||
int (*release_section_feed)(struct dmx_demux *demux,
|
||||
struct dmx_section_feed *feed);
|
||||
int (*add_frontend)(struct dmx_demux *demux,
|
||||
struct dmx_frontend *frontend);
|
||||
int (*remove_frontend)(struct dmx_demux *demux,
|
||||
struct dmx_frontend *frontend);
|
||||
struct list_head *(*get_frontends)(struct dmx_demux *demux);
|
||||
int (*connect_frontend)(struct dmx_demux *demux,
|
||||
struct dmx_frontend *frontend);
|
||||
int (*disconnect_frontend)(struct dmx_demux *demux);
|
||||
|
||||
int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids);
|
||||
int (*get_pes_pids)(struct dmx_demux *demux, u16 *pids);
|
||||
|
||||
int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps);
|
||||
/* private: */
|
||||
|
||||
int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src);
|
||||
|
||||
int (*get_stc) (struct dmx_demux* demux, unsigned int num,
|
||||
u64 *stc, unsigned int *base);
|
||||
/*
|
||||
* Only used at av7110, to read some data from firmware.
|
||||
* As this was never documented, we have no clue about what's
|
||||
* there, and its usage on other drivers aren't encouraged.
|
||||
*/
|
||||
int (*get_stc)(struct dmx_demux *demux, unsigned int num,
|
||||
u64 *stc, unsigned int *base);
|
||||
};
|
||||
|
||||
#endif /* #ifndef __DEMUX_H */
|
||||
|
||||
@@ -14,12 +14,10 @@
|
||||
* 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 Lesser 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "dmxdev: " fmt
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -28,7 +26,7 @@
|
||||
#include <linux/poll.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/wait.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include "dmxdev.h"
|
||||
|
||||
static int debug;
|
||||
@@ -36,7 +34,11 @@ static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
|
||||
|
||||
#define dprintk if (debug) printk
|
||||
#define dprintk(fmt, arg...) do { \
|
||||
if (debug) \
|
||||
printk(KERN_DEBUG pr_fmt("%s: " fmt), \
|
||||
__func__, ##arg); \
|
||||
} while (0)
|
||||
|
||||
static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
|
||||
const u8 *src, size_t len)
|
||||
@@ -50,7 +52,7 @@ static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
|
||||
|
||||
free = dvb_ringbuffer_free(buf);
|
||||
if (len > free) {
|
||||
dprintk("dmxdev: buffer overflow\n");
|
||||
dprintk("buffer overflow\n");
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
@@ -126,7 +128,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
|
||||
struct dmxdev *dmxdev = dvbdev->priv;
|
||||
struct dmx_frontend *front;
|
||||
|
||||
dprintk("function : %s\n", __func__);
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if (mutex_lock_interruptible(&dmxdev->mutex))
|
||||
return -ERESTARTSYS;
|
||||
@@ -145,6 +147,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
|
||||
void *mem;
|
||||
|
||||
if (!dvbdev->readers) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -EBUSY;
|
||||
@@ -196,6 +199,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
|
||||
dvbdev->readers++;
|
||||
if (dmxdev->dvr_buffer.data) {
|
||||
void *mem = dmxdev->dvr_buffer.data;
|
||||
/*memory barrier*/
|
||||
mb();
|
||||
spin_lock_irq(&dmxdev->lock);
|
||||
dmxdev->dvr_buffer.data = NULL;
|
||||
@@ -206,8 +210,6 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
|
||||
/* TODO */
|
||||
dvbdev->users--;
|
||||
if (dvbdev->users == 1 && dmxdev->exit == 1) {
|
||||
fops_put(file->f_op);
|
||||
file->f_op = NULL;
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
wake_up(&dvbdev->wait_queue);
|
||||
} else
|
||||
@@ -260,7 +262,7 @@ static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
|
||||
void *newmem;
|
||||
void *oldmem;
|
||||
|
||||
dprintk("function : %s\n", __func__);
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if (buf->size == size)
|
||||
return 0;
|
||||
@@ -327,10 +329,34 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
|
||||
static void dvb_dmxdev_filter_timeout(struct timer_list *t)
|
||||
{
|
||||
struct dmxdev_filter *dmxdevfilter = from_timer(dmxdevfilter, t, timer);
|
||||
|
||||
dmxdevfilter->buffer.error = -ETIMEDOUT;
|
||||
spin_lock_irq(&dmxdevfilter->dev->lock);
|
||||
dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
|
||||
spin_unlock_irq(&dmxdevfilter->dev->lock);
|
||||
wake_up(&dmxdevfilter->buffer.queue);
|
||||
}
|
||||
|
||||
static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
|
||||
{
|
||||
struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
|
||||
|
||||
del_timer(&dmxdevfilter->timer);
|
||||
if (para->timeout) {
|
||||
dmxdevfilter->timer.expires =
|
||||
jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
|
||||
add_timer(&dmxdevfilter->timer);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void dvb_dmxdev_filter_timeout(unsigned long data)
|
||||
{
|
||||
struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
|
||||
|
||||
|
||||
dmxdevfilter->buffer.error = -ETIMEDOUT;
|
||||
spin_lock_irq(&dmxdevfilter->dev->lock);
|
||||
dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
|
||||
@@ -341,7 +367,7 @@ static void dvb_dmxdev_filter_timeout(unsigned long data)
|
||||
static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
|
||||
{
|
||||
struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
|
||||
|
||||
|
||||
del_timer(&dmxdevfilter->timer);
|
||||
if (para->timeout) {
|
||||
dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
|
||||
@@ -351,11 +377,10 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
|
||||
add_timer(&dmxdevfilter->timer);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
const u8 *buffer2, size_t buffer2_len,
|
||||
struct dmx_section_filter *filter,
|
||||
enum dmx_success success)
|
||||
struct dmx_section_filter *filter)
|
||||
{
|
||||
struct dmxdev_filter *dmxdevfilter = filter->priv;
|
||||
int ret;
|
||||
@@ -370,7 +395,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
return 0;
|
||||
}
|
||||
del_timer(&dmxdevfilter->timer);
|
||||
dprintk("dmxdev: section callback %*ph\n", 6, buffer1);
|
||||
dprintk("section callback %*ph\n", 6, buffer1);
|
||||
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
|
||||
buffer1_len);
|
||||
if (ret == buffer1_len) {
|
||||
@@ -388,8 +413,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
|
||||
static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
const u8 *buffer2, size_t buffer2_len,
|
||||
struct dmx_ts_feed *feed,
|
||||
enum dmx_success success)
|
||||
struct dmx_ts_feed *feed)
|
||||
{
|
||||
struct dmxdev_filter *dmxdevfilter = feed->priv;
|
||||
struct dvb_ringbuffer *buffer;
|
||||
@@ -560,14 +584,15 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
|
||||
struct dmxdev_filter *filter,
|
||||
struct dmxdev_feed *feed)
|
||||
{
|
||||
struct timespec timeout = { 0 };
|
||||
ktime_t timeout;
|
||||
struct dmx_pes_filter_params *para = &filter->params.pes;
|
||||
dmx_output_t otype;
|
||||
enum dmx_output otype;
|
||||
int ret;
|
||||
int ts_type;
|
||||
enum dmx_ts_pes ts_pes;
|
||||
struct dmx_ts_feed *tsfeed;
|
||||
|
||||
timeout = ktime_set(0, 0);
|
||||
feed->ts = NULL;
|
||||
otype = para->output;
|
||||
|
||||
@@ -593,7 +618,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
|
||||
tsfeed = feed->ts;
|
||||
tsfeed->priv = filter;
|
||||
|
||||
ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
|
||||
ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, timeout);
|
||||
if (ret < 0) {
|
||||
dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
|
||||
return ret;
|
||||
@@ -659,15 +684,15 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
|
||||
secfeed,
|
||||
dvb_dmxdev_section_callback);
|
||||
if (ret < 0) {
|
||||
printk("DVB (%s): could not alloc feed\n",
|
||||
pr_err("DVB (%s): could not alloc feed\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = (*secfeed)->set(*secfeed, para->pid, 32768,
|
||||
ret = (*secfeed)->set(*secfeed, para->pid,
|
||||
(para->flags & DMX_CHECK_CRC) ? 1 : 0);
|
||||
if (ret < 0) {
|
||||
printk("DVB (%s): could not set feed\n",
|
||||
pr_err("DVB (%s): could not set feed\n",
|
||||
__func__);
|
||||
dvb_dmxdev_feed_restart(filter);
|
||||
return ret;
|
||||
@@ -754,7 +779,11 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
|
||||
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
|
||||
dmxdevfilter->type = DMXDEV_TYPE_NONE;
|
||||
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
|
||||
timer_setup(&dmxdevfilter->timer, dvb_dmxdev_filter_timeout, 0);
|
||||
#else
|
||||
init_timer(&dmxdevfilter->timer);
|
||||
#endif
|
||||
|
||||
dvbdev->users++;
|
||||
|
||||
@@ -787,7 +816,7 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void invert_mode(dmx_filter_t *filter)
|
||||
static inline void invert_mode(struct dmx_filter *filter)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -848,7 +877,7 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
|
||||
struct dmxdev_filter *dmxdevfilter,
|
||||
struct dmx_sct_filter_params *params)
|
||||
{
|
||||
dprintk("function : %s, PID=0x%04x, flags=%02x, timeout=%d\n",
|
||||
dprintk("%s: PID=0x%04x, flags=%02x, timeout=%d\n",
|
||||
__func__, params->pid, params->flags, params->timeout);
|
||||
|
||||
dvb_dmxdev_filter_stop(dmxdevfilter);
|
||||
@@ -874,7 +903,7 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
|
||||
dvb_dmxdev_filter_stop(dmxdevfilter);
|
||||
dvb_dmxdev_filter_reset(dmxdevfilter);
|
||||
|
||||
if ((unsigned)params->pes_type > DMX_PES_OTHER)
|
||||
if ((unsigned int)params->pes_type > DMX_PES_OTHER)
|
||||
return -EINVAL;
|
||||
|
||||
dmxdevfilter->type = DMXDEV_TYPE_PES;
|
||||
@@ -1025,22 +1054,6 @@ static int dvb_demux_do_ioctl(struct file *file,
|
||||
dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
|
||||
break;
|
||||
|
||||
case DMX_GET_CAPS:
|
||||
if (!dmxdev->demux->get_caps) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
ret = dmxdev->demux->get_caps(dmxdev->demux, parg);
|
||||
break;
|
||||
|
||||
case DMX_SET_SOURCE:
|
||||
if (!dmxdev->demux->set_source) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
ret = dmxdev->demux->set_source(dmxdev->demux, parg);
|
||||
break;
|
||||
|
||||
case DMX_GET_STC:
|
||||
if (!dmxdev->demux->get_stc) {
|
||||
ret = -EINVAL;
|
||||
@@ -1089,8 +1102,8 @@ static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
|
||||
struct dmxdev_filter *dmxdevfilter = file->private_data;
|
||||
unsigned int mask = 0;
|
||||
|
||||
if (!dmxdevfilter)
|
||||
return -EINVAL;
|
||||
if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
|
||||
return POLLERR;
|
||||
|
||||
poll_wait(file, &dmxdevfilter->buffer.queue, wait);
|
||||
|
||||
@@ -1119,9 +1132,7 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
|
||||
|
||||
mutex_lock(&dmxdev->mutex);
|
||||
dmxdev->dvbdev->users--;
|
||||
if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
|
||||
fops_put(file->f_op);
|
||||
file->f_op = NULL;
|
||||
if (dmxdev->dvbdev->users == 1 && dmxdev->exit == 1) {
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
wake_up(&dmxdev->dvbdev->wait_queue);
|
||||
} else
|
||||
@@ -1140,10 +1151,13 @@ static const struct file_operations dvb_demux_fops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static struct dvb_device dvbdev_demux = {
|
||||
static const struct dvb_device dvbdev_demux = {
|
||||
.priv = NULL,
|
||||
.users = 1,
|
||||
.writers = 1,
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
||||
.name = "dvb-demux",
|
||||
#endif
|
||||
.fops = &dvb_demux_fops
|
||||
};
|
||||
|
||||
@@ -1183,7 +1197,10 @@ static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
|
||||
struct dmxdev *dmxdev = dvbdev->priv;
|
||||
unsigned int mask = 0;
|
||||
|
||||
dprintk("function : %s\n", __func__);
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if (dmxdev->exit)
|
||||
return POLLERR;
|
||||
|
||||
poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
|
||||
|
||||
@@ -1210,13 +1227,15 @@ static const struct file_operations dvb_dvr_fops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static struct dvb_device dvbdev_dvr = {
|
||||
static const struct dvb_device dvbdev_dvr = {
|
||||
.priv = NULL,
|
||||
.readers = 1,
|
||||
.users = 1,
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
||||
.name = "dvb-dvr",
|
||||
#endif
|
||||
.fops = &dvb_dvr_fops
|
||||
};
|
||||
|
||||
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
|
||||
{
|
||||
int i;
|
||||
@@ -1238,9 +1257,9 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
|
||||
}
|
||||
|
||||
dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
|
||||
DVB_DEVICE_DEMUX);
|
||||
DVB_DEVICE_DEMUX, dmxdev->filternum);
|
||||
dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
|
||||
dmxdev, DVB_DEVICE_DVR);
|
||||
dmxdev, DVB_DEVICE_DVR, dmxdev->filternum);
|
||||
|
||||
dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
|
||||
|
||||
@@ -1251,14 +1270,14 @@ EXPORT_SYMBOL(dvb_dmxdev_init);
|
||||
|
||||
void dvb_dmxdev_release(struct dmxdev *dmxdev)
|
||||
{
|
||||
dmxdev->exit=1;
|
||||
dmxdev->exit = 1;
|
||||
if (dmxdev->dvbdev->users > 1) {
|
||||
wait_event(dmxdev->dvbdev->wait_queue,
|
||||
dmxdev->dvbdev->users==1);
|
||||
dmxdev->dvbdev->users == 1);
|
||||
}
|
||||
if (dmxdev->dvr_dvbdev->users > 1) {
|
||||
wait_event(dmxdev->dvr_dvbdev->wait_queue,
|
||||
dmxdev->dvr_dvbdev->users==1);
|
||||
dmxdev->dvr_dvbdev->users == 1);
|
||||
}
|
||||
|
||||
dvb_unregister_device(dmxdev->dvbdev);
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
* 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 Lesser 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DMXDEV_H_
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,10 +12,6 @@
|
||||
* 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 Lesser 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.
|
||||
*/
|
||||
|
||||
#ifndef _DVB_CA_EN50221_H_
|
||||
@@ -37,104 +33,110 @@
|
||||
#define DVB_CA_EN50221_CAMCHANGE_REMOVED 0
|
||||
#define DVB_CA_EN50221_CAMCHANGE_INSERTED 1
|
||||
|
||||
|
||||
|
||||
/* Structure describing a CA interface */
|
||||
/**
|
||||
* struct dvb_ca_en50221- Structure describing a CA interface
|
||||
*
|
||||
* @owner: the module owning this structure
|
||||
* @read_attribute_mem: function for reading attribute memory on the CAM
|
||||
* @write_attribute_mem: function for writing attribute memory on the CAM
|
||||
* @read_cam_control: function for reading the control interface on the CAM
|
||||
* @write_cam_control: function for reading the control interface on the CAM
|
||||
* @read_data: function for reading data (block mode)
|
||||
* @write_data: function for writing data (block mode)
|
||||
* @slot_reset: function to reset the CAM slot
|
||||
* @slot_shutdown: function to shutdown a CAM slot
|
||||
* @slot_ts_enable: function to enable the Transport Stream on a CAM slot
|
||||
* @poll_slot_status: function to poll slot status. Only necessary if
|
||||
* DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set.
|
||||
* @data: private data, used by caller.
|
||||
* @private: Opaque data used by the dvb_ca core. Do not modify!
|
||||
*
|
||||
* NOTE: the read_*, write_* and poll_slot_status functions will be
|
||||
* called for different slots concurrently and need to use locks where
|
||||
* and if appropriate. There will be no concurrent access to one slot.
|
||||
*/
|
||||
struct dvb_ca_en50221 {
|
||||
struct module *owner;
|
||||
|
||||
/* the module owning this structure */
|
||||
struct module* owner;
|
||||
int (*read_attribute_mem)(struct dvb_ca_en50221 *ca,
|
||||
int slot, int address);
|
||||
int (*write_attribute_mem)(struct dvb_ca_en50221 *ca,
|
||||
int slot, int address, u8 value);
|
||||
|
||||
/* NOTE: the read_*, write_* and poll_slot_status functions will be
|
||||
* called for different slots concurrently and need to use locks where
|
||||
* and if appropriate. There will be no concurrent access to one slot.
|
||||
*/
|
||||
int (*read_cam_control)(struct dvb_ca_en50221 *ca,
|
||||
int slot, u8 address);
|
||||
int (*write_cam_control)(struct dvb_ca_en50221 *ca,
|
||||
int slot, u8 address, u8 value);
|
||||
|
||||
/* functions for accessing attribute memory on the CAM */
|
||||
int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
|
||||
int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
|
||||
int (*read_data)(struct dvb_ca_en50221 *ca,
|
||||
int slot, u8 *ebuf, int ecount);
|
||||
int (*write_data)(struct dvb_ca_en50221 *ca,
|
||||
int slot, u8 *ebuf, int ecount);
|
||||
|
||||
/* functions for accessing the control interface on the CAM */
|
||||
int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address);
|
||||
int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value);
|
||||
int (*slot_reset)(struct dvb_ca_en50221 *ca, int slot);
|
||||
int (*slot_shutdown)(struct dvb_ca_en50221 *ca, int slot);
|
||||
int (*slot_ts_enable)(struct dvb_ca_en50221 *ca, int slot);
|
||||
|
||||
/* functions for readin/writing data */
|
||||
int (*read_data)(struct dvb_ca_en50221* ca, int slot, u8 *ebuf, int ecount);
|
||||
int (*write_data)(struct dvb_ca_en50221* ca, int slot, u8 *ebuf, int ecount);
|
||||
int (*poll_slot_status)(struct dvb_ca_en50221 *ca, int slot, int open);
|
||||
|
||||
/* Functions for controlling slots */
|
||||
int (*slot_reset)(struct dvb_ca_en50221* ca, int slot);
|
||||
int (*slot_shutdown)(struct dvb_ca_en50221* ca, int slot);
|
||||
int (*slot_ts_enable)(struct dvb_ca_en50221* ca, int slot);
|
||||
void *data;
|
||||
|
||||
/*
|
||||
* Poll slot status.
|
||||
* Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
|
||||
*/
|
||||
int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open);
|
||||
|
||||
/* private data, used by caller */
|
||||
void* data;
|
||||
|
||||
/* Opaque data used by the dvb_ca core. Do not modify! */
|
||||
void* private;
|
||||
void *private;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* ******************************************************************************** */
|
||||
/* Functions for reporting IRQ events */
|
||||
|
||||
/**
|
||||
* A CAMCHANGE IRQ has occurred.
|
||||
*
|
||||
* @param ca CA instance.
|
||||
* @param slot Slot concerned.
|
||||
* @param change_type One of the DVB_CA_CAMCHANGE_* values
|
||||
/*
|
||||
* Functions for reporting IRQ events
|
||||
*/
|
||||
void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type);
|
||||
|
||||
/**
|
||||
* A CAMREADY IRQ has occurred.
|
||||
* dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred.
|
||||
*
|
||||
* @param ca CA instance.
|
||||
* @param slot Slot concerned.
|
||||
* @pubca: CA instance.
|
||||
* @slot: Slot concerned.
|
||||
* @change_type: One of the DVB_CA_CAMCHANGE_* values
|
||||
*/
|
||||
void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot);
|
||||
void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot,
|
||||
int change_type);
|
||||
|
||||
/**
|
||||
* An FR or a DA IRQ has occurred.
|
||||
* dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred.
|
||||
*
|
||||
* @param ca CA instance.
|
||||
* @param slot Slot concerned.
|
||||
* @pubca: CA instance.
|
||||
* @slot: Slot concerned.
|
||||
*/
|
||||
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot);
|
||||
|
||||
|
||||
|
||||
/* ******************************************************************************** */
|
||||
/* Initialisation/shutdown functions */
|
||||
void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot);
|
||||
|
||||
/**
|
||||
* Initialise a new DVB CA device.
|
||||
* dvb_ca_en50221_frda_irq - An FR or a DA IRQ has occurred.
|
||||
*
|
||||
* @param dvb_adapter DVB adapter to attach the new CA device to.
|
||||
* @param ca The dvb_ca instance.
|
||||
* @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
|
||||
* @param slot_count Number of slots supported.
|
||||
* @ca: CA instance.
|
||||
* @slot: Slot concerned.
|
||||
*/
|
||||
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *ca, int slot);
|
||||
|
||||
/*
|
||||
* Initialisation/shutdown functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* dvb_ca_en50221_init - Initialise a new DVB CA device.
|
||||
*
|
||||
* @dvb_adapter: DVB adapter to attach the new CA device to.
|
||||
* @ca: The dvb_ca instance.
|
||||
* @flags: Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
|
||||
* @slot_count: Number of slots supported.
|
||||
*
|
||||
* @return 0 on success, nonzero on failure
|
||||
*/
|
||||
extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count);
|
||||
int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
|
||||
struct dvb_ca_en50221 *ca, int flags,
|
||||
int slot_count);
|
||||
|
||||
/**
|
||||
* Release a DVB CA device.
|
||||
* dvb_ca_en50221_release - Release a DVB CA device.
|
||||
*
|
||||
* @param ca The associated dvb_ca instance.
|
||||
* @ca: The associated dvb_ca instance.
|
||||
*/
|
||||
extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca);
|
||||
|
||||
|
||||
void dvb_ca_en50221_release(struct dvb_ca_en50221 *ca);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,13 +15,16 @@
|
||||
* 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 Lesser 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "dvb_demux: " fmt
|
||||
|
||||
#include <linux/version.h>
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
|
||||
#include <linux/sched/signal.h>
|
||||
#else
|
||||
#include <linux/sched.h>
|
||||
#endif
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
@@ -29,16 +32,18 @@
|
||||
#include <linux/poll.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_demux.h"
|
||||
|
||||
#define NOBUFS
|
||||
/*
|
||||
** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog
|
||||
*/
|
||||
// #define DVB_DEMUX_SECTION_LOSS_LOG
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
|
||||
static inline s64 ktime_ms_delta(const ktime_t later, const ktime_t earlier)
|
||||
{
|
||||
return ktime_to_ms(ktime_sub(later, earlier));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dvb_demux_tscheck;
|
||||
module_param(dvb_demux_tscheck, int, 0644);
|
||||
@@ -55,10 +60,13 @@ module_param(dvb_demux_feed_err_pkts, int, 0644);
|
||||
MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
|
||||
"when set to 0, drop packets with the TEI bit set (1 by default)");
|
||||
|
||||
#define dprintk_tscheck(x...) do { \
|
||||
if (dvb_demux_tscheck && printk_ratelimit()) \
|
||||
printk(x); \
|
||||
} while (0)
|
||||
#define dprintk(fmt, arg...) \
|
||||
printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg)
|
||||
|
||||
#define dprintk_tscheck(x...) do { \
|
||||
if (dvb_demux_tscheck && printk_ratelimit()) \
|
||||
dprintk(x); \
|
||||
} while (0)
|
||||
|
||||
/******************************************************************************
|
||||
* static inlined helper functions
|
||||
@@ -109,28 +117,30 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
|
||||
{
|
||||
int count = payload(buf);
|
||||
int p;
|
||||
//int ccok;
|
||||
//u8 cc;
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
int ccok;
|
||||
u8 cc;
|
||||
#endif
|
||||
|
||||
if (count == 0)
|
||||
return -1;
|
||||
|
||||
p = 188 - count;
|
||||
|
||||
/*
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
cc = buf[3] & 0x0f;
|
||||
ccok = ((feed->cc + 1) & 0x0f) == cc;
|
||||
feed->cc = cc;
|
||||
if (!ccok)
|
||||
printk("missed packet!\n");
|
||||
*/
|
||||
dprintk("missed packet!\n");
|
||||
#endif
|
||||
|
||||
if (buf[1] & 0x40) // PUSI ?
|
||||
feed->peslen = 0xfffa;
|
||||
|
||||
feed->peslen += count;
|
||||
|
||||
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
|
||||
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts);
|
||||
}
|
||||
|
||||
static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
|
||||
@@ -152,7 +162,7 @@ static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
|
||||
return 0;
|
||||
|
||||
return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
|
||||
NULL, 0, &f->filter, DMX_OK);
|
||||
NULL, 0, &f->filter);
|
||||
}
|
||||
|
||||
static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
|
||||
@@ -189,7 +199,7 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
|
||||
{
|
||||
struct dmx_section_feed *sec = &feed->feed.sec;
|
||||
|
||||
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
if (sec->secbufp < sec->tsfeedp) {
|
||||
int i, n = sec->tsfeedp - sec->secbufp;
|
||||
|
||||
@@ -199,12 +209,12 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
|
||||
* but just first and last.
|
||||
*/
|
||||
if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
|
||||
printk("dvb_demux.c section ts padding loss: %d/%d\n",
|
||||
dprintk("dvb_demux.c section ts padding loss: %d/%d\n",
|
||||
n, sec->tsfeedp);
|
||||
printk("dvb_demux.c pad data:");
|
||||
dprintk("dvb_demux.c pad data:");
|
||||
for (i = 0; i < n; i++)
|
||||
printk(" %02x", sec->secbuf[i]);
|
||||
printk("\n");
|
||||
pr_cont(" %02x", sec->secbuf[i]);
|
||||
pr_cont("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -242,8 +252,8 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
|
||||
return 0;
|
||||
|
||||
if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
|
||||
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
|
||||
printk("dvb_demux.c section buffer full loss: %d/%d\n",
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
dprintk("dvb_demux.c section buffer full loss: %d/%d\n",
|
||||
sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
|
||||
DMX_MAX_SECFEED_SIZE);
|
||||
#endif
|
||||
@@ -276,9 +286,9 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
|
||||
/* dump [secbuf .. secbuf+seclen) */
|
||||
if (feed->pusi_seen)
|
||||
dvb_dmx_swfilter_section_feed(feed);
|
||||
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
else
|
||||
printk("dvb_demux.c pusi not seen, discarding section data\n");
|
||||
dprintk("dvb_demux.c pusi not seen, discarding section data\n");
|
||||
#endif
|
||||
sec->secbufp += seclen; /* secbufp and secbuf moving together is */
|
||||
sec->secbuf += seclen; /* redundant but saves pointer arithmetic */
|
||||
@@ -312,9 +322,9 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
|
||||
}
|
||||
|
||||
if (!ccok || dc_i) {
|
||||
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
|
||||
printk("dvb_demux.c discontinuity detected %d bytes lost\n",
|
||||
count);
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
dprintk("dvb_demux.c discontinuity detected %d bytes lost\n",
|
||||
count);
|
||||
/*
|
||||
* those bytes under sume circumstances will again be reported
|
||||
* in the following dvb_dmx_swfilter_section_new
|
||||
@@ -344,9 +354,10 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
|
||||
dvb_dmx_swfilter_section_copy_dump(feed, after,
|
||||
after_len);
|
||||
}
|
||||
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
else if (count > 0)
|
||||
printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
|
||||
dprintk("dvb_demux.c PUSI=1 but %d bytes lost\n",
|
||||
count);
|
||||
#endif
|
||||
} else {
|
||||
/* PUSI=0 (is not set), no section boundary */
|
||||
@@ -367,8 +378,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
|
||||
if (feed->ts_type & TS_PAYLOAD_ONLY)
|
||||
dvb_dmx_swfilter_payload(feed, buf);
|
||||
else
|
||||
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
|
||||
DMX_OK);
|
||||
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
|
||||
}
|
||||
if (feed->ts_type & TS_DECODER)
|
||||
if (feed->demux->write_to_decoder)
|
||||
@@ -399,31 +409,26 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
|
||||
int dvr_done = 0;
|
||||
|
||||
if (dvb_demux_speedcheck) {
|
||||
struct timespec cur_time, delta_time;
|
||||
ktime_t cur_time;
|
||||
u64 speed_bytes, speed_timedelta;
|
||||
|
||||
demux->speed_pkts_cnt++;
|
||||
|
||||
/* show speed every SPEED_PKTS_INTERVAL packets */
|
||||
if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
|
||||
cur_time = current_kernel_time();
|
||||
cur_time = ktime_get();
|
||||
|
||||
if (demux->speed_last_time.tv_sec != 0 &&
|
||||
demux->speed_last_time.tv_nsec != 0) {
|
||||
delta_time = timespec_sub(cur_time,
|
||||
demux->speed_last_time);
|
||||
if (ktime_to_ns(demux->speed_last_time) != 0) {
|
||||
speed_bytes = (u64)demux->speed_pkts_cnt
|
||||
* 188 * 8;
|
||||
/* convert to 1024 basis */
|
||||
speed_bytes = 1000 * div64_u64(speed_bytes,
|
||||
1024);
|
||||
speed_timedelta =
|
||||
(u64)timespec_to_ns(&delta_time);
|
||||
speed_timedelta = div64_u64(speed_timedelta,
|
||||
1000000); /* nsec -> usec */
|
||||
printk(KERN_INFO "TS speed %llu Kbits/sec \n",
|
||||
div64_u64(speed_bytes,
|
||||
speed_timedelta));
|
||||
speed_timedelta = ktime_ms_delta(cur_time,
|
||||
demux->speed_last_time);
|
||||
dprintk("TS speed %llu Kbits/sec \n",
|
||||
div64_u64(speed_bytes,
|
||||
speed_timedelta));
|
||||
}
|
||||
|
||||
demux->speed_last_time = cur_time;
|
||||
@@ -432,10 +437,9 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
|
||||
}
|
||||
|
||||
if (buf[1] & 0x80) {
|
||||
dprintk_tscheck("TEI detected. "
|
||||
"PID=0x%x data1=0x%x\n",
|
||||
dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n",
|
||||
pid, buf[1]);
|
||||
/* data in this packet cant be trusted - drop it unless
|
||||
/* data in this packet can't be trusted - drop it unless
|
||||
* module option dvb_demux_feed_err_pkts is set */
|
||||
if (!dvb_demux_feed_err_pkts)
|
||||
return;
|
||||
@@ -469,14 +473,16 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
|
||||
if (feed->pid == pid)
|
||||
dvb_dmx_swfilter_packet_type(feed, buf);
|
||||
else if (feed->pid == 0x2000)
|
||||
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
|
||||
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
|
||||
}
|
||||
}
|
||||
|
||||
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
|
||||
size_t count)
|
||||
{
|
||||
spin_lock(&demux->lock);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&demux->lock, flags);
|
||||
|
||||
while (count--) {
|
||||
if (buf[0] == 0x47)
|
||||
@@ -484,7 +490,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
|
||||
buf += 188;
|
||||
}
|
||||
|
||||
spin_unlock(&demux->lock);
|
||||
spin_unlock_irqrestore(&demux->lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
|
||||
@@ -519,8 +525,9 @@ static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
|
||||
{
|
||||
int p = 0, i, j;
|
||||
const u8 *q;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&demux->lock);
|
||||
spin_lock_irqsave(&demux->lock, flags);
|
||||
|
||||
if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
|
||||
i = demux->tsbufp;
|
||||
@@ -564,7 +571,7 @@ static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
|
||||
}
|
||||
|
||||
bailout:
|
||||
spin_unlock(&demux->lock);
|
||||
spin_unlock_irqrestore(&demux->lock, flags);
|
||||
}
|
||||
|
||||
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
|
||||
@@ -581,11 +588,13 @@ EXPORT_SYMBOL(dvb_dmx_swfilter_204);
|
||||
|
||||
void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
|
||||
{
|
||||
spin_lock(&demux->lock);
|
||||
unsigned long flags;
|
||||
|
||||
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
|
||||
spin_lock_irqsave(&demux->lock, flags);
|
||||
|
||||
spin_unlock(&demux->lock);
|
||||
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts);
|
||||
|
||||
spin_unlock_irqrestore(&demux->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
|
||||
|
||||
@@ -636,7 +645,7 @@ static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
|
||||
{
|
||||
spin_lock_irq(&feed->demux->lock);
|
||||
if (dvb_demux_feed_find(feed)) {
|
||||
printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
|
||||
pr_err("%s: feed already in list (type=%x state=%x pid=%x)\n",
|
||||
__func__, feed->type, feed->state, feed->pid);
|
||||
goto out;
|
||||
}
|
||||
@@ -650,7 +659,7 @@ static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
|
||||
{
|
||||
spin_lock_irq(&feed->demux->lock);
|
||||
if (!(dvb_demux_feed_find(feed))) {
|
||||
printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
|
||||
pr_err("%s: feed not in list (type=%x state=%x pid=%x)\n",
|
||||
__func__, feed->type, feed->state, feed->pid);
|
||||
goto out;
|
||||
}
|
||||
@@ -661,8 +670,7 @@ out:
|
||||
}
|
||||
|
||||
static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
|
||||
enum dmx_ts_pes pes_type,
|
||||
size_t circular_buffer_size, struct timespec timeout)
|
||||
enum dmx_ts_pes pes_type, ktime_t timeout)
|
||||
{
|
||||
struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
|
||||
struct dvb_demux *demux = feed->demux;
|
||||
@@ -692,23 +700,10 @@ static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
|
||||
dvb_demux_feed_add(feed);
|
||||
|
||||
feed->pid = pid;
|
||||
feed->buffer_size = circular_buffer_size;
|
||||
feed->timeout = timeout;
|
||||
feed->ts_type = ts_type;
|
||||
feed->pes_type = pes_type;
|
||||
|
||||
if (feed->buffer_size) {
|
||||
#ifdef NOBUFS
|
||||
feed->buffer = NULL;
|
||||
#else
|
||||
feed->buffer = vmalloc(feed->buffer_size);
|
||||
if (!feed->buffer) {
|
||||
mutex_unlock(&demux->mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
feed->state = DMX_STATE_READY;
|
||||
mutex_unlock(&demux->mutex);
|
||||
|
||||
@@ -797,7 +792,6 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
|
||||
feed->demux = demux;
|
||||
feed->pid = 0xffff;
|
||||
feed->peslen = 0xfffa;
|
||||
feed->buffer = NULL;
|
||||
|
||||
(*ts_feed) = &feed->feed.ts;
|
||||
(*ts_feed)->parent = dmx;
|
||||
@@ -834,10 +828,6 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
|
||||
mutex_unlock(&demux->mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
#ifndef NOBUFS
|
||||
vfree(feed->buffer);
|
||||
feed->buffer = NULL;
|
||||
#endif
|
||||
|
||||
feed->state = DMX_STATE_FREE;
|
||||
feed->filter->state = DMX_STATE_FREE;
|
||||
@@ -889,8 +879,7 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
|
||||
}
|
||||
|
||||
static int dmx_section_feed_set(struct dmx_section_feed *feed,
|
||||
u16 pid, size_t circular_buffer_size,
|
||||
int check_crc)
|
||||
u16 pid, int check_crc)
|
||||
{
|
||||
struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
|
||||
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
|
||||
@@ -904,19 +893,8 @@ static int dmx_section_feed_set(struct dmx_section_feed *feed,
|
||||
dvb_demux_feed_add(dvbdmxfeed);
|
||||
|
||||
dvbdmxfeed->pid = pid;
|
||||
dvbdmxfeed->buffer_size = circular_buffer_size;
|
||||
dvbdmxfeed->feed.sec.check_crc = check_crc;
|
||||
|
||||
#ifdef NOBUFS
|
||||
dvbdmxfeed->buffer = NULL;
|
||||
#else
|
||||
dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
|
||||
if (!dvbdmxfeed->buffer) {
|
||||
mutex_unlock(&dvbdmx->mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
dvbdmxfeed->state = DMX_STATE_READY;
|
||||
mutex_unlock(&dvbdmx->mutex);
|
||||
return 0;
|
||||
@@ -1027,8 +1005,13 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (feed->is_filtering)
|
||||
if (feed->is_filtering) {
|
||||
/* release dvbdmx->mutex as far as it is
|
||||
acquired by stop_filtering() itself */
|
||||
mutex_unlock(&dvbdmx->mutex);
|
||||
feed->stop_filtering(feed);
|
||||
mutex_lock(&dvbdmx->mutex);
|
||||
}
|
||||
|
||||
spin_lock_irq(&dvbdmx->lock);
|
||||
f = dvbdmxfeed->filter;
|
||||
@@ -1070,7 +1053,6 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
|
||||
dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
|
||||
dvbdmxfeed->feed.sec.tsfeedp = 0;
|
||||
dvbdmxfeed->filter = NULL;
|
||||
dvbdmxfeed->buffer = NULL;
|
||||
|
||||
(*feed) = &dvbdmxfeed->feed.sec;
|
||||
(*feed)->is_filtering = 0;
|
||||
@@ -1099,10 +1081,6 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux,
|
||||
mutex_unlock(&dvbdmx->mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
#ifndef NOBUFS
|
||||
vfree(dvbdmxfeed->buffer);
|
||||
dvbdmxfeed->buffer = NULL;
|
||||
#endif
|
||||
dvbdmxfeed->state = DMX_STATE_FREE;
|
||||
|
||||
dvb_demux_feed_del(dvbdmxfeed);
|
||||
@@ -1264,7 +1242,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
|
||||
|
||||
dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
|
||||
if (!dvbdemux->cnt_storage)
|
||||
printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
|
||||
pr_warn("Couldn't allocate memory for TS/TEI check. Disabling it\n");
|
||||
|
||||
INIT_LIST_HEAD(&dvbdemux->frontend_list);
|
||||
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
* 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 Lesser 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DVB_DEMUX_H_
|
||||
@@ -80,10 +76,8 @@ struct dvb_demux_feed {
|
||||
int type;
|
||||
int state;
|
||||
u16 pid;
|
||||
u8 *buffer;
|
||||
int buffer_size;
|
||||
|
||||
struct timespec timeout;
|
||||
ktime_t timeout;
|
||||
struct dvb_demux_filter *filter;
|
||||
|
||||
int ts_type;
|
||||
@@ -134,7 +128,7 @@ struct dvb_demux {
|
||||
|
||||
uint8_t *cnt_storage; /* for TS continuity check */
|
||||
|
||||
struct timespec speed_last_time; /* for TS speed check */
|
||||
ktime_t speed_last_time; /* for TS speed check */
|
||||
uint32_t speed_pkts_cnt; /* for TS speed check */
|
||||
};
|
||||
|
||||
|
||||
@@ -18,19 +18,23 @@
|
||||
* 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
|
||||
* To obtain the license, point your browser to
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/* Enables DVBv3 compatibility bits at the headers */
|
||||
#define __DVB_CORE__
|
||||
|
||||
#define pr_fmt(fmt) "dvb_frontend: " fmt
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/version.h>
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
|
||||
#include <linux/sched/signal.h>
|
||||
#else
|
||||
#include <linux/sched.h>
|
||||
#endif
|
||||
#include <linux/wait.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
@@ -40,6 +44,7 @@
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
@@ -66,6 +71,9 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volt
|
||||
module_param(dvb_mfe_wait_time, int, 0644);
|
||||
MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
|
||||
|
||||
#define dprintk(fmt, arg...) \
|
||||
printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg)
|
||||
|
||||
#define FESTATE_IDLE 1
|
||||
#define FESTATE_RETUNE 2
|
||||
#define FESTATE_TUNING_FAST 4
|
||||
@@ -80,7 +88,6 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open(
|
||||
#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
|
||||
#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
|
||||
|
||||
#define FE_ALGO_HW 1
|
||||
/*
|
||||
* FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
|
||||
* FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
|
||||
@@ -96,14 +103,9 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open(
|
||||
* FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
|
||||
*/
|
||||
|
||||
#define DVB_FE_NO_EXIT 0
|
||||
#define DVB_FE_NORMAL_EXIT 1
|
||||
#define DVB_FE_DEVICE_REMOVED 2
|
||||
|
||||
static DEFINE_MUTEX(frontend_mutex);
|
||||
|
||||
struct dvb_frontend_private {
|
||||
|
||||
/* thread/frontend values */
|
||||
struct dvb_device *dvbdev;
|
||||
struct dvb_frontend_parameters parameters_out;
|
||||
@@ -113,9 +115,8 @@ struct dvb_frontend_private {
|
||||
wait_queue_head_t wait_queue;
|
||||
struct task_struct *thread;
|
||||
unsigned long release_jiffies;
|
||||
unsigned int exit;
|
||||
unsigned int wakeup;
|
||||
fe_status_t status;
|
||||
enum fe_status status;
|
||||
unsigned long tune_mode_flags;
|
||||
unsigned int delay;
|
||||
unsigned int reinitialise;
|
||||
@@ -136,13 +137,46 @@ struct dvb_frontend_private {
|
||||
int quality;
|
||||
unsigned int check_wrapped;
|
||||
enum dvbfe_search algo_status;
|
||||
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
||||
struct media_pipeline pipe;
|
||||
#endif
|
||||
};
|
||||
|
||||
static void dvb_frontend_invoke_release(struct dvb_frontend *fe,
|
||||
void (*release)(struct dvb_frontend *fe));
|
||||
|
||||
static void dvb_frontend_free(struct kref *ref)
|
||||
{
|
||||
struct dvb_frontend *fe =
|
||||
container_of(ref, struct dvb_frontend, refcount);
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
|
||||
dvb_free_device(fepriv->dvbdev);
|
||||
|
||||
dvb_frontend_invoke_release(fe, fe->ops.release);
|
||||
|
||||
kfree(fepriv);
|
||||
}
|
||||
|
||||
static void dvb_frontend_put(struct dvb_frontend *fe)
|
||||
{
|
||||
kref_put(&fe->refcount, dvb_frontend_free);
|
||||
}
|
||||
|
||||
static void dvb_frontend_get(struct dvb_frontend *fe)
|
||||
{
|
||||
kref_get(&fe->refcount);
|
||||
}
|
||||
|
||||
static void dvb_frontend_wakeup(struct dvb_frontend *fe);
|
||||
static int dtv_get_frontend(struct dvb_frontend *fe,
|
||||
struct dtv_frontend_properties *c,
|
||||
struct dvb_frontend_parameters *p_out);
|
||||
static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *p);
|
||||
static int
|
||||
dtv_property_legacy_params_sync(struct dvb_frontend *fe,
|
||||
const struct dtv_frontend_properties *c,
|
||||
struct dvb_frontend_parameters *p);
|
||||
|
||||
static bool has_get_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
@@ -178,6 +212,7 @@ static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
|
||||
case SYS_DVBT2:
|
||||
case SYS_ISDBT:
|
||||
case SYS_DTMB:
|
||||
case SYS_DVBC2:
|
||||
return DVBV3_OFDM;
|
||||
case SYS_ATSC:
|
||||
case SYS_ATSCMH:
|
||||
@@ -198,9 +233,11 @@ static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
|
||||
}
|
||||
}
|
||||
|
||||
static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
|
||||
static void dvb_frontend_add_event(struct dvb_frontend *fe,
|
||||
enum fe_status status)
|
||||
{
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct dvb_fe_events *events = &fepriv->events;
|
||||
struct dvb_frontend_event *e;
|
||||
int wp;
|
||||
@@ -208,7 +245,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
|
||||
if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
|
||||
dtv_get_frontend(fe, &fepriv->parameters_out);
|
||||
dtv_get_frontend(fe, c, &fepriv->parameters_out);
|
||||
|
||||
mutex_lock(&events->mtx);
|
||||
|
||||
@@ -429,7 +466,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
|
||||
|
||||
static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
|
||||
{
|
||||
fe_status_t s = 0;
|
||||
enum fe_status s = FE_NONE;
|
||||
int retval = 0;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
|
||||
@@ -565,7 +602,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
|
||||
if (fepriv->exit != DVB_FE_NO_EXIT)
|
||||
if (fe->exit != DVB_FE_NO_EXIT)
|
||||
return 1;
|
||||
|
||||
if (fepriv->dvbdev->writers == 1)
|
||||
@@ -598,10 +635,10 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
|
||||
static int dvb_frontend_thread(void *data)
|
||||
{
|
||||
struct dvb_frontend *fe = data;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
fe_status_t s;
|
||||
enum fe_status s = FE_NONE;
|
||||
enum dvbfe_algo algo;
|
||||
|
||||
bool re_tune = false;
|
||||
bool semheld = false;
|
||||
|
||||
@@ -629,7 +666,7 @@ restart:
|
||||
/* got signal or quitting */
|
||||
if (!down_interruptible(&fepriv->sem))
|
||||
semheld = true;
|
||||
fepriv->exit = DVB_FE_NORMAL_EXIT;
|
||||
fe->exit = DVB_FE_NORMAL_EXIT;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -701,7 +738,7 @@ restart:
|
||||
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
|
||||
fepriv->delay = HZ / 2;
|
||||
}
|
||||
dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
|
||||
dtv_property_legacy_params_sync(fe, c, &fepriv->parameters_out);
|
||||
fe->ops.read_status(fe, &s);
|
||||
if (s != fepriv->status) {
|
||||
dvb_frontend_add_event(fe, s); /* update event list */
|
||||
@@ -739,9 +776,9 @@ restart:
|
||||
|
||||
fepriv->thread = NULL;
|
||||
if (kthread_should_stop())
|
||||
fepriv->exit = DVB_FE_DEVICE_REMOVED;
|
||||
fe->exit = DVB_FE_DEVICE_REMOVED;
|
||||
else
|
||||
fepriv->exit = DVB_FE_NO_EXIT;
|
||||
fe->exit = DVB_FE_NO_EXIT;
|
||||
mb();
|
||||
|
||||
if (semheld)
|
||||
@@ -756,7 +793,8 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
|
||||
fepriv->exit = DVB_FE_NORMAL_EXIT;
|
||||
if (fe->exit != DVB_FE_DEVICE_REMOVED)
|
||||
fe->exit = DVB_FE_NORMAL_EXIT;
|
||||
mb();
|
||||
|
||||
if (!fepriv->thread)
|
||||
@@ -774,43 +812,22 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
|
||||
fepriv->thread);
|
||||
}
|
||||
|
||||
s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
|
||||
{
|
||||
return ((curtime.tv_usec < lasttime.tv_usec) ?
|
||||
1000000 - lasttime.tv_usec + curtime.tv_usec :
|
||||
curtime.tv_usec - lasttime.tv_usec);
|
||||
}
|
||||
EXPORT_SYMBOL(timeval_usec_diff);
|
||||
|
||||
static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
|
||||
{
|
||||
curtime->tv_usec += add_usec;
|
||||
if (curtime->tv_usec >= 1000000) {
|
||||
curtime->tv_usec -= 1000000;
|
||||
curtime->tv_sec++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sleep until gettimeofday() > waketime + add_usec
|
||||
* This needs to be as precise as possible, but as the delay is
|
||||
* usually between 2ms and 32ms, it is done using a scheduled msleep
|
||||
* followed by usleep (normally a busy-wait loop) for the remainder
|
||||
* Sleep for the amount of time given by add_usec parameter
|
||||
*
|
||||
* This needs to be as precise as possible, as it affects the detection of
|
||||
* the dish tone command at the satellite subsystem. The precision is improved
|
||||
* by using a scheduled msleep followed by udelay for the remainder.
|
||||
*/
|
||||
void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
|
||||
void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec)
|
||||
{
|
||||
struct timeval lasttime;
|
||||
s32 delta, newdelta;
|
||||
s32 delta;
|
||||
|
||||
timeval_usec_add(waketime, add_usec);
|
||||
|
||||
do_gettimeofday(&lasttime);
|
||||
delta = timeval_usec_diff(lasttime, *waketime);
|
||||
*waketime = ktime_add_us(*waketime, add_usec);
|
||||
delta = ktime_us_delta(ktime_get_boottime(), *waketime);
|
||||
if (delta > 2500) {
|
||||
msleep((delta - 1500) / 1000);
|
||||
do_gettimeofday(&lasttime);
|
||||
newdelta = timeval_usec_diff(lasttime, *waketime);
|
||||
delta = (newdelta > delta) ? 0 : newdelta;
|
||||
delta = ktime_us_delta(ktime_get_boottime(), *waketime);
|
||||
}
|
||||
if (delta > 0)
|
||||
udelay(delta);
|
||||
@@ -826,7 +843,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
|
||||
if (fepriv->thread) {
|
||||
if (fepriv->exit == DVB_FE_NO_EXIT)
|
||||
if (fe->exit == DVB_FE_NO_EXIT)
|
||||
return 0;
|
||||
else
|
||||
dvb_frontend_stop (fe);
|
||||
@@ -838,7 +855,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
|
||||
return -EINTR;
|
||||
|
||||
fepriv->state = FESTATE_IDLE;
|
||||
fepriv->exit = DVB_FE_NO_EXIT;
|
||||
fe->exit = DVB_FE_NO_EXIT;
|
||||
fepriv->thread = NULL;
|
||||
mb();
|
||||
|
||||
@@ -955,7 +972,8 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
|
||||
}
|
||||
|
||||
c->stream_id = NO_STREAM_ID_FILTER;
|
||||
c->pls = NO_SCRAMBLING_CODE;
|
||||
c->scrambling_sequence_index = 0;/* default sequence */
|
||||
c->input = NO_INPUT;
|
||||
|
||||
switch (c->delivery_system) {
|
||||
case SYS_DVBS:
|
||||
@@ -967,6 +985,11 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
|
||||
case SYS_ATSC:
|
||||
c->modulation = VSB_8;
|
||||
break;
|
||||
case SYS_ISDBS:
|
||||
c->symbol_rate = 28860000;
|
||||
c->rolloff = ROLLOFF_35;
|
||||
c->bandwidth_hz = c->symbol_rate / 100 * 135;
|
||||
break;
|
||||
default:
|
||||
c->modulation = QAM_AUTO;
|
||||
break;
|
||||
@@ -985,6 +1008,17 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
|
||||
.buffer = b \
|
||||
}
|
||||
|
||||
struct dtv_cmds_h {
|
||||
char *name; /* A display name for debugging purposes */
|
||||
|
||||
__u32 cmd; /* A unique ID */
|
||||
|
||||
/* Flags */
|
||||
__u32 set:1; /* Either a set or get property */
|
||||
__u32 buffer:1; /* Does this property use the buffer? */
|
||||
__u32 reserved:30; /* Align */
|
||||
};
|
||||
|
||||
static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
|
||||
_DTV_CMD(DTV_TUNE, 1, 0),
|
||||
_DTV_CMD(DTV_CLEAR, 1, 0),
|
||||
@@ -1030,9 +1064,9 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
|
||||
|
||||
_DTV_CMD(DTV_STREAM_ID, 1, 0),
|
||||
_DTV_CMD(DTV_DVBT2_PLP_ID_LEGACY, 1, 0),
|
||||
_DTV_CMD(DTV_SCRAMBLING_SEQUENCE_INDEX, 1, 0),
|
||||
_DTV_CMD(DTV_LNA, 1, 0),
|
||||
_DTV_CMD(DTV_INPUT, 1, 0),
|
||||
_DTV_CMD(DTV_PLS, 1, 0),
|
||||
|
||||
/* Get */
|
||||
_DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
|
||||
@@ -1068,18 +1102,24 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
|
||||
_DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0),
|
||||
};
|
||||
|
||||
static void dtv_property_dump(struct dvb_frontend *fe, struct dtv_property *tvp)
|
||||
static void dtv_property_dump(struct dvb_frontend *fe,
|
||||
bool is_set,
|
||||
struct dtv_property *tvp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
|
||||
dev_warn(fe->dvb->device, "%s: tvp.cmd = 0x%08x undefined\n",
|
||||
__func__, tvp->cmd);
|
||||
dev_warn(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x undefined\n",
|
||||
__func__,
|
||||
is_set ? "SET" : "GET",
|
||||
tvp->cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s: tvp.cmd = 0x%08x (%s)\n", __func__,
|
||||
tvp->cmd, dtv_cmds[tvp->cmd].name);
|
||||
dev_dbg(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x (%s)\n", __func__,
|
||||
is_set ? "SET" : "GET",
|
||||
tvp->cmd,
|
||||
dtv_cmds[tvp->cmd].name);
|
||||
|
||||
if (dtv_cmds[tvp->cmd].buffer) {
|
||||
dev_dbg(fe->dvb->device, "%s: tvp.u.buffer.len = 0x%02x\n",
|
||||
@@ -1174,11 +1214,11 @@ static int dtv_property_cache_sync(struct dvb_frontend *fe,
|
||||
/* Ensure the cached values are set correctly in the frontend
|
||||
* legacy tuning structures, for the advanced tuning API.
|
||||
*/
|
||||
static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
static int
|
||||
dtv_property_legacy_params_sync(struct dvb_frontend *fe,
|
||||
const struct dtv_frontend_properties *c,
|
||||
struct dvb_frontend_parameters *p)
|
||||
{
|
||||
const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
|
||||
p->frequency = c->frequency;
|
||||
p->inversion = c->inversion;
|
||||
|
||||
@@ -1250,16 +1290,17 @@ static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
|
||||
* If p_out is not null, it will update the DVBv3 params pointed by it.
|
||||
*/
|
||||
static int dtv_get_frontend(struct dvb_frontend *fe,
|
||||
struct dtv_frontend_properties *c,
|
||||
struct dvb_frontend_parameters *p_out)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (fe->ops.get_frontend) {
|
||||
r = fe->ops.get_frontend(fe);
|
||||
r = fe->ops.get_frontend(fe, c);
|
||||
if (unlikely(r < 0))
|
||||
return r;
|
||||
if (p_out)
|
||||
dtv_property_legacy_params_sync(fe, p_out);
|
||||
dtv_property_legacy_params_sync(fe, c, p_out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1282,7 +1323,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
|
||||
switch(tvp->cmd) {
|
||||
case DTV_ENUM_DELSYS:
|
||||
ncaps = 0;
|
||||
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
|
||||
while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
|
||||
tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps];
|
||||
ncaps++;
|
||||
}
|
||||
@@ -1464,8 +1505,9 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
|
||||
tvp->u.buffer.len = 4;
|
||||
break;
|
||||
|
||||
case DTV_PLS:
|
||||
tvp->u.data = c->pls;
|
||||
/* Physical layer scrambling support */
|
||||
case DTV_SCRAMBLING_SEQUENCE_INDEX:
|
||||
tvp->u.data = c->scrambling_sequence_index;
|
||||
break;
|
||||
|
||||
/* Fill quality measures */
|
||||
@@ -1507,7 +1549,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
|
||||
return r;
|
||||
}
|
||||
|
||||
dtv_property_dump(fe, tvp);
|
||||
dtv_property_dump(fe, false, tvp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1516,12 +1558,8 @@ static int dtv_set_frontend(struct dvb_frontend *fe);
|
||||
|
||||
static bool is_dvbv3_delsys(u32 delsys)
|
||||
{
|
||||
bool status;
|
||||
|
||||
status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
|
||||
(delsys == SYS_DVBS) || (delsys == SYS_ATSC);
|
||||
|
||||
return status;
|
||||
return (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
|
||||
(delsys == SYS_DVBS) || (delsys == SYS_ATSC);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1611,7 +1649,7 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
|
||||
* supported
|
||||
*/
|
||||
ncaps = 0;
|
||||
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
|
||||
while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
|
||||
if (fe->ops.delsys[ncaps] == desired_system) {
|
||||
c->delivery_system = desired_system;
|
||||
dev_dbg(fe->dvb->device,
|
||||
@@ -1643,7 +1681,7 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
|
||||
* of the desired system
|
||||
*/
|
||||
ncaps = 0;
|
||||
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
|
||||
while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
|
||||
if (dvbv3_type(fe->ops.delsys[ncaps]) == type)
|
||||
delsys = fe->ops.delsys[ncaps];
|
||||
ncaps++;
|
||||
@@ -1718,7 +1756,7 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
|
||||
* DVBv3 standard
|
||||
*/
|
||||
ncaps = 0;
|
||||
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
|
||||
while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
|
||||
if (dvbv3_type(fe->ops.delsys[ncaps]) != DVBV3_UNKNOWN) {
|
||||
delsys = fe->ops.delsys[ncaps];
|
||||
break;
|
||||
@@ -1748,6 +1786,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
|
||||
return r;
|
||||
}
|
||||
|
||||
dtv_property_dump(fe, true, tvp);
|
||||
|
||||
switch(tvp->cmd) {
|
||||
case DTV_CLEAR:
|
||||
/*
|
||||
@@ -1897,9 +1937,9 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
|
||||
c->lna = tvp->u.data;
|
||||
if (fe->ops.set_lna)
|
||||
r = fe->ops.set_lna(fe);
|
||||
if (r < 0)
|
||||
c->lna = LNA_AUTO;
|
||||
break;
|
||||
if (r < 0)
|
||||
c->lna = LNA_AUTO;
|
||||
break;
|
||||
|
||||
case DTV_INPUT:
|
||||
c->input = tvp->u.data;
|
||||
@@ -1907,10 +1947,11 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
|
||||
r = fe->ops.set_input(fe, c->input);
|
||||
break;
|
||||
|
||||
case DTV_PLS:
|
||||
c->pls = tvp->u.data;
|
||||
/* Physical layer scrambling support */
|
||||
case DTV_SCRAMBLING_SEQUENCE_INDEX:
|
||||
c->scrambling_sequence_index = tvp->u.data;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1931,7 +1972,7 @@ static int dvb_frontend_ioctl(struct file *file,
|
||||
if (down_interruptible(&fepriv->sem))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (fepriv->exit != DVB_FE_NO_EXIT) {
|
||||
if (fe->exit != DVB_FE_NO_EXIT) {
|
||||
up(&fepriv->sem);
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1963,15 +2004,13 @@ static int dvb_frontend_ioctl_properties(struct file *file,
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
int err = 0;
|
||||
|
||||
struct dtv_properties *tvps = NULL;
|
||||
struct dtv_properties *tvps = parg;
|
||||
struct dtv_property *tvp = NULL;
|
||||
int i;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
|
||||
if(cmd == FE_SET_PROPERTY) {
|
||||
tvps = (struct dtv_properties __user *)parg;
|
||||
|
||||
if (cmd == FE_SET_PROPERTY) {
|
||||
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
|
||||
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
|
||||
|
||||
@@ -1980,16 +2019,9 @@ static int dvb_frontend_ioctl_properties(struct file *file,
|
||||
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
|
||||
if (!tvp) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
|
||||
if (IS_ERR(tvp))
|
||||
return PTR_ERR(tvp);
|
||||
|
||||
for (i = 0; i < tvps->num; i++) {
|
||||
err = dtv_property_process_set(fe, tvp + i, file);
|
||||
@@ -2001,9 +2033,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
|
||||
if (c->state == DTV_TUNE)
|
||||
dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__);
|
||||
|
||||
} else
|
||||
if(cmd == FE_GET_PROPERTY) {
|
||||
tvps = (struct dtv_properties __user *)parg;
|
||||
} else if (cmd == FE_GET_PROPERTY) {
|
||||
struct dtv_frontend_properties getp = fe->dtv_property_cache;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
|
||||
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
|
||||
@@ -2013,35 +2044,30 @@ static int dvb_frontend_ioctl_properties(struct file *file,
|
||||
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
|
||||
if (!tvp) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
|
||||
if (IS_ERR(tvp))
|
||||
return PTR_ERR(tvp);
|
||||
|
||||
/*
|
||||
* Fills the cache out struct with the cache contents, plus
|
||||
* the data retrieved from get_frontend, if the frontend
|
||||
* is not idle. Otherwise, returns the cached content
|
||||
* Let's use our own copy of property cache, in order to
|
||||
* avoid mangling with DTV zigzag logic, as drivers might
|
||||
* return crap, if they don't check if the data is available
|
||||
* before updating the properties cache.
|
||||
*/
|
||||
if (fepriv->state != FESTATE_IDLE) {
|
||||
err = dtv_get_frontend(fe, NULL);
|
||||
err = dtv_get_frontend(fe, &getp, NULL);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < tvps->num; i++) {
|
||||
err = dtv_property_process_get(fe, c, tvp + i, file);
|
||||
err = dtv_property_process_get(fe, &getp, 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))) {
|
||||
if (copy_to_user((void __user *)tvps->props, tvp,
|
||||
tvps->num * sizeof(struct dtv_property))) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
@@ -2069,7 +2095,7 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
|
||||
* the user. FE_SET_FRONTEND triggers an initial frontend event
|
||||
* with status = 0, which copies output parameters to userspace.
|
||||
*/
|
||||
dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
|
||||
dtv_property_legacy_params_sync(fe, c, &fepriv->parameters_out);
|
||||
|
||||
/*
|
||||
* Be sure that the bandwidth will be filled for all
|
||||
@@ -2101,11 +2127,29 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
|
||||
case SYS_DVBC_ANNEX_C:
|
||||
rolloff = 113;
|
||||
break;
|
||||
case SYS_DVBS:
|
||||
case SYS_TURBO:
|
||||
case SYS_ISDBS:
|
||||
rolloff = 135;
|
||||
break;
|
||||
case SYS_DVBS2:
|
||||
switch (c->rolloff) {
|
||||
case ROLLOFF_20:
|
||||
rolloff = 120;
|
||||
break;
|
||||
case ROLLOFF_25:
|
||||
rolloff = 125;
|
||||
break;
|
||||
default:
|
||||
case ROLLOFF_35:
|
||||
rolloff = 135;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (rolloff)
|
||||
c->bandwidth_hz = (c->symbol_rate * rolloff) / 100;
|
||||
c->bandwidth_hz = mult_frac(c->symbol_rate, rolloff, 100);
|
||||
|
||||
/* force auto frequency inversion if requested */
|
||||
if (dvb_force_auto_inversion)
|
||||
@@ -2222,15 +2266,15 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n",
|
||||
__func__, c->delivery_system, fe->ops.info.type);
|
||||
|
||||
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
|
||||
* do it, it is done for it. */
|
||||
info->caps |= FE_CAN_INVERSION_AUTO;
|
||||
/* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */
|
||||
if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT))
|
||||
info->caps |= FE_CAN_INVERSION_AUTO;
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case FE_READ_STATUS: {
|
||||
fe_status_t* status = parg;
|
||||
enum fe_status *status = parg;
|
||||
|
||||
/* if retune was requested but hasn't occurred yet, prevent
|
||||
* that user get signal state from previous tuning */
|
||||
@@ -2292,7 +2336,13 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
|
||||
case FE_DISEQC_SEND_MASTER_CMD:
|
||||
if (fe->ops.diseqc_send_master_cmd) {
|
||||
err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
|
||||
struct dvb_diseqc_master_cmd *cmd = parg;
|
||||
|
||||
if (cmd->msg_len > sizeof(cmd->msg)) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
err = fe->ops.diseqc_send_master_cmd(fe, cmd);
|
||||
fepriv->state = FESTATE_DISEQC;
|
||||
fepriv->status = 0;
|
||||
}
|
||||
@@ -2300,7 +2350,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
|
||||
case FE_DISEQC_SEND_BURST:
|
||||
if (fe->ops.diseqc_send_burst) {
|
||||
err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
|
||||
err = fe->ops.diseqc_send_burst(fe,
|
||||
(enum fe_sec_mini_cmd)parg);
|
||||
fepriv->state = FESTATE_DISEQC;
|
||||
fepriv->status = 0;
|
||||
}
|
||||
@@ -2308,8 +2359,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
|
||||
case FE_SET_TONE:
|
||||
if (fe->ops.set_tone) {
|
||||
err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
|
||||
fepriv->tone = (fe_sec_tone_mode_t) parg;
|
||||
err = fe->ops.set_tone(fe,
|
||||
(enum fe_sec_tone_mode)parg);
|
||||
fepriv->tone = (enum fe_sec_tone_mode)parg;
|
||||
fepriv->state = FESTATE_DISEQC;
|
||||
fepriv->status = 0;
|
||||
}
|
||||
@@ -2317,8 +2369,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
|
||||
case FE_SET_VOLTAGE:
|
||||
if (fe->ops.set_voltage) {
|
||||
err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
|
||||
fepriv->voltage = (fe_sec_voltage_t) parg;
|
||||
err = fe->ops.set_voltage(fe,
|
||||
(enum fe_sec_voltage)parg);
|
||||
fepriv->voltage = (enum fe_sec_voltage)parg;
|
||||
fepriv->state = FESTATE_DISEQC;
|
||||
fepriv->status = 0;
|
||||
}
|
||||
@@ -2326,7 +2379,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
|
||||
case FE_DISHNETWORK_SEND_LEGACY_CMD:
|
||||
if (fe->ops.dishnetwork_send_legacy_command) {
|
||||
err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
|
||||
err = fe->ops.dishnetwork_send_legacy_command(fe,
|
||||
(unsigned long)parg);
|
||||
fepriv->state = FESTATE_DISEQC;
|
||||
fepriv->status = 0;
|
||||
} else if (fe->ops.set_voltage) {
|
||||
@@ -2347,13 +2401,14 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
* include the initialization or start bit
|
||||
*/
|
||||
unsigned long swcmd = ((unsigned long) parg) << 1;
|
||||
struct timeval nexttime;
|
||||
struct timeval tv[10];
|
||||
ktime_t nexttime;
|
||||
ktime_t tv[10];
|
||||
int i;
|
||||
u8 last = 1;
|
||||
if (dvb_frontend_debug)
|
||||
printk("%s switch command: 0x%04lx\n", __func__, swcmd);
|
||||
do_gettimeofday(&nexttime);
|
||||
dprintk("%s switch command: 0x%04lx\n",
|
||||
__func__, swcmd);
|
||||
nexttime = ktime_get_boottime();
|
||||
if (dvb_frontend_debug)
|
||||
tv[0] = nexttime;
|
||||
/* before sending a command, initialize by sending
|
||||
@@ -2364,7 +2419,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
if (dvb_frontend_debug)
|
||||
do_gettimeofday(&tv[i + 1]);
|
||||
tv[i+1] = ktime_get_boottime();
|
||||
if ((swcmd & 0x01) != last) {
|
||||
/* set voltage to (last ? 13V : 18V) */
|
||||
fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
|
||||
@@ -2375,10 +2430,11 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
dvb_frontend_sleep_until(&nexttime, 8000);
|
||||
}
|
||||
if (dvb_frontend_debug) {
|
||||
printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
|
||||
dprintk("%s(%d): switch delay (should be 32k followed by all 8k)\n",
|
||||
__func__, fe->dvb->num);
|
||||
for (i = 1; i < 10; i++)
|
||||
printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
|
||||
pr_info("%d: %d\n", i,
|
||||
(int) ktime_us_delta(tv[i], tv[i-1]));
|
||||
}
|
||||
err = 0;
|
||||
fepriv->state = FESTATE_DISEQC;
|
||||
@@ -2410,10 +2466,18 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
err = dvb_frontend_get_event (fe, parg, file->f_flags);
|
||||
break;
|
||||
|
||||
case FE_GET_FRONTEND:
|
||||
err = dtv_get_frontend(fe, parg);
|
||||
break;
|
||||
case FE_GET_FRONTEND: {
|
||||
struct dtv_frontend_properties getp = fe->dtv_property_cache;
|
||||
|
||||
/*
|
||||
* Let's use our own copy of property cache, in order to
|
||||
* avoid mangling with DTV zigzag logic, as drivers might
|
||||
* return crap, if they don't check if the data is available
|
||||
* before updating the properties cache.
|
||||
*/
|
||||
err = dtv_get_frontend(fe, &getp, parg);
|
||||
break;
|
||||
}
|
||||
case FE_SET_FRONTEND_TUNE_MODE:
|
||||
fepriv->tune_mode_flags = (unsigned long) parg;
|
||||
err = 0;
|
||||
@@ -2430,7 +2494,7 @@ static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struc
|
||||
struct dvb_frontend *fe = dvbdev->priv;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
|
||||
//dev_dbg_ratelimited(fe->dvb->device, "%s:\n", __func__);
|
||||
dev_dbg_ratelimited(fe->dvb->device, "%s:\n", __func__);
|
||||
|
||||
poll_wait (file, &fepriv->events.wait_queue, wait);
|
||||
|
||||
@@ -2449,7 +2513,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
int ret;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
if (fepriv->exit == DVB_FE_DEVICE_REMOVED)
|
||||
if (fe->exit == DVB_FE_DEVICE_REMOVED)
|
||||
return -ENODEV;
|
||||
|
||||
if (adapter->mfe_shared) {
|
||||
@@ -2513,19 +2577,45 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
fepriv->tone = -1;
|
||||
fepriv->voltage = -1;
|
||||
|
||||
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
|
||||
if (fe->dvb->mdev) {
|
||||
mutex_lock(&fe->dvb->mdev->graph_mutex);
|
||||
if (fe->dvb->mdev->enable_source)
|
||||
ret = fe->dvb->mdev->enable_source(
|
||||
dvbdev->entity,
|
||||
&fepriv->pipe);
|
||||
mutex_unlock(&fe->dvb->mdev->graph_mutex);
|
||||
if (ret) {
|
||||
dev_err(fe->dvb->device,
|
||||
"Tuner is busy. Error %d\n", ret);
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ret = dvb_frontend_start (fe);
|
||||
if (ret)
|
||||
goto err2;
|
||||
goto err3;
|
||||
|
||||
/* empty event queue */
|
||||
fepriv->events.eventr = fepriv->events.eventw = 0;
|
||||
}
|
||||
|
||||
dvb_frontend_get(fe);
|
||||
|
||||
if (adapter->mfe_shared)
|
||||
mutex_unlock (&adapter->mfe_lock);
|
||||
return ret;
|
||||
|
||||
err3:
|
||||
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
|
||||
if (fe->dvb->mdev) {
|
||||
mutex_lock(&fe->dvb->mdev->graph_mutex);
|
||||
if (fe->dvb->mdev->disable_source)
|
||||
fe->dvb->mdev->disable_source(dvbdev->entity);
|
||||
mutex_unlock(&fe->dvb->mdev->graph_mutex);
|
||||
}
|
||||
err2:
|
||||
#endif
|
||||
dvb_generic_release(inode, file);
|
||||
err1:
|
||||
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
|
||||
@@ -2554,12 +2644,22 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
|
||||
|
||||
if (dvbdev->users == -1) {
|
||||
wake_up(&fepriv->wait_queue);
|
||||
if (fepriv->exit != DVB_FE_NO_EXIT)
|
||||
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
|
||||
if (fe->dvb->mdev) {
|
||||
mutex_lock(&fe->dvb->mdev->graph_mutex);
|
||||
if (fe->dvb->mdev->disable_source)
|
||||
fe->dvb->mdev->disable_source(dvbdev->entity);
|
||||
mutex_unlock(&fe->dvb->mdev->graph_mutex);
|
||||
}
|
||||
#endif
|
||||
if (fe->exit != DVB_FE_NO_EXIT)
|
||||
wake_up(&dvbdev->wait_queue);
|
||||
if (fe->ops.ts_bus_ctrl)
|
||||
fe->ops.ts_bus_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
dvb_frontend_put(fe);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2579,7 +2679,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe)
|
||||
dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
|
||||
fe->id);
|
||||
|
||||
if (fe->ops.tuner_ops.sleep)
|
||||
if (fe->ops.tuner_ops.suspend)
|
||||
ret = fe->ops.tuner_ops.suspend(fe);
|
||||
else if (fe->ops.tuner_ops.sleep)
|
||||
ret = fe->ops.tuner_ops.sleep(fe);
|
||||
|
||||
if (fe->ops.sleep)
|
||||
@@ -2597,12 +2699,21 @@ int dvb_frontend_resume(struct dvb_frontend *fe)
|
||||
dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
|
||||
fe->id);
|
||||
|
||||
fe->exit = DVB_FE_DEVICE_RESUME;
|
||||
if (fe->ops.init)
|
||||
ret = fe->ops.init(fe);
|
||||
|
||||
if (fe->ops.tuner_ops.init)
|
||||
if (fe->ops.tuner_ops.resume)
|
||||
ret = fe->ops.tuner_ops.resume(fe);
|
||||
else if (fe->ops.tuner_ops.init)
|
||||
ret = fe->ops.tuner_ops.init(fe);
|
||||
|
||||
if (fe->ops.set_tone && fepriv->tone != -1)
|
||||
fe->ops.set_tone(fe, fepriv->tone);
|
||||
if (fe->ops.set_voltage && fepriv->voltage != -1)
|
||||
fe->ops.set_voltage(fe, fepriv->voltage);
|
||||
|
||||
fe->exit = DVB_FE_NO_EXIT;
|
||||
fepriv->state = FESTATE_RETUNE;
|
||||
dvb_frontend_wakeup(fe);
|
||||
|
||||
@@ -2614,11 +2725,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
|
||||
struct dvb_frontend* fe)
|
||||
{
|
||||
struct dvb_frontend_private *fepriv;
|
||||
static const struct dvb_device dvbdev_template = {
|
||||
const struct dvb_device dvbdev_template = {
|
||||
.users = ~0,
|
||||
.writers = 1,
|
||||
.readers = (~0)-1,
|
||||
.fops = &dvb_frontend_fops,
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
||||
.name = fe->ops.info.name,
|
||||
#endif
|
||||
.kernel_ioctl = dvb_frontend_ioctl
|
||||
};
|
||||
|
||||
@@ -2634,6 +2748,15 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
|
||||
}
|
||||
fepriv = fe->frontend_priv;
|
||||
|
||||
kref_init(&fe->refcount);
|
||||
|
||||
/*
|
||||
* After initialization, there need to be two references: one
|
||||
* for dvb_unregister_frontend(), and another one for
|
||||
* dvb_frontend_detach().
|
||||
*/
|
||||
dvb_frontend_get(fe);
|
||||
|
||||
sema_init(&fepriv->sem, 1);
|
||||
init_waitqueue_head (&fepriv->wait_queue);
|
||||
init_waitqueue_head (&fepriv->events.wait_queue);
|
||||
@@ -2642,7 +2765,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
|
||||
fepriv->inversion = INVERSION_OFF;
|
||||
|
||||
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
|
||||
fe, DVB_DEVICE_FRONTEND);
|
||||
fe, DVB_DEVICE_FRONTEND, 0);
|
||||
|
||||
dev_info(fe->dvb->device,
|
||||
"DVB: registering adapter %i frontend %i (%s)...\n",
|
||||
@@ -2667,57 +2790,33 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
|
||||
mutex_lock(&frontend_mutex);
|
||||
dvb_frontend_stop (fe);
|
||||
mutex_unlock(&frontend_mutex);
|
||||
|
||||
if (fepriv->dvbdev->users < -1)
|
||||
wait_event(fepriv->dvbdev->wait_queue,
|
||||
fepriv->dvbdev->users==-1);
|
||||
|
||||
mutex_lock(&frontend_mutex);
|
||||
dvb_unregister_device (fepriv->dvbdev);
|
||||
dvb_frontend_stop(fe);
|
||||
dvb_remove_device(fepriv->dvbdev);
|
||||
|
||||
/* fe is invalid now */
|
||||
kfree(fepriv);
|
||||
mutex_unlock(&frontend_mutex);
|
||||
dvb_frontend_put(fe);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_unregister_frontend);
|
||||
|
||||
static void dvb_frontend_invoke_release(struct dvb_frontend *fe,
|
||||
void (*release)(struct dvb_frontend *fe))
|
||||
{
|
||||
if (release) {
|
||||
release(fe);
|
||||
#ifdef CONFIG_MEDIA_ATTACH
|
||||
void dvb_frontend_detach(struct dvb_frontend* fe)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (fe->ops.release_sec) {
|
||||
fe->ops.release_sec(fe);
|
||||
symbol_put_addr(fe->ops.release_sec);
|
||||
}
|
||||
if (fe->ops.tuner_ops.release) {
|
||||
fe->ops.tuner_ops.release(fe);
|
||||
symbol_put_addr(fe->ops.tuner_ops.release);
|
||||
}
|
||||
if (fe->ops.analog_ops.release) {
|
||||
fe->ops.analog_ops.release(fe);
|
||||
symbol_put_addr(fe->ops.analog_ops.release);
|
||||
}
|
||||
ptr = (void*)fe->ops.release;
|
||||
if (ptr) {
|
||||
fe->ops.release(fe);
|
||||
symbol_put_addr(ptr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void dvb_frontend_detach(struct dvb_frontend* fe)
|
||||
{
|
||||
if (fe->ops.release_sec)
|
||||
fe->ops.release_sec(fe);
|
||||
if (fe->ops.tuner_ops.release)
|
||||
fe->ops.tuner_ops.release(fe);
|
||||
if (fe->ops.analog_ops.release)
|
||||
fe->ops.analog_ops.release(fe);
|
||||
if (fe->ops.release)
|
||||
fe->ops.release(fe);
|
||||
}
|
||||
dvb_detach(release);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void dvb_frontend_detach(struct dvb_frontend* fe)
|
||||
{
|
||||
dvb_frontend_invoke_release(fe, fe->ops.release_sec);
|
||||
dvb_frontend_invoke_release(fe, fe->ops.tuner_ops.release);
|
||||
dvb_frontend_invoke_release(fe, fe->ops.analog_ops.release);
|
||||
dvb_frontend_invoke_release(fe, fe->ops.detach);
|
||||
dvb_frontend_put(fe);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_frontend_detach);
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
/*
|
||||
* dvb_frontend.h
|
||||
*
|
||||
* The Digital TV Frontend kABI defines a driver-internal interface for
|
||||
* registering low-level, hardware specific driver to a hardware independent
|
||||
* frontend layer.
|
||||
*
|
||||
* Copyright (C) 2001 convergence integrated media GmbH
|
||||
* Copyright (C) 2004 convergence GmbH
|
||||
*
|
||||
@@ -29,7 +33,12 @@
|
||||
#define _DVB_FRONTEND_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/version.h>
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
|
||||
#include <linux/sched/signal.h>
|
||||
#else
|
||||
#include <linux/sched.h>
|
||||
#endif
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
@@ -48,6 +57,15 @@
|
||||
*/
|
||||
#define MAX_DELSYS 8
|
||||
|
||||
/**
|
||||
* struct dvb_frontend_tune_settings - parameters to adjust frontend tuning
|
||||
*
|
||||
* @min_delay_ms: minimum delay for tuning, in ms
|
||||
* @step_size: step size between two consecutive frequencies
|
||||
* @max_drift: maximum drift
|
||||
*
|
||||
* NOTE: step_size is in Hz, for terrestrial/cable or kHz for satellite
|
||||
*/
|
||||
struct dvb_frontend_tune_settings {
|
||||
int min_delay_ms;
|
||||
int step_size;
|
||||
@@ -56,6 +74,20 @@ struct dvb_frontend_tune_settings {
|
||||
|
||||
struct dvb_frontend;
|
||||
|
||||
/**
|
||||
* struct dvb_tuner_info - Frontend name and min/max ranges/bandwidths
|
||||
*
|
||||
* @name: name of the Frontend
|
||||
* @frequency_min: minimal frequency supported
|
||||
* @frequency_max: maximum frequency supported
|
||||
* @frequency_step: frequency step
|
||||
* @bandwidth_min: minimal frontend bandwidth supported
|
||||
* @bandwidth_max: maximum frontend bandwidth supported
|
||||
* @bandwidth_step: frontend bandwidth step
|
||||
*
|
||||
* NOTE: frequency parameters are in Hz, for terrestrial/cable or kHz for
|
||||
* satellite.
|
||||
*/
|
||||
struct dvb_tuner_info {
|
||||
char name[128];
|
||||
|
||||
@@ -68,6 +100,20 @@ struct dvb_tuner_info {
|
||||
u32 bandwidth_step;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct analog_parameters - Parameters to tune into an analog/radio channel
|
||||
*
|
||||
* @frequency: Frequency used by analog TV tuner (either in 62.5 kHz step,
|
||||
* for TV, or 62.5 Hz for radio)
|
||||
* @mode: Tuner mode, as defined on enum v4l2_tuner_type
|
||||
* @audmode: Audio mode as defined for the rxsubchans field at videodev2.h,
|
||||
* e. g. V4L2_TUNER_MODE_*
|
||||
* @std: TV standard bitmap as defined at videodev2.h, e. g. V4L2_STD_*
|
||||
*
|
||||
* Hybrid tuners should be supported by both V4L2 and DVB APIs. This
|
||||
* struct contains the data that are used by the V4L2 side. To avoid
|
||||
* dependencies from V4L2 headers, all enums here are declared as integers.
|
||||
*/
|
||||
struct analog_parameters {
|
||||
unsigned int frequency;
|
||||
unsigned int mode;
|
||||
@@ -75,76 +121,28 @@ struct analog_parameters {
|
||||
u64 std;
|
||||
};
|
||||
|
||||
enum dvbfe_modcod {
|
||||
DVBFE_MODCOD_DUMMY_PLFRAME = 0,
|
||||
DVBFE_MODCOD_QPSK_1_4,
|
||||
DVBFE_MODCOD_QPSK_1_3,
|
||||
DVBFE_MODCOD_QPSK_2_5,
|
||||
DVBFE_MODCOD_QPSK_1_2,
|
||||
DVBFE_MODCOD_QPSK_3_5,
|
||||
DVBFE_MODCOD_QPSK_2_3,
|
||||
DVBFE_MODCOD_QPSK_3_4,
|
||||
DVBFE_MODCOD_QPSK_4_5,
|
||||
DVBFE_MODCOD_QPSK_5_6,
|
||||
DVBFE_MODCOD_QPSK_8_9,
|
||||
DVBFE_MODCOD_QPSK_9_10,
|
||||
DVBFE_MODCOD_8PSK_3_5,
|
||||
DVBFE_MODCOD_8PSK_2_3,
|
||||
DVBFE_MODCOD_8PSK_3_4,
|
||||
DVBFE_MODCOD_8PSK_5_6,
|
||||
DVBFE_MODCOD_8PSK_8_9,
|
||||
DVBFE_MODCOD_8PSK_9_10,
|
||||
DVBFE_MODCOD_16APSK_2_3,
|
||||
DVBFE_MODCOD_16APSK_3_4,
|
||||
DVBFE_MODCOD_16APSK_4_5,
|
||||
DVBFE_MODCOD_16APSK_5_6,
|
||||
DVBFE_MODCOD_16APSK_8_9,
|
||||
DVBFE_MODCOD_16APSK_9_10,
|
||||
DVBFE_MODCOD_32APSK_3_4,
|
||||
DVBFE_MODCOD_32APSK_4_5,
|
||||
DVBFE_MODCOD_32APSK_5_6,
|
||||
DVBFE_MODCOD_32APSK_8_9,
|
||||
DVBFE_MODCOD_32APSK_9_10,
|
||||
DVBFE_MODCOD_RESERVED_1,
|
||||
DVBFE_MODCOD_BPSK_1_3,
|
||||
DVBFE_MODCOD_BPSK_1_4,
|
||||
DVBFE_MODCOD_RESERVED_2
|
||||
};
|
||||
|
||||
enum tuner_param {
|
||||
DVBFE_TUNER_FREQUENCY = (1 << 0),
|
||||
DVBFE_TUNER_TUNERSTEP = (1 << 1),
|
||||
DVBFE_TUNER_IFFREQ = (1 << 2),
|
||||
DVBFE_TUNER_BANDWIDTH = (1 << 3),
|
||||
DVBFE_TUNER_REFCLOCK = (1 << 4),
|
||||
DVBFE_TUNER_IQSENSE = (1 << 5),
|
||||
DVBFE_TUNER_DUMMY = (1 << 31)
|
||||
};
|
||||
|
||||
/*
|
||||
* ALGO_HW: (Hardware Algorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* Devices that support this algorithm do everything in hardware
|
||||
* and no software support is needed to handle them.
|
||||
* Requesting these devices to LOCK is the only thing required,
|
||||
* device is supposed to do everything in the hardware.
|
||||
/**
|
||||
* enum dvbfe_algo - defines the algorithm used to tune into a channel
|
||||
*
|
||||
* ALGO_SW: (Software Algorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* @DVBFE_ALGO_HW: Hardware Algorithm -
|
||||
* Devices that support this algorithm do everything in hardware
|
||||
* and no software support is needed to handle them.
|
||||
* Requesting these devices to LOCK is the only thing required,
|
||||
* device is supposed to do everything in the hardware.
|
||||
*
|
||||
* @DVBFE_ALGO_SW: Software Algorithm -
|
||||
* These are dumb devices, that require software to do everything
|
||||
*
|
||||
* ALGO_CUSTOM: (Customizable Agorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* Devices having this algorithm can be customized to have specific
|
||||
* algorithms in the frontend driver, rather than simply doing a
|
||||
* software zig-zag. In this case the zigzag maybe hardware assisted
|
||||
* or it maybe completely done in hardware. In all cases, usage of
|
||||
* this algorithm, in conjunction with the search and track
|
||||
* callbacks, utilizes the driver specific algorithm.
|
||||
* @DVBFE_ALGO_CUSTOM: Customizable Agorithm -
|
||||
* Devices having this algorithm can be customized to have specific
|
||||
* algorithms in the frontend driver, rather than simply doing a
|
||||
* software zig-zag. In this case the zigzag maybe hardware assisted
|
||||
* or it maybe completely done in hardware. In all cases, usage of
|
||||
* this algorithm, in conjunction with the search and track
|
||||
* callbacks, utilizes the driver specific algorithm.
|
||||
*
|
||||
* ALGO_RECOVERY: (Recovery Algorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* These devices have AUTO recovery capabilities from LOCK failure
|
||||
* @DVBFE_ALGO_RECOVERY: Recovery Algorithm -
|
||||
* These devices have AUTO recovery capabilities from LOCK failure
|
||||
*/
|
||||
enum dvbfe_algo {
|
||||
DVBFE_ALGO_HW = (1 << 0),
|
||||
@@ -153,36 +151,27 @@ enum dvbfe_algo {
|
||||
DVBFE_ALGO_RECOVERY = (1 << 31)
|
||||
};
|
||||
|
||||
struct tuner_state {
|
||||
u32 frequency;
|
||||
u32 tunerstep;
|
||||
u32 ifreq;
|
||||
u32 bandwidth;
|
||||
u32 iqsense;
|
||||
u32 refclock;
|
||||
};
|
||||
|
||||
/*
|
||||
* search callback possible return status
|
||||
/**
|
||||
* enum dvbfe_search - search callback possible return status
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_SUCCESS
|
||||
* The frontend search algorithm completed and returned successfully
|
||||
* @DVBFE_ALGO_SEARCH_SUCCESS:
|
||||
* The frontend search algorithm completed and returned successfully
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_ASLEEP
|
||||
* The frontend search algorithm is sleeping
|
||||
* @DVBFE_ALGO_SEARCH_ASLEEP:
|
||||
* The frontend search algorithm is sleeping
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_FAILED
|
||||
* The frontend search for a signal failed
|
||||
* @DVBFE_ALGO_SEARCH_FAILED:
|
||||
* The frontend search for a signal failed
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_INVALID
|
||||
* The frontend search algorith was probably supplied with invalid
|
||||
* parameters and the search is an invalid one
|
||||
* @DVBFE_ALGO_SEARCH_INVALID:
|
||||
* The frontend search algorith was probably supplied with invalid
|
||||
* parameters and the search is an invalid one
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_ERROR
|
||||
* The frontend search algorithm failed due to some error
|
||||
* @DVBFE_ALGO_SEARCH_ERROR:
|
||||
* The frontend search algorithm failed due to some error
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_AGAIN
|
||||
* The frontend search algorithm was requested to search again
|
||||
* @DVBFE_ALGO_SEARCH_AGAIN:
|
||||
* The frontend search algorithm was requested to search again
|
||||
*/
|
||||
enum dvbfe_search {
|
||||
DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0),
|
||||
@@ -193,23 +182,64 @@ enum dvbfe_search {
|
||||
DVBFE_ALGO_SEARCH_ERROR = (1 << 31),
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct dvb_tuner_ops - Tuner information and callbacks
|
||||
*
|
||||
* @info: embedded struct dvb_tuner_info with tuner properties
|
||||
* @release: callback function called when frontend is dettached.
|
||||
* drivers should free any allocated memory.
|
||||
* @init: callback function used to initialize the tuner device.
|
||||
* @sleep: callback function used to put the tuner to sleep.
|
||||
* @suspend: callback function used to inform that the Kernel will
|
||||
* suspend.
|
||||
* @resume: callback function used to inform that the Kernel is
|
||||
* resuming from suspend.
|
||||
* @set_params: callback function used to inform the tuner to tune
|
||||
* into a digital TV channel. The properties to be used
|
||||
* are stored at @dvb_frontend.dtv_property_cache;. The
|
||||
* tuner demod can change the parameters to reflect the
|
||||
* changes needed for the channel to be tuned, and
|
||||
* update statistics. This is the recommended way to set
|
||||
* the tuner parameters and should be used on newer
|
||||
* drivers.
|
||||
* @set_analog_params: callback function used to tune into an analog TV
|
||||
* channel on hybrid tuners. It passes @analog_parameters;
|
||||
* to the driver.
|
||||
* @set_config: callback function used to send some tuner-specific
|
||||
* parameters.
|
||||
* @get_frequency: get the actual tuned frequency
|
||||
* @get_bandwidth: get the bandwitdh used by the low pass filters
|
||||
* @get_if_frequency: get the Intermediate Frequency, in Hz. For baseband,
|
||||
* should return 0.
|
||||
* @get_status: returns the frontend lock status
|
||||
* @get_rf_strength: returns the RF signal strengh. Used mostly to support
|
||||
* analog TV and radio. Digital TV should report, instead,
|
||||
* via DVBv5 API (@dvb_frontend.dtv_property_cache;).
|
||||
* @get_afc: Used only by analog TV core. Reports the frequency
|
||||
* drift due to AFC.
|
||||
* @calc_regs: callback function used to pass register data settings
|
||||
* for simple tuners. Shouldn't be used on newer drivers.
|
||||
* @set_frequency: Set a new frequency. Shouldn't be used on newer drivers.
|
||||
* @set_bandwidth: Set a new frequency. Shouldn't be used on newer drivers.
|
||||
*
|
||||
* NOTE: frequencies used on get_frequency and set_frequency are in Hz for
|
||||
* terrestrial/cable or kHz for satellite.
|
||||
*
|
||||
*/
|
||||
struct dvb_tuner_ops {
|
||||
|
||||
struct dvb_tuner_info info;
|
||||
|
||||
int (*release)(struct dvb_frontend *fe);
|
||||
void (*release)(struct dvb_frontend *fe);
|
||||
int (*init)(struct dvb_frontend *fe);
|
||||
int (*sleep)(struct dvb_frontend *fe);
|
||||
int (*suspend)(struct dvb_frontend *fe);
|
||||
int (*resume)(struct dvb_frontend *fe);
|
||||
|
||||
/** This is for simple PLLs - set all parameters in one go. */
|
||||
/* This is the recomended way to set the tuner */
|
||||
int (*set_params)(struct dvb_frontend *fe);
|
||||
int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
|
||||
|
||||
/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
|
||||
int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
|
||||
|
||||
/** This is to allow setting tuner-specific configs */
|
||||
int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
|
||||
|
||||
int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
|
||||
@@ -222,23 +252,56 @@ struct dvb_tuner_ops {
|
||||
int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
|
||||
int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
|
||||
|
||||
/** These are provided separately from set_params in order to facilitate silicon
|
||||
* tuners which require sophisticated tuning loops, controlling each parameter separately. */
|
||||
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
|
||||
int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
|
||||
/*
|
||||
* This is support for demods like the mt352 - fills out the supplied
|
||||
* buffer with what to write.
|
||||
*
|
||||
* Don't use on newer drivers.
|
||||
*/
|
||||
int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
|
||||
|
||||
/*
|
||||
* These are provided separately from set_params in order to facilitate silicon
|
||||
* tuners which require sophisticated tuning loops, controlling each parameter separately.
|
||||
* These are provided separately from set_params in order to
|
||||
* facilitate silicon tuners which require sophisticated tuning loops,
|
||||
* controlling each parameter separately.
|
||||
*
|
||||
* Don't use on newer drivers.
|
||||
*/
|
||||
int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
|
||||
int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
|
||||
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
|
||||
int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct analog_demod_info - Information struct for analog TV part of the demod
|
||||
*
|
||||
* @name: Name of the analog TV demodulator
|
||||
*/
|
||||
struct analog_demod_info {
|
||||
char *name;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct analog_demod_ops - Demodulation information and callbacks for
|
||||
* analog TV and radio
|
||||
*
|
||||
* @info: pointer to struct analog_demod_info
|
||||
* @set_params: callback function used to inform the demod to set the
|
||||
* demodulator parameters needed to decode an analog or
|
||||
* radio channel. The properties are passed via
|
||||
* struct @analog_params;.
|
||||
* @has_signal: returns 0xffff if has signal, or 0 if it doesn't.
|
||||
* @get_afc: Used only by analog TV core. Reports the frequency
|
||||
* drift due to AFC.
|
||||
* @tuner_status: callback function that returns tuner status bits, e. g.
|
||||
* TUNER_STATUS_LOCKED and TUNER_STATUS_STEREO.
|
||||
* @standby: set the tuner to standby mode.
|
||||
* @release: callback function called when frontend is dettached.
|
||||
* drivers should free any allocated memory.
|
||||
* @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C
|
||||
* mux support instead.
|
||||
* @set_config: callback function used to send some tuner-specific
|
||||
* parameters.
|
||||
*/
|
||||
struct analog_demod_ops {
|
||||
|
||||
struct analog_demod_info info;
|
||||
@@ -258,12 +321,103 @@ struct analog_demod_ops {
|
||||
|
||||
struct dtv_frontend_properties;
|
||||
|
||||
|
||||
/**
|
||||
* struct dvb_frontend_ops - Demodulation information and callbacks for
|
||||
* ditialt TV
|
||||
*
|
||||
* @info: embedded struct dvb_tuner_info with tuner properties
|
||||
* @delsys: Delivery systems supported by the frontend
|
||||
* @detach: callback function called when frontend is detached.
|
||||
* drivers should clean up, but not yet free the struct
|
||||
* dvb_frontend allocation.
|
||||
* @release: callback function called when frontend is ready to be
|
||||
* freed.
|
||||
* drivers should free any allocated memory.
|
||||
* @release_sec: callback function requesting that the Satelite Equipment
|
||||
* Control (SEC) driver to release and free any memory
|
||||
* allocated by the driver.
|
||||
* @init: callback function used to initialize the tuner device.
|
||||
* @sleep: callback function used to put the tuner to sleep.
|
||||
* @write: callback function used by some demod legacy drivers to
|
||||
* allow other drivers to write data into their registers.
|
||||
* Should not be used on new drivers.
|
||||
* @tune: callback function used by demod drivers that use
|
||||
* @DVBFE_ALGO_HW; to tune into a frequency.
|
||||
* @get_frontend_algo: returns the desired hardware algorithm.
|
||||
* @set_frontend: callback function used to inform the demod to set the
|
||||
* parameters for demodulating a digital TV channel.
|
||||
* The properties to be used are stored at
|
||||
* @dvb_frontend.dtv_property_cache;. The demod can change
|
||||
* the parameters to reflect the changes needed for the
|
||||
* channel to be decoded, and update statistics.
|
||||
* @get_tune_settings: callback function
|
||||
* @get_frontend: callback function used to inform the parameters
|
||||
* actuall in use. The properties to be used are stored at
|
||||
* @dvb_frontend.dtv_property_cache; and update
|
||||
* statistics. Please notice that it should not return
|
||||
* an error code if the statistics are not available
|
||||
* because the demog is not locked.
|
||||
* @read_status: returns the locking status of the frontend.
|
||||
* @read_ber: legacy callback function to return the bit error rate.
|
||||
* Newer drivers should provide such info via DVBv5 API,
|
||||
* e. g. @set_frontend;/@get_frontend;, implementing this
|
||||
* callback only if DVBv3 API compatibility is wanted.
|
||||
* @read_signal_strength: legacy callback function to return the signal
|
||||
* strength. Newer drivers should provide such info via
|
||||
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
|
||||
* implementing this callback only if DVBv3 API
|
||||
* compatibility is wanted.
|
||||
* @read_snr: legacy callback function to return the Signal/Noise
|
||||
* rate. Newer drivers should provide such info via
|
||||
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
|
||||
* implementing this callback only if DVBv3 API
|
||||
* compatibility is wanted.
|
||||
* @read_ucblocks: legacy callback function to return the Uncorrected Error
|
||||
* Blocks. Newer drivers should provide such info via
|
||||
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
|
||||
* implementing this callback only if DVBv3 API
|
||||
* compatibility is wanted.
|
||||
* @diseqc_reset_overload: callback function to implement the
|
||||
* FE_DISEQC_RESET_OVERLOAD ioctl (only Satellite)
|
||||
* @diseqc_send_master_cmd: callback function to implement the
|
||||
* FE_DISEQC_SEND_MASTER_CMD ioctl (only Satellite).
|
||||
* @diseqc_recv_slave_reply: callback function to implement the
|
||||
* FE_DISEQC_RECV_SLAVE_REPLY ioctl (only Satellite)
|
||||
* @diseqc_send_burst: callback function to implement the
|
||||
* FE_DISEQC_SEND_BURST ioctl (only Satellite).
|
||||
* @set_tone: callback function to implement the
|
||||
* FE_SET_TONE ioctl (only Satellite).
|
||||
* @set_voltage: callback function to implement the
|
||||
* FE_SET_VOLTAGE ioctl (only Satellite).
|
||||
* @enable_high_lnb_voltage: callback function to implement the
|
||||
* FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite).
|
||||
* @dishnetwork_send_legacy_command: callback function to implement the
|
||||
* FE_DISHNETWORK_SEND_LEGACY_CMD ioctl (only Satellite).
|
||||
* Drivers should not use this, except when the DVB
|
||||
* core emulation fails to provide proper support (e.g.
|
||||
* if @set_voltage takes more than 8ms to work), and
|
||||
* when backward compatibility with this legacy API is
|
||||
* required.
|
||||
* @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C
|
||||
* mux support instead.
|
||||
* @ts_bus_ctrl: callback function used to take control of the TS bus.
|
||||
* @set_lna: callback function to power on/off/auto the LNA.
|
||||
* @search: callback function used on some custom algo search algos.
|
||||
* @tuner_ops: pointer to struct dvb_tuner_ops
|
||||
* @analog_ops: pointer to struct analog_demod_ops
|
||||
* @set_property: callback function to allow the frontend to validade
|
||||
* incoming properties. Should not be used on new drivers.
|
||||
* @get_property: callback function to allow the frontend to override
|
||||
* outcoming properties. Should not be used on new drivers.
|
||||
*/
|
||||
struct dvb_frontend_ops {
|
||||
|
||||
struct dvb_frontend_info info;
|
||||
|
||||
u8 delsys[MAX_DELSYS];
|
||||
|
||||
void (*detach)(struct dvb_frontend *fe);
|
||||
void (*release)(struct dvb_frontend* fe);
|
||||
void (*release_sec)(struct dvb_frontend* fe);
|
||||
|
||||
@@ -277,7 +431,8 @@ struct dvb_frontend_ops {
|
||||
bool re_tune,
|
||||
unsigned int mode_flags,
|
||||
unsigned int *delay,
|
||||
fe_status_t *status);
|
||||
enum fe_status *status);
|
||||
|
||||
/* get frontend tuning algorithm from the module */
|
||||
enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
|
||||
|
||||
@@ -285,9 +440,10 @@ struct dvb_frontend_ops {
|
||||
int (*set_frontend)(struct dvb_frontend *fe);
|
||||
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
|
||||
|
||||
int (*get_frontend)(struct dvb_frontend *fe);
|
||||
int (*get_frontend)(struct dvb_frontend *fe,
|
||||
struct dtv_frontend_properties *props);
|
||||
|
||||
int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
|
||||
int (*read_status)(struct dvb_frontend *fe, enum fe_status *status);
|
||||
int (*read_ber)(struct dvb_frontend* fe, u32* ber);
|
||||
int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
|
||||
int (*read_snr)(struct dvb_frontend* fe, u16* snr);
|
||||
@@ -296,9 +452,11 @@ struct dvb_frontend_ops {
|
||||
int (*diseqc_reset_overload)(struct dvb_frontend* fe);
|
||||
int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
|
||||
int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
|
||||
int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
|
||||
int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
|
||||
int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
|
||||
int (*diseqc_send_burst)(struct dvb_frontend *fe,
|
||||
enum fe_sec_mini_cmd minicmd);
|
||||
int (*set_tone)(struct dvb_frontend *fe, enum fe_sec_tone_mode tone);
|
||||
int (*set_voltage)(struct dvb_frontend *fe,
|
||||
enum fe_sec_voltage voltage);
|
||||
int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
|
||||
int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
|
||||
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
|
||||
@@ -306,7 +464,8 @@ struct dvb_frontend_ops {
|
||||
int (*set_lna)(struct dvb_frontend *);
|
||||
int (*set_input)(struct dvb_frontend *, int);
|
||||
|
||||
/* These callbacks are for devices that implement their own
|
||||
/*
|
||||
* These callbacks are for devices that implement their own
|
||||
* tuning algorithms, rather than a simple swzigzag
|
||||
*/
|
||||
enum dvbfe_search (*search)(struct dvb_frontend *fe);
|
||||
@@ -323,6 +482,7 @@ struct dvb_frontend_ops {
|
||||
#ifdef __DVB_CORE__
|
||||
#define MAX_EVENT 8
|
||||
|
||||
/* Used only internally at dvb_frontend.c */
|
||||
struct dvb_fe_events {
|
||||
struct dvb_frontend_event events[MAX_EVENT];
|
||||
int eventw;
|
||||
@@ -333,30 +493,102 @@ struct dvb_fe_events {
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct dtv_frontend_properties - contains a list of properties that are
|
||||
* specific to a digital TV standard.
|
||||
*
|
||||
* @frequency: frequency in Hz for terrestrial/cable or in kHz for
|
||||
* Satellite
|
||||
* @modulation: Frontend modulation type
|
||||
* @voltage: SEC voltage (only Satellite)
|
||||
* @sectone: SEC tone mode (only Satellite)
|
||||
* @inversion: Spectral inversion
|
||||
* @fec_inner: Forward error correction inner Code Rate
|
||||
* @transmission_mode: Transmission Mode
|
||||
* @bandwidth_hz: Bandwidth, in Hz. A zero value means that userspace
|
||||
* wants to autodetect.
|
||||
* @guard_interval: Guard Interval
|
||||
* @hierarchy: Hierarchy
|
||||
* @symbol_rate: Symbol Rate
|
||||
* @code_rate_HP: high priority stream code rate
|
||||
* @code_rate_LP: low priority stream code rate
|
||||
* @pilot: Enable/disable/autodetect pilot tones
|
||||
* @rolloff: Rolloff factor (alpha)
|
||||
* @delivery_system: FE delivery system (e. g. digital TV standard)
|
||||
* @interleaving: interleaving
|
||||
* @isdbt_partial_reception: ISDB-T partial reception (only ISDB standard)
|
||||
* @isdbt_sb_mode: ISDB-T Sound Broadcast (SB) mode (only ISDB standard)
|
||||
* @isdbt_sb_subchannel: ISDB-T SB subchannel (only ISDB standard)
|
||||
* @isdbt_sb_segment_idx: ISDB-T SB segment index (only ISDB standard)
|
||||
* @isdbt_sb_segment_count: ISDB-T SB segment count (only ISDB standard)
|
||||
* @isdbt_layer_enabled: ISDB Layer enabled (only ISDB standard)
|
||||
* @layer: ISDB per-layer data (only ISDB standard)
|
||||
* @layer.segment_count: Segment Count;
|
||||
* @layer.fec: per layer code rate;
|
||||
* @layer.modulation: per layer modulation;
|
||||
* @layer.interleaving: per layer interleaving.
|
||||
* @stream_id: If different than zero, enable substream filtering, if
|
||||
* hardware supports (DVB-S2 and DVB-T2).
|
||||
* @scrambling_sequence_index: Carries the index of the DVB-S2 physical layer
|
||||
* scrambling sequence.
|
||||
* @atscmh_fic_ver: Version number of the FIC (Fast Information Channel)
|
||||
* signaling data (only ATSC-M/H)
|
||||
* @atscmh_parade_id: Parade identification number (only ATSC-M/H)
|
||||
* @atscmh_nog: Number of MH groups per MH subframe for a designated
|
||||
* parade (only ATSC-M/H)
|
||||
* @atscmh_tnog: Total number of MH groups including all MH groups
|
||||
* belonging to all MH parades in one MH subframe
|
||||
* (only ATSC-M/H)
|
||||
* @atscmh_sgn: Start group number (only ATSC-M/H)
|
||||
* @atscmh_prc: Parade repetition cycle (only ATSC-M/H)
|
||||
* @atscmh_rs_frame_mode: Reed Solomon (RS) frame mode (only ATSC-M/H)
|
||||
* @atscmh_rs_frame_ensemble: RS frame ensemble (only ATSC-M/H)
|
||||
* @atscmh_rs_code_mode_pri: RS code mode pri (only ATSC-M/H)
|
||||
* @atscmh_rs_code_mode_sec: RS code mode sec (only ATSC-M/H)
|
||||
* @atscmh_sccc_block_mode: Series Concatenated Convolutional Code (SCCC)
|
||||
* Block Mode (only ATSC-M/H)
|
||||
* @atscmh_sccc_code_mode_a: SCCC code mode A (only ATSC-M/H)
|
||||
* @atscmh_sccc_code_mode_b: SCCC code mode B (only ATSC-M/H)
|
||||
* @atscmh_sccc_code_mode_c: SCCC code mode C (only ATSC-M/H)
|
||||
* @atscmh_sccc_code_mode_d: SCCC code mode D (only ATSC-M/H)
|
||||
* @lna: Power ON/OFF/AUTO the Linear Now-noise Amplifier (LNA)
|
||||
* @strength: DVBv5 API statistics: Signal Strength
|
||||
* @cnr: DVBv5 API statistics: Signal to Noise ratio of the
|
||||
* (main) carrier
|
||||
* @pre_bit_error: DVBv5 API statistics: pre-Viterbi bit error count
|
||||
* @pre_bit_count: DVBv5 API statistics: pre-Viterbi bit count
|
||||
* @post_bit_error: DVBv5 API statistics: post-Viterbi bit error count
|
||||
* @post_bit_count: DVBv5 API statistics: post-Viterbi bit count
|
||||
* @block_error: DVBv5 API statistics: block error count
|
||||
* @block_count: DVBv5 API statistics: block count
|
||||
*
|
||||
* NOTE: derivated statistics like Uncorrected Error blocks (UCE) are
|
||||
* calculated on userspace.
|
||||
*
|
||||
* Only a subset of the properties are needed for a given delivery system.
|
||||
* For more info, consult the media_api.html with the documentation of the
|
||||
* Userspace API.
|
||||
*/
|
||||
struct dtv_frontend_properties {
|
||||
|
||||
/* Cache State */
|
||||
u32 state;
|
||||
|
||||
u32 frequency;
|
||||
fe_modulation_t modulation;
|
||||
enum fe_modulation modulation;
|
||||
|
||||
fe_sec_voltage_t voltage;
|
||||
fe_sec_tone_mode_t sectone;
|
||||
fe_spectral_inversion_t inversion;
|
||||
fe_code_rate_t fec_inner;
|
||||
fe_transmit_mode_t transmission_mode;
|
||||
enum fe_sec_voltage voltage;
|
||||
enum fe_sec_tone_mode sectone;
|
||||
enum fe_spectral_inversion inversion;
|
||||
enum fe_code_rate fec_inner;
|
||||
enum fe_transmit_mode transmission_mode;
|
||||
u32 bandwidth_hz; /* 0 = AUTO */
|
||||
fe_guard_interval_t guard_interval;
|
||||
fe_hierarchy_t hierarchy;
|
||||
enum fe_guard_interval guard_interval;
|
||||
enum fe_hierarchy hierarchy;
|
||||
u32 symbol_rate;
|
||||
fe_code_rate_t code_rate_HP;
|
||||
fe_code_rate_t code_rate_LP;
|
||||
enum fe_code_rate code_rate_HP;
|
||||
enum fe_code_rate code_rate_LP;
|
||||
|
||||
fe_pilot_t pilot;
|
||||
fe_rolloff_t rolloff;
|
||||
enum fe_pilot pilot;
|
||||
enum fe_rolloff rolloff;
|
||||
|
||||
fe_delivery_system_t delivery_system;
|
||||
enum fe_delivery_system delivery_system;
|
||||
|
||||
enum fe_interleaving interleaving;
|
||||
|
||||
@@ -369,14 +601,17 @@ struct dtv_frontend_properties {
|
||||
u8 isdbt_layer_enabled;
|
||||
struct {
|
||||
u8 segment_count;
|
||||
fe_code_rate_t fec;
|
||||
fe_modulation_t modulation;
|
||||
enum fe_code_rate fec;
|
||||
enum fe_modulation modulation;
|
||||
u8 interleaving;
|
||||
} layer[3];
|
||||
|
||||
/* Multistream specifics */
|
||||
u32 stream_id;
|
||||
|
||||
/* Physical Layer Scrambling specifics */
|
||||
u32 scrambling_sequence_index;
|
||||
|
||||
/* ATSC-MH specifics */
|
||||
u8 atscmh_fic_ver;
|
||||
u8 atscmh_parade_id;
|
||||
@@ -397,8 +632,7 @@ struct dtv_frontend_properties {
|
||||
|
||||
u32 lna;
|
||||
s32 input;
|
||||
u32 pls;
|
||||
|
||||
|
||||
/* statistics data */
|
||||
struct dtv_fe_stats strength;
|
||||
struct dtv_fe_stats cnr;
|
||||
@@ -408,9 +642,41 @@ struct dtv_frontend_properties {
|
||||
struct dtv_fe_stats post_bit_count;
|
||||
struct dtv_fe_stats block_error;
|
||||
struct dtv_fe_stats block_count;
|
||||
|
||||
/* private: */
|
||||
/* Cache State */
|
||||
u32 state;
|
||||
|
||||
};
|
||||
|
||||
#define DVB_FE_NO_EXIT 0
|
||||
#define DVB_FE_NORMAL_EXIT 1
|
||||
#define DVB_FE_DEVICE_REMOVED 2
|
||||
#define DVB_FE_DEVICE_RESUME 3
|
||||
|
||||
/**
|
||||
* struct dvb_frontend - Frontend structure to be used on drivers.
|
||||
*
|
||||
* @refcount: refcount to keep track of struct dvb_frontend
|
||||
* references
|
||||
* @ops: embedded struct dvb_frontend_ops
|
||||
* @dvb: pointer to struct dvb_adapter
|
||||
* @demodulator_priv: demod private data
|
||||
* @tuner_priv: tuner private data
|
||||
* @frontend_priv: frontend private data
|
||||
* @sec_priv: SEC private data
|
||||
* @analog_demod_priv: Analog demod private data
|
||||
* @dtv_property_cache: embedded struct dtv_frontend_properties
|
||||
* @callback: callback function used on some drivers to call
|
||||
* either the tuner or the demodulator.
|
||||
* @id: Frontend ID
|
||||
* @exit: Used to inform the DVB core that the frontend
|
||||
* thread should exit (usually, means that the hardware
|
||||
* got disconnected.
|
||||
*/
|
||||
|
||||
struct dvb_frontend {
|
||||
struct kref refcount;
|
||||
struct dvb_frontend_ops ops;
|
||||
struct dvb_adapter *dvb;
|
||||
void *demodulator_priv;
|
||||
@@ -423,20 +689,129 @@ struct dvb_frontend {
|
||||
#define DVB_FRONTEND_COMPONENT_DEMOD 1
|
||||
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
|
||||
int id;
|
||||
unsigned int exit;
|
||||
};
|
||||
|
||||
extern int dvb_register_frontend(struct dvb_adapter *dvb,
|
||||
/**
|
||||
* dvb_register_frontend() - Registers a DVB frontend at the adapter
|
||||
*
|
||||
* @dvb: pointer to the dvb adapter
|
||||
* @fe: pointer to the frontend struct
|
||||
*
|
||||
* Allocate and initialize the private data needed by the frontend core to
|
||||
* manage the frontend and calls dvb_register_device() to register a new
|
||||
* frontend. It also cleans the property cache that stores the frontend
|
||||
* parameters and selects the first available delivery system.
|
||||
*/
|
||||
int dvb_register_frontend(struct dvb_adapter *dvb,
|
||||
struct dvb_frontend *fe);
|
||||
|
||||
extern int dvb_unregister_frontend(struct dvb_frontend *fe);
|
||||
/**
|
||||
* dvb_unregister_frontend() - Unregisters a DVB frontend
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
*
|
||||
* Stops the frontend kthread, calls dvb_unregister_device() and frees the
|
||||
* private frontend data allocated by dvb_register_frontend().
|
||||
*
|
||||
* NOTE: This function doesn't frees the memory allocated by the demod,
|
||||
* by the SEC driver and by the tuner. In order to free it, an explicit call to
|
||||
* dvb_frontend_detach() is needed, after calling this function.
|
||||
*/
|
||||
int dvb_unregister_frontend(struct dvb_frontend *fe);
|
||||
|
||||
extern void dvb_frontend_detach(struct dvb_frontend *fe);
|
||||
/**
|
||||
* dvb_frontend_detach() - Detaches and frees frontend specific data
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
*
|
||||
* This function should be called after dvb_unregister_frontend(). It
|
||||
* calls the SEC, tuner and demod release functions:
|
||||
* &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_ops.release,
|
||||
* &dvb_frontend_ops.analog_ops.release and &dvb_frontend_ops.release.
|
||||
*
|
||||
* If the driver is compiled with CONFIG_MEDIA_ATTACH, it also decreases
|
||||
* the module reference count, needed to allow userspace to remove the
|
||||
* previously used DVB frontend modules.
|
||||
*/
|
||||
void dvb_frontend_detach(struct dvb_frontend *fe);
|
||||
|
||||
extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
|
||||
extern int dvb_frontend_suspend(struct dvb_frontend *fe);
|
||||
extern int dvb_frontend_resume(struct dvb_frontend *fe);
|
||||
/**
|
||||
* dvb_frontend_suspend() - Suspends a Digital TV frontend
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
*
|
||||
* This function prepares a Digital TV frontend to suspend.
|
||||
*
|
||||
* In order to prepare the tuner to suspend, if
|
||||
* &dvb_frontend_ops.tuner_ops.suspend\(\) is available, it calls it. Otherwise,
|
||||
* it will call &dvb_frontend_ops.tuner_ops.sleep\(\), if available.
|
||||
*
|
||||
* It will also call &dvb_frontend_ops.sleep\(\) to put the demod to suspend.
|
||||
*
|
||||
* The drivers should also call dvb_frontend_suspend\(\) as part of their
|
||||
* handler for the &device_driver.suspend\(\).
|
||||
*/
|
||||
int dvb_frontend_suspend(struct dvb_frontend *fe);
|
||||
|
||||
extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
|
||||
extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
|
||||
/**
|
||||
* dvb_frontend_resume() - Resumes a Digital TV frontend
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
*
|
||||
* This function resumes the usual operation of the tuner after resume.
|
||||
*
|
||||
* In order to resume the frontend, it calls the demod &dvb_frontend_ops.init\(\).
|
||||
*
|
||||
* If &dvb_frontend_ops.tuner_ops.resume\(\) is available, It, it calls it.
|
||||
* Otherwise,t will call &dvb_frontend_ops.tuner_ops.init\(\), if available.
|
||||
*
|
||||
* Once tuner and demods are resumed, it will enforce that the SEC voltage and
|
||||
* tone are restored to their previous values and wake up the frontend's
|
||||
* kthread in order to retune the frontend.
|
||||
*
|
||||
* The drivers should also call dvb_frontend_resume() as part of their
|
||||
* handler for the &device_driver.resume\(\).
|
||||
*/
|
||||
int dvb_frontend_resume(struct dvb_frontend *fe);
|
||||
|
||||
/**
|
||||
* dvb_frontend_reinitialise() - forces a reinitialisation at the frontend
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
*
|
||||
* Calls &dvb_frontend_ops.init\(\) and &dvb_frontend_ops.tuner_ops.init\(\),
|
||||
* and resets SEC tone and voltage (for Satellite systems).
|
||||
*
|
||||
* NOTE: Currently, this function is used only by one driver (budget-av).
|
||||
* It seems to be due to address some special issue with that specific
|
||||
* frontend.
|
||||
*/
|
||||
void dvb_frontend_reinitialise(struct dvb_frontend *fe);
|
||||
|
||||
/**
|
||||
* dvb_frontend_sleep_until() - Sleep for the amount of time given by
|
||||
* add_usec parameter
|
||||
*
|
||||
* @waketime: pointer to a struct ktime_t
|
||||
* @add_usec: time to sleep, in microseconds
|
||||
*
|
||||
* This function is used to measure the time required for the
|
||||
* %FE_DISHNETWORK_SEND_LEGACY_CMD ioctl to work. It needs to be as precise
|
||||
* as possible, as it affects the detection of the dish tone command at the
|
||||
* satellite subsystem.
|
||||
*
|
||||
* Its used internally by the DVB frontend core, in order to emulate
|
||||
* %FE_DISHNETWORK_SEND_LEGACY_CMD using the &dvb_frontend_ops.set_voltage\(\)
|
||||
* callback.
|
||||
*
|
||||
* NOTE: it should not be used at the drivers, as the emulation for the
|
||||
* legacy callback is provided by the Kernel. The only situation where this
|
||||
* should be at the drivers is when there are some bugs at the hardware that
|
||||
* would prevent the core emulation to work. On such cases, the driver would
|
||||
* be writing a &dvb_frontend_ops.dishnetwork_send_legacy_command\(\) and
|
||||
* calling this function directly.
|
||||
*/
|
||||
void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __DVB_MATH_H
|
||||
@@ -25,33 +21,45 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* computes log2 of a value; the result is shifted left by 24 bits
|
||||
* intlog2 - computes log2 of a value; the result is shifted left by 24 bits
|
||||
*
|
||||
* @value: The value (must be != 0)
|
||||
*
|
||||
* to use rational values you can use the following method:
|
||||
*
|
||||
* intlog2(value) = intlog2(value * 2^x) - x * 2^24
|
||||
*
|
||||
* example: intlog2(8) will give 3 << 24 = 3 * 2^24
|
||||
* example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
|
||||
* example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
|
||||
* Some usecase examples:
|
||||
*
|
||||
* @param value The value (must be != 0)
|
||||
* @return log2(value) * 2^24
|
||||
* intlog2(8) will give 3 << 24 = 3 * 2^24
|
||||
*
|
||||
* intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
|
||||
*
|
||||
* intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
|
||||
*
|
||||
*
|
||||
* return: log2(value) * 2^24
|
||||
*/
|
||||
extern unsigned int intlog2(u32 value);
|
||||
|
||||
/**
|
||||
* computes log10 of a value; the result is shifted left by 24 bits
|
||||
* intlog10 - computes log10 of a value; the result is shifted left by 24 bits
|
||||
*
|
||||
* @value: The value (must be != 0)
|
||||
*
|
||||
* to use rational values you can use the following method:
|
||||
*
|
||||
* intlog10(value) = intlog10(value * 10^x) - x * 2^24
|
||||
*
|
||||
* example: intlog10(1000) will give 3 << 24 = 3 * 2^24
|
||||
* An usecase example:
|
||||
*
|
||||
* intlog10(1000) will give 3 << 24 = 3 * 2^24
|
||||
*
|
||||
* due to the implementation intlog10(1000) might be not exactly 3 * 2^24
|
||||
*
|
||||
* look at intlog2 for similar examples
|
||||
*
|
||||
* @param value The value (must be != 0)
|
||||
* @return log10(value) * 2^24
|
||||
* return: log10(value) * 2^24
|
||||
*/
|
||||
extern unsigned int intlog10(u32 value);
|
||||
|
||||
|
||||
1090
dvb-core/dvb_net.c
1090
dvb-core/dvb_net.c
File diff suppressed because it is too large
Load Diff
@@ -13,10 +13,6 @@
|
||||
* 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 Lesser 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DVB_NET_H_
|
||||
|
||||
@@ -241,7 +241,7 @@ int dvb_netstream_init(struct dvb_adapter *dvb_adapter,
|
||||
spin_lock_init(&ns->lock);
|
||||
ns->exit = 0;
|
||||
dvb_register_device(dvb_adapter, &ns->dvbdev, &ns_dev, ns,
|
||||
DVB_DEVICE_NS);
|
||||
DVB_DEVICE_NS, 0);
|
||||
INIT_LIST_HEAD(&ns->nssl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,10 +18,6 @@
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -31,7 +27,12 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/version.h>
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
|
||||
#include <asm/uaccess.h>
|
||||
#else
|
||||
#include <linux/uaccess.h>
|
||||
#endif
|
||||
|
||||
#include "dvb_ringbuffer.h"
|
||||
|
||||
@@ -55,7 +56,17 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
|
||||
|
||||
int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
return (rbuf->pread==rbuf->pwrite);
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
return (rbuf->pread == rbuf->pwrite);
|
||||
#else
|
||||
/* smp_load_acquire() to load write pointer on reader side
|
||||
* this pairs with smp_store_release() in dvb_ringbuffer_write(),
|
||||
* dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
|
||||
*
|
||||
* for memory barriers also see Documentation/circular-buffers.txt
|
||||
*/
|
||||
return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +75,16 @@ ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
ssize_t free;
|
||||
|
||||
free = rbuf->pread - rbuf->pwrite;
|
||||
/* ACCESS_ONCE() to load read pointer on writer side
|
||||
* this pairs with smp_store_release() in dvb_ringbuffer_read(),
|
||||
* dvb_ringbuffer_read_user(), dvb_ringbuffer_flush(),
|
||||
* or dvb_ringbuffer_reset()
|
||||
*/
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
|
||||
free = READ_ONCE(rbuf->pread) - rbuf->pwrite;
|
||||
#else
|
||||
free = ACCESS_ONCE(rbuf->pread) - rbuf->pwrite;
|
||||
#endif
|
||||
if (free <= 0)
|
||||
free += rbuf->size;
|
||||
return free-1;
|
||||
@@ -76,7 +96,15 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
ssize_t avail;
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
avail = rbuf->pwrite - rbuf->pread;
|
||||
#else
|
||||
/* smp_load_acquire() to load write pointer on reader side
|
||||
* this pairs with smp_store_release() in dvb_ringbuffer_write(),
|
||||
* dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
|
||||
*/
|
||||
avail = smp_load_acquire(&rbuf->pwrite) - rbuf->pread;
|
||||
#endif
|
||||
if (avail < 0)
|
||||
avail += rbuf->size;
|
||||
return avail;
|
||||
@@ -86,14 +114,33 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
|
||||
|
||||
void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
rbuf->pread = rbuf->pwrite;
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
rbuf->pread = &rbuf->pwrite;
|
||||
#else
|
||||
/* dvb_ringbuffer_flush() counts as read operation
|
||||
* smp_load_acquire() to load write pointer
|
||||
* smp_store_release() to update read pointer, this ensures that the
|
||||
* correct pointer is visible for subsequent dvb_ringbuffer_free()
|
||||
* calls on other cpu cores
|
||||
*/
|
||||
smp_store_release(&rbuf->pread, smp_load_acquire(&rbuf->pwrite));
|
||||
#endif
|
||||
rbuf->error = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_flush);
|
||||
|
||||
void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
rbuf->pread = rbuf->pwrite = 0;
|
||||
#else
|
||||
/* dvb_ringbuffer_reset() counts as read and write operation
|
||||
* smp_store_release() to update read pointer
|
||||
*/
|
||||
smp_store_release(&rbuf->pread, 0);
|
||||
/* smp_store_release() to update write pointer */
|
||||
smp_store_release(&rbuf->pwrite, 0);
|
||||
#endif
|
||||
rbuf->error = 0;
|
||||
}
|
||||
|
||||
@@ -119,13 +166,25 @@ ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, si
|
||||
return -EFAULT;
|
||||
buf += split;
|
||||
todo -= split;
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
rbuf->pread = 0;
|
||||
#else
|
||||
/* smp_store_release() for read pointer update to ensure
|
||||
* that buf is not overwritten until read is complete,
|
||||
* this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
|
||||
*/
|
||||
smp_store_release(&rbuf->pread, 0);
|
||||
#endif
|
||||
}
|
||||
if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
|
||||
return -EFAULT;
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
rbuf->pread = (rbuf->pread + todo) % rbuf->size;
|
||||
|
||||
#else
|
||||
/* smp_store_release() to update read pointer, see above */
|
||||
smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -139,11 +198,24 @@ void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
|
||||
memcpy(buf, rbuf->data+rbuf->pread, split);
|
||||
buf += split;
|
||||
todo -= split;
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
rbuf->pread = 0;
|
||||
#else
|
||||
/* smp_store_release() for read pointer update to ensure
|
||||
* that buf is not overwritten until read is complete,
|
||||
* this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
|
||||
*/
|
||||
smp_store_release(&rbuf->pread, 0);
|
||||
#endif
|
||||
}
|
||||
memcpy(buf, rbuf->data+rbuf->pread, todo);
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
rbuf->pread = (rbuf->pread + todo) % rbuf->size;
|
||||
#else
|
||||
/* smp_store_release() to update read pointer, see above */
|
||||
smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -158,10 +230,63 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t
|
||||
memcpy(rbuf->data+rbuf->pwrite, buf, split);
|
||||
buf += split;
|
||||
todo -= split;
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
rbuf->pwrite = 0;
|
||||
#else
|
||||
/* smp_store_release() for write pointer update to ensure that
|
||||
* written data is visible on other cpu cores before the pointer
|
||||
* update, this pairs with smp_load_acquire() in
|
||||
* dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
|
||||
*/
|
||||
smp_store_release(&rbuf->pwrite, 0);
|
||||
#endif
|
||||
}
|
||||
memcpy(rbuf->data+rbuf->pwrite, buf, todo);
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
|
||||
#else
|
||||
/* smp_store_release() for write pointer update, see above */
|
||||
smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
|
||||
#endif
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
|
||||
const u8 __user *buf, size_t len)
|
||||
{
|
||||
int status;
|
||||
size_t todo = len;
|
||||
size_t split;
|
||||
|
||||
split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
|
||||
|
||||
if (split > 0) {
|
||||
status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split);
|
||||
if (status)
|
||||
return len - todo;
|
||||
buf += split;
|
||||
todo -= split;
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
rbuf->pwrite = 0;
|
||||
#else
|
||||
/* smp_store_release() for write pointer update to ensure that
|
||||
* written data is visible on other cpu cores before the pointer
|
||||
* update, this pairs with smp_load_acquire() in
|
||||
* dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
|
||||
*/
|
||||
smp_store_release(&rbuf->pwrite, 0);
|
||||
#endif
|
||||
}
|
||||
status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
|
||||
if (status)
|
||||
return len - todo;
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
|
||||
rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
|
||||
#else
|
||||
/* smp_store_release() for write pointer update, see above */
|
||||
smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
|
||||
#endif
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -297,3 +422,4 @@ EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_read_user);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_read);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_write);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_write_user);
|
||||
|
||||
@@ -18,10 +18,6 @@
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.
|
||||
*/
|
||||
|
||||
#ifndef _DVB_RINGBUFFER_H_
|
||||
@@ -30,6 +26,18 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
/**
|
||||
* struct dvb_ringbuffer - Describes a ring buffer used at DVB framework
|
||||
*
|
||||
* @data: Area were the ringbuffer data is written
|
||||
* @size: size of the ringbuffer
|
||||
* @pread: next position to read
|
||||
* @pwrite: next position to write
|
||||
* @error: used by ringbuffer clients to indicate that an error happened.
|
||||
* @queue: Wait queue used by ringbuffer clients to indicate when buffer
|
||||
* was filled
|
||||
* @lock: Spinlock used to protect the ringbuffer
|
||||
*/
|
||||
struct dvb_ringbuffer {
|
||||
u8 *data;
|
||||
ssize_t size;
|
||||
@@ -43,144 +51,230 @@ struct dvb_ringbuffer {
|
||||
|
||||
#define DVB_RINGBUFFER_PKTHDRSIZE 3
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_init - initialize ring buffer, lock and queue
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
* @data: pointer to the buffer where the data will be stored
|
||||
* @len: bytes from ring buffer into @buf
|
||||
*/
|
||||
extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data,
|
||||
size_t len);
|
||||
|
||||
/*
|
||||
** Notes:
|
||||
** ------
|
||||
** (1) For performance reasons read and write routines don't check buffer sizes
|
||||
** and/or number of bytes free/available. This has to be done before these
|
||||
** routines are called. For example:
|
||||
**
|
||||
** *** write <buflen> bytes ***
|
||||
** free = dvb_ringbuffer_free(rbuf);
|
||||
** if (free >= buflen)
|
||||
** count = dvb_ringbuffer_write(rbuf, buffer, buflen);
|
||||
** else
|
||||
** ...
|
||||
**
|
||||
** *** read min. 1000, max. <bufsize> bytes ***
|
||||
** avail = dvb_ringbuffer_avail(rbuf);
|
||||
** if (avail >= 1000)
|
||||
** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
|
||||
** else
|
||||
** ...
|
||||
**
|
||||
** (2) If there is exactly one reader and one writer, there is no need
|
||||
** to lock read or write operations.
|
||||
** Two or more readers must be locked against each other.
|
||||
** Flushing the buffer counts as a read operation.
|
||||
** Resetting the buffer counts as a read and write operation.
|
||||
** Two or more writers must be locked against each other.
|
||||
*/
|
||||
|
||||
/* initialize ring buffer, lock and queue */
|
||||
extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len);
|
||||
|
||||
/* test whether buffer is empty */
|
||||
/**
|
||||
* dvb_ringbuffer_empty - test whether buffer is empty
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
*/
|
||||
extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
/* return the number of free bytes in the buffer */
|
||||
/**
|
||||
* dvb_ringbuffer_free - returns the number of free bytes in the buffer
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
*
|
||||
* Return: number of free bytes in the buffer
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
/* return the number of bytes waiting in the buffer */
|
||||
/**
|
||||
* dvb_ringbuffer_avail - returns the number of bytes waiting in the buffer
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
*
|
||||
* Return: number of bytes waiting in the buffer
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
|
||||
/*
|
||||
** Reset the read and write pointers to zero and flush the buffer
|
||||
** This counts as a read and write operation
|
||||
*/
|
||||
/**
|
||||
* dvb_ringbuffer_reset - resets the ringbuffer to initial state
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
*
|
||||
* Resets the read and write pointers to zero and flush the buffer.
|
||||
*
|
||||
* This counts as a read and write operation
|
||||
*/
|
||||
extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
/*
|
||||
* read routines & macros
|
||||
*/
|
||||
|
||||
/* read routines & macros */
|
||||
/* ---------------------- */
|
||||
/* flush buffer */
|
||||
/**
|
||||
* dvb_ringbuffer_flush - flush buffer
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
*/
|
||||
extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
/* flush buffer protected by spinlock and wake-up waiting task(s) */
|
||||
/**
|
||||
* dvb_ringbuffer_flush_spinlock_wakeup- flush buffer protected by spinlock
|
||||
* and wake-up waiting task(s)
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
*/
|
||||
extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
/* peek at byte <offs> in the buffer */
|
||||
#define DVB_RINGBUFFER_PEEK(rbuf,offs) \
|
||||
(rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size]
|
||||
/**
|
||||
* DVB_RINGBUFFER_PEEK - peek at byte @offs in the buffer
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
* @offs: offset inside the ringbuffer
|
||||
*/
|
||||
#define DVB_RINGBUFFER_PEEK(rbuf, offs) \
|
||||
((rbuf)->data[((rbuf)->pread + (offs)) % (rbuf)->size])
|
||||
|
||||
/* advance read ptr by <num> bytes */
|
||||
#define DVB_RINGBUFFER_SKIP(rbuf,num) \
|
||||
(rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
|
||||
/**
|
||||
* DVB_RINGBUFFER_SKIP - advance read ptr by @num bytes
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
* @num: number of bytes to advance
|
||||
*/
|
||||
#define DVB_RINGBUFFER_SKIP(rbuf, num) {\
|
||||
(rbuf)->pread = ((rbuf)->pread + (num)) % (rbuf)->size;\
|
||||
}
|
||||
|
||||
/*
|
||||
** read <len> bytes from ring buffer into <buf>
|
||||
** <usermem> specifies whether <buf> resides in user space
|
||||
** returns number of bytes transferred or -EFAULT
|
||||
*/
|
||||
/**
|
||||
* dvb_ringbuffer_read_user - Reads a buffer into a user pointer
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
* @buf: pointer to the buffer where the data will be stored
|
||||
* @len: bytes from ring buffer into @buf
|
||||
*
|
||||
* This variant assumes that the buffer is a memory at the userspace. So,
|
||||
* it will internally call copy_to_user().
|
||||
*
|
||||
* Return: number of bytes transferred or -EFAULT
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
|
||||
u8 __user *buf, size_t len);
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_read - Reads a buffer into a pointer
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
* @buf: pointer to the buffer where the data will be stored
|
||||
* @len: bytes from ring buffer into @buf
|
||||
*
|
||||
* This variant assumes that the buffer is a memory at the Kernel space
|
||||
*
|
||||
* Return: number of bytes transferred or -EFAULT
|
||||
*/
|
||||
extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
|
||||
u8 *buf, size_t len);
|
||||
|
||||
|
||||
/* write routines & macros */
|
||||
/* ----------------------- */
|
||||
/* write single byte to ring buffer */
|
||||
#define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte) \
|
||||
{ (rbuf)->data[(rbuf)->pwrite]=(byte); \
|
||||
(rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; }
|
||||
/*
|
||||
** write <len> bytes to ring buffer
|
||||
** <usermem> specifies whether <buf> resides in user space
|
||||
** returns number of bytes transferred or -EFAULT
|
||||
*/
|
||||
* write routines & macros
|
||||
*/
|
||||
|
||||
/**
|
||||
* DVB_RINGBUFFER_WRITE_BYTE - write single byte to ring buffer
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
* @byte: byte to write
|
||||
*/
|
||||
#define DVB_RINGBUFFER_WRITE_BYTE(rbuf, byte) \
|
||||
{ (rbuf)->data[(rbuf)->pwrite] = (byte); \
|
||||
(rbuf)->pwrite = ((rbuf)->pwrite + 1) % (rbuf)->size; }
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_write - Writes a buffer into the ringbuffer
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
* @buf: pointer to the buffer where the data will be read
|
||||
* @len: bytes from ring buffer into @buf
|
||||
*
|
||||
* This variant assumes that the buffer is a memory at the Kernel space
|
||||
*
|
||||
* return: number of bytes transferred or -EFAULT
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_write_user - Writes a buffer received via a user pointer
|
||||
*
|
||||
* @rbuf: pointer to struct dvb_ringbuffer
|
||||
* @buf: pointer to the buffer where the data will be read
|
||||
* @len: bytes from ring buffer into @buf
|
||||
*
|
||||
* This variant assumes that the buffer is a memory at the userspace. So,
|
||||
* it will internally call copy_from_user().
|
||||
*
|
||||
* Return: number of bytes transferred or -EFAULT
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
|
||||
const u8 __user *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Write a packet into the ringbuffer.
|
||||
* dvb_ringbuffer_pkt_write - Write a packet into the ringbuffer.
|
||||
*
|
||||
* <rbuf> Ringbuffer to write to.
|
||||
* <buf> Buffer to write.
|
||||
* <len> Length of buffer (currently limited to 65535 bytes max).
|
||||
* returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
|
||||
* @rbuf: Ringbuffer to write to.
|
||||
* @buf: Buffer to write.
|
||||
* @len: Length of buffer (currently limited to 65535 bytes max).
|
||||
*
|
||||
* Return: Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
|
||||
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
|
||||
* does NOT update the read pointer in the ringbuffer. You must use
|
||||
* dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required.
|
||||
* dvb_ringbuffer_pkt_read_user - Read from a packet in the ringbuffer.
|
||||
*
|
||||
* <rbuf> Ringbuffer concerned.
|
||||
* <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
|
||||
* <offset> Offset into packet to read from.
|
||||
* <buf> Destination buffer for data.
|
||||
* <len> Size of destination buffer.
|
||||
* <usermem> Set to 1 if <buf> is in userspace.
|
||||
* returns Number of bytes read, or -EFAULT.
|
||||
* @rbuf: Ringbuffer concerned.
|
||||
* @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
|
||||
* @offset: Offset into packet to read from.
|
||||
* @buf: Destination buffer for data.
|
||||
* @len: Size of destination buffer.
|
||||
*
|
||||
* Return: Number of bytes read, or -EFAULT.
|
||||
*
|
||||
* .. note::
|
||||
*
|
||||
* unlike dvb_ringbuffer_read(), this does **NOT** update the read pointer
|
||||
* in the ringbuffer. You must use dvb_ringbuffer_pkt_dispose() to mark a
|
||||
* packet as no longer required.
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf,
|
||||
size_t idx,
|
||||
int offset, u8 __user *buf,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* dvb_ringbuffer_pkt_read - Read from a packet in the ringbuffer.
|
||||
* Note: unlike dvb_ringbuffer_read_user(), this DOES update the read pointer
|
||||
* in the ringbuffer.
|
||||
*
|
||||
* @rbuf: Ringbuffer concerned.
|
||||
* @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
|
||||
* @offset: Offset into packet to read from.
|
||||
* @buf: Destination buffer for data.
|
||||
* @len: Size of destination buffer.
|
||||
*
|
||||
* Return: Number of bytes read, or -EFAULT.
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8 __user *buf, size_t len);
|
||||
extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Dispose of a packet in the ring buffer.
|
||||
* dvb_ringbuffer_pkt_dispose - Dispose of a packet in the ring buffer.
|
||||
*
|
||||
* <rbuf> Ring buffer concerned.
|
||||
* <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
|
||||
* @rbuf: Ring buffer concerned.
|
||||
* @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
|
||||
*/
|
||||
extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
|
||||
|
||||
/**
|
||||
* Get the index of the next packet in a ringbuffer.
|
||||
* dvb_ringbuffer_pkt_next - Get the index of the next packet in a ringbuffer.
|
||||
*
|
||||
* <rbuf> Ringbuffer concerned.
|
||||
* <idx> Previous packet index, or -1 to return the first packet index.
|
||||
* <pktlen> On success, will be updated to contain the length of the packet in bytes.
|
||||
* @rbuf: Ringbuffer concerned.
|
||||
* @idx: Previous packet index, or -1 to return the first packet index.
|
||||
* @pktlen: On success, will be updated to contain the length of the packet
|
||||
* in bytes.
|
||||
* returns Packet index (if >=0), or -1 if no packets available.
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen);
|
||||
|
||||
extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf,
|
||||
size_t idx, size_t *pktlen);
|
||||
|
||||
#endif /* _DVB_RINGBUFFER_H_ */
|
||||
|
||||
@@ -15,12 +15,10 @@
|
||||
* 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 Lesser 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "dvbdev: " fmt
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
@@ -35,13 +33,22 @@
|
||||
#include <linux/version.h>
|
||||
#include "dvbdev.h"
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0))
|
||||
/* Due to enum tuner_pad_index */
|
||||
#include <media/tuner.h>
|
||||
#endif
|
||||
|
||||
static DEFINE_MUTEX(dvbdev_mutex);
|
||||
static int dvbdev_debug;
|
||||
|
||||
module_param(dvbdev_debug, int, 0644);
|
||||
MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
|
||||
|
||||
#define dprintk if (dvbdev_debug) printk
|
||||
#define dprintk(fmt, arg...) do { \
|
||||
if (dvbdev_debug) \
|
||||
printk(KERN_DEBUG pr_fmt("%s: " fmt), \
|
||||
__func__, ##arg); \
|
||||
} while (0)
|
||||
|
||||
static LIST_HEAD(dvb_adapter_list);
|
||||
static DEFINE_MUTEX(dvbdev_register_lock);
|
||||
@@ -52,11 +59,11 @@ static const char * const dnames[] = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DVB_DYNAMIC_MINORS
|
||||
#define MAX_DVB_MINORS 256
|
||||
#define MAX_DVB_MINORS 512
|
||||
#define DVB_MAX_IDS MAX_DVB_MINORS
|
||||
#else
|
||||
#define DVB_MAX_IDS 4
|
||||
#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
|
||||
#define nums2minor(num, type, id) ((num << 6) | (id << 4) | type)
|
||||
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
|
||||
#endif
|
||||
|
||||
@@ -75,22 +82,15 @@ static int dvb_device_open(struct inode *inode, struct file *file)
|
||||
|
||||
if (dvbdev && dvbdev->fops) {
|
||||
int err = 0;
|
||||
const struct file_operations *old_fops;
|
||||
const struct file_operations *new_fops;
|
||||
|
||||
file->private_data = dvbdev;
|
||||
old_fops = file->f_op;
|
||||
file->f_op = fops_get(dvbdev->fops);
|
||||
if (file->f_op == NULL) {
|
||||
file->f_op = old_fops;
|
||||
new_fops = fops_get(dvbdev->fops);
|
||||
if (!new_fops)
|
||||
goto fail;
|
||||
}
|
||||
if(file->f_op->open)
|
||||
err = file->f_op->open(inode,file);
|
||||
if (err) {
|
||||
fops_put(file->f_op);
|
||||
file->f_op = fops_get(old_fops);
|
||||
}
|
||||
fops_put(old_fops);
|
||||
file->private_data = dvbdev;
|
||||
replace_fops(file, new_fops);
|
||||
if (file->f_op->open)
|
||||
err = file->f_op->open(inode, file);
|
||||
up_read(&minor_rwsem);
|
||||
mutex_unlock(&dvbdev_mutex);
|
||||
return err;
|
||||
@@ -188,26 +188,266 @@ skip:
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
static void dvb_media_device_free(struct dvb_device *dvbdev)
|
||||
{
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
||||
if (dvbdev->entity) {
|
||||
media_device_unregister_entity(dvbdev->entity);
|
||||
kfree(dvbdev->entity);
|
||||
kfree(dvbdev->pads);
|
||||
dvbdev->entity = NULL;
|
||||
dvbdev->pads = NULL;
|
||||
}
|
||||
|
||||
if (dvbdev->tsout_entity) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dvbdev->tsout_num_entities; i++) {
|
||||
media_device_unregister_entity(&dvbdev->tsout_entity[i]);
|
||||
kfree(dvbdev->tsout_entity[i].name);
|
||||
}
|
||||
kfree(dvbdev->tsout_entity);
|
||||
kfree(dvbdev->tsout_pads);
|
||||
dvbdev->tsout_entity = NULL;
|
||||
dvbdev->tsout_pads = NULL;
|
||||
|
||||
dvbdev->tsout_num_entities = 0;
|
||||
}
|
||||
|
||||
if (dvbdev->intf_devnode) {
|
||||
media_devnode_remove(dvbdev->intf_devnode);
|
||||
dvbdev->intf_devnode = NULL;
|
||||
}
|
||||
|
||||
if (dvbdev->adapter->conn) {
|
||||
media_device_unregister_entity(dvbdev->adapter->conn);
|
||||
dvbdev->adapter->conn = NULL;
|
||||
kfree(dvbdev->adapter->conn_pads);
|
||||
dvbdev->adapter->conn_pads = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
||||
static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
|
||||
const char *name, int npads)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads),
|
||||
GFP_KERNEL);
|
||||
if (!dvbdev->tsout_pads)
|
||||
return -ENOMEM;
|
||||
|
||||
dvbdev->tsout_entity = kcalloc(npads, sizeof(*dvbdev->tsout_entity),
|
||||
GFP_KERNEL);
|
||||
if (!dvbdev->tsout_entity)
|
||||
return -ENOMEM;
|
||||
|
||||
dvbdev->tsout_num_entities = npads;
|
||||
|
||||
for (i = 0; i < npads; i++) {
|
||||
struct media_pad *pads = &dvbdev->tsout_pads[i];
|
||||
struct media_entity *entity = &dvbdev->tsout_entity[i];
|
||||
|
||||
entity->name = kasprintf(GFP_KERNEL, "%s #%d", name, i);
|
||||
if (!entity->name)
|
||||
return -ENOMEM;
|
||||
|
||||
entity->function = MEDIA_ENT_F_IO_DTV;
|
||||
pads->flags = MEDIA_PAD_FL_SINK;
|
||||
|
||||
ret = media_entity_pads_init(entity, 1, pads);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = media_device_register_entity(dvbdev->adapter->mdev,
|
||||
entity);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DEMUX_TSOUT "demux-tsout"
|
||||
#define DVR_TSOUT "dvr-tsout"
|
||||
|
||||
static int dvb_create_media_entity(struct dvb_device *dvbdev,
|
||||
int type, int demux_sink_pads)
|
||||
{
|
||||
int i, ret, npads;
|
||||
|
||||
switch (type) {
|
||||
case DVB_DEVICE_FRONTEND:
|
||||
npads = 2;
|
||||
break;
|
||||
case DVB_DEVICE_DVR:
|
||||
ret = dvb_create_tsout_entity(dvbdev, DVR_TSOUT,
|
||||
demux_sink_pads);
|
||||
return ret;
|
||||
case DVB_DEVICE_DEMUX:
|
||||
npads = 1 + demux_sink_pads;
|
||||
ret = dvb_create_tsout_entity(dvbdev, DEMUX_TSOUT,
|
||||
demux_sink_pads);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
case DVB_DEVICE_CA:
|
||||
npads = 2;
|
||||
break;
|
||||
case DVB_DEVICE_NET:
|
||||
/*
|
||||
* We should be creating entities for the MPE/ULE
|
||||
* decapsulation hardware (or software implementation).
|
||||
*
|
||||
* However, the number of for the MPE/ULE decaps may not be
|
||||
* fixed. As we don't have yet dynamic support for PADs at
|
||||
* the Media Controller, let's not create the decap
|
||||
* entities yet.
|
||||
*/
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL);
|
||||
if (!dvbdev->entity)
|
||||
return -ENOMEM;
|
||||
|
||||
dvbdev->entity->name = dvbdev->name;
|
||||
|
||||
if (npads) {
|
||||
dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
|
||||
GFP_KERNEL);
|
||||
if (!dvbdev->pads)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case DVB_DEVICE_FRONTEND:
|
||||
dvbdev->entity->function = MEDIA_ENT_F_DTV_DEMOD;
|
||||
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
|
||||
dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
|
||||
break;
|
||||
case DVB_DEVICE_DEMUX:
|
||||
dvbdev->entity->function = MEDIA_ENT_F_TS_DEMUX;
|
||||
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
|
||||
for (i = 1; i < npads; i++)
|
||||
dvbdev->pads[i].flags = MEDIA_PAD_FL_SOURCE;
|
||||
break;
|
||||
case DVB_DEVICE_CA:
|
||||
dvbdev->entity->function = MEDIA_ENT_F_DTV_CA;
|
||||
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
|
||||
dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
|
||||
break;
|
||||
default:
|
||||
/* Should never happen, as the first switch prevents it */
|
||||
kfree(dvbdev->entity);
|
||||
kfree(dvbdev->pads);
|
||||
dvbdev->entity = NULL;
|
||||
dvbdev->pads = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (npads) {
|
||||
ret = media_entity_pads_init(dvbdev->entity, npads, dvbdev->pads);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = media_device_register_entity(dvbdev->adapter->mdev,
|
||||
dvbdev->entity);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pr_info("%s: media entity '%s' registered.\n",
|
||||
__func__, dvbdev->entity->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dvb_register_media_device(struct dvb_device *dvbdev,
|
||||
int type, int minor,
|
||||
unsigned demux_sink_pads)
|
||||
{
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
||||
struct media_link *link;
|
||||
u32 intf_type;
|
||||
int ret;
|
||||
|
||||
if (!dvbdev->adapter->mdev)
|
||||
return 0;
|
||||
|
||||
ret = dvb_create_media_entity(dvbdev, type, demux_sink_pads);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (type) {
|
||||
case DVB_DEVICE_FRONTEND:
|
||||
intf_type = MEDIA_INTF_T_DVB_FE;
|
||||
break;
|
||||
case DVB_DEVICE_DEMUX:
|
||||
intf_type = MEDIA_INTF_T_DVB_DEMUX;
|
||||
break;
|
||||
case DVB_DEVICE_DVR:
|
||||
intf_type = MEDIA_INTF_T_DVB_DVR;
|
||||
break;
|
||||
case DVB_DEVICE_CA:
|
||||
intf_type = MEDIA_INTF_T_DVB_CA;
|
||||
break;
|
||||
case DVB_DEVICE_NET:
|
||||
intf_type = MEDIA_INTF_T_DVB_NET;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
dvbdev->intf_devnode = media_devnode_create(dvbdev->adapter->mdev,
|
||||
intf_type, 0,
|
||||
DVB_MAJOR, minor);
|
||||
|
||||
if (!dvbdev->intf_devnode)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Create the "obvious" link, e. g. the ones that represent
|
||||
* a direct association between an interface and an entity.
|
||||
* Other links should be created elsewhere, like:
|
||||
* DVB FE intf -> tuner
|
||||
* DVB demux intf -> dvr
|
||||
*/
|
||||
|
||||
if (!dvbdev->entity)
|
||||
return 0;
|
||||
|
||||
link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
const struct dvb_device *template, void *priv, int type)
|
||||
const struct dvb_device *template, void *priv, int type,
|
||||
int demux_sink_pads)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
struct file_operations *dvbdevfops;
|
||||
struct device *clsdev;
|
||||
int minor;
|
||||
int id;
|
||||
int id, ret;
|
||||
|
||||
mutex_lock(&dvbdev_register_lock);
|
||||
|
||||
if ((id = dvbdev_get_free_id (adap, type)) < 0){
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
*pdvbdev = NULL;
|
||||
printk(KERN_ERR "%s: couldn't find free device id\n", __func__);
|
||||
pr_err("%s: couldn't find free device id\n", __func__);
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
*pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
|
||||
*pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
|
||||
|
||||
if (!dvbdev){
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
@@ -256,18 +496,30 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
dvb_minors[minor] = dvbdev;
|
||||
up_write(&minor_rwsem);
|
||||
|
||||
ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
|
||||
if (ret) {
|
||||
pr_err("%s: dvb_register_media_device failed to create the mediagraph\n",
|
||||
__func__);
|
||||
|
||||
dvb_media_device_free(dvbdev);
|
||||
kfree(dvbdevfops);
|
||||
kfree(dvbdev);
|
||||
up_write(&minor_rwsem);
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
|
||||
clsdev = device_create(dvb_class, adap->device,
|
||||
MKDEV(DVB_MAJOR, minor),
|
||||
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
|
||||
if (IS_ERR(clsdev)) {
|
||||
printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
|
||||
pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
|
||||
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
|
||||
return PTR_ERR(clsdev);
|
||||
}
|
||||
|
||||
dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
|
||||
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
|
||||
adap->num, dnames[type], id, minor, minor);
|
||||
|
||||
return 0;
|
||||
@@ -275,7 +527,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
EXPORT_SYMBOL(dvb_register_device);
|
||||
|
||||
|
||||
void dvb_unregister_device(struct dvb_device *dvbdev)
|
||||
void dvb_remove_device(struct dvb_device *dvbdev)
|
||||
{
|
||||
if (!dvbdev)
|
||||
return;
|
||||
@@ -284,14 +536,244 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
|
||||
dvb_minors[dvbdev->minor] = NULL;
|
||||
up_write(&minor_rwsem);
|
||||
|
||||
dvb_media_device_free(dvbdev);
|
||||
|
||||
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
|
||||
|
||||
list_del (&dvbdev->list_head);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_remove_device);
|
||||
|
||||
|
||||
void dvb_free_device(struct dvb_device *dvbdev)
|
||||
{
|
||||
if (!dvbdev)
|
||||
return;
|
||||
|
||||
kfree (dvbdev->fops);
|
||||
kfree (dvbdev);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_free_device);
|
||||
|
||||
|
||||
void dvb_unregister_device(struct dvb_device *dvbdev)
|
||||
{
|
||||
dvb_remove_device(dvbdev);
|
||||
dvb_free_device(dvbdev);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_unregister_device);
|
||||
|
||||
|
||||
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
|
||||
|
||||
static int dvb_create_io_intf_links(struct dvb_adapter *adap,
|
||||
struct media_interface *intf,
|
||||
char *name)
|
||||
{
|
||||
struct media_device *mdev = adap->mdev;
|
||||
struct media_entity *entity;
|
||||
struct media_link *link;
|
||||
|
||||
media_device_for_each_entity(entity, mdev) {
|
||||
if (entity->function == MEDIA_ENT_F_IO_DTV) {
|
||||
if (strncmp(entity->name, name, strlen(name)))
|
||||
continue;
|
||||
link = media_create_intf_link(entity, intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
bool create_rf_connector)
|
||||
{
|
||||
struct media_device *mdev = adap->mdev;
|
||||
struct media_entity *entity, *tuner = NULL, *demod = NULL, *conn;
|
||||
struct media_entity *demux = NULL, *ca = NULL;
|
||||
struct media_link *link;
|
||||
struct media_interface *intf;
|
||||
unsigned demux_pad = 0;
|
||||
unsigned dvr_pad = 0;
|
||||
unsigned ntuner = 0, ndemod = 0;
|
||||
int ret;
|
||||
static const char *connector_name = "Television";
|
||||
|
||||
if (!mdev)
|
||||
return 0;
|
||||
|
||||
media_device_for_each_entity(entity, mdev) {
|
||||
switch (entity->function) {
|
||||
case MEDIA_ENT_F_TUNER:
|
||||
tuner = entity;
|
||||
ntuner++;
|
||||
break;
|
||||
case MEDIA_ENT_F_DTV_DEMOD:
|
||||
demod = entity;
|
||||
ndemod++;
|
||||
break;
|
||||
case MEDIA_ENT_F_TS_DEMUX:
|
||||
demux = entity;
|
||||
break;
|
||||
case MEDIA_ENT_F_DTV_CA:
|
||||
ca = entity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare to signalize to media_create_pad_links() that multiple
|
||||
* entities of the same type exists and a 1:n or n:1 links need to be
|
||||
* created.
|
||||
* NOTE: if both tuner and demod have multiple instances, it is up
|
||||
* to the caller driver to create such links.
|
||||
*/
|
||||
if (ntuner > 1)
|
||||
tuner = NULL;
|
||||
if (ndemod > 1)
|
||||
demod = NULL;
|
||||
|
||||
if (create_rf_connector) {
|
||||
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
|
||||
if (!conn)
|
||||
return -ENOMEM;
|
||||
adap->conn = conn;
|
||||
|
||||
adap->conn_pads = kzalloc(sizeof(*adap->conn_pads), GFP_KERNEL);
|
||||
if (!adap->conn_pads)
|
||||
return -ENOMEM;
|
||||
|
||||
conn->flags = MEDIA_ENT_FL_CONNECTOR;
|
||||
conn->function = MEDIA_ENT_F_CONN_RF;
|
||||
conn->name = connector_name;
|
||||
adap->conn_pads->flags = MEDIA_PAD_FL_SOURCE;
|
||||
|
||||
ret = media_entity_pads_init(conn, 1, adap->conn_pads);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = media_device_register_entity(mdev, conn);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!ntuner)
|
||||
ret = media_create_pad_links(mdev,
|
||||
MEDIA_ENT_F_CONN_RF,
|
||||
conn, 0,
|
||||
MEDIA_ENT_F_DTV_DEMOD,
|
||||
demod, 0,
|
||||
MEDIA_LNK_FL_ENABLED,
|
||||
false);
|
||||
else
|
||||
ret = media_create_pad_links(mdev,
|
||||
MEDIA_ENT_F_CONN_RF,
|
||||
conn, 0,
|
||||
MEDIA_ENT_F_TUNER,
|
||||
tuner, TUNER_PAD_RF_INPUT,
|
||||
MEDIA_LNK_FL_ENABLED,
|
||||
false);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ntuner && ndemod) {
|
||||
ret = media_create_pad_links(mdev,
|
||||
MEDIA_ENT_F_TUNER,
|
||||
tuner, TUNER_PAD_OUTPUT,
|
||||
MEDIA_ENT_F_DTV_DEMOD,
|
||||
demod, 0, MEDIA_LNK_FL_ENABLED,
|
||||
false);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ndemod && demux) {
|
||||
ret = media_create_pad_links(mdev,
|
||||
MEDIA_ENT_F_DTV_DEMOD,
|
||||
demod, 1,
|
||||
MEDIA_ENT_F_TS_DEMUX,
|
||||
demux, 0, MEDIA_LNK_FL_ENABLED,
|
||||
false);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (demux && ca) {
|
||||
ret = media_create_pad_link(demux, 1, ca,
|
||||
0, MEDIA_LNK_FL_ENABLED);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create demux links for each ringbuffer/pad */
|
||||
if (demux) {
|
||||
media_device_for_each_entity(entity, mdev) {
|
||||
if (entity->function == MEDIA_ENT_F_IO_DTV) {
|
||||
if (!strncmp(entity->name, DVR_TSOUT,
|
||||
strlen(DVR_TSOUT))) {
|
||||
ret = media_create_pad_link(demux,
|
||||
++dvr_pad,
|
||||
entity, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (!strncmp(entity->name, DEMUX_TSOUT,
|
||||
strlen(DEMUX_TSOUT))) {
|
||||
ret = media_create_pad_link(demux,
|
||||
++demux_pad,
|
||||
entity, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create interface links for FE->tuner, DVR->demux and CA->ca */
|
||||
media_device_for_each_intf(intf, mdev) {
|
||||
if (intf->type == MEDIA_INTF_T_DVB_CA && ca) {
|
||||
link = media_create_intf_link(ca, intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) {
|
||||
link = media_create_intf_link(tuner, intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
#if 0
|
||||
/*
|
||||
* Indirect link - let's not create yet, as we don't know how
|
||||
* to handle indirect links, nor if this will
|
||||
* actually be needed.
|
||||
*/
|
||||
if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) {
|
||||
link = media_create_intf_link(demux, intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
if (intf->type == MEDIA_INTF_T_DVB_DVR) {
|
||||
ret = dvb_create_io_intf_links(adap, intf, DVR_TSOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (intf->type == MEDIA_INTF_T_DVB_DEMUX) {
|
||||
ret = dvb_create_io_intf_links(adap, intf, DEMUX_TSOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dvb_create_media_graph);
|
||||
#endif
|
||||
|
||||
static int dvbdev_check_free_adapter_num(int num)
|
||||
{
|
||||
struct list_head *entry;
|
||||
@@ -347,7 +829,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
||||
memset (adap, 0, sizeof(struct dvb_adapter));
|
||||
INIT_LIST_HEAD (&adap->device_list);
|
||||
|
||||
printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
|
||||
pr_info("DVB: registering new adapter (%s)\n", name);
|
||||
|
||||
adap->num = num;
|
||||
adap->name = name;
|
||||
@@ -406,7 +888,7 @@ int dvb_usercopy(struct file *file,
|
||||
parg = sbuf;
|
||||
} else {
|
||||
/* too big to allocate from stack */
|
||||
mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
|
||||
mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
|
||||
if (NULL == mbuf)
|
||||
return -ENOMEM;
|
||||
parg = mbuf;
|
||||
@@ -419,11 +901,8 @@ int dvb_usercopy(struct file *file,
|
||||
}
|
||||
|
||||
/* call driver */
|
||||
/* this lock is much too coarse */
|
||||
//mutex_lock(&dvbdev_mutex);
|
||||
if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
|
||||
err = -ENOTTY;
|
||||
//mutex_unlock(&dvbdev_mutex);
|
||||
|
||||
if (err < 0)
|
||||
goto out;
|
||||
@@ -454,11 +933,7 @@ static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0))
|
||||
static char *dvb_devnode(struct device *dev, mode_t *mode)
|
||||
#else
|
||||
static char *dvb_devnode(struct device *dev, umode_t *mode)
|
||||
#endif
|
||||
{
|
||||
struct dvb_device *dvbdev = dev_get_drvdata(dev);
|
||||
|
||||
@@ -473,13 +948,13 @@ static int __init init_dvbdev(void)
|
||||
dev_t dev = MKDEV(DVB_MAJOR, 0);
|
||||
|
||||
if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
|
||||
printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
|
||||
pr_err("dvb-core: unable to get major %d\n", DVB_MAJOR);
|
||||
return retval;
|
||||
}
|
||||
|
||||
cdev_init(&dvb_device_cdev, &dvb_device_fops);
|
||||
if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
|
||||
printk(KERN_ERR "dvb-core: unable register character device\n");
|
||||
pr_err("dvb-core: unable register character device\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
* 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 Lesser 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DVBDEV_H_
|
||||
@@ -27,13 +23,14 @@
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <media/media-device.h>
|
||||
|
||||
#define DVB_MAJOR 212
|
||||
|
||||
#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
|
||||
#define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
|
||||
#else
|
||||
#define DVB_MAX_ADAPTERS 8
|
||||
#define DVB_MAX_ADAPTERS 64
|
||||
#endif
|
||||
|
||||
#define DVB_UNSET (-1)
|
||||
@@ -60,6 +57,28 @@
|
||||
|
||||
struct dvb_frontend;
|
||||
|
||||
/**
|
||||
* struct dvb_adapter - represents a Digital TV adapter using Linux DVB API
|
||||
*
|
||||
* @num: Number of the adapter
|
||||
* @list_head: List with the DVB adapters
|
||||
* @device_list: List with the DVB devices
|
||||
* @name: Name of the adapter
|
||||
* @proposed_mac: proposed MAC address for the adapter
|
||||
* @priv: private data
|
||||
* @device: pointer to struct device
|
||||
* @module: pointer to struct module
|
||||
* @mfe_shared: mfe shared: indicates mutually exclusive frontends
|
||||
* Thie usage of this flag is currently deprecated
|
||||
* @mfe_dvbdev: Frontend device in use, in the case of MFE
|
||||
* @mfe_lock: Lock to prevent using the other frontends when MFE is
|
||||
* used.
|
||||
* @mdev: pointer to struct media_device, used when the media
|
||||
* controller is used.
|
||||
* @conn: RF connector. Used only if the device has no separate
|
||||
* tuner.
|
||||
* @conn_pads: pointer to struct media_pad associated with @conn;
|
||||
*/
|
||||
struct dvb_adapter {
|
||||
int num;
|
||||
struct list_head list_head;
|
||||
@@ -75,9 +94,47 @@ struct dvb_adapter {
|
||||
int mfe_shared; /* indicates mutually exclusive frontends */
|
||||
struct dvb_device *mfe_dvbdev; /* frontend device in use */
|
||||
struct mutex mfe_lock; /* access lock for thread creation */
|
||||
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
||||
struct media_device *mdev;
|
||||
struct media_entity *conn;
|
||||
struct media_pad *conn_pads;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct dvb_device - represents a DVB device node
|
||||
*
|
||||
* @list_head: List head with all DVB devices
|
||||
* @fops: pointer to struct file_operations
|
||||
* @adapter: pointer to the adapter that holds this device node
|
||||
* @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND,
|
||||
* DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET
|
||||
* @minor: devnode minor number. Major number is always DVB_MAJOR.
|
||||
* @id: device ID number, inside the adapter
|
||||
* @readers: Initialized by the caller. Each call to open() in Read Only mode
|
||||
* decreases this counter by one.
|
||||
* @writers: Initialized by the caller. Each call to open() in Read/Write
|
||||
* mode decreases this counter by one.
|
||||
* @users: Initialized by the caller. Each call to open() in any mode
|
||||
* decreases this counter by one.
|
||||
* @wait_queue: wait queue, used to wait for certain events inside one of
|
||||
* the DVB API callers
|
||||
* @kernel_ioctl: callback function used to handle ioctl calls from userspace.
|
||||
* @name: Name to be used for the device at the Media Controller
|
||||
* @entity: pointer to struct media_entity associated with the device node
|
||||
* @pads: pointer to struct media_pad associated with @entity;
|
||||
* @priv: private data
|
||||
* @intf_devnode: Pointer to media_intf_devnode. Used by the dvbdev core to
|
||||
* store the MC device node interface
|
||||
* @tsout_num_entities: Number of Transport Stream output entities
|
||||
* @tsout_entity: array with MC entities associated to each TS output node
|
||||
* @tsout_pads: array with the source pads for each @tsout_entity
|
||||
*
|
||||
* This structure is used by the DVB core (frontend, CA, net, demux) in
|
||||
* order to create the device nodes. Usually, driver should not initialize
|
||||
* this struct diretly.
|
||||
*/
|
||||
struct dvb_device {
|
||||
struct list_head list_head;
|
||||
const struct file_operations *fops;
|
||||
@@ -96,34 +153,145 @@ struct dvb_device {
|
||||
/* don't really need those !? -- FIXME: use video_usercopy */
|
||||
int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
|
||||
|
||||
/* Needed for media controller register/unregister */
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
||||
const char *name;
|
||||
|
||||
/* Allocated and filled inside dvbdev.c */
|
||||
struct media_intf_devnode *intf_devnode;
|
||||
|
||||
unsigned tsout_num_entities;
|
||||
struct media_entity *entity, *tsout_entity;
|
||||
struct media_pad *pads, *tsout_pads;
|
||||
#endif
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* dvb_register_adapter - Registers a new DVB adapter
|
||||
*
|
||||
* @adap: pointer to struct dvb_adapter
|
||||
* @name: Adapter's name
|
||||
* @module: initialized with THIS_MODULE at the caller
|
||||
* @device: pointer to struct device that corresponds to the device driver
|
||||
* @adapter_nums: Array with a list of the numbers for @dvb_register_adapter;
|
||||
* to select among them. Typically, initialized with:
|
||||
* DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums)
|
||||
*/
|
||||
int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
||||
struct module *module, struct device *device,
|
||||
short *adapter_nums);
|
||||
|
||||
extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
||||
struct module *module, struct device *device,
|
||||
short *adapter_nums);
|
||||
extern int dvb_unregister_adapter (struct dvb_adapter *adap);
|
||||
/**
|
||||
* dvb_unregister_adapter - Unregisters a DVB adapter
|
||||
*
|
||||
* @adap: pointer to struct dvb_adapter
|
||||
*/
|
||||
int dvb_unregister_adapter(struct dvb_adapter *adap);
|
||||
|
||||
extern int dvb_register_device (struct dvb_adapter *adap,
|
||||
struct dvb_device **pdvbdev,
|
||||
const struct dvb_device *template,
|
||||
void *priv,
|
||||
int type);
|
||||
/**
|
||||
* dvb_register_device - Registers a new DVB device
|
||||
*
|
||||
* @adap: pointer to struct dvb_adapter
|
||||
* @pdvbdev: pointer to the place where the new struct dvb_device will be
|
||||
* stored
|
||||
* @template: Template used to create &pdvbdev;
|
||||
* @priv: private data
|
||||
* @type: type of the device: %DVB_DEVICE_SEC, %DVB_DEVICE_FRONTEND,
|
||||
* %DVB_DEVICE_DEMUX, %DVB_DEVICE_DVR, %DVB_DEVICE_CA,
|
||||
* %DVB_DEVICE_NET
|
||||
* @demux_sink_pads: Number of demux outputs, to be used to create the TS
|
||||
* outputs via the Media Controller.
|
||||
*/
|
||||
int dvb_register_device(struct dvb_adapter *adap,
|
||||
struct dvb_device **pdvbdev,
|
||||
const struct dvb_device *template,
|
||||
void *priv,
|
||||
int type,
|
||||
int demux_sink_pads);
|
||||
|
||||
extern void dvb_unregister_device (struct dvb_device *dvbdev);
|
||||
/**
|
||||
* dvb_remove_device - Remove a registered DVB device
|
||||
*
|
||||
* This does not free memory. To do that, call dvb_free_device().
|
||||
*
|
||||
* @dvbdev: pointer to struct dvb_device
|
||||
*/
|
||||
void dvb_remove_device(struct dvb_device *dvbdev);
|
||||
|
||||
extern int dvb_generic_open (struct inode *inode, struct file *file);
|
||||
extern int dvb_generic_release (struct inode *inode, struct file *file);
|
||||
extern long dvb_generic_ioctl (struct file *file,
|
||||
/**
|
||||
* dvb_free_device - Free memory occupied by a DVB device.
|
||||
*
|
||||
* Call dvb_unregister_device() before calling this function.
|
||||
*
|
||||
* @dvbdev: pointer to struct dvb_device
|
||||
*/
|
||||
void dvb_free_device(struct dvb_device *dvbdev);
|
||||
|
||||
/**
|
||||
* dvb_unregister_device - Unregisters a DVB device
|
||||
*
|
||||
* This is a combination of dvb_remove_device() and dvb_free_device().
|
||||
* Using this function is usually a mistake, and is often an indicator
|
||||
* for a use-after-free bug (when a userspace process keeps a file
|
||||
* handle to a detached device).
|
||||
*
|
||||
* @dvbdev: pointer to struct dvb_device
|
||||
*/
|
||||
void dvb_unregister_device(struct dvb_device *dvbdev);
|
||||
|
||||
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
|
||||
/**
|
||||
* dvb_create_media_graph - Creates media graph for the Digital TV part of the
|
||||
* device.
|
||||
*
|
||||
* @adap: pointer to struct dvb_adapter
|
||||
* @create_rf_connector: if true, it creates the RF connector too
|
||||
*
|
||||
* This function checks all DVB-related functions at the media controller
|
||||
* entities and creates the needed links for the media graph. It is
|
||||
* capable of working with multiple tuners or multiple frontends, but it
|
||||
* won't create links if the device has multiple tuners and multiple frontends
|
||||
* or if the device has multiple muxes. In such case, the caller driver should
|
||||
* manually create the remaining links.
|
||||
*/
|
||||
__must_check int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
bool create_rf_connector);
|
||||
|
||||
static inline void dvb_register_media_controller(struct dvb_adapter *adap,
|
||||
struct media_device *mdev)
|
||||
{
|
||||
adap->mdev = mdev;
|
||||
}
|
||||
|
||||
static inline struct media_device
|
||||
*dvb_get_media_controller(struct dvb_adapter *adap)
|
||||
{
|
||||
return adap->mdev;
|
||||
}
|
||||
#else
|
||||
static inline
|
||||
int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
bool create_rf_connector)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
#define dvb_register_media_controller(a, b) {}
|
||||
#define dvb_get_media_controller(a) NULL
|
||||
#endif
|
||||
|
||||
int dvb_generic_open (struct inode *inode, struct file *file);
|
||||
int dvb_generic_release (struct inode *inode, struct file *file);
|
||||
long dvb_generic_ioctl (struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
|
||||
/* we don't mess with video_usercopy() any more,
|
||||
we simply define out own dvb_usercopy(), which will hopefully become
|
||||
generic_usercopy() someday... */
|
||||
|
||||
extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
||||
int (*func)(struct file *file, unsigned int cmd, void *arg));
|
||||
int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
||||
int (*func)(struct file *file, unsigned int cmd, void *arg));
|
||||
|
||||
/** generic DVB attach function. */
|
||||
#ifdef CONFIG_MEDIA_ATTACH
|
||||
@@ -140,11 +308,15 @@ extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
||||
__r; \
|
||||
})
|
||||
|
||||
#define dvb_detach(FUNC) symbol_put_addr(FUNC)
|
||||
|
||||
#else
|
||||
#define dvb_attach(FUNCTION, ARGS...) ({ \
|
||||
FUNCTION(ARGS); \
|
||||
})
|
||||
|
||||
#define dvb_detach(FUNC) {}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef _DVBDEV_H_ */
|
||||
|
||||
838
frontends/Kconfig
Normal file
838
frontends/Kconfig
Normal file
@@ -0,0 +1,838 @@
|
||||
menu "Customise DVB Frontends"
|
||||
visible if !MEDIA_SUBDRV_AUTOSELECT
|
||||
|
||||
comment "Multistandard (satellite) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_STB0899
|
||||
tristate "STB0899 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want
|
||||
to support this demodulator based frontends
|
||||
|
||||
config DVB_STB6100
|
||||
tristate "STB6100 based tuners"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A Silicon tuner from ST used in conjunction with the STB0899
|
||||
demodulator. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_STV090x
|
||||
tristate "STV0900/STV0903(A/B) based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
|
||||
Say Y when you want to support these frontends.
|
||||
|
||||
config DVB_STV6110x
|
||||
tristate "STV6110/(A) based tuners"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A Silicon tuner that supports DVB-S and DVB-S2 modes
|
||||
|
||||
config DVB_STV0910
|
||||
tristate "STV0910 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
|
||||
Say Y when you want to support these frontends.
|
||||
|
||||
config DVB_MXL5XX
|
||||
tristate "MXL5XX based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
|
||||
Say Y when you want to support these frontends.
|
||||
|
||||
config DVB_STV6111
|
||||
tristate "STV6111 based tuners"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A Silicon tuner that supports DVB-S and DVB-S2 modes
|
||||
|
||||
config DVB_M88DS3103
|
||||
tristate "Montage M88DS3103"
|
||||
depends on DVB_CORE && I2C && I2C_MUX
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "Multistandard (cable + terrestrial) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_DRXK
|
||||
tristate "Micronas DRXK based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Micronas DRX-K DVB-C/T demodulator.
|
||||
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
|
||||
config DVB_TDA18271C2DD
|
||||
tristate "NXP TDA18271C2 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
NXP TDA18271 silicon tuner.
|
||||
|
||||
Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_SI2165
|
||||
tristate "Silicon Labs si2165 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-C/T demodulator.
|
||||
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "DVB-S (satellite) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_CX24110
|
||||
tristate "Conexant CX24110 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_CX24123
|
||||
tristate "Conexant CX24123 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_MT312
|
||||
tristate "Zarlink VP310/MT312/ZL10313 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_ZL10036
|
||||
tristate "Zarlink ZL10036 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_ZL10039
|
||||
tristate "Zarlink ZL10039 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_S5H1420
|
||||
tristate "Samsung S5H1420 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STV0288
|
||||
tristate "ST STV0288 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STB6000
|
||||
tristate "ST STB6000 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_STV0299
|
||||
tristate "ST STV0299 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STV6110
|
||||
tristate "ST STV6110 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_STV0900
|
||||
tristate "ST STV0900 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/S2 demodulator. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA8083
|
||||
tristate "Philips TDA8083 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA10086
|
||||
tristate "Philips TDA10086 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA8261
|
||||
tristate "Philips TDA8261 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_VES1X93
|
||||
tristate "VLSI VES1893 or VES1993 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TUNER_ITD1000
|
||||
tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TUNER_CX24113
|
||||
tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
|
||||
config DVB_TDA826X
|
||||
tristate "Philips TDA826X silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_TUA6100
|
||||
tristate "Infineon TUA6100 PLL"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S PLL chip.
|
||||
|
||||
config DVB_CX24116
|
||||
tristate "Conexant CX24116 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_CX24117
|
||||
tristate "Conexant CX24117 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A Dual DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_SI21XX
|
||||
tristate "Silicon Labs SI21XX based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TS2020
|
||||
tristate "Montage Tehnology TS2020 based tuners"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/S2 silicon tuner. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_DS3000
|
||||
tristate "Montage Tehnology DS3000 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_MB86A16
|
||||
tristate "Fujitsu MB86A16 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/DSS Direct Conversion reveiver.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA10071
|
||||
tristate "NXP TDA10071"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "DVB-T (terrestrial) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_SP8870
|
||||
tristate "Spase sp8870 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the command
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
|
||||
download/extract it, and then copy it to /usr/lib/hotplug/firmware
|
||||
or /lib/firmware (depending on configuration of firmware hotplug).
|
||||
|
||||
config DVB_SP887X
|
||||
tristate "Spase sp887x based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the command
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
|
||||
download/extract it, and then copy it to /usr/lib/hotplug/firmware
|
||||
or /lib/firmware (depending on configuration of firmware hotplug).
|
||||
|
||||
config DVB_CX22700
|
||||
tristate "Conexant CX22700 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_CX22702
|
||||
tristate "Conexant cx22702 demodulator (OFDM)"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_S5H1432
|
||||
tristate "Samsung s5h1432 demodulator (OFDM)"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_DRXD
|
||||
tristate "Micronas DRXD driver"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
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"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA1004X
|
||||
tristate "Philips TDA10045H/TDA10046H based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the commands
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
|
||||
download/extract them, and then copy them to /usr/lib/hotplug/firmware
|
||||
or /lib/firmware (depending on configuration of firmware hotplug).
|
||||
|
||||
config DVB_NXT6000
|
||||
tristate "NxtWave Communications NXT6000 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_MT352
|
||||
tristate "Zarlink MT352 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_ZL10353
|
||||
tristate "Zarlink ZL10353 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_DIB3000MB
|
||||
tristate "DiBcom 3000M-B"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_DIB3000MC
|
||||
tristate "DiBcom 3000P/M-C"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_DIB7000M
|
||||
tristate "DiBcom 7000MA/MB/PA/PB/MC"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_DIB7000P
|
||||
tristate "DiBcom 7000PC"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_DIB9000
|
||||
tristate "DiBcom 9000"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_TDA10048
|
||||
tristate "Philips TDA10048HN based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA18212DD
|
||||
tristate "Philips TDA18212 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_AF9013
|
||||
tristate "Afatech AF9013 demodulator"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_EC100
|
||||
tristate "E3C EC100"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_HD29L2
|
||||
tristate "HDIC HD29L2"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STV0367
|
||||
tristate "ST STV0367 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T/C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STV0367DD
|
||||
tristate "ST STV0367dd based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T/C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_CXD2843
|
||||
tristate "Sony CXD2843"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T/T2/C/C2 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 !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_RTL2830
|
||||
tristate "Realtek RTL2830 DVB-T"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_RTL2832
|
||||
tristate "Realtek RTL2832 DVB-T"
|
||||
depends on DVB_CORE && I2C && I2C_MUX
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_RTL2832_SDR
|
||||
tristate "Realtek RTL2832 SDR"
|
||||
depends on DVB_CORE && I2C && I2C_MUX && VIDEO_V4L2 && MEDIA_SDR_SUPPORT && USB
|
||||
select DVB_RTL2832
|
||||
select VIDEOBUF2_VMALLOC
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this SDR module.
|
||||
|
||||
config DVB_SI2168
|
||||
tristate "Silicon Labs Si2168"
|
||||
depends on DVB_CORE && I2C && I2C_MUX
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "DVB-C (cable) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_VES1820
|
||||
tristate "VLSI VES1820 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA10021
|
||||
tristate "Philips TDA10021 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA10023
|
||||
tristate "Philips TDA10023 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STV0297
|
||||
tristate "ST STV0297 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_NXT200X
|
||||
tristate "NxtWave Communications NXT2002/NXT2004 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the commands
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
|
||||
download/extract them, and then copy them to /usr/lib/hotplug/firmware
|
||||
or /lib/firmware (depending on configuration of firmware hotplug).
|
||||
|
||||
config DVB_OR51211
|
||||
tristate "Oren OR51211 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the command
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
|
||||
download it, and then copy it to /usr/lib/hotplug/firmware
|
||||
or /lib/firmware (depending on configuration of firmware hotplug).
|
||||
|
||||
config DVB_OR51132
|
||||
tristate "Oren OR51132 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the commands
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_qam" to
|
||||
download firmwares for 8VSB and QAM64/256, respectively. Copy them to
|
||||
/usr/lib/hotplug/firmware or /lib/firmware (depending on
|
||||
configuration of firmware hotplug).
|
||||
|
||||
config DVB_BCM3510
|
||||
tristate "Broadcom BCM3510"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
|
||||
support this frontend.
|
||||
|
||||
config DVB_LGDT330X
|
||||
tristate "LG Electronics LGDT3302/LGDT3303 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_LGDT3305
|
||||
tristate "LG Electronics LGDT3304 and LGDT3305 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_LG2160
|
||||
tristate "LG Electronics LG216x based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC/MH demodulator module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_S5H1409
|
||||
tristate "Samsung S5H1409 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_AU8522
|
||||
depends on I2C
|
||||
tristate
|
||||
|
||||
config DVB_AU8522_DTV
|
||||
tristate "Auvitek AU8522 based DTV demod"
|
||||
depends on DVB_CORE && I2C
|
||||
select DVB_AU8522
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
|
||||
you want to enable DTV demodulation support for this frontend.
|
||||
|
||||
config DVB_AU8522_V4L
|
||||
tristate "Auvitek AU8522 based ATV demod"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
select DVB_AU8522
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
|
||||
you want to enable ATV demodulation support for this frontend.
|
||||
|
||||
config DVB_S5H1411
|
||||
tristate "Samsung S5H1411 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
comment "ISDB-T (terrestrial) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_S921
|
||||
tristate "Sharp S921 frontend"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_DIB8000
|
||||
tristate "DiBcom 8000MB/MC"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_MB86A20S
|
||||
tristate "Fujitsu mb86a20s"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "Digital terrestrial only tuners/PLL"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_PLL
|
||||
tristate "Generic I2C PLL based tuners"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
This module drives a number of tuners based on PLL chips with a
|
||||
common I2C interface. Say Y when you want to support these tuners.
|
||||
|
||||
config DVB_TUNER_DIB0070
|
||||
tristate "DiBcom DiB0070 silicon base-band tuner"
|
||||
depends on I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A driver for the silicon baseband tuner DiB0070 from DiBcom.
|
||||
This device is only used inside a SiP called together with a
|
||||
demodulator for now.
|
||||
|
||||
config DVB_TUNER_DIB0090
|
||||
tristate "DiBcom DiB0090 silicon base-band tuner"
|
||||
depends on I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A driver for the silicon baseband tuner DiB0090 from DiBcom.
|
||||
This device is only used inside a SiP called together with a
|
||||
demodulator for now.
|
||||
|
||||
comment "SEC control devices for DVB-S"
|
||||
depends on DVB_CORE
|
||||
|
||||
source "drivers/media/dvb-frontends/drx39xyj/Kconfig"
|
||||
|
||||
config DVB_LNBP21
|
||||
tristate "LNBP21/LNBH24 SEC controllers"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An SEC control chips.
|
||||
|
||||
config DVB_LNBH25
|
||||
tristate "LNBH25 SEC controllers"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An SEC control chips.
|
||||
|
||||
config DVB_LNBP22
|
||||
tristate "LNBP22 SEC controllers"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
LNB power supply and control voltage
|
||||
regulator chip with step-up converter
|
||||
and I2C interface.
|
||||
Say Y when you want to support this chip.
|
||||
|
||||
config DVB_ISL6405
|
||||
tristate "ISL6405 SEC controller"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An SEC control chip.
|
||||
|
||||
config DVB_ISL6421
|
||||
tristate "ISL6421 SEC controller"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An SEC control chip.
|
||||
|
||||
config DVB_ISL6423
|
||||
tristate "ISL6423 SEC controller"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A SEC controller chip from Intersil
|
||||
|
||||
config DVB_A8293
|
||||
tristate "Allegro A8293"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
|
||||
config DVB_LGS8GL5
|
||||
tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DMB-TH tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_LGS8GXX
|
||||
tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
|
||||
depends on DVB_CORE && I2C
|
||||
select FW_LOADER
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DMB-TH tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_ATBM8830
|
||||
tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DMB-TH tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA665x
|
||||
tristate "TDA665x tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Support for tuner modules based on Philips TDA6650/TDA6651 chips.
|
||||
Say Y when you want to support this chip.
|
||||
|
||||
Currently supported tuners:
|
||||
* Panasonic ENV57H12D5 (ET-50DT)
|
||||
|
||||
config DVB_IX2505V
|
||||
tristate "Sharp IX2505V silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_M88RS2000
|
||||
tristate "M88RS2000 DVB-S demodulator and tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_AF9033
|
||||
tristate "Afatech AF9033 DVB-T demodulator"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
|
||||
config DVB_CXD2099
|
||||
tristate "cxd2099"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
|
||||
comment "Tools to develop new frontends"
|
||||
|
||||
config DVB_DUMMY_FE
|
||||
tristate "Dummy frontend driver"
|
||||
default n
|
||||
endmenu
|
||||
@@ -14,6 +14,7 @@ EXTRA_CFLAGS += -DCONFIG_DVB_STV6111
|
||||
EXTRA_CFLAGS += -DCONFIG_DVB_STV0910
|
||||
EXTRA_CFLAGS += -DCONFIG_DVB_LNBH25
|
||||
EXTRA_CFLAGS += -DCONFIG_DVB_MXL5XX
|
||||
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2099
|
||||
EXTRA_CFLAGS += -DDBVALS
|
||||
NOSTDINC_FLAGS += -I$(SUBDIRS)/include -I$(SUBDIRS)/dvb-core
|
||||
|
||||
|
||||
123
frontends/Makefile.kernel
Normal file
123
frontends/Makefile.kernel
Normal file
@@ -0,0 +1,123 @@
|
||||
#
|
||||
# Makefile for the kernel DVB frontend device drivers.
|
||||
#
|
||||
|
||||
ccflags-y += -I$(srctree)/drivers/media/dvb-core/
|
||||
ccflags-y += -I$(srctree)/drivers/media/tuners/
|
||||
|
||||
# FIXME: RTL2832 SDR driver uses power management directly from USB IF driver
|
||||
ifdef CONFIG_DVB_RTL2832_SDR
|
||||
ccflags-y += -I$(srctree)/drivers/media/usb/dvb-usb-v2
|
||||
endif
|
||||
|
||||
stb0899-objs := stb0899_drv.o stb0899_algo.o
|
||||
stv0900-objs := stv0900_core.o stv0900_sw.o
|
||||
drxd-objs := drxd_firm.o drxd_hard.o
|
||||
cxd2820r-objs := cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
|
||||
drxk-objs := drxk_hard.o
|
||||
|
||||
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
|
||||
obj-$(CONFIG_DVB_STV0299) += stv0299.o
|
||||
obj-$(CONFIG_DVB_STB0899) += stb0899.o
|
||||
obj-$(CONFIG_DVB_STB6100) += stb6100.o
|
||||
obj-$(CONFIG_DVB_SP8870) += sp8870.o
|
||||
obj-$(CONFIG_DVB_CX22700) += cx22700.o
|
||||
obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
|
||||
obj-$(CONFIG_DVB_CX24110) += cx24110.o
|
||||
obj-$(CONFIG_DVB_TDA8083) += tda8083.o
|
||||
obj-$(CONFIG_DVB_L64781) += l64781.o
|
||||
obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
|
||||
obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_DIB9000) += dib9000.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_MT312) += mt312.o
|
||||
obj-$(CONFIG_DVB_VES1820) += ves1820.o
|
||||
obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
|
||||
obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
|
||||
obj-$(CONFIG_DVB_SP887X) += sp887x.o
|
||||
obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
|
||||
obj-$(CONFIG_DVB_MT352) += mt352.o
|
||||
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_DRXD) += drxd.o
|
||||
obj-$(CONFIG_DVB_TDA10021) += tda10021.o
|
||||
obj-$(CONFIG_DVB_TDA10023) += tda10023.o
|
||||
obj-$(CONFIG_DVB_STV0297) += stv0297.o
|
||||
obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
|
||||
obj-$(CONFIG_DVB_OR51211) += or51211.o
|
||||
obj-$(CONFIG_DVB_OR51132) += or51132.o
|
||||
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
|
||||
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
|
||||
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
|
||||
obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
|
||||
obj-$(CONFIG_DVB_LG2160) += lg2160.o
|
||||
obj-$(CONFIG_DVB_CX24123) += cx24123.o
|
||||
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
|
||||
obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
|
||||
obj-$(CONFIG_DVB_ISL6405) += isl6405.o
|
||||
obj-$(CONFIG_DVB_ISL6421) += isl6421.o
|
||||
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
|
||||
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
|
||||
obj-$(CONFIG_DVB_TDA8261) += tda8261.o
|
||||
obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
|
||||
obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o
|
||||
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
|
||||
obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
|
||||
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
|
||||
obj-$(CONFIG_DVB_AU8522) += au8522_common.o
|
||||
obj-$(CONFIG_DVB_AU8522_DTV) += au8522_dig.o
|
||||
obj-$(CONFIG_DVB_AU8522_V4L) += au8522_decoder.o
|
||||
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
|
||||
obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
|
||||
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
|
||||
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
|
||||
obj-$(CONFIG_DVB_TDA665x) += tda665x.o
|
||||
obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
|
||||
obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
|
||||
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
|
||||
obj-$(CONFIG_DVB_AF9013) += af9013.o
|
||||
obj-$(CONFIG_DVB_CX24116) += cx24116.o
|
||||
obj-$(CONFIG_DVB_CX24117) += cx24117.o
|
||||
obj-$(CONFIG_DVB_SI21XX) += si21xx.o
|
||||
obj-$(CONFIG_DVB_SI2168) += si2168.o
|
||||
obj-$(CONFIG_DVB_STV0288) += stv0288.o
|
||||
obj-$(CONFIG_DVB_STB6000) += stb6000.o
|
||||
obj-$(CONFIG_DVB_S921) += s921.o
|
||||
obj-$(CONFIG_DVB_STV6110) += stv6110.o
|
||||
obj-$(CONFIG_DVB_STV0900) += stv0900.o
|
||||
obj-$(CONFIG_DVB_STV090x) += stv090x.o
|
||||
obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
|
||||
obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
|
||||
obj-$(CONFIG_DVB_ISL6423) += isl6423.o
|
||||
obj-$(CONFIG_DVB_EC100) += ec100.o
|
||||
obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
|
||||
obj-$(CONFIG_DVB_DS3000) += ds3000.o
|
||||
obj-$(CONFIG_DVB_TS2020) += ts2020.o
|
||||
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
|
||||
obj-$(CONFIG_DVB_DRX39XYJ) += drx39xyj/
|
||||
obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
|
||||
obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
|
||||
obj-$(CONFIG_DVB_STV0367) += stv0367.o
|
||||
obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
|
||||
obj-$(CONFIG_DVB_DRXK) += drxk.o
|
||||
obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
|
||||
obj-$(CONFIG_DVB_SI2165) += si2165.o
|
||||
obj-$(CONFIG_DVB_A8293) += a8293.o
|
||||
obj-$(CONFIG_DVB_TDA10071) += tda10071.o
|
||||
obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
|
||||
obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
|
||||
obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o
|
||||
obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
|
||||
obj-$(CONFIG_DVB_AF9033) += af9033.o
|
||||
obj-$(CONFIG_DVB_STV0367DD) += stv0367dd.o
|
||||
obj-$(CONFIG_DVB_TDA18212DD) += tda18212dd.o
|
||||
obj-$(CONFIG_DVB_CXD2099) += cxd2099.o
|
||||
obj-$(CONFIG_DVB_CXD2843) += cxd2843.o
|
||||
obj-$(CONFIG_DVB_STV6111) += stv6111.o
|
||||
obj-$(CONFIG_DVB_STV0910) += stv0910.o
|
||||
obj-$(CONFIG_DVB_LNBH25) += lnbh25.o
|
||||
obj-$(CONFIG_DVB_MXL5XX) += mxl5xx.o
|
||||
@@ -22,12 +22,9 @@
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -36,7 +33,9 @@
|
||||
|
||||
#include "cxd2099.h"
|
||||
|
||||
//#define BUFFER_MODE 1
|
||||
static int buffermode;
|
||||
module_param(buffermode, int, 0444);
|
||||
MODULE_PARM_DESC(buffermode, "Enable use of the CXD2099AR buffer mode (default: disabled)");
|
||||
|
||||
static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount);
|
||||
|
||||
@@ -73,8 +72,9 @@ static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
|
||||
struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2};
|
||||
|
||||
if (i2c_transfer(adapter, &msg, 1) != 1) {
|
||||
pr_err("Failed to write to I2C register %02x@%02x!\n",
|
||||
reg, adr);
|
||||
dev_err(&adapter->dev,
|
||||
"Failed to write to I2C register %02x@%02x!\n",
|
||||
reg, adr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -86,7 +86,7 @@ static int i2c_write(struct i2c_adapter *adapter, u8 adr,
|
||||
struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len};
|
||||
|
||||
if (i2c_transfer(adapter, &msg, 1) != 1) {
|
||||
pr_err("Failed to write to I2C!\n");
|
||||
dev_err(&adapter->dev, "Failed to write to I2C!\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -101,7 +101,7 @@ static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
|
||||
.buf = val, .len = 1} };
|
||||
|
||||
if (i2c_transfer(adapter, msgs, 2) != 2) {
|
||||
pr_err("error in i2c_read_reg\n");
|
||||
dev_err(&adapter->dev, "error in i2c_read_reg\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -114,9 +114,9 @@ static int i2c_read(struct i2c_adapter *adapter, u8 adr,
|
||||
.buf = ®, .len = 1},
|
||||
{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = data, .len = n} };
|
||||
|
||||
|
||||
if (i2c_transfer(adapter, msgs, 2) != 2) {
|
||||
pr_err("error in i2c_read\n");
|
||||
dev_err(&adapter->dev, "error in i2c_read\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -133,9 +133,8 @@ static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
|
||||
|
||||
while (n) {
|
||||
int len = n;
|
||||
|
||||
if (ci->cfg.max_i2c &&
|
||||
len > ci->cfg.max_i2c)
|
||||
|
||||
if (ci->cfg.max_i2c && (len > ci->cfg.max_i2c))
|
||||
len = ci->cfg.max_i2c;
|
||||
status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, len);
|
||||
if (status)
|
||||
@@ -152,7 +151,6 @@ static int read_reg(struct cxd *ci, u8 reg, u8 *val)
|
||||
return read_block(ci, reg, val, 1);
|
||||
}
|
||||
|
||||
|
||||
static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
|
||||
{
|
||||
int status;
|
||||
@@ -174,7 +172,7 @@ static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
|
||||
u8 buf[256] = {3};
|
||||
|
||||
memcpy(buf + 1, data, n);
|
||||
status = i2c_write(ci->i2c, ci->cfg.adr, buf, n+1);
|
||||
status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -253,7 +251,6 @@ static int write_reg(struct cxd *ci, u8 reg, u8 val)
|
||||
return write_regm(ci, reg, val, 0xff);
|
||||
}
|
||||
|
||||
#ifdef BUFFER_MODE
|
||||
static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
|
||||
{
|
||||
int status = 0;
|
||||
@@ -263,17 +260,14 @@ static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
|
||||
status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
|
||||
if (status)
|
||||
return status;
|
||||
printk("write_block %d\n", n);
|
||||
|
||||
ci->lastaddress = adr;
|
||||
buf[0] = 1;
|
||||
while (n) {
|
||||
int len = n;
|
||||
|
||||
if (ci->cfg.max_i2c &&
|
||||
len + 1 > ci->cfg.max_i2c)
|
||||
|
||||
if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c))
|
||||
len = ci->cfg.max_i2c - 1;
|
||||
printk("write %d\n", len);
|
||||
memcpy(buf + 1, data, len);
|
||||
status = i2c_write(ci->i2c, ci->cfg.adr, buf, len + 1);
|
||||
if (status)
|
||||
@@ -283,7 +277,6 @@ static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
|
||||
}
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void set_mode(struct cxd *ci, int mode)
|
||||
{
|
||||
@@ -318,7 +311,7 @@ static void cam_mode(struct cxd *ci, int mode)
|
||||
if (!ci->en.read_data)
|
||||
return;
|
||||
ci->write_busy = 0;
|
||||
pr_info("enable cam buffer mode\n");
|
||||
dev_info(&ci->i2c->dev, "enable cam buffer mode\n");
|
||||
write_reg(ci, 0x0d, 0x00);
|
||||
write_reg(ci, 0x0e, 0x01);
|
||||
write_regm(ci, 0x08, 0x40, 0x40);
|
||||
@@ -331,8 +324,6 @@ static void cam_mode(struct cxd *ci, int mode)
|
||||
ci->cammode = mode;
|
||||
}
|
||||
|
||||
#define CHK_ERROR(s) if ((status = s)) break
|
||||
|
||||
static int init(struct cxd *ci)
|
||||
{
|
||||
int status;
|
||||
@@ -340,67 +331,140 @@ static int init(struct cxd *ci)
|
||||
mutex_lock(&ci->lock);
|
||||
ci->mode = -1;
|
||||
do {
|
||||
CHK_ERROR(write_reg(ci, 0x00, 0x00));
|
||||
CHK_ERROR(write_reg(ci, 0x01, 0x00));
|
||||
CHK_ERROR(write_reg(ci, 0x02, 0x10));
|
||||
CHK_ERROR(write_reg(ci, 0x03, 0x00));
|
||||
CHK_ERROR(write_reg(ci, 0x05, 0xFF));
|
||||
CHK_ERROR(write_reg(ci, 0x06, 0x1F));
|
||||
CHK_ERROR(write_reg(ci, 0x07, 0x1F));
|
||||
CHK_ERROR(write_reg(ci, 0x08, 0x28));
|
||||
CHK_ERROR(write_reg(ci, 0x14, 0x20));
|
||||
status = write_reg(ci, 0x00, 0x00);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x01, 0x00);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x02, 0x10);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x03, 0x00);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x05, 0xFF);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x06, 0x1F);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x07, 0x1F);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x08, 0x28);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x14, 0x20);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
/* TOSTRT = 8, Mode B (gated clock), falling Edge,
|
||||
Serial, POL=HIGH, MSB */
|
||||
CHK_ERROR(write_reg(ci, 0x0A, 0xA7));
|
||||
* Serial, POL=HIGH, MSB
|
||||
*/
|
||||
status = write_reg(ci, 0x0A, 0xA7);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
CHK_ERROR(write_reg(ci, 0x0B, 0x33));
|
||||
CHK_ERROR(write_reg(ci, 0x0C, 0x33));
|
||||
status = write_reg(ci, 0x0B, 0x33);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x0C, 0x33);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
CHK_ERROR(write_regm(ci, 0x14, 0x00, 0x0F));
|
||||
CHK_ERROR(write_reg(ci, 0x15, ci->clk_reg_b));
|
||||
CHK_ERROR(write_regm(ci, 0x16, 0x00, 0x0F));
|
||||
CHK_ERROR(write_reg(ci, 0x17, ci->clk_reg_f));
|
||||
status = write_regm(ci, 0x14, 0x00, 0x0F);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x15, ci->clk_reg_b);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_regm(ci, 0x16, 0x00, 0x0F);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x17, ci->clk_reg_f);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
if (ci->cfg.clock_mode == 2) {
|
||||
/* bitrate*2^13/ 72000 */
|
||||
u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000;
|
||||
|
||||
|
||||
if (ci->cfg.polarity) {
|
||||
CHK_ERROR(write_reg(ci, 0x09, 0x6f));
|
||||
status = write_reg(ci, 0x09, 0x6f);
|
||||
if (status < 0)
|
||||
break;
|
||||
} else {
|
||||
CHK_ERROR(write_reg(ci, 0x09, 0x6d));
|
||||
status = write_reg(ci, 0x09, 0x6d);
|
||||
if (status < 0)
|
||||
break;
|
||||
}
|
||||
CHK_ERROR(write_reg(ci, 0x20, 0x08));
|
||||
CHK_ERROR(write_reg(ci, 0x21, (reg >> 8) & 0xff));
|
||||
CHK_ERROR(write_reg(ci, 0x22, reg & 0xff));
|
||||
status = write_reg(ci, 0x20, 0x08);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x21, (reg >> 8) & 0xff);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x22, reg & 0xff);
|
||||
if (status < 0)
|
||||
break;
|
||||
} else if (ci->cfg.clock_mode == 1) {
|
||||
if (ci->cfg.polarity) {
|
||||
CHK_ERROR(write_reg(ci, 0x09, 0x6f)); /* D */
|
||||
status = write_reg(ci, 0x09, 0x6f); /* D */
|
||||
if (status < 0)
|
||||
break;
|
||||
} else {
|
||||
CHK_ERROR(write_reg(ci, 0x09, 0x6d));
|
||||
status = write_reg(ci, 0x09, 0x6d);
|
||||
if (status < 0)
|
||||
break;
|
||||
}
|
||||
CHK_ERROR(write_reg(ci, 0x20, 0x68));
|
||||
CHK_ERROR(write_reg(ci, 0x21, 0x00));
|
||||
CHK_ERROR(write_reg(ci, 0x22, 0x02));
|
||||
status = write_reg(ci, 0x20, 0x68);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x21, 0x00);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x22, 0x02);
|
||||
if (status < 0)
|
||||
break;
|
||||
} else {
|
||||
if (ci->cfg.polarity) {
|
||||
CHK_ERROR(write_reg(ci, 0x09, 0x4f)); /* C */
|
||||
status = write_reg(ci, 0x09, 0x4f); /* C */
|
||||
if (status < 0)
|
||||
break;
|
||||
} else {
|
||||
CHK_ERROR(write_reg(ci, 0x09, 0x4d));
|
||||
status = write_reg(ci, 0x09, 0x4d);
|
||||
if (status < 0)
|
||||
break;
|
||||
}
|
||||
CHK_ERROR(write_reg(ci, 0x20, 0x28));
|
||||
CHK_ERROR(write_reg(ci, 0x21, 0x00));
|
||||
CHK_ERROR(write_reg(ci, 0x22, 0x07));
|
||||
status = write_reg(ci, 0x20, 0x28);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x21, 0x00);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x22, 0x07);
|
||||
if (status < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
CHK_ERROR(write_regm(ci, 0x20, 0x80, 0x80));
|
||||
CHK_ERROR(write_regm(ci, 0x03, 0x02, 0x02));
|
||||
CHK_ERROR(write_reg(ci, 0x01, 0x04));
|
||||
CHK_ERROR(write_reg(ci, 0x00, 0x31));
|
||||
status = write_regm(ci, 0x20, 0x80, 0x80);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_regm(ci, 0x03, 0x02, 0x02);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x01, 0x04);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x00, 0x31);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
/* Put TS in bypass */
|
||||
CHK_ERROR(write_regm(ci, 0x09, 0x08, 0x08));
|
||||
status = write_regm(ci, 0x09, 0x08, 0x08);
|
||||
if (status < 0)
|
||||
break;
|
||||
ci->cammode = -1;
|
||||
cam_mode(ci, 0);
|
||||
} while (0);
|
||||
@@ -504,14 +568,16 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
|
||||
ci->ready = 0;
|
||||
#endif
|
||||
#endif
|
||||
ci->ready = 0;
|
||||
ci->mode = -1;
|
||||
{
|
||||
int i;
|
||||
#if 0
|
||||
u8 val;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
msleep(20);
|
||||
usleep_range(10000, 11000);
|
||||
#if 0
|
||||
read_reg(ci, 0x06, &val);
|
||||
pr_info(KERN_INFO "%d:%02x\n", i, val);
|
||||
@@ -524,7 +590,10 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ci->lock);
|
||||
/* msleep(500); */
|
||||
|
||||
/* Ensure cam stability after reset */
|
||||
msleep(2000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -532,7 +601,7 @@ static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
|
||||
pr_info("slot_shutdown\n");
|
||||
dev_info(&ci->i2c->dev, "%s\n", __func__);
|
||||
if (ci->cammode)
|
||||
read_data(ca, slot, ci->rbuf, 0);
|
||||
mutex_lock(&ci->lock);
|
||||
@@ -562,7 +631,6 @@ static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int campoll(struct cxd *ci)
|
||||
{
|
||||
u8 istat;
|
||||
@@ -576,6 +644,7 @@ static int campoll(struct cxd *ci)
|
||||
ci->dr = 1;
|
||||
if (istat & 0x20)
|
||||
ci->write_busy = 0;
|
||||
|
||||
if (istat & 2) {
|
||||
u8 slotstat;
|
||||
|
||||
@@ -583,7 +652,7 @@ static int campoll(struct cxd *ci)
|
||||
if (!(2 & slotstat)) {
|
||||
if (!ci->slot_stat) {
|
||||
ci->slot_stat |=
|
||||
DVB_CA_EN50221_POLL_CAM_PRESENT;
|
||||
DVB_CA_EN50221_POLL_CAM_PRESENT;
|
||||
write_regm(ci, 0x03, 0x08, 0x08);
|
||||
}
|
||||
|
||||
@@ -591,7 +660,7 @@ static int campoll(struct cxd *ci)
|
||||
if (ci->slot_stat) {
|
||||
ci->slot_stat = 0;
|
||||
write_regm(ci, 0x03, 0x00, 0x08);
|
||||
pr_info("NO CAM\n");
|
||||
dev_info(&ci->i2c->dev, "NO CAM\n");
|
||||
ci->ready = 0;
|
||||
}
|
||||
}
|
||||
@@ -604,7 +673,6 @@ static int campoll(struct cxd *ci)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
@@ -634,7 +702,7 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
|
||||
mutex_lock(&ci->lock);
|
||||
read_reg(ci, 0x0f, &msb);
|
||||
read_reg(ci, 0x10, &lsb);
|
||||
len = ((u16) msb << 8) | lsb;
|
||||
len = ((u16)msb << 8) | lsb;
|
||||
if (len > ecount || len < 2) {
|
||||
/* read it anyway or cxd may hang */
|
||||
read_block(ci, 0x12, ci->rbuf, len);
|
||||
@@ -644,21 +712,9 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
|
||||
read_block(ci, 0x12, ebuf, len);
|
||||
ci->dr = 0;
|
||||
mutex_unlock(&ci->lock);
|
||||
#if 0
|
||||
pr_info("read_data %d\n", len);
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
pr_info("%02x ", ebuf[i]);
|
||||
pr_info("\n");
|
||||
}
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef BUFFER_MODE
|
||||
|
||||
static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
@@ -673,7 +729,6 @@ static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
|
||||
mutex_unlock(&ci->lock);
|
||||
return ecount;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct dvb_ca_en50221 en_templ = {
|
||||
.read_attribute_mem = read_attribute_mem,
|
||||
@@ -684,43 +739,49 @@ static struct dvb_ca_en50221 en_templ = {
|
||||
.slot_shutdown = slot_shutdown,
|
||||
.slot_ts_enable = slot_ts_enable,
|
||||
.poll_slot_status = poll_slot_status,
|
||||
#ifdef BUFFER_MODE
|
||||
.read_data = read_data,
|
||||
.write_data = write_data,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
|
||||
void *priv,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct cxd *ci = 0;
|
||||
struct cxd *ci;
|
||||
u8 val;
|
||||
|
||||
if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) {
|
||||
pr_info("No CXD2099 detected at %02x\n", cfg->adr);
|
||||
return 0;
|
||||
dev_info(&i2c->dev, "No CXD2099 detected at %02x\n", cfg->adr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ci = kzalloc(sizeof(struct cxd), GFP_KERNEL);
|
||||
ci = kzalloc(sizeof(*ci), GFP_KERNEL);
|
||||
if (!ci)
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
mutex_init(&ci->lock);
|
||||
memcpy(&ci->cfg, cfg, sizeof(struct cxd2099_cfg));
|
||||
ci->cfg = *cfg;
|
||||
ci->i2c = i2c;
|
||||
ci->lastaddress = 0xff;
|
||||
ci->clk_reg_b = 0x4a;
|
||||
ci->clk_reg_f = 0x1b;
|
||||
|
||||
memcpy(&ci->en, &en_templ, sizeof(en_templ));
|
||||
ci->en = en_templ;
|
||||
ci->en.data = ci;
|
||||
init(ci);
|
||||
pr_info("Attached CXD2099AR at %02x\n", ci->cfg.adr);
|
||||
dev_info(&i2c->dev, "Attached CXD2099AR at %02x\n", ci->cfg.adr);
|
||||
|
||||
if (!buffermode) {
|
||||
ci->en.read_data = NULL;
|
||||
ci->en.write_data = NULL;
|
||||
} else {
|
||||
dev_info(&i2c->dev, "Using CXD2099AR buffer mode");
|
||||
}
|
||||
|
||||
return &ci->en;
|
||||
}
|
||||
EXPORT_SYMBOL(cxd2099_attach);
|
||||
|
||||
MODULE_DESCRIPTION("cxd2099");
|
||||
MODULE_AUTHOR("Ralph Metzler");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -36,8 +36,18 @@ struct cxd2099_cfg {
|
||||
u32 max_i2c;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_CXD2099) || \
|
||||
(defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE))
|
||||
struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
|
||||
void *priv, struct i2c_adapter *i2c);
|
||||
#else
|
||||
|
||||
static inline struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
|
||||
void *priv, struct i2c_adapter *i2c)
|
||||
{
|
||||
dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -96,7 +96,7 @@ static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
|
||||
struct i2c_msg msg = {
|
||||
.addr = adr, .flags = 0, .buf = data, .len = len};
|
||||
if (i2c_transfer(adap, &msg, 1) != 1) {
|
||||
pr_err("cxd2843: i2c_write error\n");
|
||||
pr_err("cxd2843: i2c_write error adr %02x data %02x\n", adr, data[0]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -270,9 +270,10 @@ static int writebitsx(struct cxd_state *cxd, u8 Bank, u8 Address,
|
||||
mutex_lock(&cxd->mutex);
|
||||
status = readregsx_unlocked(cxd, Bank, Address, &tmp, 1);
|
||||
if (status < 0)
|
||||
return status;
|
||||
goto out;
|
||||
tmp = (tmp & ~Mask) | Value;
|
||||
status = writeregsx_unlocked(cxd, Bank, Address, &tmp, 1);
|
||||
out:
|
||||
mutex_unlock(&cxd->mutex);
|
||||
return status;
|
||||
}
|
||||
@@ -286,9 +287,10 @@ static int writebitst(struct cxd_state *cxd, u8 Bank, u8 Address,
|
||||
mutex_lock(&cxd->mutex);
|
||||
status = readregst_unlocked(cxd, Bank, Address, &Tmp, 1);
|
||||
if (status < 0)
|
||||
return status;
|
||||
goto out;
|
||||
Tmp = (Tmp & ~Mask) | Value;
|
||||
status = writeregst_unlocked(cxd, Bank, Address, &Tmp, 1);
|
||||
out:
|
||||
mutex_unlock(&cxd->mutex);
|
||||
return status;
|
||||
}
|
||||
@@ -508,8 +510,12 @@ static void ActiveC2_to_Sleep(struct cxd_state *state)
|
||||
writebitst(state, 0x2B, 0x2B, 0x00, 0x1F);
|
||||
{
|
||||
u8 data[2] = { 0x75, 0x75 };
|
||||
u8 data24[2] = { 0x89, 0x89 };
|
||||
|
||||
writeregst(state, 0x2D, 0x24, data, sizeof(data));
|
||||
if (state->is24MHz)
|
||||
writeregst(state, 0x2D, 0x24, data24, sizeof(data24));
|
||||
else
|
||||
writeregst(state, 0x2D, 0x24, data, sizeof(data));
|
||||
}
|
||||
|
||||
writeregx(state, 0x00, 0x18, 0x01); /* Disable ADC 4 */
|
||||
@@ -554,62 +560,115 @@ static int ConfigureTS(struct cxd_state *state,
|
||||
return status;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int set_tr(struct cxd_state *state, u32 bw, u32 osc24)
|
||||
{
|
||||
u64 tr = 7 *(osc24 ? 0x1800000000 : 0x1480000000);
|
||||
|
||||
div64_32(tr, bw);
|
||||
printk("TR %016llx\n", tr);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void BandSettingT(struct cxd_state *state, u32 iffreq)
|
||||
{
|
||||
u8 IF_data[3] = { (iffreq >> 16) & 0xff,
|
||||
(iffreq >> 8) & 0xff, iffreq & 0xff};
|
||||
u8 data[] = { 0x01, 0x14 };
|
||||
|
||||
writeregst(state, 0x13, 0x9c, data, sizeof(data));
|
||||
switch (state->bw) {
|
||||
default:
|
||||
case 8:
|
||||
{
|
||||
u8 TR_data[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 };
|
||||
u8 CL_data[] = { 0x01, 0xE0 };
|
||||
u8 NF_data[] = { 0x01, 0x02 };
|
||||
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x15, 0x00, 0x00, 0x00, 0x00 };
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 };
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
writebitst(state, 0x10, 0xD7, 0x00, 0x07);
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
if (state->is24MHz) {
|
||||
u8 CL_data[] = { 0x15, 0x28 };
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
} else {
|
||||
u8 CL_data[] = { 0x01, 0xE0 };
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
}
|
||||
writeregst(state, 0x17, 0x38, NF_data, sizeof(NF_data));
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
u8 TR_data[] = { 0x14, 0x80, 0x00, 0x00, 0x00 };
|
||||
u8 CL_data[] = { 0x12, 0xF8 };
|
||||
u8 NF_data[] = { 0x00, 0x03 };
|
||||
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x18, 0x00, 0x00, 0x00, 0x00 };
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x14, 0x80, 0x00, 0x00, 0x00 };
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
writebitst(state, 0x10, 0xD7, 0x02, 0x07);
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
if (state->is24MHz) {
|
||||
u8 CL_data[] = { 0x1f, 0xf8 };
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
} else {
|
||||
u8 CL_data[] = { 0x12, 0xF8 };
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
}
|
||||
writeregst(state, 0x17, 0x38, NF_data, sizeof(NF_data));
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
u8 TR_data[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA };
|
||||
u8 CL_data[] = { 0x1F, 0xDC };
|
||||
u8 NF_data[] = { 0x00, 0x03 };
|
||||
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x1c, 0x00, 0x00, 0x00, 0x00 };
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA };
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
writebitst(state, 0x10, 0xD7, 0x04, 0x07);
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
if (state->is24MHz) {
|
||||
u8 CL_data[] = { 0x25, 0x4c };
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
} else {
|
||||
u8 CL_data[] = { 0x1F, 0xDC };
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
}
|
||||
writeregst(state, 0x17, 0x38, NF_data, sizeof(NF_data));
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
static u8 TR_data[] = { 0x1C, 0xB3, 0x33, 0x33, 0x33 };
|
||||
static u8 CL_data[] = { 0x26, 0x3C };
|
||||
static u8 NF_data[] = { 0x00, 0x03 };
|
||||
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x21, 0x99, 0x99, 0x99, 0x99 };
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
static u8 TR_data[] = { 0x1C, 0xB3, 0x33, 0x33, 0x33 };
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
writebitst(state, 0x10, 0xD7, 0x06, 0x07);
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
if (state->is24MHz) {
|
||||
static u8 CL_data[] = { 0x2c, 0xc2 };
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
} else {
|
||||
static u8 CL_data[] = { 0x26, 0x3C };
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
}
|
||||
writeregst(state, 0x17, 0x38, NF_data, sizeof(NF_data));
|
||||
break;
|
||||
}
|
||||
@@ -626,7 +685,7 @@ static void Sleep_to_ActiveT(struct cxd_state *state, u32 iffreq)
|
||||
writeregt(state, 0x00, 0x30, 0x00); /* Enable ADC Clock */
|
||||
writeregt(state, 0x00, 0x41, 0x1A); /* Enable ADC1 */
|
||||
{
|
||||
u8 data[2] = { 0x09, 0x54 }; /* 20.5 MHz */
|
||||
u8 data[2] = { 0x09, 0x54 }; /* 20.5/24 MHz */
|
||||
/*u8 data[2] = { 0x0A, 0xD4 }; */ /* 41 MHz */
|
||||
|
||||
writeregst(state, 0x00, 0x43, data, 2); /* Enable ADC 2+3 */
|
||||
@@ -634,7 +693,7 @@ static void Sleep_to_ActiveT(struct cxd_state *state, u32 iffreq)
|
||||
writeregx(state, 0x00, 0x18, 0x00); /* Enable ADC 4 */
|
||||
|
||||
writebitst(state, 0x10, 0xD2, 0x0C, 0x1F); /* IF AGC Gain */
|
||||
writeregt(state, 0x11, 0x6A, 0x48); /* BB AGC Target Level */
|
||||
writeregt(state, 0x11, 0x6A, 0x50); /* BB AGC Target Level */
|
||||
|
||||
writebitst(state, 0x10, 0xA5, 0x00, 0x01); /* ASCOT Off */
|
||||
|
||||
@@ -645,6 +704,13 @@ static void Sleep_to_ActiveT(struct cxd_state *state, u32 iffreq)
|
||||
writebitst(state, 0x00, 0xCE, 0x01, 0x01); /* TSIF ONOPARITY */
|
||||
writebitst(state, 0x00, 0xCF, 0x01, 0x01);/*TSIF ONOPARITY_MANUAL_ON*/
|
||||
|
||||
if (state->is24MHz) {
|
||||
u8 data[3] = { 0xdc, 0x6c, 0x00 };
|
||||
|
||||
writeregt(state, 0x10, 0xbf, 0x60);
|
||||
writeregst(state, 0x18, 0x24, data, 3);
|
||||
}
|
||||
|
||||
BandSettingT(state, iffreq);
|
||||
|
||||
writebitst(state, 0x10, 0x60, 0x11, 0x1f); /* BER scaling */
|
||||
@@ -662,10 +728,16 @@ static void BandSettingT2(struct cxd_state *state, u32 iffreq)
|
||||
default:
|
||||
case 8:
|
||||
{
|
||||
u8 TR_data[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 };
|
||||
|
||||
/* Timing recovery */
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x15, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 };
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
/* Add EQ Optimisation for tuner here */
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
/* System Bandwidth */
|
||||
@@ -674,36 +746,60 @@ static void BandSettingT2(struct cxd_state *state, u32 iffreq)
|
||||
break;
|
||||
case 7:
|
||||
{
|
||||
u8 TR_data[] = { 0x14, 0x80, 0x00, 0x00, 0x00 };
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x18, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x14, 0x80, 0x00, 0x00, 0x00 };
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
writebitst(state, 0x10, 0xD7, 0x02, 0x07);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
u8 TR_data[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA };
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x1c, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA };
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
writebitst(state, 0x10, 0xD7, 0x04, 0x07);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
u8 TR_data[] = { 0x1C, 0xB3, 0x33, 0x33, 0x33 };
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x21, 0x99, 0x99, 0x99, 0x99 };
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x1C, 0xB3, 0x33, 0x33, 0x33 };
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
writebitst(state, 0x10, 0xD7, 0x06, 0x07);
|
||||
}
|
||||
break;
|
||||
case 2: /* 1.7 MHz */
|
||||
{
|
||||
u8 TR_data[] = { 0x58, 0xE2, 0xAF, 0xE0, 0xBC };
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x68, 0x0f, 0xa2, 0x32, 0xd0 };
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x58, 0xE2, 0xAF, 0xE0, 0xBC };
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
writebitst(state, 0x10, 0xD7, 0x03, 0x07);
|
||||
}
|
||||
@@ -724,7 +820,7 @@ static void Sleep_to_ActiveT2(struct cxd_state *state, u32 iffreq)
|
||||
writeregt(state, 0x00, 0x41, 0x1A); /* Enable ADC1 */
|
||||
|
||||
{
|
||||
u8 data[2] = { 0x09, 0x54 }; /* 20.5 MHz */
|
||||
u8 data[2] = { 0x09, 0x54 }; /* 20.5/24 MHz */
|
||||
/*u8 data[2] = { 0x0A, 0xD4 }; */ /* 41 MHz */
|
||||
|
||||
writeregst(state, 0x00, 0x43, data, 2); /* Enable ADC 2+3 */
|
||||
@@ -737,6 +833,7 @@ static void Sleep_to_ActiveT2(struct cxd_state *state, u32 iffreq)
|
||||
|
||||
writeregt(state, 0x20, 0x8B, 0x3C); /* SNR Good count */
|
||||
writebitst(state, 0x2B, 0x76, 0x20, 0x70); /* Noise Gain ACQ */
|
||||
writebitst(state, 0x23, 0xe6, 0x00, 0x03);
|
||||
|
||||
writebitst(state, 0x00, 0xCE, 0x01, 0x01); /* TSIF ONOPARITY */
|
||||
writebitst(state, 0x00, 0xCF, 0x01, 0x01);/*TSIF ONOPARITY_MANUAL_ON*/
|
||||
@@ -745,7 +842,34 @@ static void Sleep_to_ActiveT2(struct cxd_state *state, u32 iffreq)
|
||||
writeregt(state, 0x13, 0x86, 0x34);
|
||||
writebitst(state, 0x13, 0x9E, 0x09, 0x0F);
|
||||
writeregt(state, 0x13, 0x9F, 0xD8);
|
||||
writebitst(state, 0x23, 0x11, 0x20, 0x3F);
|
||||
|
||||
|
||||
if (state->is24MHz ) {
|
||||
static u8 data1[] = { 0xEB, 0x03, 0x3B };
|
||||
static u8 data2[] = { 0x5E, 0x5E, 0x47 };
|
||||
static u8 data3[] = { 0x3F, 0xFF };
|
||||
static u8 data4[] = { 0x0B, 0x72 };
|
||||
static u8 data5[] = { 0x93, 0xF3, 0x00 };
|
||||
static u8 data6[] = { 0x05, 0xB8, 0xD8 };
|
||||
static u8 data7[] = { 0x89, 0x89 };
|
||||
static u8 data8[] = { 0x24, 0x95 };
|
||||
|
||||
writeregst(state, 0x11, 0x33, data1, sizeof(data1));
|
||||
writeregst(state, 0x20, 0x95, data2, sizeof(data2));
|
||||
writeregt(state, 0x20, 0x99, 0x18);
|
||||
writeregst(state, 0x20, 0xD9, data3, sizeof(data3));
|
||||
writeregst(state, 0x24, 0x34, data4, sizeof(data4));
|
||||
writeregst(state, 0x24, 0xD2, data5, sizeof(data5));
|
||||
writeregst(state, 0x24, 0xDD, data6, sizeof(data6));
|
||||
writeregt(state, 0x24, 0xE0, 0x00);
|
||||
writeregt(state, 0x25, 0xED, 0x60);
|
||||
writeregt(state, 0x27, 0xFA, 0x34);
|
||||
writeregt(state, 0x2B, 0x4B, 0x2F);
|
||||
writeregt(state, 0x2B, 0x9E, 0x0E);
|
||||
writeregst(state, 0x2D, 0x24, data7, sizeof(data7));
|
||||
writeregst(state, 0x5E, 0x8C, data8, sizeof(data8));
|
||||
}
|
||||
BandSettingT2(state, iffreq);
|
||||
|
||||
writebitst(state, 0x20, 0x72, 0x08, 0x0f); /* BER scaling */
|
||||
@@ -777,7 +901,7 @@ static void Sleep_to_ActiveC(struct cxd_state *state, u32 iffreq)
|
||||
writeregt(state, 0x00, 0x41, 0x1A); /* Enable ADC1 */
|
||||
|
||||
{
|
||||
u8 data[2] = { 0x09, 0x54 }; /* 20.5 MHz */
|
||||
u8 data[2] = { 0x09, 0x54 }; /* 20.5/24 MHz */
|
||||
/*u8 data[2] = { 0x0A, 0xD4 }; */ /* 41 MHz */
|
||||
|
||||
writeregst(state, 0x00, 0x43, data, 2); /* Enable ADC 2+3 */
|
||||
@@ -793,6 +917,18 @@ static void Sleep_to_ActiveC(struct cxd_state *state, u32 iffreq)
|
||||
writebitst(state, 0x00, 0xCE, 0x01, 0x01); /* TSIF ONOPARITY */
|
||||
writebitst(state, 0x00, 0xCF, 0x01, 0x01);/*TSIF ONOPARITY_MANUAL_ON*/
|
||||
|
||||
if (state->is24MHz) {
|
||||
u8 data1[2] = { 0x29, 0x09 };
|
||||
u8 data2[4] = { 0x08, 0x38, 0x83, 0x0E };
|
||||
u8 data3[3] = { 0xDC, 0x6C, 0x00 };
|
||||
u8 data4[2] = { 0x77, 0x00 };
|
||||
|
||||
writeregst(state,0x40,0x54,data1,2);
|
||||
writeregst(state,0x40,0x8b,data2,4);
|
||||
writeregt(state,0x40,0xBF,0x60);
|
||||
writeregst(state,0x48,0x24,data3,2);
|
||||
writeregst(state,0x49,0x11,data4,2);
|
||||
}
|
||||
BandSettingC(state, iffreq);
|
||||
|
||||
writebitst(state, 0x40, 0x60, 0x11, 0x1f); /* BER scaling */
|
||||
@@ -810,28 +946,57 @@ static void BandSettingC2(struct cxd_state *state, u32 iffreq)
|
||||
default:
|
||||
case 8:
|
||||
{
|
||||
u8 TR_data[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 };
|
||||
u8 data[2] = { 0x11, 0x9E };
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x15, 0x00, 0x00, 0x00, 0x00 };
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 };
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writebitst(state, 0x27, 0x7a, 0x00, 0x0f);
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
writebitst(state, 0x10, 0xD7, 0x00, 0x07);
|
||||
writeregst(state, 0x50, 0xEC, data, sizeof(data));
|
||||
writeregt(state, 0x50, 0xEF, 0x11);
|
||||
writeregt(state, 0x50, 0xF1, 0x9E);
|
||||
|
||||
if (state->is24MHz) {
|
||||
u8 data[2] = { 0x14, 0xa0 };
|
||||
|
||||
writeregst(state, 0x50, 0xEC, data, sizeof(data));
|
||||
writeregt(state, 0x50, 0xEF, 0x14);
|
||||
writeregt(state, 0x50, 0xF1, 0xa0);
|
||||
} else {
|
||||
u8 data[2] = { 0x11, 0x9E };
|
||||
|
||||
writeregst(state, 0x50, 0xEC, data, sizeof(data));
|
||||
writeregt(state, 0x50, 0xEF, 0x11);
|
||||
writeregt(state, 0x50, 0xF1, 0x9E);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
u8 TR_data[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA };
|
||||
u8 data[2] = { 0x17, 0x70 };
|
||||
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x1c, 0x00, 0x00, 0x00, 0x00 };
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA };
|
||||
writeregst(state, 0x20, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
writebitst(state, 0x10, 0xD7, 0x04, 0x07);
|
||||
writeregst(state, 0x50, 0xEC, data, sizeof(data));
|
||||
writeregt(state, 0x50, 0xEF, 0x17);
|
||||
writeregt(state, 0x50, 0xF1, 0x70);
|
||||
if (state->is24MHz) {
|
||||
u8 data[2] = { 0x1b, 0x70 };
|
||||
|
||||
writeregst(state, 0x50, 0xEC, data, sizeof(data));
|
||||
writeregt(state, 0x50, 0xEF, 0x1b);
|
||||
writeregt(state, 0x50, 0xF1, 0x70);
|
||||
} else {
|
||||
u8 data[2] = { 0x17, 0x70 };
|
||||
|
||||
writeregst(state, 0x50, 0xEC, data, sizeof(data));
|
||||
writeregt(state, 0x50, 0xEF, 0x17);
|
||||
writeregt(state, 0x50, 0xF1, 0x70);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -849,7 +1014,7 @@ static void Sleep_to_ActiveC2(struct cxd_state *state, u32 iffreq)
|
||||
writeregt(state, 0x00, 0x41, 0x1A); /* Enable ADC1 */
|
||||
|
||||
{
|
||||
u8 data[2] = { 0x09, 0x54 }; /* 20.5 MHz */
|
||||
u8 data[2] = { 0x09, 0x54 }; /* 20.5/24 MHz */
|
||||
/*u8 data[2] = { 0x0A, 0xD4 }; */ /* 41 MHz */
|
||||
|
||||
writeregst(state, 0x00, 0x43, data, sizeof(data));
|
||||
@@ -891,7 +1056,23 @@ static void Sleep_to_ActiveC2(struct cxd_state *state, u32 iffreq)
|
||||
|
||||
writeregst(state, 0x2D, 0x24, data, sizeof(data));
|
||||
}
|
||||
|
||||
if (state->is24MHz) {
|
||||
u8 data1[3] = { 0xEB, 0x03, 0x3B };
|
||||
u8 data2[2] = { 0x3F, 0xFF };
|
||||
u8 data3[2] = { 0x0B, 0x72 };
|
||||
u8 data4[3] = { 0x93, 0xF3, 0x00 };
|
||||
u8 data5[4] = { 0x05, 0xB8, 0xD8, 0x00 };
|
||||
u8 data6[9] = { 0x18, 0x1E, 0x71, 0x5D, 0xA9, 0x5D, 0xA9, 0x46, 0x3F };
|
||||
|
||||
writeregst(state,0x11,0x33,data1,sizeof(data1));
|
||||
writeregst(state,0x20,0xD9,data2,sizeof(data2));
|
||||
writeregst(state,0x24,0x34,data3,sizeof(data3));
|
||||
writeregst(state,0x24,0xD2,data4,sizeof(data4));
|
||||
writeregst(state,0x24,0xDD,data5,sizeof(data5));
|
||||
writeregt(state,0x25,0xED,0x60);
|
||||
writeregst(state,0x5E,0xDB,data6,sizeof(data6));
|
||||
}
|
||||
|
||||
BandSettingC2(state, iffreq);
|
||||
|
||||
writeregt(state, 0x00, 0x80, 0x28); /* Disable HiZ Setting 1 */
|
||||
@@ -908,34 +1089,51 @@ static void BandSettingIT(struct cxd_state *state, u32 iffreq)
|
||||
default:
|
||||
case 8:
|
||||
{
|
||||
u8 TR_data[] = { 0x0F, 0x22, 0x80, 0x00, 0x00 }; /* 20.5/41 */
|
||||
u8 CL_data[] = { 0x15, 0xA8 };
|
||||
|
||||
/*u8 TR_data[] = { 0x11, 0xB8, 0x00, 0x00, 0x00 }; */ /* 24 */
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x11, 0xb8, 0x00, 0x00, 0x00 }; /* 24 */
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x0F, 0x22, 0x80, 0x00, 0x00 }; /* 20.5/41 */
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
/* Add EQ Optimisation for tuner here */
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
|
||||
writebitst(state, 0x10, 0xD7, 0x00, 0x07); /* System Bandwidth */
|
||||
/*u8 CL_data[] = { 0x13, 0xFC }; */
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
if (state->is24MHz) {
|
||||
u8 CL_data[] = { 0x13, 0xfc };
|
||||
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
} else {
|
||||
u8 CL_data[] = { 0x15, 0xA8 };
|
||||
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
}
|
||||
writebitst(state, 0x12, 0x71, 0x03, 0x07);
|
||||
writeregt(state, 0x15, 0xbe, 0x03);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
{
|
||||
u8 TR_data[] = { 0x11, 0x4c, 0x00, 0x00, 0x00 };
|
||||
u8 CL_data[] = { 0x1B, 0x5D };
|
||||
|
||||
/*u8 TR_data[] = { 0x14, 0x40, 0x00, 0x00, 0x00 }; */
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x14, 0x40, 0x00, 0x00, 0x00 }; /* 24 */
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x11, 0x4c, 0x00, 0x00, 0x00 };
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
|
||||
writebitst(state, 0x10, 0xD7, 0x02, 0x07);
|
||||
/*static u8 CL_data[] = { 0x1A, 0xFA };*/
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
if (state->is24MHz) {
|
||||
u8 CL_data[] = { 0x1a, 0xfa };
|
||||
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
} else {
|
||||
u8 CL_data[] = { 0x1B, 0x5D };
|
||||
|
||||
writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));
|
||||
}
|
||||
|
||||
writebitst(state, 0x12, 0x71, 0x03, 0x07);
|
||||
writeregt(state, 0x15, 0xbe, 0x02);
|
||||
@@ -943,22 +1141,30 @@ static void BandSettingIT(struct cxd_state *state, u32 iffreq)
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
u8 TR_data[] = { 0x14, 0x2E, 0x00, 0x00, 0x00 };
|
||||
/*u8 TR_data[] = { 0x17, 0xA0, 0x00, 0x00, 0x00 }; */
|
||||
/*u8 CL_data[] = { 0x1F, 0x79 }; */
|
||||
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
if (state->is24MHz) {
|
||||
u8 TR_data[] = { 0x17, 0xa0, 0x00, 0x00, 0x00 }; /* 24 */
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
} else {
|
||||
u8 TR_data[] = { 0x14, 0x2E, 0x00, 0x00, 0x00 };
|
||||
writeregst(state, 0x10, 0x9F, TR_data, sizeof(TR_data));
|
||||
}
|
||||
writeregst(state, 0x10, 0xB6, IF_data, sizeof(IF_data));
|
||||
writebitst(state, 0x10, 0xD7, 0x04, 0x07);
|
||||
|
||||
if (state->is2k14) {
|
||||
u8 CL_data[] = { 0x1a, 0xe2 };
|
||||
|
||||
writeregst(state, 0x10, 0xDd9, CL_data, sizeof(CL_data));
|
||||
} else {
|
||||
u8 CL_data[] = { 0x1F, 0xec };
|
||||
if (state->is24MHz) {
|
||||
u8 CL_data[] = { 0x1f, 0x79 };
|
||||
|
||||
writeregst(state, 0x10, 0xd9, CL_data, sizeof(CL_data));
|
||||
} else {
|
||||
if (state->is2k14) {
|
||||
u8 CL_data[] = { 0x1a, 0xe2 };
|
||||
|
||||
writeregst(state, 0x10, 0xd9, CL_data, sizeof(CL_data));
|
||||
} else {
|
||||
u8 CL_data[] = { 0x1F, 0xec };
|
||||
|
||||
writeregst(state, 0x10, 0xd9, CL_data, sizeof(CL_data));
|
||||
}
|
||||
}
|
||||
writebitst(state, 0x12, 0x71, 0x07, 0x07);
|
||||
writeregt(state, 0x15, 0xbe, 0x02);
|
||||
@@ -969,12 +1175,6 @@ static void BandSettingIT(struct cxd_state *state, u32 iffreq)
|
||||
|
||||
static void Sleep_to_ActiveIT(struct cxd_state *state, u32 iffreq)
|
||||
{
|
||||
u8 data2[3] = { 0xB9, 0xBA, 0x63 }; /* 20.5/41 MHz */
|
||||
/*u8 data2[3] = { 0xB7,0x1B,0x00 }; */ /* 24 MHz */
|
||||
u8 TSIF_data[2] = { 0x61, 0x60 } ; /* 20.5/41 MHz */
|
||||
/*u8 TSIF_data[2] = { 0x60,0x00 } ; */ /* 24 MHz */
|
||||
|
||||
|
||||
ConfigureTS(state, ActiveIT);
|
||||
|
||||
/* writeregx(state, 0x00,0x17,0x01); */ /* 2838 has only one Mode */
|
||||
@@ -989,7 +1189,7 @@ static void Sleep_to_ActiveIT(struct cxd_state *state, u32 iffreq)
|
||||
writeregt(state, 0x00, 0x41, 0x1A); /* Enable ADC1 */
|
||||
|
||||
{
|
||||
u8 data[2] = { 0x09, 0x54 }; /* 20.5 MHz, 24 MHz */
|
||||
u8 data[2] = { 0x09, 0x54 }; /* 20.5 MHz/24 MHz */
|
||||
/*u8 data[2] = { 0x0A, 0xD4 }; */ /* 41 MHz */
|
||||
|
||||
writeregst(state, 0x00, 0x43, data, 2); /* Enable ADC 2+3 */
|
||||
@@ -998,6 +1198,9 @@ static void Sleep_to_ActiveIT(struct cxd_state *state, u32 iffreq)
|
||||
|
||||
|
||||
if (state->is2k14) {
|
||||
writebitst(state, 0x10, 0xd2, 0x0c, 0x1f);
|
||||
writeregt(state, 0x11, 0x6a, 0x50);
|
||||
|
||||
writebitst(state, 0x10, 0xA5, 0x00, 0x01); /* ASCOT Off */
|
||||
|
||||
writebitst(state, 0x18, 0x30, 0x01, 0x01);
|
||||
@@ -1018,16 +1221,19 @@ static void Sleep_to_ActiveIT(struct cxd_state *state, u32 iffreq)
|
||||
writebitst(state, 0x1e, 0x73, 0x68, 0xff);
|
||||
writebitst(state, 0x63, 0x81, 0x00, 0x01);
|
||||
}
|
||||
//if( m_is24MHz )
|
||||
//{
|
||||
// static BYTE TSIF_data[2] = { 0x60,0x00 } ; // 24 MHz
|
||||
// CHK_ERROR(WriteRegT(0x10,0xBF,TSIF_data,sizeof(TSIF_data)));
|
||||
// static BYTE data[3] = { 0xB7,0x1B,0x00 }; // 24 MHz
|
||||
// CHK_ERROR(WriteRegT(0x60,0xA8,data,sizeof(data)));
|
||||
//}
|
||||
//else
|
||||
writeregst(state, 0x10, 0xBF, TSIF_data, sizeof(TSIF_data));
|
||||
writeregst(state, 0x60, 0xa8, data2, sizeof(data2));
|
||||
if (state->is24MHz) {
|
||||
static u8 TSIF_data[2] = { 0x60,0x00 } ; // 24 MHz
|
||||
static u8 data[3] = { 0xB7,0x1B,0x00 }; // 24 MHz
|
||||
|
||||
writeregst(state, 0x10, 0xBF, TSIF_data, sizeof(TSIF_data));
|
||||
writeregst(state, 0x60, 0xA8, data, sizeof(data));
|
||||
} else {
|
||||
u8 TSIF_data[2] = { 0x61, 0x60 } ; /* 20.5/41 MHz */
|
||||
u8 data[3] = { 0xB9, 0xBA, 0x63 }; /* 20.5/41 MHz */
|
||||
|
||||
writeregst(state, 0x10, 0xBF, TSIF_data, sizeof(TSIF_data));
|
||||
writeregst(state, 0x60, 0xa8, data, sizeof(data));
|
||||
}
|
||||
|
||||
if (!state->is2k14) {
|
||||
writeregt(state, 0x10, 0xE2, 0xCE); /* OREG_PNC_DISABLE */
|
||||
@@ -1042,11 +1248,11 @@ static void Sleep_to_ActiveIT(struct cxd_state *state, u32 iffreq)
|
||||
static void T2_SetParameters(struct cxd_state *state)
|
||||
{
|
||||
u8 Profile = 0x01; /* Profile Base */
|
||||
u8 notT2time = 12; /* early unlock detection time */
|
||||
u8 notT2time = state->is24MHz ? 24 : 12; /* early unlock detection time */
|
||||
|
||||
if (state->T2Profile == T2P_Lite) {
|
||||
Profile = 0x05;
|
||||
notT2time = 40;
|
||||
notT2time = state->is24MHz ? 46 : 40;
|
||||
}
|
||||
|
||||
if (state->plp != 0xffffffff) {
|
||||
@@ -1182,7 +1388,7 @@ static int Start(struct cxd_state *state, u32 IntermediateFrequency)
|
||||
if (state->state < Sleep)
|
||||
return -EINVAL;
|
||||
|
||||
iffreq = MulDiv32(IntermediateFrequency, 16777216, 41000000);
|
||||
iffreq = MulDiv32(IntermediateFrequency, 16777216, state->is24MHz ? 48000000 : 41000000);
|
||||
|
||||
switch (state->omode) {
|
||||
case OM_DVBT:
|
||||
@@ -1368,9 +1574,16 @@ static void init(struct cxd_state *state)
|
||||
|
||||
writeregx(state, 0x00, 0x10, 0x01);
|
||||
|
||||
writeregsx(state, 0x00, 0x13, data, 2);
|
||||
writeregx(state, 0x00, 0x15, 0x00);
|
||||
usleep_range(3000, 4000);
|
||||
|
||||
writeregsx(state, 0x00, 0x13, data, 0);
|
||||
if (state->is24MHz)
|
||||
writeregx(state, 0x00, 0x12, 0x00);
|
||||
|
||||
writeregx(state, 0x00, 0x14, state->is24MHz ? 0x03 : 0x00);
|
||||
|
||||
|
||||
writeregx(state, 0x00, 0x10, 0x00);
|
||||
usleep_range(2000, 3000);
|
||||
|
||||
@@ -1382,6 +1595,12 @@ static void init(struct cxd_state *state)
|
||||
if (state->type == CXD2838)
|
||||
writeregt(state, 0x60, 0x5A, 0x00);
|
||||
|
||||
if (state->type == CXD2854) {
|
||||
writeregt(state, 0x00, 0x63, 0x16);
|
||||
writeregt(state, 0x00, 0x65, 0x27);
|
||||
writeregt(state, 0x00, 0x69, 0x06);
|
||||
}
|
||||
|
||||
writebitst(state, 0x10, 0xCB, 0x00, 0x40);
|
||||
writeregt(state, 0x10, 0xCD, state->IF_FS);
|
||||
|
||||
@@ -1416,6 +1635,8 @@ static void init_state(struct cxd_state *state, struct cxd2843_cfg *cfg)
|
||||
cfg->ts_clock : 1; /* 1 = fastest (82 MBit/s), 5 = slowest */
|
||||
/* IF Fullscale 0x50 = 1.4V, 0x39 = 1V, 0x28 = 0.7V */
|
||||
state->IF_FS = 0x50;
|
||||
state->is24MHz = (cfg->osc == 24000000) ? 1 : 0;
|
||||
printk("is24Mhz = %u\n", state->is24MHz);
|
||||
}
|
||||
|
||||
static int get_tune_settings(struct dvb_frontend *fe,
|
||||
@@ -1448,17 +1669,17 @@ static int get_stats(struct dvb_frontend *fe)
|
||||
str -= 108750;
|
||||
p->strength.len = 1;
|
||||
p->strength.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
p->strength.stat[0].uvalue = str;
|
||||
p->strength.stat[0].svalue = str;
|
||||
|
||||
read_snr(fe, &val);
|
||||
p->cnr.len = 1;
|
||||
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
p->cnr.stat[0].uvalue = 100 * (s64) (s16) val;
|
||||
p->cnr.stat[0].svalue = 100 * (s64) (s16) val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
|
||||
{
|
||||
struct cxd_state *state = fe->demodulator_priv;
|
||||
u8 rdata;
|
||||
@@ -1738,7 +1959,7 @@ static int read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
|
||||
do
|
||||
{
|
||||
+ BYTE tmp;
|
||||
+ u8 tmp;
|
||||
+
|
||||
CHK_ERROR(FreezeRegsT());
|
||||
|
||||
@@ -1757,11 +1978,11 @@ static int read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
+ pT2_PLPIDS->CommonPLPID = tmp;
|
||||
+ }
|
||||
+
|
||||
BYTE nPids = 0;
|
||||
u8 nPids = 0;
|
||||
CHK_ERROR(ReadRegT(0x22,0x7F,&nPids));
|
||||
|
||||
- pValues[0] = nPids;
|
||||
- if( nPids >= nValues ) nPids = BYTE(nValues-1);
|
||||
- if( nPids >= nValues ) nPids = nValues - 1;
|
||||
+ pT2_PLPIDS->NumPLPS = nPids;
|
||||
+ CHK_ERROR(ReadRegT(0x22,0x80,&pT2_PLPIDS->PLPList[0], nPids > 128 ? 128 : nPids));
|
||||
|
||||
@@ -1815,11 +2036,14 @@ static void GetSignalToNoiseIT(struct cxd_state *state, u32 *SignalToNoise)
|
||||
u8 Data[2];
|
||||
u32 reg;
|
||||
|
||||
*SignalToNoise = 0;
|
||||
freeze_regst(state);
|
||||
readregst_unlocked(state, 0x60, 0x28, Data, sizeof(Data));
|
||||
unfreeze_regst(state);
|
||||
|
||||
reg = (Data[0] << 8) | Data[1];
|
||||
if (reg == 0)
|
||||
return;
|
||||
if (reg > 51441)
|
||||
reg = 51441;
|
||||
|
||||
@@ -1837,11 +2061,14 @@ static void GetSignalToNoiseC2(struct cxd_state *state, u32 *SignalToNoise)
|
||||
u8 Data[2];
|
||||
u32 reg;
|
||||
|
||||
*SignalToNoise = 0;
|
||||
freeze_regst(state);
|
||||
readregst_unlocked(state, 0x20, 0x28, Data, sizeof(Data));
|
||||
unfreeze_regst(state);
|
||||
|
||||
reg = (Data[0] << 8) | Data[1];
|
||||
if (reg == 0)
|
||||
return;
|
||||
if (reg > 51441)
|
||||
reg = 51441;
|
||||
|
||||
@@ -1854,11 +2081,14 @@ static void GetSignalToNoiseT2(struct cxd_state *state, u32 *SignalToNoise)
|
||||
u8 Data[2];
|
||||
u32 reg;
|
||||
|
||||
*SignalToNoise = 0;
|
||||
freeze_regst(state);
|
||||
readregst_unlocked(state, 0x20, 0x28, Data, sizeof(Data));
|
||||
unfreeze_regst(state);
|
||||
|
||||
reg = (Data[0] << 8) | Data[1];
|
||||
if (reg == 0)
|
||||
return;
|
||||
if (reg > 10876)
|
||||
reg = 10876;
|
||||
|
||||
@@ -1870,11 +2100,14 @@ static void GetSignalToNoiseT(struct cxd_state *state, u32 *SignalToNoise)
|
||||
u8 Data[2];
|
||||
u32 reg;
|
||||
|
||||
*SignalToNoise = 0;
|
||||
freeze_regst(state);
|
||||
readregst_unlocked(state, 0x10, 0x28, Data, sizeof(Data));
|
||||
unfreeze_regst(state);
|
||||
|
||||
reg = (Data[0] << 8) | Data[1];
|
||||
if (reg == 0)
|
||||
return;
|
||||
if (reg > 4996)
|
||||
reg = 4996;
|
||||
|
||||
@@ -1888,7 +2121,6 @@ static void GetSignalToNoiseC(struct cxd_state *state, u32 *SignalToNoise)
|
||||
u32 reg;
|
||||
|
||||
*SignalToNoise = 0;
|
||||
|
||||
freeze_regst(state);
|
||||
readregst_unlocked(state, 0x40, 0x19, &Constellation, 1);
|
||||
readregst_unlocked(state, 0x40, 0x4C, Data, sizeof(Data));
|
||||
@@ -1947,7 +2179,7 @@ static int read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
*snr = SNR;
|
||||
p->cnr.len = 1;
|
||||
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
p->cnr.stat[0].uvalue = 10 * (s64) SNR;
|
||||
p->cnr.stat[0].svalue = 10 * (s64) SNR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1959,7 +2191,7 @@ static int read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
|
||||
static int tune(struct dvb_frontend *fe, bool re_tune,
|
||||
unsigned int mode_flags,
|
||||
unsigned int *delay, fe_status_t *status)
|
||||
unsigned int *delay, enum fe_status *status)
|
||||
{
|
||||
struct cxd_state *state = fe->demodulator_priv;
|
||||
int r;
|
||||
@@ -1971,12 +2203,13 @@ static int tune(struct dvb_frontend *fe, bool re_tune,
|
||||
state->tune_time = jiffies;
|
||||
|
||||
}
|
||||
if (*status & FE_HAS_LOCK)
|
||||
return 0;
|
||||
/* *delay = 50; */
|
||||
r = read_status(fe, status);
|
||||
if (r)
|
||||
return r;
|
||||
if (*status & FE_HAS_LOCK) {
|
||||
*delay = HZ;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1984,7 +2217,7 @@ static enum dvbfe_search search(struct dvb_frontend *fe)
|
||||
{
|
||||
int r;
|
||||
u32 loops = 20, i;
|
||||
fe_status_t status;
|
||||
enum fe_status status;
|
||||
|
||||
r = set_parameters(fe);
|
||||
|
||||
@@ -2008,10 +2241,9 @@ static int get_algo(struct dvb_frontend *fe)
|
||||
return DVBFE_ALGO_HW;
|
||||
}
|
||||
|
||||
static int get_fe_t2(struct cxd_state *state)
|
||||
static int get_fe_t2(struct cxd_state *state, struct dtv_frontend_properties *p)
|
||||
{
|
||||
struct dvb_frontend *fe = &state->frontend;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
u8 ofdm[5], modcod[2];
|
||||
|
||||
freeze_regst(state);
|
||||
@@ -2080,9 +2312,6 @@ static int get_fe_t2(struct cxd_state *state)
|
||||
case 5:
|
||||
p->transmission_mode = TRANSMISSION_MODE_32K;
|
||||
break;
|
||||
case 6:
|
||||
p->transmission_mode = TRANSMISSION_MODE_64K;
|
||||
break;
|
||||
}
|
||||
|
||||
switch ((ofdm[1] >> 4) & 0x07) {
|
||||
@@ -2112,10 +2341,9 @@ static int get_fe_t2(struct cxd_state *state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_fe_t(struct cxd_state *state)
|
||||
static int get_fe_t(struct cxd_state *state, struct dtv_frontend_properties *p)
|
||||
{
|
||||
struct dvb_frontend *fe = &state->frontend;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
u8 tps[7];
|
||||
|
||||
read_tps(state, tps);
|
||||
@@ -2214,10 +2442,9 @@ static int get_fe_t(struct cxd_state *state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_fe_c(struct cxd_state *state)
|
||||
static int get_fe_c(struct cxd_state *state, struct dtv_frontend_properties *p)
|
||||
{
|
||||
struct dvb_frontend *fe = &state->frontend;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
u8 qam;
|
||||
|
||||
freeze_regst(state);
|
||||
@@ -2227,7 +2454,7 @@ static int get_fe_c(struct cxd_state *state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_frontend(struct dvb_frontend *fe)
|
||||
static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
|
||||
{
|
||||
struct cxd_state *state = fe->demodulator_priv;
|
||||
|
||||
@@ -2236,13 +2463,13 @@ static int get_frontend(struct dvb_frontend *fe)
|
||||
|
||||
switch (state->state) {
|
||||
case ActiveT:
|
||||
get_fe_t(state);
|
||||
get_fe_t(state, p);
|
||||
break;
|
||||
case ActiveT2:
|
||||
get_fe_t2(state);
|
||||
get_fe_t2(state, p);
|
||||
break;
|
||||
case ActiveC:
|
||||
get_fe_c(state);
|
||||
get_fe_c(state, p);
|
||||
break;
|
||||
case ActiveC2:
|
||||
break;
|
||||
@@ -2404,13 +2631,12 @@ static int probe(struct cxd_state *state)
|
||||
int status;
|
||||
|
||||
status = readregst(state, 0x00, 0xFD, &ChipID, 1);
|
||||
|
||||
if (status)
|
||||
status = readregsx(state, 0x00, 0xFD, &ChipID, 1);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/*printk("ChipID = %02X\n", ChipID);*/
|
||||
printk("ChipID = %02X\n", ChipID);
|
||||
switch (ChipID) {
|
||||
case 0xa4:
|
||||
state->type = CXD2843;
|
||||
@@ -2445,6 +2671,7 @@ struct dvb_frontend *cxd2843_attach(struct i2c_adapter *i2c,
|
||||
{
|
||||
struct cxd_state *state = NULL;
|
||||
|
||||
pr_info("attach\n");
|
||||
state = kzalloc(sizeof(struct cxd_state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
@@ -2463,4 +2690,4 @@ EXPORT_SYMBOL(cxd2843_attach);
|
||||
|
||||
MODULE_DESCRIPTION("CXD2843/37/38 driver");
|
||||
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -8,6 +8,7 @@ struct cxd2843_cfg {
|
||||
u8 adr;
|
||||
u32 ts_clock;
|
||||
u8 parallel;
|
||||
u32 osc;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_CXD2843) || \
|
||||
|
||||
@@ -4892,14 +4892,14 @@ static int drxk_set_parameters (struct dvb_frontend *fe,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drxk_c_get_frontend(struct dvb_frontend *fe)
|
||||
static int drxk_c_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
|
||||
{
|
||||
//struct drxk_state *state = fe->demodulator_priv;
|
||||
//printk("%s\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
static int drxk_read_status(struct dvb_frontend *fe, enum fe_status *status)
|
||||
{
|
||||
struct drxk_state *state = fe->demodulator_priv;
|
||||
u32 stat;
|
||||
@@ -4986,7 +4986,7 @@ static int drxk_t_sleep(struct dvb_frontend* fe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drxk_t_get_frontend(struct dvb_frontend *fe)
|
||||
static int drxk_t_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
|
||||
{
|
||||
//struct drxk_state *state = fe->demodulator_priv;
|
||||
//printk("%s\n", __FUNCTION__);
|
||||
@@ -5088,6 +5088,6 @@ error:
|
||||
|
||||
MODULE_DESCRIPTION("DRX-K driver");
|
||||
MODULE_AUTHOR("Ralph Metzler");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
EXPORT_SYMBOL(drxk_attach);
|
||||
|
||||
@@ -62,7 +62,7 @@ static int lnbh25_write_regs(struct lnbh25 *lnbh, int reg, int len)
|
||||
}
|
||||
|
||||
static int lnbh25_set_voltage(struct dvb_frontend *fe,
|
||||
fe_sec_voltage_t voltage)
|
||||
enum fe_sec_voltage voltage)
|
||||
{
|
||||
struct lnbh25 *lnbh = (struct lnbh25 *) fe->sec_priv;
|
||||
u8 oldreg0 = lnbh->reg[0];
|
||||
@@ -107,7 +107,7 @@ static int lnbh25_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
|
||||
}
|
||||
|
||||
static int lnbh25_set_tone(struct dvb_frontend *fe,
|
||||
fe_sec_tone_mode_t tone)
|
||||
enum fe_sec_tone_mode tone)
|
||||
{
|
||||
/* struct lnbh25 *lnbh = (struct lnbh25 *) fe->sec_priv; */
|
||||
|
||||
@@ -146,7 +146,7 @@ struct dvb_frontend *lnbh25_attach(struct dvb_frontend *fe,
|
||||
fe->ops.enable_high_lnb_voltage = lnbh25_enable_high_lnb_voltage;
|
||||
fe->ops.release_sec = lnbh25_release;
|
||||
|
||||
pr_info("LNB25 on %02x\n", lnbh->adr);
|
||||
pr_info("LNBH25 on %02x\n", lnbh->adr);
|
||||
|
||||
return fe;
|
||||
}
|
||||
@@ -154,4 +154,4 @@ EXPORT_SYMBOL(lnbh25_attach);
|
||||
|
||||
MODULE_DESCRIPTION("LNBH25");
|
||||
MODULE_AUTHOR("Ralph Metzler");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -45,7 +45,7 @@ struct lnbp21 {
|
||||
};
|
||||
|
||||
static int lnbp21_set_voltage(struct dvb_frontend *fe,
|
||||
fe_sec_voltage_t voltage)
|
||||
enum fe_sec_voltage voltage)
|
||||
{
|
||||
struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
|
||||
struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,
|
||||
@@ -98,7 +98,7 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
|
||||
}
|
||||
|
||||
static int lnbp21_set_tone(struct dvb_frontend *fe,
|
||||
fe_sec_tone_mode_t tone)
|
||||
enum fe_sec_tone_mode tone)
|
||||
{
|
||||
struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
|
||||
struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,
|
||||
|
||||
@@ -424,9 +424,22 @@ static int get_algo(struct dvb_frontend *fe)
|
||||
return DVBFE_ALGO_HW;
|
||||
}
|
||||
|
||||
/*
|
||||
static int cfg_scrambler(struct mxl *state)
|
||||
/* This should maybe go into dvb-core/dvb_math.c */
|
||||
|
||||
static u32 gold2root(u32 gold)
|
||||
{
|
||||
u32 x, g;
|
||||
|
||||
if (gold >= 0x3ffff)
|
||||
gold = 0;
|
||||
for (g = 0, x = 1; g < gold; g++)
|
||||
x = (((x ^ (x >> 7)) & 1) << 17) | (x >> 1);
|
||||
return x;
|
||||
}
|
||||
|
||||
static int cfg_scrambler(struct mxl *state, u32 gold)
|
||||
{
|
||||
u32 root;
|
||||
u8 buf[26] = {
|
||||
MXL_HYDRA_PLID_CMD_WRITE, 24,
|
||||
0, MXL_HYDRA_DEMOD_SCRAMBLE_CODE_CMD, 0, 0,
|
||||
@@ -435,11 +448,15 @@ static int cfg_scrambler(struct mxl *state)
|
||||
0, 0, 0, 0, 1, 0, 0, 0,
|
||||
};
|
||||
|
||||
root = gold2root(gold);
|
||||
buf[25] = (root >> 24) & 0xff;
|
||||
buf[24] = (root >> 16) & 0xff;
|
||||
buf[23] = (root >> 8) & 0xff;
|
||||
buf[22] = root & 0xff;
|
||||
|
||||
return send_command(state, sizeof(buf), buf);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
static int CfgDemodAbortTune(struct mxl *state)
|
||||
{
|
||||
MXL_HYDRA_DEMOD_ABORT_TUNE_T abortTuneCmd;
|
||||
@@ -510,7 +527,7 @@ static int set_parameters(struct dvb_frontend *fe)
|
||||
demodChanCfg.rollOff = MXL_HYDRA_ROLLOFF_AUTO;
|
||||
demodChanCfg.modulationScheme = MXL_HYDRA_MOD_AUTO;
|
||||
demodChanCfg.pilots = MXL_HYDRA_PILOTS_AUTO;
|
||||
//cfg_scrambler(state);
|
||||
cfg_scrambler(state, p->scrambling_sequence_index);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -540,7 +557,7 @@ static int set_parameters(struct dvb_frontend *fe)
|
||||
|
||||
static int get_stats(struct dvb_frontend *fe);
|
||||
|
||||
static int read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
|
||||
{
|
||||
struct mxl *state = fe->demodulator_priv;
|
||||
|
||||
@@ -562,10 +579,10 @@ static int read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
|
||||
static int tune(struct dvb_frontend *fe, bool re_tune,
|
||||
unsigned int mode_flags,
|
||||
unsigned int *delay, fe_status_t *status)
|
||||
unsigned int *delay, enum fe_status *status)
|
||||
{
|
||||
struct mxl *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
/* struct dtv_frontend_properties *p = &fe->dtv_property_cache; */
|
||||
int r = 0;
|
||||
|
||||
*delay = HZ / 2;
|
||||
@@ -576,17 +593,13 @@ static int tune(struct dvb_frontend *fe, bool re_tune,
|
||||
state->tune_time = jiffies;
|
||||
return 0;
|
||||
}
|
||||
if (*status & FE_HAS_LOCK)
|
||||
return 0;
|
||||
|
||||
r = read_status(fe, status);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
#if 0
|
||||
if (*status & FE_HAS_LOCK)
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
if (p->delivery_system == SYS_DVBS)
|
||||
p->delivery_system = SYS_DVBS2;
|
||||
else
|
||||
@@ -635,7 +648,7 @@ static int read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
*snr = (s16) (regData & 0xFFFF); /* 100x dB */
|
||||
p->cnr.len = 1;
|
||||
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
p->cnr.stat[0].uvalue = 10 * (s64) *snr;
|
||||
p->cnr.stat[0].svalue = 10 * (s64) *snr;
|
||||
return stat;
|
||||
}
|
||||
|
||||
@@ -643,7 +656,7 @@ static int read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct mxl *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
u32 reg[8], reg2[4], n = 0, d = 0;
|
||||
u32 reg[8], reg2[4];
|
||||
int stat;
|
||||
|
||||
*ber = 0;
|
||||
@@ -673,7 +686,7 @@ static int read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
p->pre_bit_error.stat[0].uvalue = reg[5];
|
||||
p->pre_bit_count.len = 1;
|
||||
p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
|
||||
p->pre_bit_count.stat[0].uvalue = reg[6] * 188 * 8;
|
||||
p->pre_bit_count.stat[0].uvalue = 8 * 188 * (u64)reg[6];
|
||||
break;
|
||||
case SYS_DVBS2:
|
||||
break;
|
||||
@@ -698,6 +711,10 @@ static int read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
int stat;
|
||||
u32 regData = 0;
|
||||
|
||||
#if 0
|
||||
if (!firmware_is_alive(state))
|
||||
pr_info("FW dead!\n");
|
||||
#endif
|
||||
mutex_lock(&state->base->status_lock);
|
||||
HYDRA_DEMOD_STATUS_LOCK(state, state->demod);
|
||||
stat = read_register(state, (HYDRA_DMD_STATUS_INPUT_POWER_ADDR +
|
||||
@@ -708,7 +725,7 @@ static int read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
*strength = (u16) (regData & 0xFFFF); /* 10x dBm */
|
||||
p->strength.len = 1;
|
||||
p->strength.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
p->strength.stat[0].uvalue = 10 * (s64) (s16) (regData & 0xFFFF);
|
||||
p->strength.stat[0].svalue = 10 * (s64) (s16) (regData & 0xFFFF);
|
||||
return stat;
|
||||
}
|
||||
|
||||
@@ -728,7 +745,7 @@ static int get_stats(struct dvb_frontend *fe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static fe_code_rate_t conv_fec(MXL_HYDRA_FEC_E fec)
|
||||
static enum fe_code_rate conv_fec(MXL_HYDRA_FEC_E fec)
|
||||
{
|
||||
enum fe_code_rate fec2fec[11] = {
|
||||
FEC_NONE, FEC_1_2, FEC_3_5, FEC_2_3,
|
||||
@@ -741,10 +758,9 @@ static fe_code_rate_t conv_fec(MXL_HYDRA_FEC_E fec)
|
||||
return fec2fec[fec];
|
||||
}
|
||||
|
||||
static int get_frontend(struct dvb_frontend *fe)
|
||||
static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
|
||||
{
|
||||
struct mxl *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
u32 regData[MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE];
|
||||
u32 freq;
|
||||
int stat;
|
||||
@@ -837,8 +853,8 @@ static struct dvb_frontend_ops mxl_ops = {
|
||||
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
|
||||
.info = {
|
||||
.name = "MXL5XX",
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_min = 300000,
|
||||
.frequency_max = 2350000,
|
||||
.frequency_stepsize = 0,
|
||||
.frequency_tolerance = 0,
|
||||
.symbol_rate_min = 1000000,
|
||||
@@ -1639,7 +1655,7 @@ static int load_fw(struct mxl *state, struct mxl5xx_cfg *cfg)
|
||||
|
||||
static int validate_sku(struct mxl *state)
|
||||
{
|
||||
u32 padMuxBond, prcmChipId, prcmSoCId;
|
||||
u32 padMuxBond = 0, prcmChipId = 0, prcmSoCId = 0;
|
||||
int status;
|
||||
u32 type = state->base->type;
|
||||
|
||||
@@ -1929,4 +1945,4 @@ EXPORT_SYMBOL_GPL(mxl5xx_attach);
|
||||
|
||||
MODULE_DESCRIPTION("MXL5XX driver");
|
||||
MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -58,7 +58,7 @@ enum EDemodState { Off, QAMSet, OFDMSet, QAMStarted, OFDMStarted };
|
||||
|
||||
struct stv_state {
|
||||
struct dvb_frontend frontend;
|
||||
fe_modulation_t modulation;
|
||||
enum fe_modulation modulation;
|
||||
u32 symbol_rate;
|
||||
u32 bandwidth;
|
||||
struct device *dev;
|
||||
@@ -1861,7 +1861,7 @@ static int OFDM_GetLockStatus(struct stv_state *state, LOCK_STATUS* pLockStatus,
|
||||
|
||||
#endif
|
||||
|
||||
static int read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
|
||||
{
|
||||
struct stv_state *state = fe->demodulator_priv;
|
||||
*status=0;
|
||||
@@ -2128,8 +2128,7 @@ static void init_state(struct stv_state *state, struct stv0367_cfg *cfg)
|
||||
}
|
||||
|
||||
|
||||
struct dvb_frontend *stv0367_attach(struct i2c_adapter *i2c, struct stv0367_cfg *cfg,
|
||||
struct dvb_frontend **fe_t)
|
||||
struct dvb_frontend *stv0367_attach(struct i2c_adapter *i2c, struct stv0367_cfg *cfg)
|
||||
{
|
||||
struct stv_state *state = NULL;
|
||||
|
||||
@@ -2153,7 +2152,7 @@ error:
|
||||
|
||||
MODULE_DESCRIPTION("STV0367DD driver");
|
||||
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
EXPORT_SYMBOL(stv0367_attach);
|
||||
|
||||
|
||||
@@ -13,6 +13,5 @@ struct stv0367_cfg {
|
||||
|
||||
|
||||
extern struct dvb_frontend *stv0367_attach(struct i2c_adapter *i2c,
|
||||
struct stv0367_cfg *cfg,
|
||||
struct dvb_frontend **fe_t);
|
||||
struct stv0367_cfg *cfg);
|
||||
#endif
|
||||
|
||||
@@ -3446,11 +3446,11 @@ err:
|
||||
static int stv090x_set_pls(struct stv090x_state *state, u8 pls_mode, u32 pls_code)
|
||||
{
|
||||
dprintk(FE_DEBUG, 1, "Set PLS code %d (mode %d)", pls_code, pls_mode);
|
||||
if (STV090x_WRITE_DEMOD(state, PLROOT2, (pls_mode << 2) | (pls_code >> 16)) < 0)
|
||||
if (STV090x_WRITE_DEMOD(state, PLROOT0, pls_code & 0xff) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, PLROOT1, (pls_code >> 8) & 0xff) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, PLROOT0, pls_code & 0xff) < 0)
|
||||
if (STV090x_WRITE_DEMOD(state, PLROOT2, (pls_mode << 2) | (pls_code >> 16)) < 0)
|
||||
goto err;
|
||||
return 0;
|
||||
err:
|
||||
@@ -3537,8 +3537,8 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_fron
|
||||
if ((props->stream_id != NO_STREAM_ID_FILTER) &&
|
||||
(props->stream_id & 0xffffff00))
|
||||
pls = props->stream_id >> 8;
|
||||
if (props->pls != NO_SCRAMBLING_CODE)
|
||||
pls = props->pls | 0x40000; /* props->pls is always gold code */
|
||||
/* props->scrambling_sequence_index is always gold code */
|
||||
pls = props->scrambling_sequence_index | 0x40000;
|
||||
stv090x_set_pls(state, (pls >> 18) & 3, pls & 0x3ffff);
|
||||
stv090x_set_mis(state, props->stream_id);
|
||||
|
||||
@@ -4927,15 +4927,6 @@ static int stv090x_init(struct dvb_frontend *fe)
|
||||
if (stv090x_i2c_gate_ctrl(state, 0) < 0)
|
||||
goto err;
|
||||
|
||||
#if 0
|
||||
if (state->device == STV0900) {
|
||||
if (stv0900_set_tspath(state) < 0)
|
||||
goto err;
|
||||
} else {
|
||||
if (stv0903_set_tspath(state) < 0)
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
err_gateoff:
|
||||
@@ -5081,10 +5072,9 @@ static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir,
|
||||
return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg);
|
||||
}
|
||||
|
||||
static int stv090x_get_frontend(struct dvb_frontend *fe)
|
||||
static int stv090x_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
|
||||
{
|
||||
struct stv090x_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
u8 tmp;
|
||||
u32 reg = 0;
|
||||
|
||||
|
||||
1640
frontends/stv0910.c
1640
frontends/stv0910.c
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ struct stv0910_cfg {
|
||||
u8 adr;
|
||||
u8 parallel;
|
||||
u8 rptlvl;
|
||||
u8 single;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_STV0910) || \
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,9 @@
|
||||
#include "stv6110x.h"
|
||||
#include "stv6110x_priv.h"
|
||||
|
||||
/* Max transfer size done by I2C transfer functions */
|
||||
#define MAX_XFER_SIZE 64
|
||||
|
||||
static unsigned int verbose;
|
||||
module_param(verbose, int, 0644);
|
||||
MODULE_PARM_DESC(verbose, "Set Verbosity level");
|
||||
@@ -61,7 +64,8 @@ static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 da
|
||||
{
|
||||
int ret;
|
||||
const struct stv6110x_config *config = stv6110x->config;
|
||||
u8 buf[len + 1];
|
||||
u8 buf[MAX_XFER_SIZE];
|
||||
|
||||
struct i2c_msg msg = {
|
||||
.addr = config->addr,
|
||||
.flags = 0,
|
||||
@@ -69,6 +73,13 @@ static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 da
|
||||
.len = len + 1
|
||||
};
|
||||
|
||||
if (1 + len > sizeof(buf)) {
|
||||
printk(KERN_WARNING
|
||||
"%s: i2c wr: len=%d is too big!\n",
|
||||
KBUILD_MODNAME, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (start + len > 8)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -324,17 +335,15 @@ static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
|
||||
}
|
||||
|
||||
|
||||
static int stv6110x_release(struct dvb_frontend *fe)
|
||||
static void stv6110x_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct stv6110x_state *stv6110x = fe->tuner_priv;
|
||||
|
||||
fe->tuner_priv = NULL;
|
||||
kfree(stv6110x);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_tuner_ops stv6110x_ops = {
|
||||
static const struct dvb_tuner_ops stv6110x_ops = {
|
||||
.info = {
|
||||
.name = "STV6110(A) Silicon Tuner",
|
||||
.frequency_min = 950000,
|
||||
@@ -344,7 +353,7 @@ static struct dvb_tuner_ops stv6110x_ops = {
|
||||
.release = stv6110x_release
|
||||
};
|
||||
|
||||
static struct stv6110x_devctl stv6110x_ctl = {
|
||||
static const struct stv6110x_devctl stv6110x_ctl = {
|
||||
.tuner_init = stv6110x_init,
|
||||
.tuner_sleep = stv6110x_sleep,
|
||||
.tuner_set_mode = stv6110x_set_mode,
|
||||
@@ -358,7 +367,7 @@ static struct stv6110x_devctl stv6110x_ctl = {
|
||||
.tuner_get_status = stv6110x_get_status,
|
||||
};
|
||||
|
||||
struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
|
||||
const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
|
||||
const struct stv6110x_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
|
||||
@@ -53,14 +53,20 @@ struct stv6110x_devctl {
|
||||
};
|
||||
|
||||
|
||||
#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE))
|
||||
#include <linux/version.h>
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0))
|
||||
#define IS_REACHABLE(option) (config_enabled(option) || \
|
||||
(config_enabled(option##_MODULE) && config_enabled(MODULE)))
|
||||
#endif
|
||||
|
||||
extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
|
||||
#if IS_REACHABLE(CONFIG_DVB_STV6110x)
|
||||
|
||||
extern const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
|
||||
const struct stv6110x_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
|
||||
#else
|
||||
static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
|
||||
static inline const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
|
||||
const struct stv6110x_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
|
||||
@@ -70,7 +70,7 @@ struct stv6110x_state {
|
||||
const struct stv6110x_config *config;
|
||||
u8 regs[8];
|
||||
|
||||
struct stv6110x_devctl *devctl;
|
||||
const struct stv6110x_devctl *devctl;
|
||||
};
|
||||
|
||||
#endif /* __STV6110x_PRIV_H */
|
||||
|
||||
@@ -203,17 +203,17 @@ static int init(struct dvb_frontend *fe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int release(struct dvb_frontend *fe)
|
||||
static void release(struct dvb_frontend *fe)
|
||||
{
|
||||
kfree(fe->tuner_priv);
|
||||
fe->tuner_priv = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_bandwidth(struct dvb_frontend *fe, u32 CutOffFrequency)
|
||||
{
|
||||
struct stv *state = fe->tuner_priv;
|
||||
u32 index = (CutOffFrequency + 999999) / 1000000;
|
||||
int stat = 0;
|
||||
|
||||
if (index < 6)
|
||||
index = 6;
|
||||
@@ -225,12 +225,14 @@ static int set_bandwidth(struct dvb_frontend *fe, u32 CutOffFrequency)
|
||||
state->reg[0x08] = (state->reg[0x08] & ~0xFC) | ((index-6) << 2);
|
||||
state->reg[0x09] = (state->reg[0x09] & ~0x0C) | 0x08;
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
write_regs(state, 0x08, 2);
|
||||
wait_for_call_done(state, 0x08);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
return 0;
|
||||
stat = fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (!stat) {
|
||||
write_regs(state, 0x08, 2);
|
||||
wait_for_call_done(state, 0x08);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int set_lof(struct stv *state, u32 LocalFrequency, u32 CutOffFrequency)
|
||||
@@ -312,6 +314,7 @@ static int set_params(struct dvb_frontend *fe)
|
||||
struct stv *state = fe->tuner_priv;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
u32 freq, symb, cutoff;
|
||||
int stat = 0;
|
||||
|
||||
if (p->delivery_system != SYS_DVBS && p->delivery_system != SYS_DVBS2)
|
||||
return -EINVAL;
|
||||
@@ -321,16 +324,20 @@ static int set_params(struct dvb_frontend *fe)
|
||||
cutoff = 5000000 + MulDiv32(p->symbol_rate, 135, 200);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
set_lof(state, freq, cutoff);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
return 0;
|
||||
stat = fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (!stat) {
|
||||
set_lof(state, freq, cutoff);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
*frequency = 0;
|
||||
struct stv *state = fe->tuner_priv;
|
||||
|
||||
*frequency = state->Frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -631,15 +638,18 @@ static int get_rf_strength(struct dvb_frontend *fe, u16 *st)
|
||||
// RF Mode
|
||||
// Read AGC ADC
|
||||
u8 Reg = 0;
|
||||
|
||||
int stat = 0;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
write_reg(state, 0x02, state->reg[0x02] | 0x20);
|
||||
read_reg(state, 2, &Reg);
|
||||
if( Reg & 0x20 )
|
||||
stat = fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (!stat) {
|
||||
write_reg(state, 0x02, state->reg[0x02] | 0x20);
|
||||
read_reg(state, 2, &Reg);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
if (Reg & 0x20)
|
||||
read_reg(state, 2, &Reg);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
if((state->reg[0x02] & 0x80) == 0)
|
||||
// NF
|
||||
@@ -715,7 +725,7 @@ struct dvb_frontend *stv6111_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c, u8 adr)
|
||||
{
|
||||
struct stv *state;
|
||||
int stat;
|
||||
int stat = 0;
|
||||
|
||||
state = kzalloc(sizeof(struct stv), GFP_KERNEL);
|
||||
if (!state)
|
||||
@@ -726,13 +736,15 @@ struct dvb_frontend *stv6111_attach(struct dvb_frontend *fe,
|
||||
init_state(state);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
stat = attach_init(state);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
stat = fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (!stat) {
|
||||
stat = attach_init(state);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
if (stat < 0) {
|
||||
kfree(state);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
fe->tuner_priv = state;
|
||||
return fe;
|
||||
@@ -741,7 +753,7 @@ EXPORT_SYMBOL_GPL(stv6111_attach);
|
||||
|
||||
MODULE_DESCRIPTION("STV6111 driver");
|
||||
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
||||
@@ -790,11 +790,10 @@ static int init(struct dvb_frontend *fe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int release(struct dvb_frontend *fe)
|
||||
static void release(struct dvb_frontend *fe)
|
||||
{
|
||||
kfree(fe->tuner_priv);
|
||||
fe->tuner_priv = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_params(struct dvb_frontend *fe)
|
||||
@@ -934,7 +933,7 @@ EXPORT_SYMBOL_GPL(tda18212dd_attach);
|
||||
|
||||
MODULE_DESCRIPTION("TDA18212 driver");
|
||||
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
||||
@@ -1144,11 +1144,10 @@ static int init(struct dvb_frontend *fe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int release(struct dvb_frontend *fe)
|
||||
static void release(struct dvb_frontend *fe)
|
||||
{
|
||||
kfree(fe->tuner_priv);
|
||||
fe->tuner_priv = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1327,4 +1326,4 @@ EXPORT_SYMBOL_GPL(tda18271c2dd_attach);
|
||||
|
||||
MODULE_DESCRIPTION("TDA18271C2 driver");
|
||||
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -24,67 +24,138 @@
|
||||
#ifndef _DVBCA_H_
|
||||
#define _DVBCA_H_
|
||||
|
||||
/* slot interface types and info */
|
||||
/**
|
||||
* struct ca_slot_info - CA slot interface types and info.
|
||||
*
|
||||
* @num: slot number.
|
||||
* @type: slot type.
|
||||
* @flags: flags applicable to the slot.
|
||||
*
|
||||
* This struct stores the CA slot information.
|
||||
*
|
||||
* @type can be:
|
||||
*
|
||||
* - %CA_CI - CI high level interface;
|
||||
* - %CA_CI_LINK - CI link layer level interface;
|
||||
* - %CA_CI_PHYS - CI physical layer level interface;
|
||||
* - %CA_DESCR - built-in descrambler;
|
||||
* - %CA_SC -simple smart card interface.
|
||||
*
|
||||
* @flags can be:
|
||||
*
|
||||
* - %CA_CI_MODULE_PRESENT - module (or card) inserted;
|
||||
* - %CA_CI_MODULE_READY - module is ready for usage.
|
||||
*/
|
||||
|
||||
typedef struct ca_slot_info {
|
||||
int num; /* slot number */
|
||||
|
||||
int type; /* CA interface this slot supports */
|
||||
#define CA_CI 1 /* CI high level interface */
|
||||
#define CA_CI_LINK 2 /* CI link layer level interface */
|
||||
#define CA_CI_PHYS 4 /* CI physical layer level interface */
|
||||
#define CA_DESCR 8 /* built-in descrambler */
|
||||
#define CA_SC 128 /* simple smart card interface */
|
||||
struct ca_slot_info {
|
||||
int num;
|
||||
int type;
|
||||
#define CA_CI 1
|
||||
#define CA_CI_LINK 2
|
||||
#define CA_CI_PHYS 4
|
||||
#define CA_DESCR 8
|
||||
#define CA_SC 128
|
||||
|
||||
unsigned int flags;
|
||||
#define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */
|
||||
#define CA_CI_MODULE_PRESENT 1
|
||||
#define CA_CI_MODULE_READY 2
|
||||
} ca_slot_info_t;
|
||||
};
|
||||
|
||||
|
||||
/* descrambler types and info */
|
||||
|
||||
typedef struct ca_descr_info {
|
||||
unsigned int num; /* number of available descramblers (keys) */
|
||||
unsigned int type; /* type of supported scrambling system */
|
||||
/**
|
||||
* struct ca_descr_info - descrambler types and info.
|
||||
*
|
||||
* @num: number of available descramblers (keys).
|
||||
* @type: type of supported scrambling system.
|
||||
*
|
||||
* Identifies the number of descramblers and their type.
|
||||
*
|
||||
* @type can be:
|
||||
*
|
||||
* - %CA_ECD - European Common Descrambler (ECD) hardware;
|
||||
* - %CA_NDS - Videoguard (NDS) hardware;
|
||||
* - %CA_DSS - Distributed Sample Scrambling (DSS) hardware.
|
||||
*/
|
||||
struct ca_descr_info {
|
||||
unsigned int num;
|
||||
unsigned int type;
|
||||
#define CA_ECD 1
|
||||
#define CA_NDS 2
|
||||
#define CA_DSS 4
|
||||
} ca_descr_info_t;
|
||||
};
|
||||
|
||||
typedef struct ca_caps {
|
||||
unsigned int slot_num; /* total number of CA card and module slots */
|
||||
unsigned int slot_type; /* OR of all supported types */
|
||||
unsigned int descr_num; /* total number of descrambler slots (keys) */
|
||||
unsigned int descr_type; /* OR of all supported types */
|
||||
} ca_caps_t;
|
||||
/**
|
||||
* struct ca_caps - CA slot interface capabilities.
|
||||
*
|
||||
* @slot_num: total number of CA card and module slots.
|
||||
* @slot_type: bitmap with all supported types as defined at
|
||||
* &struct ca_slot_info (e. g. %CA_CI, %CA_CI_LINK, etc).
|
||||
* @descr_num: total number of descrambler slots (keys)
|
||||
* @descr_type: bitmap with all supported types as defined at
|
||||
* &struct ca_descr_info (e. g. %CA_ECD, %CA_NDS, etc).
|
||||
*/
|
||||
struct ca_caps {
|
||||
unsigned int slot_num;
|
||||
unsigned int slot_type;
|
||||
unsigned int descr_num;
|
||||
unsigned int descr_type;
|
||||
};
|
||||
|
||||
/* a message to/from a CI-CAM */
|
||||
typedef struct ca_msg {
|
||||
/**
|
||||
* struct ca_msg - a message to/from a CI-CAM
|
||||
*
|
||||
* @index: unused
|
||||
* @type: unused
|
||||
* @length: length of the message
|
||||
* @msg: message
|
||||
*
|
||||
* This struct carries a message to be send/received from a CI CA module.
|
||||
*/
|
||||
struct ca_msg {
|
||||
unsigned int index;
|
||||
unsigned int type;
|
||||
unsigned int length;
|
||||
unsigned char msg[256];
|
||||
} ca_msg_t;
|
||||
};
|
||||
|
||||
typedef struct ca_descr {
|
||||
/**
|
||||
* struct ca_descr - CA descrambler control words info
|
||||
*
|
||||
* @index: CA Descrambler slot
|
||||
* @parity: control words parity, where 0 means even and 1 means odd
|
||||
* @cw: CA Descrambler control words
|
||||
*/
|
||||
struct ca_descr {
|
||||
unsigned int index;
|
||||
unsigned int parity; /* 0 == even, 1 == odd */
|
||||
unsigned int parity;
|
||||
unsigned char cw[8];
|
||||
} ca_descr_t;
|
||||
};
|
||||
|
||||
typedef struct ca_pid {
|
||||
struct ca_pid {
|
||||
unsigned int pid;
|
||||
int index; /* -1 == disable*/
|
||||
} ca_pid_t;
|
||||
int index;/* -1 == disable*/
|
||||
};
|
||||
|
||||
#define CA_RESET _IO('o', 128)
|
||||
#define CA_GET_CAP _IOR('o', 129, ca_caps_t)
|
||||
#define CA_GET_SLOT_INFO _IOR('o', 130, ca_slot_info_t)
|
||||
#define CA_GET_DESCR_INFO _IOR('o', 131, ca_descr_info_t)
|
||||
#define CA_GET_MSG _IOR('o', 132, ca_msg_t)
|
||||
#define CA_SEND_MSG _IOW('o', 133, ca_msg_t)
|
||||
#define CA_SET_DESCR _IOW('o', 134, ca_descr_t)
|
||||
#define CA_SET_PID _IOW('o', 135, ca_pid_t)
|
||||
#define CA_GET_CAP _IOR('o', 129, struct ca_caps)
|
||||
#define CA_GET_SLOT_INFO _IOR('o', 130, struct ca_slot_info)
|
||||
#define CA_GET_DESCR_INFO _IOR('o', 131, struct ca_descr_info)
|
||||
#define CA_GET_MSG _IOR('o', 132, struct ca_msg)
|
||||
#define CA_SEND_MSG _IOW('o', 133, struct ca_msg)
|
||||
#define CA_SET_DESCR _IOW('o', 134, struct ca_descr)
|
||||
#define CA_SET_PID _IOW('o', 135, struct ca_pid)
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
/* This is needed for legacy userspace support */
|
||||
typedef struct ca_slot_info ca_slot_info_t;
|
||||
typedef struct ca_descr_info ca_descr_info_t;
|
||||
typedef struct ca_caps ca_caps_t;
|
||||
typedef struct ca_msg ca_msg_t;
|
||||
typedef struct ca_descr ca_descr_t;
|
||||
typedef struct ca_pid ca_pid_t;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -32,27 +32,74 @@
|
||||
|
||||
#define DMX_FILTER_SIZE 16
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DMX_OUT_DECODER, /* Streaming directly to decoder. */
|
||||
DMX_OUT_TAP, /* Output going to a memory buffer */
|
||||
/* (to be retrieved via the read command).*/
|
||||
DMX_OUT_TS_TAP, /* Output multiplexed into a new TS */
|
||||
/* (to be retrieved by reading from the */
|
||||
/* logical DVR device). */
|
||||
DMX_OUT_TSDEMUX_TAP /* Like TS_TAP but retrieved from the DMX device */
|
||||
} dmx_output_t;
|
||||
/**
|
||||
* enum dmx_output - Output for the demux.
|
||||
*
|
||||
* @DMX_OUT_DECODER:
|
||||
* Streaming directly to decoder.
|
||||
* @DMX_OUT_TAP:
|
||||
* Output going to a memory buffer (to be retrieved via the read command).
|
||||
* Delivers the stream output to the demux device on which the ioctl
|
||||
* is called.
|
||||
* @DMX_OUT_TS_TAP:
|
||||
* Output multiplexed into a new TS (to be retrieved by reading from the
|
||||
* logical DVR device). Routes output to the logical DVR device
|
||||
* ``/dev/dvb/adapter?/dvr?``, which delivers a TS multiplexed from all
|
||||
* filters for which @DMX_OUT_TS_TAP was specified.
|
||||
* @DMX_OUT_TSDEMUX_TAP:
|
||||
* Like @DMX_OUT_TS_TAP but retrieved from the DMX device.
|
||||
*/
|
||||
enum dmx_output {
|
||||
DMX_OUT_DECODER,
|
||||
DMX_OUT_TAP,
|
||||
DMX_OUT_TS_TAP,
|
||||
DMX_OUT_TSDEMUX_TAP
|
||||
};
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DMX_IN_FRONTEND, /* Input from a front-end device. */
|
||||
DMX_IN_DVR /* Input from the logical DVR device. */
|
||||
} dmx_input_t;
|
||||
/**
|
||||
* enum dmx_input - Input from the demux.
|
||||
*
|
||||
* @DMX_IN_FRONTEND: Input from a front-end device.
|
||||
* @DMX_IN_DVR: Input from the logical DVR device.
|
||||
*/
|
||||
enum dmx_input {
|
||||
DMX_IN_FRONTEND,
|
||||
DMX_IN_DVR
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dmx_ts_pes - type of the PES filter.
|
||||
*
|
||||
* @DMX_PES_AUDIO0: first audio PID. Also referred as @DMX_PES_AUDIO.
|
||||
* @DMX_PES_VIDEO0: first video PID. Also referred as @DMX_PES_VIDEO.
|
||||
* @DMX_PES_TELETEXT0: first teletext PID. Also referred as @DMX_PES_TELETEXT.
|
||||
* @DMX_PES_SUBTITLE0: first subtitle PID. Also referred as @DMX_PES_SUBTITLE.
|
||||
* @DMX_PES_PCR0: first Program Clock Reference PID.
|
||||
* Also referred as @DMX_PES_PCR.
|
||||
*
|
||||
* @DMX_PES_AUDIO1: second audio PID.
|
||||
* @DMX_PES_VIDEO1: second video PID.
|
||||
* @DMX_PES_TELETEXT1: second teletext PID.
|
||||
* @DMX_PES_SUBTITLE1: second subtitle PID.
|
||||
* @DMX_PES_PCR1: second Program Clock Reference PID.
|
||||
*
|
||||
* @DMX_PES_AUDIO2: third audio PID.
|
||||
* @DMX_PES_VIDEO2: third video PID.
|
||||
* @DMX_PES_TELETEXT2: third teletext PID.
|
||||
* @DMX_PES_SUBTITLE2: third subtitle PID.
|
||||
* @DMX_PES_PCR2: third Program Clock Reference PID.
|
||||
*
|
||||
* @DMX_PES_AUDIO3: fourth audio PID.
|
||||
* @DMX_PES_VIDEO3: fourth video PID.
|
||||
* @DMX_PES_TELETEXT3: fourth teletext PID.
|
||||
* @DMX_PES_SUBTITLE3: fourth subtitle PID.
|
||||
* @DMX_PES_PCR3: fourth Program Clock Reference PID.
|
||||
*
|
||||
* @DMX_PES_OTHER: any other PID.
|
||||
*/
|
||||
|
||||
typedef enum dmx_ts_pes
|
||||
{
|
||||
enum dmx_ts_pes {
|
||||
DMX_PES_AUDIO0,
|
||||
DMX_PES_VIDEO0,
|
||||
DMX_PES_TELETEXT0,
|
||||
@@ -78,7 +125,7 @@ typedef enum dmx_ts_pes
|
||||
DMX_PES_PCR3,
|
||||
|
||||
DMX_PES_OTHER
|
||||
} dmx_pes_type_t;
|
||||
};
|
||||
|
||||
#define DMX_PES_AUDIO DMX_PES_AUDIO0
|
||||
#define DMX_PES_VIDEO DMX_PES_VIDEO0
|
||||
@@ -87,69 +134,100 @@ typedef enum dmx_ts_pes
|
||||
#define DMX_PES_PCR DMX_PES_PCR0
|
||||
|
||||
|
||||
typedef struct dmx_filter
|
||||
{
|
||||
|
||||
/**
|
||||
* struct dmx_filter - Specifies a section header filter.
|
||||
*
|
||||
* @filter: bit array with bits to be matched at the section header.
|
||||
* @mask: bits that are valid at the filter bit array.
|
||||
* @mode: mode of match: if bit is zero, it will match if equal (positive
|
||||
* match); if bit is one, it will match if the bit is negated.
|
||||
*
|
||||
* Note: All arrays in this struct have a size of DMX_FILTER_SIZE (16 bytes).
|
||||
*/
|
||||
struct dmx_filter {
|
||||
__u8 filter[DMX_FILTER_SIZE];
|
||||
__u8 mask[DMX_FILTER_SIZE];
|
||||
__u8 mode[DMX_FILTER_SIZE];
|
||||
} dmx_filter_t;
|
||||
};
|
||||
|
||||
|
||||
struct dmx_sct_filter_params
|
||||
{
|
||||
__u16 pid;
|
||||
dmx_filter_t filter;
|
||||
__u32 timeout;
|
||||
__u32 flags;
|
||||
/**
|
||||
* struct dmx_sct_filter_params - Specifies a section filter.
|
||||
*
|
||||
* @pid: PID to be filtered.
|
||||
* @filter: section header filter, as defined by &struct dmx_filter.
|
||||
* @timeout: maximum time to filter, in milliseconds.
|
||||
* @flags: extra flags for the section filter.
|
||||
*
|
||||
* Carries the configuration for a MPEG-TS section filter.
|
||||
*
|
||||
* The @flags can be:
|
||||
*
|
||||
* - %DMX_CHECK_CRC - only deliver sections where the CRC check succeeded;
|
||||
* - %DMX_ONESHOT - disable the section filter after one section
|
||||
* has been delivered;
|
||||
* - %DMX_IMMEDIATE_START - Start filter immediately without requiring a
|
||||
* :ref:`DMX_START`.
|
||||
*/
|
||||
struct dmx_sct_filter_params {
|
||||
__u16 pid;
|
||||
struct dmx_filter filter;
|
||||
__u32 timeout;
|
||||
__u32 flags;
|
||||
#define DMX_CHECK_CRC 1
|
||||
#define DMX_ONESHOT 2
|
||||
#define DMX_IMMEDIATE_START 4
|
||||
#define DMX_KERNEL_CLIENT 0x8000
|
||||
};
|
||||
|
||||
|
||||
struct dmx_pes_filter_params
|
||||
{
|
||||
__u16 pid;
|
||||
dmx_input_t input;
|
||||
dmx_output_t output;
|
||||
dmx_pes_type_t pes_type;
|
||||
__u32 flags;
|
||||
/**
|
||||
* struct dmx_pes_filter_params - Specifies Packetized Elementary Stream (PES)
|
||||
* filter parameters.
|
||||
*
|
||||
* @pid: PID to be filtered.
|
||||
* @input: Demux input, as specified by &enum dmx_input.
|
||||
* @output: Demux output, as specified by &enum dmx_output.
|
||||
* @pes_type: Type of the pes filter, as specified by &enum dmx_pes_type.
|
||||
* @flags: Demux PES flags.
|
||||
*/
|
||||
struct dmx_pes_filter_params {
|
||||
__u16 pid;
|
||||
enum dmx_input input;
|
||||
enum dmx_output output;
|
||||
enum dmx_ts_pes pes_type;
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
typedef struct dmx_caps {
|
||||
__u32 caps;
|
||||
int num_decoders;
|
||||
} dmx_caps_t;
|
||||
|
||||
typedef enum {
|
||||
DMX_SOURCE_FRONT0 = 0,
|
||||
DMX_SOURCE_FRONT1,
|
||||
DMX_SOURCE_FRONT2,
|
||||
DMX_SOURCE_FRONT3,
|
||||
DMX_SOURCE_DVR0 = 16,
|
||||
DMX_SOURCE_DVR1,
|
||||
DMX_SOURCE_DVR2,
|
||||
DMX_SOURCE_DVR3
|
||||
} dmx_source_t;
|
||||
|
||||
/**
|
||||
* struct dmx_stc - Stores System Time Counter (STC) information.
|
||||
*
|
||||
* @num: input data: number of the STC, from 0 to N.
|
||||
* @base: output: divisor for STC to get 90 kHz clock.
|
||||
* @stc: output: stc in @base * 90 kHz units.
|
||||
*/
|
||||
struct dmx_stc {
|
||||
unsigned int num; /* input : which STC? 0..N */
|
||||
unsigned int base; /* output: divisor for stc to get 90 kHz clock */
|
||||
__u64 stc; /* output: stc in 'base'*90 kHz units */
|
||||
unsigned int num;
|
||||
unsigned int base;
|
||||
__u64 stc;
|
||||
};
|
||||
|
||||
|
||||
#define DMX_START _IO('o', 41)
|
||||
#define DMX_STOP _IO('o', 42)
|
||||
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
|
||||
#define DMX_SET_PES_FILTER _IOW('o', 44, struct dmx_pes_filter_params)
|
||||
#define DMX_SET_BUFFER_SIZE _IO('o', 45)
|
||||
#define DMX_GET_PES_PIDS _IOR('o', 47, __u16[5])
|
||||
#define DMX_GET_CAPS _IOR('o', 48, dmx_caps_t)
|
||||
#define DMX_SET_SOURCE _IOW('o', 49, dmx_source_t)
|
||||
#define DMX_GET_STC _IOWR('o', 50, struct dmx_stc)
|
||||
#define DMX_ADD_PID _IOW('o', 51, __u16)
|
||||
#define DMX_REMOVE_PID _IOW('o', 52, __u16)
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
/* This is needed for legacy userspace support */
|
||||
typedef enum dmx_output dmx_output_t;
|
||||
typedef enum dmx_input dmx_input_t;
|
||||
typedef enum dmx_ts_pes dmx_pes_type_t;
|
||||
typedef struct dmx_filter dmx_filter_t;
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _UAPI_DVBDMX_H_ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,4 +19,19 @@ struct dvb_mod_channel_params {
|
||||
#define DVB_MOD_SET _IOW('o', 208, struct dvb_mod_params)
|
||||
#define DVB_MOD_CHANNEL_SET _IOW('o', 209, struct dvb_mod_channel_params)
|
||||
|
||||
#define MODULATOR_UNDEFINED 0
|
||||
#define MODULATOR_START 1
|
||||
#define MODULATOR_STOP 2
|
||||
#define MODULATOR_FREQUENCY 3
|
||||
#define MODULATOR_MODULATION 4
|
||||
#define MODULATOR_SYMBOL_RATE 5 /* Hz */
|
||||
#define MODULATOR_BASE_FREQUENCY 6
|
||||
#define MODULATOR_ATTENUATOR 32
|
||||
#define MODULATOR_INPUT_BITRATE 33 /* Hz */
|
||||
#define MODULATOR_PCR_MODE 34 /* 1=pcr correction enabled */
|
||||
#define MODULATOR_GAIN 35
|
||||
#define MODULATOR_RESET 36
|
||||
#define MODULATOR_STATUS 37
|
||||
#define MODULATOR_OUTPUT_ARI 64
|
||||
|
||||
#endif /*_UAPI_DVBMOD_H_*/
|
||||
|
||||
@@ -26,6 +26,21 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* struct dvb_net_if - describes a DVB network interface
|
||||
*
|
||||
* @pid: Packet ID (PID) of the MPEG-TS that contains data
|
||||
* @if_num: number of the Digital TV interface.
|
||||
* @feedtype: Encapsulation type of the feed.
|
||||
*
|
||||
* A MPEG-TS stream may contain packet IDs with IP packages on it.
|
||||
* This struct describes it, and the type of encoding.
|
||||
*
|
||||
* @feedtype can be:
|
||||
*
|
||||
* - %DVB_NET_FEEDTYPE_MPE for MPE encoding
|
||||
* - %DVB_NET_FEEDTYPE_ULE for ULE encoding.
|
||||
*/
|
||||
struct dvb_net_if {
|
||||
__u16 pid;
|
||||
__u16 if_num;
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
#define _DVBVERSION_H_
|
||||
|
||||
#define DVB_API_VERSION 5
|
||||
#define DVB_API_VERSION_MINOR 10
|
||||
#define DVB_API_VERSION_MINOR 11
|
||||
|
||||
#endif /*_DVBVERSION_H_*/
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#ifndef __KERNEL__
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
@@ -139,7 +138,8 @@ struct video_event {
|
||||
#define VIDEO_EVENT_FRAME_RATE_CHANGED 2
|
||||
#define VIDEO_EVENT_DECODER_STOPPED 3
|
||||
#define VIDEO_EVENT_VSYNC 4
|
||||
__kernel_time_t timestamp;
|
||||
/* unused, make sure to use atomic time for y2038 if it ever gets used */
|
||||
long timestamp;
|
||||
union {
|
||||
video_size_t size;
|
||||
unsigned int frame_rate; /* in frames per 1000sec */
|
||||
@@ -211,7 +211,8 @@ typedef __u16 video_attributes_t;
|
||||
/* 6 line 21-2 data present in GOP (1=yes, 0=no) */
|
||||
/* 5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 */
|
||||
/* 2 source letterboxed (1=yes, 0=no) */
|
||||
/* 0 film/camera mode (0=camera, 1=film (625/50 only)) */
|
||||
/* 0 film/camera mode (0=
|
||||
*camera, 1=film (625/50 only)) */
|
||||
|
||||
|
||||
/* bit definitions for capabilities: */
|
||||
|
||||
Reference in New Issue
Block a user