Compare commits

..

No commits in common. "master" and "0.9.23" have entirely different histories.

164 changed files with 49649 additions and 71218 deletions

8
.gitignore vendored
View File

@ -1,3 +1,7 @@
#
# Normal rules
#
.*
*.o
*.o.*
@ -7,9 +11,5 @@
*.so
*.so.dbg
*.orig
*.mod.c
*.ko
*~
\#*#
Module.symvers
modules.order

View File

@ -1,10 +1,3 @@
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
0.9.19c 2015.07.20
- MAX S8:
do not turn on diseqc and tuners on init

View File

@ -1,339 +0,0 @@
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.

6
Kbuild
View File

@ -2,12 +2,6 @@
# Makefile for the kernel multimedia device drivers.
#
ifeq ($(KERNEL_DVB_CORE),y)
obj-y := ddbridge/ \
frontends/
else
obj-y := dvb-core/ \
ddbridge/ \
frontends/
endif

View File

@ -1,41 +1,19 @@
kernelver ?= $(shell uname -r)
MDIR ?=
KDIR ?= /lib/modules/$(kernelver)/build
KDIR ?= /lib/modules/$(shell uname -r)/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 DDDVB=y
KBUILD_EXTMOD = $(PWD)
ifeq ($(KERNEL_DVB_CORE),y)
DDDVB_INC = "--include=$(KBUILD_EXTMOD)/include/dd_compat.h -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD) -DKERNEL_DVB_CORE=y"
else
MODDEFS += CONFIG_DVB_NET=y
DDDVB_INC = "--include=$(KBUILD_EXTMOD)/include/dd_compat.h -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/include/linux"
endif
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
all:
$(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) $(MODDEFS) modules NOSTDINC_FLAGS=$(DDDVB_INC)
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) $(MODDEFS) modules
$(MAKE) -C apps
libdddvb:
$(MAKE) -C lib
libdddvb-install:
$(MAKE) -C lib install
libdddvb-clean:
$(MAKE) -C lib clean
dep:
DIR=`pwd`; (cd $(TOPDIR); make KBUILD_EXTMOD=$$DIR dep)
DIR=`pwd`; (cd $(TOPDIR); make SUBDIRS=$$DIR dep)
install: all
$(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) INSTALL_MOD_PATH=$(MDIR) modules_install
depmod $(kernelver)
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules_install
clean:
rm -rf */.*.o.d */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules*
$(MAKE) -C apps clean
rm -rf */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules*

View File

@ -1,33 +1,11 @@
# DDBridge Driver
Device driver for all Digital Devices DVB demodulator and modulator cards.
###Prepare for Building
### Patches
We can only accept patches which don't break compilation for older kernels (as far back as 2.6.37).
TBD
Due to this and other changes not approved by us the kernel version of the ddbridge driver might contain
incompatiblities to this driver package.
###Building
For installation instructions see:
http://support.digital-devices.eu/index.php?article=152
TBD
To compile against the dvb-core of a current kernel compile with KERNEL_DVB_CORE=y:
make KERNEL_DVB_CORE=y install
This will only work with current mainline kernels.
Some features will also not work correctly with the mainline kernel dvb-core:
- some devices will have fewer delivery systems enumerated
if one you need is missing you will have to fix it yourself
- the DTV_INPUT property will not work
- local bugfixes in dvb-core will be missing
- Some device names will be different because they do not exist in the kernel
Also, do not forget to delete old dvb-core modules from e.g. /lib/modules/x.y.z-amd64/updates/ !

View File

@ -1,34 +1,19 @@
TARGETS = cit ddtest setmod1 setmod2 modconfig ddinfo getiq modtest ddlicense
all: $(TARGETS)
CFLAGS = -g -Wall -Wno-unused -Wno-format
FFMPEG := $(shell command -v ffmpeg 2> /dev/null)
modtest: modtest.c
$(CC) -o modtest modtest.c -I../include/ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
test.ts:
ifndef FFMPEG
$(error "ffmpeg is not available please install to create test.ts")
endif
ffmpeg -f lavfi -i testsrc=duration=10:size=1280x720:rate=30 \
-f lavfi -i sine=f=440:b=4 -shortest -metadata \
service_provider="DD" -metadata service_name="Test" test.ts
all: cit citin flashprog modt ddtest setmod ddflash
cit: cit.c
$(CC) -o cit cit.c -lpthread
gcc -o cit cit.c -lpthread
%: %.c
$(CC) $(CFLAGS) -I../ddbridge -I../include/ $< -o $@
modt: modt.c
gcc -o modt modt.c -lpthread
%.o: %.c
$(CC) $(CFLAGS) -I../ddbridge -o $@ $<
setmod: setmod.c
gcc -o setmod setmod.c -I../include/
clean:
rm test.ts -f
for f in $(TARGETS) *.o *~ ; do \
if [ -e "$$f" ]; then \
rm "$$f" || exit 1; \
fi \
done
flashprog: flashprog.c
gcc -o flashprog flashprog.c
ddtest: ddtest.c
gcc -o ddtest ddtest.c
ddflash: ddflash.c
gcc -o ddflash ddflash.c

View File

@ -9,10 +9,6 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <getopt.h>
#include <linux/dvb/ca.h>
uint32_t adapter = 0, device = 0, snum = 256, rnum = 256, do_reset = 0;
uint8_t fill[188]={0x47, 0x1f, 0xff, 0x10,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
@ -28,7 +24,6 @@ uint8_t fill[188]={0x47, 0x1f, 0xff, 0x10,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff };
#if 0
uint8_t ts[188]={0x47, 0x0a, 0xaa, 0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
@ -42,21 +37,6 @@ uint8_t ts[188]={0x47, 0x0a, 0xaa, 0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff };
#else
uint8_t ts[188]={0x47, 0x0a, 0xaa, 0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa };
#endif
void proc_buf(uint8_t *buf, uint32_t *d)
{
@ -84,45 +64,28 @@ void proc_buf(uint8_t *buf, uint32_t *d)
c=(buf[4]<<24)|(buf[5]<<16)|(buf[6]<<8)|buf[7];
if (c!=*d) {
printf("CONT ERROR: got %08x expected %08x\n", c, *d);
//if (!*d && (c+100) > 100)
// return;
*d=c;
} else {
if (memcmp(ts+8, buf+8, 180))
printf("error\n");
if (!(c&0xffff)) {
printf("R %08x\r", c);
fflush(0);
}
if (!(c&0xffff))
printf("R %08x\n", c);
}
(*d)++;
}
void *get_ts(void *a)
{
uint8_t *buf;
uint8_t buf[188*1024];
int len, off;
int fdi;
char fname[80];
int fdi=open("/dev/dvb/adapter2/ci0", O_RDONLY);
uint32_t d=0;
buf = malloc(188*rnum);
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);
len=read(fdi, buf, 188*1024);
if (len<0)
continue;
//printf("read %u\n", len);
if (buf[0]!=0x47) {
read(fdi, buf, 1);
continue;
@ -133,28 +96,20 @@ void *get_ts(void *a)
}
}
int send(void)
#define SNUM 233
//671
void send(void)
{
uint8_t *buf, *cts;
uint8_t buf[188*SNUM], *cts;
int i;
uint32_t c=0;
int fdo;
char fname[80];
buf = malloc(188*snum);
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);
}
fdo=open("/dev/dvb/adapter2/ci0", O_WRONLY);
while (1) {
for (i=0; i<snum; i++) {
for (i=0; i<SNUM; i++) {
cts=buf+i*188;
memcpy(cts, ts, 188);
cts[4]=(c>>24);
@ -167,94 +122,15 @@ int send(void)
//usleep(100000+0xffff&rand());
//usleep(1000);
}
write(fdo, buf, 188*snum);
write(fdo, buf, 188*SNUM);
}
}
void reset()
{
char fname[80];
int fd, i;
sprintf(fname, "/dev/dvb/adapter%u/ca%u", adapter, device);
fd=open(fname, O_WRONLY);
if (fd < 0)
return;
ioctl(fd, CA_RESET);
for (i=0; i<24; i++) {
ca_slot_info_t info;
usleep(500000);
info.num = 0;
if (ioctl(fd, CA_GET_SLOT_INFO, &info))
return;
if (info.flags & CA_CI_MODULE_READY)
break;
}
if (i==24)
dprintf(2, "RESET failed\n");
}
int main(int argc, char **argv)
int main()
{
pthread_t th;
while (1) {
int option_index = 0;
int c;
static struct option long_options[] = {
{"adapter", required_argument, 0, 'a'},
{"device", required_argument, 0, 'd'},
{"snum", required_argument, 0, 's'},
{"rnum", required_argument, 0, 'r'},
{"reset", no_argument, 0, 'R'},
{"help", no_argument , 0, 'h'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"a:d:hs:R",
long_options, &option_index);
if (c==-1)
break;
switch (c) {
case 'd':
device = strtoul(optarg, NULL, 10);
break;
case 'a':
adapter = strtoul(optarg, NULL, 10);
break;
case 's':
snum = strtoul(optarg, NULL, 10);
break;
case 'r':
rnum = strtoul(optarg, NULL, 10);
break;
case 'R':
do_reset = 1;
break;
case 'h':
printf("cit -a<adapter> -d<device>\n");
exit(-1);
default:
break;
}
}
if (optind < argc) {
printf("Warning: unused arguments\n");
}
if (do_reset) {
reset();
exit(0);
}
printf("adapter %d, device: %d\n", adapter, device);
memset(ts+8, 180, 0x5a);
pthread_create(&th, NULL, get_ts, NULL);
usleep(10000);

61
apps/citin.c Normal file
View File

@ -0,0 +1,61 @@
#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 <linux/dvb/dmx.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/video.h>
void proc_ts(int i, uint8_t *buf)
{
uint16_t pid=0x1fff&((buf[1]<<8)|buf[2]);
if (buf[3]&0xc0) /* only descrambled packets */
return;
/* only ORF */
if (pid==160 || pid==161 || pid==1001||pid==13001 || pid==0)
write(1, buf, 188);
}
#define TSBUFSIZE (100*188)
void citest()
{
uint8_t *buf;
uint8_t id;
int i, nts;
int len;
int ts=open("/dev/dvb/adapter4/ci0", O_RDONLY);
buf=(uint8_t *)malloc(TSBUFSIZE);
while(1) {
len=read(ts, buf, TSBUFSIZE);
if (len<0) {
continue;
}
if (buf[0]!=0x47) {
read(ts, buf, 1);
continue;
}
if (len%188) { /* should not happen */
printf("blah\n");
continue;
}
nts=len/188;
for (i=0; i<nts; i++)
proc_ts(i, buf+i*188);
}
}
int main()
{
citest();
}

55
apps/citout.c Normal file
View File

@ -0,0 +1,55 @@
#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 <linux/dvb/dmx.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/video.h>
#define TSBUFSIZE (100*188)
void citest()
{
uint8_t *buf;
uint8_t id;
int i, nts;
int len;
int ts0=open("/dev/dvb/adapter0/dvr0", O_RDONLY);
int ts1=open("/dev/dvb/adapter4/sec0", O_WRONLY);
int demux0=open("/dev/dvb/adapter0/demux0", O_RDWR);
struct dmx_pes_filter_params pesFilterParams;
pesFilterParams.input = DMX_IN_FRONTEND;
pesFilterParams.output = DMX_OUT_TS_TAP;
pesFilterParams.pes_type = DMX_PES_OTHER;
pesFilterParams.flags = DMX_IMMEDIATE_START;
pesFilterParams.pid = 8192;
if (ioctl(demux0, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
printf("Could not set PES filter\n");
return;
}
buf=(uint8_t *)malloc(TSBUFSIZE);
while(1) {
len=read(ts0, buf, TSBUFSIZE);
if (len<=0)
break;
if (buf[0]!=0x47)
printf("oops\n");
write(ts1, buf, len);
}
}
int main()
{
citest();
}

1
apps/ddflash.c Symbolic link
View File

@ -0,0 +1 @@
octonet/ddflash.c

View File

@ -1,593 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/types.h>
#include <getopt.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef uint64_t u64;
#include "../ddbridge/ddbridge-mci.h"
#include "../ddbridge/ddbridge-ioctl.h"
char *Rolloff[8] = {
"0.35",
"0.25",
"0.20",
"0.10",
"0.05",
"0.15",
"rsvd",
"rsvd",
};
void dump(uint8_t *b, int l)
{
int i, j;
for (j = 0; j < l; j += 16, b += 16) {
printf("%04x: ", j);
for (i = 0; i < 16; i++)
if (i + j < l)
printf("%02x ", b[i]);
else
printf(" ");
printf("\n");
}
}
void ldump(uint8_t *b, int l)
{
int i;
for (i = 0; i < l; i++)
printf("%02X", b[i]);
printf("\n");
}
void print_temp(struct mci_result *res)
{
printf("Die temperature = %u\n", res->sx8_bist.temperature);
}
int temp_info(int dev, uint32_t link)
{
struct ddb_mci_msg msg = {
.link = link,
.cmd.command = SX8_CMD_GETBIST,
};
int ret;
int i;
ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg);
if (ret < 0) {
printf("Error: %d %d\n", ret, errno);
return ret;
}
if (msg.res.status & 0x80) {
printf("MCI errror %02x\n", msg.res.status);
return ret;
}
print_temp(&msg.res);
printf("BIST info dump: ");
dump((uint8_t *) &msg.res, 16);
return ret;
}
#define SIZE_OF_ARRAY(a) (sizeof(a)/sizeof(a[0]))
char *DemodStatus[] = {
"Idle",
"IQ Mode",
"Wait for Signal",
"DVB-S2 Wait for MATYPE",
"DVB-S2 Wait for FEC",
"DVB-S1 Wait for FEC",
"Wait for TS",
"Unknown 7",
"Unknown 8",
"Unknown 9",
"Unknown 10",
"Unknown 11",
"Unknown 12",
"Unknown 13",
"Timeout",
"Locked",
"C2 Scan",
};
char* S2ModCods[32] = {
/* 0x00 */ "DummyPL" ,
// Legacy S2: index is S2_Modcod * 2 + short
/* 0x01 */ "QPSK 1/4" ,
/* 0x02 */ "QPSK 1/3" ,
/* 0x03 */ "QPSK 2/5" ,
/* 0x04 */ "QPSK 1/2" ,
/* 0x05 */ "QPSK 3/5" ,
/* 0x06 */ "QPSK 2/3" ,
/* 0x07 */ "QPSK 3/4" ,
/* 0x08 */ "QPSK 4/5" ,
/* 0x09 */ "QPSK 5/6" ,
/* 0x0A */ "QPSK 8/9" ,
/* 0x0B */ "QPSK 9/10" ,
/* 0x0C */ "8PSK 3/5" ,
/* 0x0D */ "8PSK 2/3" ,
/* 0x0E */ "8PSK 3/4" ,
/* 0x0F */ "8PSK 5/6" ,
/* 0x10 */ "8PSK 8/9" ,
/* 0x11 */ "8PSK 9/10" ,
/* 0x12 */ "16APSK 2/3" ,
/* 0x13 */ "16APSK 3/4" ,
/* 0x14 */ "16APSK 4/5" ,
/* 0x15 */ "16APSK 5/6" ,
/* 0x16 */ "16APSK 8/9" ,
/* 0x17 */ "16APSK 9/10" ,
/* 0x18 */ "32APSK 3/4" ,
/* 0x19 */ "32APSK 4/5" ,
/* 0x1A */ "32APSK 5/6" ,
/* 0x1B */ "32APSK 8/9" ,
/* 0x1C */ "32APSK 9/10" ,
/* 0x1D */ "rsvd 0x1D" ,
/* 0x1E */ "rsvd 0x1E" ,
/* 0x1F */ "rsvd 0x1F" ,
};
///* 129 */ "VLSNR1" ,
///* 131 */ "VLSNR2" ,
char* S2XModCods[59] = {
/* 0x42 */ "QPSK 13/45" ,
/* 0x43 */ "QPSK 9/20" ,
/* 0x44 */ "QPSK 11/20" ,
/* 0x45 */ "8APSK 5/9-L" ,
/* 0x46 */ "8APSK 26/45-L" ,
/* 0x47 */ "8PSK 23/36" ,
/* 0x48 */ "8PSK 25/36" ,
/* 0x49 */ "8PSK 13/18" ,
/* 0x4A */ "16APSK 1/2-L" ,
/* 0x4B */ "16APSK 8/15-L" ,
/* 0x4C */ "16APSK 5/9-L" ,
/* 0x4D */ "16APSK 26/45" ,
/* 0x4E */ "16APSK 3/5" ,
/* 0x4F */ "16APSK 3/5-L" ,
/* 0x50 */ "16APSK 28/45" ,
/* 0x51 */ "16APSK 23/36" ,
/* 0x52 */ "16APSK 2/3-L" ,
/* 0x53 */ "16APSK 25/36" ,
/* 0x54 */ "16APSK 13/18" ,
/* 0x55 */ "16APSK 7/9" ,
/* 0x56 */ "16APSK 77/90" ,
/* 0x57 */ "32APSK 2/3-L" ,
/* 0x58 */ "rsvd 32APSK" ,
/* 0x59 */ "32APSK 32/45" ,
/* 0x5A */ "32APSK 11/15" ,
/* 0x5B */ "32APSK 7/9" ,
/* 0x5C */ "64APSK 32/45-L" ,
/* 0x5D */ "64APSK 11/15" ,
/* 0x5E */ "rsvd 64APSK" ,
/* 0x5F */ "64APSK 7/9" ,
/* 0x60 */ "rsvd 64APSK" ,
/* 0x61 */ "64APSK 4/5" ,
/* 0x62 */ "rsvd 64APSK" ,
/* 0x63 */ "64APSK 5/6" ,
/* 0x64 */ "128APSK 3/4" ,
/* 0x65 */ "128APSK 7/9" ,
/* 0x66 */ "256APSK 29/45-L" ,
/* 0x67 */ "256APSK 2/3-L" ,
/* 0x68 */ "256APSK 31/45-L" ,
/* 0x69 */ "256APSK 32/45" ,
/* 0x6A */ "256APSK 11/15-L" ,
/* 0x6B */ "256APSK 3/4" ,
/* 0x6C */ "QPSK 11/45-S" ,
/* 0x6D */ "QPSK 4/15-S" ,
/* 0x6E */ "QPSK 14/45-S" ,
/* 0x6F */ "QPSK 7/15-S" ,
/* 0x70 */ "QPSK 8/15-S" ,
/* 0x71 */ "QPSK 32/45-S" ,
/* 0x72 */ "8PSK 7/15-S" ,
/* 0x73 */ "8PSK 8/15-S" ,
/* 0x74 */ "8PSK 26/45-S" ,
/* 0x75 */ "8PSK 32/45-S" ,
/* 0x76 */ "16APSK 7/15-S" ,
/* 0x77 */ "16APSK 8/15-S" ,
/* 0x78 */ "16APSK 26/45-S" ,
/* 0x79 */ "16APSK 3/5-S" ,
/* 0x7A */ "16APSK 32/45-S" ,
/* 0x7B */ "32APSK 2/3-S" ,
/* 0x7C */ "32APSK 32/45-S" ,
};
char* S2Xrsvd[] = {
/* 250 */ "rsvd 8PSK" ,
/* 251 */ "rsvd 16APSK" ,
/* 252 */ "rsvd 32APSK" ,
/* 253 */ "rsvd 64APSK" ,
/* 254 */ "rsvd 256APSK" ,
/* 255 */ "rsvd 1024APSK" ,
};
char* PunctureRates[32] = {
/* 0x00 */ "QPSK 1/2", // DVB-S1
/* 0x01 */ "QPSK 2/3", // DVB-S1
/* 0x02 */ "QPSK 3/4", // DVB-S1
/* 0x03 */ "QPSK 5/6", // DVB-S1
/* 0x04 */ "QPSK 6/7", // DSS
/* 0x05 */ "QPSK 7/8", // DVB-S1
/* 0x06 */ "rsvd 6.0",
/* 0x07 */ "rsvd 7.0",
};
int mci_bb(int dev, uint32_t link, uint8_t demod)
{
struct ddb_mci_msg msg = {
.link = link,
.cmd.command = MCI_CMD_GET_BBHEADER,
.cmd.demod = demod,
.cmd.get_bb_header.select = 0,
};
struct mci_result *res = &msg.res;
int ret;
int i;
ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg);
if (ret < 0) {
printf("Error: %d %d\n", ret, errno);
return ret;
}
if (res->bb_header.valid) {
printf("MATYPE1: %02x\n", res->bb_header.matype_1);
printf("MATYPE2: %02x\n", res->bb_header.matype_2);
}
return ret;
}
void print_info(int dev, uint32_t link, uint8_t demod, struct mci_result *res)
{
if (res->status == MCI_DEMOD_STOPPED) {
printf("\nDemod %u: stopped\n", demod);
return;
}
printf("\nDemod %u:\n", demod);
if (res->status == MCI_DEMOD_LOCKED) {
switch (res->mode) {
case 0:
case MX_MODE_DVBSX:
if (res->dvbs2_signal_info.standard != 1) {
int short_frame = 0, pilots = 0;
char *modcod = "unknown";
uint8_t pls = res->dvbs2_signal_info.pls_code;
if ((pls >= 128) || ((res->dvbs2_signal_info.roll_off & 0x7f) > 2))
printf("Demod Locked: DVB-S2X\n");
else
printf("Demod Locked: DVB-S2\n");
printf("PLS-Code: %u\n", res->dvbs2_signal_info.pls_code);
if (pls >= 250) {
pilots = 1;
modcod = S2Xrsvd[pls - 250];
} else if (pls >= 132) {
pilots = pls & 1;
short_frame = pls > 216;
modcod = S2XModCods[(pls - 132)/2];
} else if (pls < 128) {
pilots = pls & 1;
short_frame = pls & 2;
modcod = S2ModCods[pls / 4];
}
printf("ModCod: %s\n", modcod);
mci_bb(dev, link, demod);
printf("Roll-Off: %s\n", Rolloff[res->dvbs2_signal_info.roll_off & 7]);
printf("Pilots: %s\n", pilots ? "On" : "Off");
printf("Frame: %s\n", short_frame ? "Short" : "Normal");
} else {
printf("Demod Locked: DVB-S\n");
printf("PR: %s\n",
PunctureRates[res->dvbs2_signal_info.pls_code & 0x07]);
}
printf("Inversion: %s\n", (res->dvbs2_signal_info.roll_off & 0x80) ? "on": "off");
break;
case MX_MODE_DVBT:
printf("Locked DVB-T\n");
break;
case MX_MODE_DVBT2:
printf("Locked DVB-T2\n");
break;
}
printf("SNR: %.2f dB\n", (float) res->dvbs2_signal_info.signal_to_noise / 100);
printf("Packet Errors: %u\n", res->dvbs2_signal_info.packet_errors);
printf("BER Numerator: %u\n", res->dvbs2_signal_info.ber_numerator);
printf("BER Denom.: %u\n", res->dvbs2_signal_info.ber_denominator);
} else {
printf("Demod State: %s\n",
res->status < SIZE_OF_ARRAY(DemodStatus) ? DemodStatus[res->status] : "?");
}
printf("Frequency: %u Hz\n", res->dvbs2_signal_info.frequency);
printf("Symbol Rate: %u Symbols/s\n", res->dvbs2_signal_info.symbol_rate);
printf("Channel Power: %.2f dBm\n", (float) res->dvbs2_signal_info.channel_power / 100);
if (res->dvbs2_signal_info.band_power > -10000)
printf("Band Power: %.2f dBm\n", (float) res->dvbs2_signal_info.band_power / 100);
}
int readreg(int dev, uint32_t reg, uint32_t link, uint32_t *val)
{
struct ddb_reg ddbreg;
ddbreg.reg = reg + (link << 28);
if (ioctl(dev, IOCTL_DDB_READ_REG, &ddbreg) < 0)
return -1;
*val = ddbreg.val;
return 0;
}
void mci_firmware(int dev, uint32_t link, uint32_t base)
{
union {
uint32_t u[4];
char s[16];
} version;
base += 0xf0;
readreg(dev, base , link, &version.u[0]);
readreg(dev, base + 4, link, &version.u[1]);
readreg(dev, base + 8, link, &version.u[2]);
readreg(dev, base + 12, link, &version.u[3]);
printf("MCI firmware: %s.%d\n", &version.s, version.s[15]);
}
int mci_info(int dev, uint32_t link, uint8_t demod)
{
struct ddb_mci_msg msg = {
.link = link,
.cmd.command = MCI_CMD_GETSIGNALINFO,
.cmd.demod = demod
};
int ret;
ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg);
if (ret < 0) {
printf("Error: %d %d\n", ret, errno);
return ret;
}
print_info(dev, link, demod, &msg.res);
return ret;
}
void print_license(int dev, struct mci_result *res)
{
if (res->license.serial_number[0] == 0xff)
res->license.serial_number[0] = 0;
printf("SERNBR:%s\n", (char *) &res->license.serial_number);
printf("ID:");
ldump(res->license.ID, 8);
printf("LK:");
ldump(res->license.LK, 24);
}
int mci_license(int dev)
{
struct ddb_mci_msg msg = {
.link = 0,
.cmd.command = CMD_GET_SERIALNUMBER,
};
int ret;
ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg);
if (ret < 0) {
printf("Error: %d %d\n", ret, errno);
return ret;
}
print_license(dev, &msg.res);
return ret;
}
static int get_id(int fd, int link, struct ddb_id *id)
{
struct ddb_reg ddbreg;
if (link == 0) {
if (ioctl(fd, IOCTL_DDB_ID, id) < 0)
return -1;
return 0;
}
ddbreg.reg = 8 + (link << 28);
if (ioctl(fd, IOCTL_DDB_READ_REG, &ddbreg) < 0)
return -1;
id->vendor = ddbreg.val;
id->device = ddbreg.val >> 16;
ddbreg.reg = 12 + (link << 28);
if (ioctl(fd, IOCTL_DDB_READ_REG, &ddbreg) < 0)
return -1;
id->subvendor = ddbreg.val;
id->subdevice = ddbreg.val >> 16;
ddbreg.reg = 0 + (link << 28);
if (ioctl(fd, IOCTL_DDB_READ_REG, &ddbreg) < 0)
return -1;
id->hw = ddbreg.val;
ddbreg.reg = 4 + (link << 28);
if (ioctl(fd, IOCTL_DDB_READ_REG, &ddbreg) < 0)
return -1;
id->regmap = ddbreg.val;
return 0;
}
static char *id2name(uint16_t id)
{
switch (id) {
case 0x210:
return "FSM";
case 0x222:
return "MOD";
case 0x0009:
return "MAX SX8";
case 0x000b:
return "MAX SX8 Basic";
case 0x000a:
return "MAX M4";
case 0x0014:
return "MAX CI M2";
default:
return " ";
}
}
static int card_info(int ddbnum, int demod)
{
char ddbname[80];
struct ddb_id ddbid;
int ddb, ret, link, links = 1, i, num=8;
struct ddb_id id;
sprintf(ddbname, "/dev/ddbridge/card%d", ddbnum);
ddb = open(ddbname, O_RDWR);
if (ddb < 0)
return -3;
for (link = 0; link < links; link++) {
ret = get_id(ddb, link, &id);
if (ret < 0)
goto out;
if (!link) {
switch (id.device) {
case 0x20:
links = 4;
break;
case 0x300:
case 0x301:
case 0x307:
links = 2;
break;
default:
break;
}
}
printf("\n\nCard %s link %u id %04x (%s):\n",
ddbname, link, id.device, id2name(id.device));
printf("HW %08x REGMAP %08x FW %u.%u\n",
id.hw, id.regmap, (id.hw & 0xff0000) >> 16, (id.hw & 0xffff));
switch (id.device) {
case 0x0009:
case 0x000b:
temp_info(ddb, link);
case 0x000a:
case 0x0014:
if (id.device == 0x000a)
num = 4;
if (id.device == 0x0014)
num = 2;
mci_firmware(ddb, link, 0x600);
if (demod >= 0)
mci_info(ddb, link, demod);
else {
for (i = 0; i < num; i++)
mci_info(ddb, link, i);
}
break;
case 0x0210:
if (!(id.hw & 0x01000000))
break;
mci_firmware(ddb, link, 0x300);
printf("VEN:DD01\n");
printf("DEV:0210\n");
mci_license(ddb);
break;
default:
break;
}
}
out:
close(ddb);
return ret;
}
int main(int argc, char*argv[])
{
int fd = -1, all = 1, i, ret = 0;
char fn[128];
int32_t device = -1, demod = -1;
while (1) {
int cur_optind = optind ? optind : 1;
int option_index = 0;
int c;
static struct option long_options[] = {
{"device", required_argument, 0, 'd'},
{"demod", required_argument, 0, 'n'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "ad:n:",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'd':
device = strtoul(optarg, NULL, 0);
break;
case 'n':
demod = strtoul(optarg, NULL, 0);
break;
case 'a':
all = 1;
break;
default:
break;
}
}
if (optind < argc) {
printf("too many arguments\n");
exit(1);
}
if (device >=0)
ret = card_info(device, demod);
else
for (i = 0; i < 100; i++) {
ret = card_info(i, -1);
if (ret == -3) /* could not open, no more cards! */
break;
if (ret < 0)
return i; /* fatal error */
}
}

View File

@ -1,255 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/types.h>
#include <getopt.h>
#include <ctype.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef uint64_t u64;
#include "../ddbridge/ddbridge-mci.h"
#include "../ddbridge/ddbridge-ioctl.h"
static void dump(const uint8_t *b, int l)
{
int i, j;
for (j = 0; j < l; j += 16, b += 16) {
printf("%04x: ", j);
for (i = 0; i < 16; i++)
if (i + j < l)
printf("%02x ", b[i]);
else
printf(" ");
printf("\n");
}
}
static void ldump(FILE *f, uint8_t *b, int l)
{
int i;
for (i = 0; i < l; i++)
fprintf(f, "%02X", b[i]);
fprintf(f, "\n");
}
static int mci_get_license(int dev, uint8_t *ID, uint8_t *LK, uint8_t *SN)
{
struct ddb_mci_msg msg = {
.link = 0,
.cmd.command = CMD_GET_SERIALNUMBER,
};
int ret;
ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg);
if (ret < 0) {
dprintf(2, "Error: %d\n", ret, errno);
return ret;
}
if (msg.res.status != 0x00) {
dprintf(2, "MCI error: %02x, check firmware and license file.\n", msg.res.status);
return -1;
}
memcpy(ID, msg.res.license.ID, 8);
memcpy(LK, msg.res.license.LK, 24);
memcpy(SN, msg.res.license.serial_number, 24);
return 0;
}
static int mci_set_license(int dev, uint8_t *ID, uint8_t *LK)
{
struct ddb_mci_msg msg = {
.link = 0,
.cmd.command = CMD_IMPORT_LICENSE,
};
int ret;
memcpy(msg.cmd.license.ID, ID, 8);
memcpy(msg.cmd.license.LK, LK, 24);
ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg);
if (ret < 0) {
printf("Error: %d %d\n", ret, errno);
return ret;
}
if (msg.res.status != 0x00) {
dprintf(2, "MCI error: %02x, check firmware and license file.\n", msg.res.status);
return -1;
}
return ret;
}
static int GetHex(char* s, uint32_t nBytes, uint8_t *Buffer)
{
int i;
if( strlen(s) < (nBytes * 2) )
return -1;
for (i = 0; i < nBytes; i += 1) {
char d0, d1;
d0 = s[i*2];
if( !isxdigit(d0) ) return -1;
d1 = s[i*2+1];
if( !isxdigit(d1) ) return -1;
d0 = toupper(d0);
d1 = toupper(d1);
Buffer[i] =(uint8_t) ((d0 > '9' ? d0 - 'A' + 10 : d0 - '0') << 4) | ((d1 > '9' ? d1 - 'A' + 10 : d1 - '0'));
}
return (nBytes * 2);
}
static int get_id_lk(char *fn, uint8_t *ID, uint8_t *LK)
{
FILE *fin = fopen(fn, "r");
if (!fin) {
printf("License file not found\n");
return -1;
}
memset(ID, 0, 8);
memset(LK, 0xff, 24);
while (1) {
char s[128];
if (fgets(s, sizeof(s), fin) == NULL)
break;
if (strncmp(s,"ID:",3) == 0) {
if (GetHex(&s[3], 8, ID) < 0 )
return -1;
}
if (strncmp(s,"LK:",3) == 0) {
if (GetHex(&s[3],24, LK) < 0 )
return -1;
}
}
//dump(ID, 8);
//dump(LK, 24);
fclose(fin);
return 0;
}
static int get_license(int ddb, struct ddb_id *id, char *ename)
{
uint8_t ID[8], LK[24], SN[17];
int stat;
FILE *f = fopen(ename, "w+");
if (!f) {
dprintf(2, "Could not write to output file.\n");
return -1;
}
stat = mci_get_license(ddb, ID, LK, SN);
if (stat < 0) {
dprintf(2, "Could not read license.\n");
return stat;
}
if (SN[0] == 0xff)
SN[0] = 0;
fprintf(f, "VEN:%04X\n", id->vendor);
fprintf(f, "DEV:%04X\n", id->device);
fprintf(f, "SERNBR:%s\n", (char *) SN);
fprintf(f, "ID:");
ldump(f, ID, 8);
fprintf(f, "LK:");
ldump(f, LK, 24);
fclose(f);
return 0;
}
static int set_license(int ddb, char *iname)
{
uint8_t ID[8], LK[24];
int stat=0;
stat = get_id_lk(iname, ID, LK);
if (stat < 0)
return stat;
return mci_set_license(ddb, ID, LK);
}
static int get_set_license(int ddbnum, char *ename, char *iname)
{
int ddb, stat = 0;
char ddbname[80];
struct ddb_id id;
sprintf(ddbname, "/dev/ddbridge/card%d", ddbnum);
ddb = open(ddbname, O_RDWR);
if (ddb < 0) {
dprintf(2, "Error opening device %s\n", ddbname);
return -3;
}
if (ioctl(ddb, IOCTL_DDB_ID, &id) < 0) {
dprintf(2, "Unsupported device %s.\n", ddbname);
return -1;
}
if (id.device != 0x210) {
dprintf(2, "Unsupported device %s with ID %04x.\n", ddbname, id.device);
return -1;
}
if (ename)
stat = get_license(ddb, &id, ename);
if (iname)
stat = set_license(ddb, iname);
close(ddb);
return stat;
}
int main(int argc, char*argv[])
{
int fd = -1, all = 1, i, ret = 0;
char fn[128];
int32_t device = 0;
char *iname = 0, *ename = 0;
while (1) {
int cur_optind = optind ? optind : 1;
int option_index = 0;
int c;
static struct option long_options[] = {
{"device", required_argument, 0, 'd'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "ad:i:e:",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'd':
device = strtoul(optarg, NULL, 0);
break;
case 'a':
all = 1;
break;
case 'i':
iname = optarg;
break;
case 'e':
ename = optarg;
break;
default:
break;
}
}
if (optind < argc) {
printf("too many arguments\n");
exit(1);
}
if (!ename && !iname) {
dprintf(2, "Neither export nor import file name provided.\n");
return -1;
}
get_set_license(device, ename, iname);
return 0;
}

View File

@ -1 +0,0 @@
./octonet/flash.c

722
apps/flashprog.c Normal file
View File

@ -0,0 +1,722 @@
/*
/* flashprog - Programmer for flash on Digital Devices Octopus
*
* Copyright (C) 2010-2011 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
* 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 <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#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;
}
void get_id(int ddb, struct ddb_id *ddbid) {
uint8_t id[4];
if (ioctl(ddb, IOCTL_DDB_ID, ddbid)>=0)
return;
memset(ddbid, 0, sizeof(*ddbid));
flashread(ddb, id, 0, 4);
printf("%02x %02x %02x %02x\n",
id[0], id[1], id[2], id[3]);
ddbid->subvendor=(id[0] << 8) | id[1];
ddbid->subdevice=(id[2] << 8) | id[3];
}
int sure()
{
char c;
printf("\n\nWARNING! Flashing a new FPGA image might make your card unusable!\n");
printf("\n\nWARNUNG! Das Flashen eines neuen FPGA-Images kann Ihre Karte unbrauchbar machen.\n");
printf("\n\nAre you sure? y/n?");
printf("\n\nSind Sie sicher? y/n?");
fflush(0);
c = getchar();
if (c!='y') {
printf("\nFlashing aborted.\n\n");
return -1;
}
printf("\nStarting to flash\n\n");
return 0;
}
int main(int argc, char **argv)
{
char ddbname[80];
int type = 0;
struct ddb_id ddbid;
uint8_t *buffer;
int BufferSize = 0;
int BlockErase = 0;
uint32_t FlashOffset = 0x10000;
int ddb;
int i, err;
int SectorSize=0;
int FlashSize=0;
int Flash;
uint32_t svid=0, jump=0, dump=0;
int bin;
int ddbnum = 0;
int force = 0;
while (1) {
int option_index = 0;
int c;
static struct option long_options[] = {
{"svid", required_argument, NULL, 's'},
{"help", no_argument , NULL, 'h'},
{"force", no_argument , NULL, 'f'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"d:n:s:o:l:dfhj",
long_options, &option_index);
if (c==-1)
break;
switch (c) {
case 'd':
dump = strtoul(optarg, NULL, 16);
break;
case 's':
svid = strtoul(optarg, NULL, 16);
break;
case 'o':
FlashOffset = strtoul(optarg, NULL, 16);
break;
case 'n':
ddbnum = strtol(optarg, NULL, 0);
break;
case 'l':
linknr = strtol(optarg, NULL, 0);
break;
case 'f':
force = 1;
break;
case 'j':
jump = 1;
break;
case 'h':
default:
break;
}
}
if (optind<argc) {
printf("Warning: unused arguments\n");
}
sprintf(ddbname, "/dev/ddbridge/card%d", ddbnum);
ddb=open(ddbname, O_RDWR);
if (ddb < 0) {
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;
}
get_id(ddb, &ddbid);
#if 1
printf("%04x %04x %04x %04x %08x %08x\n",
ddbid.vendor, ddbid.device,
ddbid.subvendor, ddbid.subdevice,
ddbid.hw, ddbid.regmap);
#endif
if (dump) {
flashdump(ddb, dump, 128);
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 (!SectorSize)
return 0;
if (jump) {
uint32_t Jump = 0x200000;
BufferSize = SectorSize;
FlashOffset = FlashSize - SectorSize;
buffer = malloc(BufferSize);
if (!buffer) {
printf("out of memory\n");
return 0;
}
memset(buffer, 0xFF, BufferSize);
memset(&buffer[BufferSize - 256 + 0x10], 0x00, 16);
buffer[BufferSize - 256 + 0x10] = 0xbd;
buffer[BufferSize - 256 + 0x11] = 0xb3;
buffer[BufferSize - 256 + 0x12] = 0xc4;
buffer[BufferSize - 256 + 0x1a] = 0xfe;
buffer[BufferSize - 256 + 0x1e] = 0x03;
buffer[BufferSize - 256 + 0x1f] = ( ( Jump >> 16 ) & 0xFF );
buffer[BufferSize - 256 + 0x20] = ( ( Jump >> 8 ) & 0xFF );
buffer[BufferSize - 256 + 0x21] = ( ( Jump ) & 0xFF );
} else if (svid) {
BufferSize = SectorSize;
FlashOffset = 0;
buffer = malloc(BufferSize);
if (!buffer) {
printf("out of memory\n");
return 0;
}
memset(buffer,0xFF,BufferSize);
buffer[0] = ((svid >> 24 ) & 0xFF);
buffer[1] = ((svid >> 16 ) & 0xFF);
buffer[2] = ((svid >> 8 ) & 0xFF);
buffer[3] = ((svid ) & 0xFF);
} 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:
fname="DVBBridgeV1A_DVBBridgeV1A.bit";
printf("Octopus 35\n");
break;
case 4:
fname="DVBBridgeV2A_DD01_0007_MXL.bit";
printf("Octopus 4/8\n");
break;
case 6:
fname="DVBBridgeV2B_DD01_0013_PRO.fpga";
printf("Octopus PRO\n");
break;
case 7:
fname="DVBBridgeV2B_DD01_0012_STD.fpga";
printf("Octopus CI\n");
break;
default:
printf("UNKNOWN\n");
break;
}
fh = open(fname, O_RDONLY);
if (fh < 0 ) {
printf("File not found \n");
return 0;
}
printf("Using bitstream %s\n", fname);
fsize = lseek(fh,0,SEEK_END);
if( fsize > 4000000 || fsize < SectorSize )
{
close(fh);
printf("Invalid File Size \n");
return 0;
}
if( Flash == ATMEL_AT45DB642D ) {
BlockErase = fsize >= 8192;
if( BlockErase )
BufferSize = (fsize + 8191) & ~8191;
else
BufferSize = (fsize + 1023) & ~1023;
} else {
BufferSize = (fsize + SectorSize - 1 ) & ~(SectorSize - 1);
}
printf(" Size %08x, target %08x\n", BufferSize, FlashOffset);
buffer = malloc(BufferSize);
if( buffer == NULL ) {
close(fh);
printf("out of memory\n");
return 0;
}
memset(buffer, 0xFF, BufferSize);
lseek(fh, 0, SEEK_SET);
read(fh, buffer, fsize);
close(fh);
if (BufferSize >= 0x10000) {
for(i = 0; i < 0x200; i += 1 ) {
if ( *(uint16_t *) (&buffer[i]) == 0xFFFF )
break;
buffer[i] = 0xFF;
}
}
}
if (!force && sure()<0)
return 0;
switch(Flash) {
case ATMEL_AT45DB642D:
err = FlashWriteAtmel(ddb,FlashOffset,buffer,BufferSize);
break;
case SSTI_SST25VF016B:
case SSTI_SST25VF032B:
err = FlashWriteSSTI_B(ddb,FlashOffset,buffer,BufferSize);
break;
case SSTI_SST25VF064C:
err = FlashWritePageMode(ddb,FlashOffset,buffer,BufferSize,0x3C);
break;
case SPANSION_S25FL116K:
err = FlashWritePageMode(ddb,FlashOffset,buffer,BufferSize,0x1C);
break;
}
if (err < 0)
printf("Programming Error\n");
else
printf("Programming Done\n");
free(buffer);
return 0;
}

View File

@ -1,100 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/types.h>
#include <getopt.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef uint64_t u64;
#include "../ddbridge/ddbridge-mci.h"
#include "../ddbridge/ddbridge-ioctl.h"
void print_iq(struct mci_result *res, int fd)
{
dprintf(fd, "%d,%d\n", res->iq_symbol.i, res->iq_symbol.q);
}
int get_iq(int dev, uint32_t link, uint8_t demod, int fd)
{
struct ddb_mci_msg msg = {
.link = link,
.cmd.command = MCI_CMD_GET_IQSYMBOL,
.cmd.demod = demod,
.cmd.get_iq_symbol.tap = 0,
.cmd.get_iq_symbol.point = 0,
};
int ret;
int i;
ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg);
if (ret < 0) {
printf("Error: %d %d\n", ret, errno);
return ret;
}
if (msg.res.status & 0x80) {
printf("MCI errror %02x\n", msg.res.status);
return ret;
}
print_iq(&msg.res, fd);
return ret;
}
#define SIZE_OF_ARRAY(a) (sizeof(a)/sizeof(a[0]))
int main(int argc, char*argv[])
{
char ddbname[80];
int fd = -1, all = 1, i, ret = 0, ddb;
char fn[128];
int32_t device = -1, demod = -1;
while (1) {
int cur_optind = optind ? optind : 1;
int option_index = 0;
int c;
static struct option long_options[] = {
{"device", required_argument, 0, 'd'},
{"demod", required_argument, 0, 'n'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "ad:n:",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'd':
device = strtoul(optarg, NULL, 0);
break;
case 'n':
demod = strtoul(optarg, NULL, 0);
break;
case 'a':
all = 1;
break;
default:
break;
}
}
if (optind < argc) {
printf("too many arguments\n");
exit(1);
}
sprintf(ddbname, "/dev/ddbridge/card%d", device);
ddb = open(ddbname, O_RDWR);
if (ddb < 0)
return -3;
for (i = 0; i < 20000; i++)
get_iq(ddb, 0, demod, 1);
}

View File

@ -1,550 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/types.h>
#include <getopt.h>
#include <ctype.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef uint64_t u64;
#include "../ddbridge/ddbridge-mci.h"
#include "../ddbridge/ddbridge-ioctl.h"
struct mconf {
int set_output;
int set_channels;
int fd;
int chanset;
struct mci_command channels;
struct mci_command stream;
struct mci_command output;
};
void dump(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 strim(char *s)
{
int l = strlen(s);
while (l && isspace(s[l-1]))
l--;
s[l] = 0;
}
int parse(char *fname, char *sec, void *priv, void (*cb)(void *, char *, char *))
{
char line[256], csec[80], par[80], val[80], *p;
FILE *f;
if ((f = fopen(fname, "r")) == NULL) {
dprintf(2, "Could not open %s\n", fname);
return -1;
}
while ((p = fgets(line, sizeof(line), f))) {
if (*p == '\r' || *p == '\n' || *p == '#')
continue;
if (*p == '[') {
if ((p = strtok(line + 1, "]")) == NULL)
continue;
strncpy(csec, p, sizeof(csec));
if (!strcmp(sec, csec) && cb)
cb(priv, NULL, NULL);
continue;
}
if (!(p = strtok(line, "=")))
continue;
while (isspace(*p))
p++;
strncpy(par, p, sizeof(par));
strim(par);
if (!(p = strtok(NULL, "=")))
continue;
while (isspace(*p))
p++;
strncpy (val, p, sizeof(val));
strim(val);
if (!strcmp(sec, csec) && cb)
cb(priv, par, val);
}
if (!strcmp(sec, csec) && cb)
cb(priv, NULL, NULL);
fclose(f);
return 0;
}
struct param_table_entry {
int value;
char* name;
};
struct param_table_entry mod_standard_table[] = {
{ .name = "0", .value = MOD_STANDARD_GENERIC },
{ .name = "GENERIC", .value = MOD_STANDARD_GENERIC },
{ .name = "1", .value = MOD_STANDARD_DVBT_8 },
{ .name = "DVBT_8", .value = MOD_STANDARD_DVBT_8 },
{ .name = "DVBT2_8", .value = MOD_STANDARD_DVBT_8 },
{ .name = "2", .value = MOD_STANDARD_DVBT_7 },
{ .name = "DVBT_7", .value = MOD_STANDARD_DVBT_7 },
{ .name = "DVBT2_7", .value = MOD_STANDARD_DVBT_7 },
{ .name = "3", .value = MOD_STANDARD_DVBT_6 },
{ .name = "DVBT_6", .value = MOD_STANDARD_DVBT_6 },
{ .name = "DVBT2_6", .value = MOD_STANDARD_DVBT_6 },
{ .name = "4", .value = MOD_STANDARD_DVBT_5 },
{ .name = "DVBT_5", .value = MOD_STANDARD_DVBT_5 },
{ .name = "DVBT2_5", .value = MOD_STANDARD_DVBT_5 },
{ .name = "8", .value = MOD_STANDARD_DVBC_8 },
{ .name = "DVBC_8", .value = MOD_STANDARD_DVBC_8 },
{ .name = "9", .value = MOD_STANDARD_DVBC_7 },
{ .name = "DVBC_7", .value = MOD_STANDARD_DVBC_7 },
{ .name = "10", .value = MOD_STANDARD_DVBC_6 },
{ .name = "DVBC_6", .value = MOD_STANDARD_DVBC_6 },
{ .name = "11", .value = MOD_STANDARD_J83B_QAM64 },
{ .name = "J83B_QAM64", .value = MOD_STANDARD_J83B_QAM64 },
{ .name = "12", .value = MOD_STANDARD_J83B_QAM256 },
{ .name = "J83B_QAM256", .value = MOD_STANDARD_J83B_QAM256 },
{ .name = "13", .value = MOD_STANDARD_ISDBC_QAM64 },
{ .name = "ISDBC_QAM64", .value = MOD_STANDARD_ISDBC_QAM64 },
{ .name = "J83C_QAM64", .value = MOD_STANDARD_ISDBC_QAM64 },
{ .name = "14", .value = MOD_STANDARD_ISDBC_QAM256 },
{ .name = "ISDBC_QAM256", .value = MOD_STANDARD_ISDBC_QAM256 },
{ .name = "J83C_QAM256", .value = MOD_STANDARD_ISDBC_QAM256 },
{ .name = NULL, .value = 0 }
};
struct param_table_entry stream_format_table[] = {
{ .name = "0", .value = MOD_FORMAT_DEFAULT },
{ .name = "default", .value = MOD_FORMAT_DEFAULT },
{ .name = "1", .value = MOD_FORMAT_IQ16 },
{ .name = "IQ16", .value = MOD_FORMAT_IQ16 },
{ .name = "2", .value = MOD_FORMAT_IQ8 },
{ .name = "IQ8", .value = MOD_FORMAT_IQ8 },
{ .name = "3", .value = MOD_FORMAT_IDX8 },
{ .name = "IDX8", .value = MOD_FORMAT_IDX8 },
{ .name = "4", .value = MOD_FORMAT_TS },
{ .name = "TS", .value = MOD_FORMAT_TS },
{ .name = NULL, .value = 0 }
};
struct param_table_entry guard_interval_table[] = {
{ .name = "0", .value = MOD_DVBT_GI_1_32 },
{ .name = "1/32", .value = MOD_DVBT_GI_1_32 },
{ .name = "1", .value = MOD_DVBT_GI_1_16 },
{ .name = "1/16", .value = MOD_DVBT_GI_1_16 },
{ .name = "2", .value = MOD_DVBT_GI_1_8 },
{ .name = "1/8", .value = MOD_DVBT_GI_1_8 },
{ .name = "3", .value = MOD_DVBT_GI_1_4 },
{ .name = "1/4", .value = MOD_DVBT_GI_1_4 },
{ .name = NULL, .value = 0 }
};
struct param_table_entry puncture_rate_table[] = {
{ .name = "1", .value = MOD_DVBT_PR_1_2 },
{ .name = "1/2", .value = MOD_DVBT_PR_1_2 },
{ .name = "2", .value = MOD_DVBT_PR_2_3 },
{ .name = "2/3", .value = MOD_DVBT_PR_2_3 },
{ .name = "3", .value = MOD_DVBT_PR_3_4 },
{ .name = "3/4", .value = MOD_DVBT_PR_3_4 },
{ .name = "5", .value = MOD_DVBT_PR_5_6 },
{ .name = "5/6", .value = MOD_DVBT_PR_5_6 },
{ .name = "7", .value = MOD_DVBT_PR_7_8 },
{ .name = "7/8", .value = MOD_DVBT_PR_7_8 },
{ .name = NULL, .value = 0 }
};
struct param_table_entry dvbt_constellation_table[] = {
{ .name = "0", .value = MOD_DVBT_QPSK },
{ .name = "qpsk", .value = MOD_DVBT_QPSK },
{ .name = "1", .value = MOD_DVBT_16QAM },
{ .name = "16qam", .value = MOD_DVBT_16QAM },
{ .name = "qam16", .value = MOD_DVBT_16QAM },
{ .name = "2", .value = MOD_DVBT_64QAM },
{ .name = "64qam", .value = MOD_DVBT_64QAM },
{ .name = "qam64", .value = MOD_DVBT_64QAM },
{ .name = NULL, .value = 0 }
};
struct param_table_entry qam_modulation_table[] = {
{ .name = "0", .value = MOD_QAM_DVBC_16 },
{ .name = "qam_dvbc_16", .value = MOD_QAM_DVBC_16 },
{ .name = "1", .value = MOD_QAM_DVBC_32 },
{ .name = "qam_dvbc_32", .value = MOD_QAM_DVBC_32 },
{ .name = "2", .value = MOD_QAM_DVBC_64 },
{ .name = "qam_dvbc_64", .value = MOD_QAM_DVBC_64 },
{ .name = "3", .value = MOD_QAM_DVBC_128 },
{ .name = "qam_dvbc_128", .value = MOD_QAM_DVBC_128 },
{ .name = "4", .value = MOD_QAM_DVBC_256 },
{ .name = "qam_dvbc_256", .value = MOD_QAM_DVBC_256 },
{ .name = "5", .value = MOD_QAM_J83B_64 },
{ .name = "qam_j83b_64", .value = MOD_QAM_J83B_64 },
{ .name = "6", .value = MOD_QAM_DVBC_256 },
{ .name = "qam_j83b_256", .value = MOD_QAM_J83B_256 },
{ .name = "7", .value = MOD_QAM_GENERIC },
{ .name = "qam_generic", .value = MOD_QAM_GENERIC },
{ .name = "8", .value = MOD_QAM_ISDBC_64 },
{ .name = "qam_isdbc_64", .value = MOD_QAM_ISDBC_64 },
{ .name = "9", .value = MOD_QAM_ISDBC_256 },
{ .name = "qam_isdbc_256", .value = MOD_QAM_ISDBC_256 },
{ .name = NULL, .value = 0 }
};
int parse_param(char *val, struct param_table_entry *table, int *value) {
if (value) {
*value = 0;
if (table) {
while (table->name) {
if( !strcasecmp(val,table->name)) {
*value = table->value;
printf("%s=%u\n", val, *value);
return 0;
}
table++;
}
}
}
printf("unknown value %s\n", val);
return -1;
}
int mci_cmd(int dev, struct mci_command *cmd)
{
int ret;
struct ddb_mci_msg msg;
uint8_t status;
memset(&msg, 0, sizeof(msg));
msg.link = 0;
memcpy(&msg.cmd, cmd, sizeof(msg.cmd));
dump((uint8_t *) &msg.cmd, sizeof(msg.cmd));
ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg);
if (ret < 0) {
dprintf(2, "mci_cmd error %d (%s)\n", errno, strerror(errno));
return ret;
}
status = msg.res.status;
if (status == MCI_STATUS_OK)
return ret;
if (status == MCI_STATUS_UNSUPPORTED) {
dprintf(2, "Unsupported MCI command\n");
return ret;
}
if (status == MCI_STATUS_INVALID_PARAMETER) {
dprintf(2, "Invalid MCI parameters\n");
return ret;
}
return ret;
}
struct mci_command msg_channels = {
.mod_command = MOD_SETUP_CHANNELS,
.mod_channel = 0,
.mod_stream = 0,
.mod_setup_channels[0] = {
.flags = 0,
.standard = MOD_STANDARD_DVBT_8,
.num_channels = 25,
.frequency = 474000000,
},
};
struct mci_command msg_stream = {
.mod_command = MOD_SETUP_STREAM,
.mod_channel = 0,
.mod_stream = 0,
.mod_setup_stream = {
.standard = MOD_STANDARD_DVBC_8,
},
};
struct mci_command msg_output = {
.mod_command = MOD_SETUP_OUTPUT,
.mod_channel = 0,
.mod_stream = 0,
.mod_setup_output = {
.connector = MOD_CONNECTOR_F,
.num_channels = 16,
.unit = MOD_UNIT_DBUV,
.channel_power = 5000,
},
};
void output_cb(void *priv, char *par, char *val)
{
struct mconf *mc = (struct mconf *) priv;
if (!par && !val) {
mc->set_output = 1;
return;
}
if (!strcasecmp(par, "connector")) {
if (!strcasecmp(val, "F")) {
mc->output.mod_setup_output.connector = MOD_CONNECTOR_F;
} else if (!strcasecmp(val, "SMA")) {
mc->output.mod_setup_output.connector = MOD_CONNECTOR_SMA;
} else if (!strcasecmp(val, "OFF")) {
mc->output.mod_setup_output.connector = MOD_CONNECTOR_OFF;
} else
printf("invalid connector\n");
} else if (!strcasecmp(par, "power")) {
mc->output.mod_setup_output.channel_power = (int16_t) (strtod(val, NULL) * 100.0);
} else if (!strcasecmp(par, "channels")) {
mc->output.mod_setup_output.num_channels = strtol(val, NULL, 10);
} else if (!strcasecmp(par, "unit")) {
if (!strcasecmp(val, "DBUV")) {
mc->output.mod_setup_output.unit = MOD_UNIT_DBUV;
} else if (!strcasecmp(val, "DBM")) {
mc->output.mod_setup_output.unit = MOD_UNIT_DBM;
} else
printf("invalid unit\n");
} else
printf("invalid output parameter: %s\n", par);
}
void channels_cb(void *priv, char *par, char *val)
{
struct mconf *mc = (struct mconf *) priv;
int value;
if (!par && !val) {
mc->set_channels = 1;
return;
}
if (!strcasecmp(par, "frequency")) {
mc->chanset++;
if (mc->chanset > 3)
return;
mc->channels.mod_setup_channels[mc->chanset].frequency = (uint32_t) (strtod(val, NULL) * 1000000.0);
printf("frequency %u = %u\n", mc->chanset + 1, mc->channels.mod_setup_channels[mc->chanset].frequency);
} else
if (mc->chanset>=0 && mc->chanset < 4) {
if (!strcasecmp(par, "channels")) {
mc->channels.mod_setup_channels[mc->chanset].num_channels = strtol(val, NULL, 10);
printf("channels = %u\n", mc->channels.mod_setup_channels[mc->chanset].num_channels);
} else if (!strcasecmp(par, "standard")) {
if (!parse_param(val,mod_standard_table, &value))
mc->channels.mod_setup_channels[mc->chanset].standard = value;
printf("standard = %u\n", value);
} else if (!strcasecmp(par, "offset")) {
mc->channels.mod_setup_channels[mc->chanset].offset = (uint32_t) (strtod(val, NULL) * 1000000.0);
} else if (!strcasecmp(par, "bandwidth")) {
mc->channels.mod_setup_channels[mc->chanset].bandwidth = (uint32_t) (strtod(val, NULL) * 1000000.0);
mc->channels.mod_setup_channels[mc->chanset].offset =
mc->channels.mod_setup_channels[mc->chanset].bandwidth / 2;
} else
printf("invalid channels parameter: %s\n", par);
}
}
void streams_cb(void *priv, char *par, char *val)
{
struct mconf *mc = (struct mconf *) priv;
int value;
if (!par && !val) {
return;
}
if (!strcasecmp(par, "fft_size")) {
mc->stream.mod_setup_stream.ofdm.fft_size = strtol(val, NULL, 10);
} else if (!strcasecmp(par, "guard_interval")) {
if (!parse_param(val, guard_interval_table, &value))
mc->stream.mod_setup_stream.ofdm.guard_interval = value;
} else if (!strcasecmp(par, "puncture_rate")) {
if (!parse_param(val, puncture_rate_table, &value))
mc->stream.mod_setup_stream.ofdm.puncture_rate = value;
} else if (!strcasecmp(par, "constellation")) {
if (!parse_param(val,dvbt_constellation_table,&value))
mc->stream.mod_setup_stream.ofdm.constellation = value;
} else if (!strcasecmp(par, "cell_identifier")) {
mc->stream.mod_setup_stream.ofdm.cell_identifier = strtol(val, NULL, 0);
} else if (!strcasecmp(par, "modulation")) {
if (!parse_param(val, qam_modulation_table, &value))
mc->stream.mod_setup_stream.qam.modulation = value;
} else if (!strcasecmp(par, "rolloff")) {
mc->stream.mod_setup_stream.qam.rolloff = strtol(val, NULL, 0);
} else if (!strcasecmp(par, "standard")) {
if (!parse_param(val,mod_standard_table,&value))
mc->stream.mod_setup_stream.standard = value;
} else if (!strcasecmp(par, "stream_format")) {
if (!parse_param(val,stream_format_table,&value))
mc->stream.mod_setup_stream.stream_format = value;
} else if (!strcasecmp(par, "symbol_rate")) {
mc->stream.mod_setup_stream.symbol_rate = (uint32_t) (strtod(val, NULL) * 1000000.0);
} else if (!strcasecmp(par, "channel")) {
mc->stream.mod_channel = strtol(val, NULL, 10);
} else if (!strcasecmp(par, "stream")) {
mc->stream.mod_stream = strtol(val, NULL, 10);
printf("set stream %u to channel %u\n", mc->stream.mod_stream, mc->stream.mod_channel);
printf("%u %u %u %u %u %u %u %u\n",
mc->stream.mod_command,
mc->stream.mod_channel,
mc->stream.mod_stream,
mc->stream.mod_setup_stream.standard,
mc->stream.mod_setup_stream.symbol_rate,
mc->stream.mod_setup_stream.stream_format,
mc->stream.mod_setup_stream.qam.modulation,
mc->stream.mod_setup_stream.qam.rolloff);
mci_cmd(mc->fd, &mc->stream);
} else
printf("invalid streams parameter: %s = %s\n", par, val);
}
int mci_lic(int dev)
{
struct ddb_mci_msg msg = {
.cmd.command = CMD_EXPORT_LICENSE,
.cmd.get_bb_header.select = 0,
};
struct mci_result *res = &msg.res;
int ret;
int i;
ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg);
if (ret < 0) {
printf("Error: %d %d\n", ret, errno);
return ret;
}
if (res->bb_header.valid) {
printf("MATYPE1: %02x\n", res->bb_header.matype_1);
printf("MATYPE2: %02x\n", res->bb_header.matype_2);
}
//dump((const uint8_t *)&res->license, sizeof(res->license));
return ret;
}
int main(int argc, char*argv[])
{
int fd = -1;
char fn[128];
uint32_t device = 0;
char *configname = "modulator.conf";
struct mconf mc;
memset(&mc, 0, sizeof(mc));
mc.channels = msg_channels;
mc.stream = msg_stream;
mc.output = msg_output;
mc.chanset = -1;
while (1) {
int cur_optind = optind ? optind : 1;
int option_index = 0;
int c;
static struct option long_options[] = {
{"device", required_argument, 0, 'd'},
{"config", required_argument, 0, 'c'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "d:c:",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'd':
device = strtoul(optarg, NULL, 0);
break;
case 'c':
configname = optarg;
break;
case 'h':
dprintf(2, "modconfig [-d device_number] [-c config_file]\n");
break;
default:
break;
}
}
if (optind < argc) {
printf("too many arguments\n");
exit(1);
}
//snprintf(fn, 127, "/dev/ddbridge/card%u", device);
snprintf(fn, 127, "/dev/dvb/adapter%u/mod0", device);
fd = open(fn, O_RDWR);
if (fd < 0) {
dprintf(2, "Could not open %s\n", fn);
return -1;
}
//mci_lic(fd);
mc.fd = fd;
if (parse(configname, "channels", (void *) &mc, channels_cb))
exit(-1);
if (mc.set_channels) {
for (int i = 0; i <= mc.chanset; i++)
mc.channels.mod_setup_channels[i].flags = MOD_SETUP_FLAG_VALID;
mc.channels.mod_setup_channels[0].flags |= MOD_SETUP_FLAG_FIRST;
mc.channels.mod_setup_channels[mc.chanset].flags |= MOD_SETUP_FLAG_LAST;
printf("setting channels, %u groups.\n", mc.chanset + 1);
mci_cmd(fd, &mc.channels);
}
parse(configname, "streams", (void *) &mc, streams_cb);
parse(configname, "output", (void *) &mc, output_cb);
if (mc.set_output) {
printf("setting output.\n");
mci_cmd(fd, &mc.output);
}
}

36
apps/modt.c Normal file
View File

@ -0,0 +1,36 @@
#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>
#define SNUM 1000
//671
void send(void)
{
uint8_t buf[188*SNUM], *cts;
int i;
uint32_t c=0;
int fdo;
fdo=open("/dev/dvb/adapter0/mod0", O_WRONLY);
while (1) {
read(0, buf, sizeof(buf));
write(fdo, buf, 188*SNUM);
}
}
int main()
{
send();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,63 +0,0 @@
[output]
# connector = OFF, SMA or F
connector = F
# number of total channels to be used at the same time
# use lower number to have fewer channels but stronger signal per channel
channels = 16
# unit of power in DBUV or DBM
unit = DBUV
# power output in units of above unit
power = 70.0
# define channels:
# channels are frequency slots to which a stream (mod0, mod1 ...) can be assigned
[channels]
# frequency of channel 0, following channels are spaced according to set standard
# frequency parameter has to come first!
frequency = 474.0
# numbers of channels to allocate, starting from frequency below
# this defines 16 channels at 474, 474+8, 474+16, etc. Mhz
channels = 16
# standard: 0 = generic, 1 = DVB-T 8MHz, 2 = DVB-T 7 MHz, 3 = DVB-T 6 MHz
standard = DVBC_8
frequency = 640.0
channels = 8
standard = DVBC_8
[streams]
# number of streams depends on the card hardware
# streams correspond to devices mod0, mod1, ...
# channels are defined above in channels section
standard = DVBC_8
stream_format = TS
symbol_rate = 6.9
modulation = qam_dvbc_256
channel = 0
stream = 0
channel = 1
stream = 1
channel = 2
stream = 2
channel = 3
stream = 3
channel = 4
stream = 4
channel = 5
stream = 5
channel = 6
stream = 6
#symbol_rate = 6.5
#modulation = qam_dvbc_64
channel = 7
stream = 7

View File

@ -1,54 +0,0 @@
[output]
# connector = OFF, SMA or F
connector = F
# number of total channels to be used at the same time
# use lower number to have fewer channels but stronger signal per channel
channels = 16
# unit of power in DBUV or DBM
unit = DBUV
# power output in units of above unit
power = 90.0
# define channels:
# channels are frequency slots to which a stream (mod0, mod1 ...) can be assigned
[channels]
frequency = 474.0
# standard: 0 = generic, 1 = DVB-T 8MHz, 2 = DVB-T 7 MHz, 3 = DVB-T 6 MHz
standard = DVBT_8
# numbers of channels to allocate, starting from frequency below
# this defines 25 channels at 474, 474+8, 474+16, etc. Mhz
channels = 25
# frequency of channel 0, following channels are spaced according to set standard
[streams]
stream_format = TS
standard = DVBT_8
# number of streams depends on the card hardware
# streams correspond to devices mod0, mod1, ...
# channels are defined above in channels section
# 0 = 1/32, 1 = 1/16, 2 = 1/8, 3 = 1/4
guard_interval = 0
# 0 = 2K, 1 = 8K (2K not yet supported)
fft_size = 1
puncture_rate = 7/8
constellation = qam64
cell_identifier = 0
# all following streams will be set according to the last set other parameters
# example:
# this would set mod 1 to 474 MHz and mod0 to 482 MHz (474 + 8 MHz)
# both with guard interval 1/32 and 8K FFT
# and mod2 to 490MHz, guard interval 1/16 and 8K FFT
channel = 1
stream = 0
#
channel = 0
stream = 1
#
guard_interval = 1
channel = 2
stream = 2

View File

@ -1,21 +1,17 @@
all: ddtest octonet octokey ddflash ddupdate
all: ddtest octonet octokey ddflash
install: all
install -m 0755 ddtest $(DESTDIR)/usr/bin
install -m 0755 octonet $(DESTDIR)/usr/bin
install -m 0755 octokey $(DESTDIR)/usr/bin
install -m 0755 ddflash $(DESTDIR)/usr/bin
install -m 0755 ddupdate $(DESTDIR)/usr/bin
ddflash: ddflash.c flash.h flash.c
ddflash: ddflash.c
$(CC) -o ddflash ddflash.c
ddtest: ddtest.c flash.h flash.c
ddtest: ddtest.c
$(CC) -o ddtest ddtest.c
ddupdate: ddupdate.c flash.h flash.c
$(CC) -o ddupdate ddupdate.c
octonet: octonet.c
$(CC) -o octonet octonet.c

View File

@ -36,7 +36,794 @@
#include <linux/types.h>
#include "flash.h"
#include "flash.c"
static int reboot(uint32_t off)
{
FILE *f;
uint32_t time;
if ((f = fopen ("/sys/class/rtc/rtc0/since_epoch", "r")) == NULL)
return -1;
fscanf(f, "%u", &time);
fclose(f);
if ((f = fopen ("/sys/class/rtc/rtc0/wakealarm", "r+")) == NULL)
return -1;
fprintf(f, "%u", time + off);
fclose(f);
system("/sbin/poweroff");
return 0;
}
struct ddflash {
int fd;
struct ddb_id id;
uint32_t type;
uint32_t version;
uint32_t flash_type;
uint32_t sector_size;
uint32_t size;
uint32_t bufsize;
uint32_t block_erase;
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)
{
int err = 0;
uint8_t cmd[260];
int i, j;
uint32_t flen, blen;
blen = flen = lseek(dev, 0, SEEK_END) - fw_off;
if (blen % 0xff)
blen = (blen + 0xff) & 0xffffff00;
printf("blen = %u, flen = %u\n", blen, flen);
do {
cmd[0] = 0x50; // EWSR
err = flashio(ddf->fd, cmd, 1, NULL, 0);
if (err < 0)
break;
cmd[0] = 0x01; // WRSR
cmd[1] = 0x00; // BPx = 0, Unlock all blocks
err = flashio(ddf->fd, cmd, 2, NULL, 0);
if (err < 0)
break;
for (i = 0; i < flen; i += 4096) {
if ((i & 0xFFFF) == 0)
printf(" Erase %08x\n", FlashOffset + i);
cmd[0] = 0x06; // WREN
err = flashio(ddf->fd, 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(ddf->fd, cmd, 4, NULL, 0);
if (err < 0)
break;
while (1) {
cmd[0] = 0x05; // RDRS
err = flashio(ddf->fd, 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 = blen - 256; j >= 0; j -= 256 ) {
uint32_t len = 256;
ssize_t rlen;
if (lseek(dev, j + fw_off, SEEK_SET) < 0) {
printf("seek error\n");
return -1;
}
if (flen - j < 256) {
len = flen - j;
memset(ddf->buffer, 0xff, 256);
}
rlen = read(dev, ddf->buffer, len);
if (rlen < 0 || rlen != len) {
printf("file read error %d,%d at %u\n", rlen, errno, j);
return -1;
}
printf ("write %u bytes at %08x\n", len, j);
if ((j & 0xFFFF) == 0)
printf(" Programm %08x\n", FlashOffset + j);
cmd[0] = 0x06; // WREN
err = flashio(ddf->fd, 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], ddf->buffer, 256);
err = flashio(ddf->fd, cmd, 260, NULL, 0);
if (err < 0)
break;
while(1) {
cmd[0] = 0x05; // RDRS
err = flashio(ddf->fd, 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(ddf->fd, cmd, 1, NULL, 0);
if (err < 0)
break;
cmd[0] = 0x01; // WRSR
cmd[1] = LockBits; // BPx = 0, Lock all blocks
err = flashio(ddf->fd, cmd, 2, NULL, 0);
} while(0);
return err;
}
static int flashwrite_SSTI(struct ddflash *ddf, int fs, uint32_t FlashOffset, uint32_t maxlen, uint32_t fw_off)
{
int err = 0;
uint8_t cmd[6];
int i, j;
uint32_t flen, blen;
blen = flen = lseek(fs, 0, SEEK_END) - fw_off;
if (blen % 0xfff)
blen = (blen + 0xfff) & 0xfffff000;
printf("blen = %u, flen = %u\n", blen, flen);
do {
#if 1
cmd[0] = 0x50; // EWSR
err = flashio(ddf->fd, cmd, 1, NULL, 0);
if (err < 0)
break;
cmd[0] = 0x01; // WRSR
cmd[1] = 0x00; // BPx = 0, Unlock all blocks
err = flashio(ddf->fd, cmd, 2, NULL, 0);
if (err < 0 )
break;
for (i = 0; i < flen; i += 4096) {
if ((i & 0xFFFF) == 0 )
printf("Erase %08x\n", FlashOffset + i);
cmd[0] = 0x06; // WREN
err = flashio(ddf->fd, 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(ddf->fd,cmd,4,NULL,0);
if (err < 0 )
break;
while(1) {
cmd[0] = 0x05; // RDRS
err = flashio(ddf->fd,cmd,1,&cmd[0],1);
if (err < 0 ) break;
if ((cmd[0] & 0x01) == 0 ) break;
}
if (err < 0 ) break;
}
if (err < 0 )
break;
#endif
for (j = blen - 4096; j >= 0; j -= 4096 ) {
uint32_t len = 4096;
ssize_t rlen;
if (lseek(fs, j + fw_off, SEEK_SET) < 0) {
printf("seek error\n");
return -1;
}
if (flen - j < 4096) {
len = flen - j;
memset(ddf->buffer, 0xff, 4096);
}
rlen = read(fs, ddf->buffer, len);
if (rlen < 0 || rlen != len) {
printf("file read error %d,%d at %u\n", rlen, errno, j);
return -1;
}
printf ("write %u bytes at %08x\n", len, j);
if ((j & 0xFFFF) == 0 )
printf(" Program %08x\n",FlashOffset + j);
#if 1
for (i = 0; i < 4096; i += 2) {
if (i == 0) {
cmd[0] = 0x06; // WREN
err = flashio(ddf->fd, 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] = ddf->buffer[i];
cmd[5] = ddf->buffer[i + 1];
err = flashio(ddf->fd,cmd,6,NULL,0);
} else {
cmd[0] = 0xAD; // AAI
cmd[1] = ddf->buffer[i];
cmd[2] = ddf->buffer[i + 1];
err = flashio(ddf->fd,cmd,3,NULL,0);
}
if (err < 0 )
break;
while(1) {
cmd[0] = 0x05; // RDRS
err = flashio(ddf->fd,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(ddf->fd, cmd, 1, NULL, 0);
if (err < 0 )
break;
#endif
}
if (err < 0 ) break;
cmd[0] = 0x50; // EWSR
err = flashio(ddf->fd,cmd,1,NULL,0);
if (err < 0 ) break;
cmd[0] = 0x01; // WRSR
cmd[1] = 0x1C; // BPx = 0, Lock all blocks
err = flashio(ddf->fd,cmd,2,NULL,0);
} while(0);
return err;
}
static int flashwrite(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, uint32_t fw_off)
{
switch (ddf->flash_type) {
case SSTI_SST25VF016B:
case SSTI_SST25VF032B:
return flashwrite_SSTI(ddf, fs, addr, maxlen, fw_off);
case SSTI_SST25VF064C:
return flashwrite_pagemode(ddf, fs, addr, 0x3c, fw_off);
case SPANSION_S25FL116K:
case SPANSION_S25FL132K:
case SPANSION_S25FL164K:
return flashwrite_pagemode(ddf, fs, addr, 0x1c, fw_off);
}
return -1;
}
static int flashcmp(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, uint32_t fw_off)
{
off_t off;
uint32_t len;
int i, j, rlen;
uint8_t buf[256], buf2[256];
int bl = sizeof(buf);
off = lseek(fs, 0, SEEK_END);
if (off < 0)
return -1;
len = off - fw_off;
lseek(fs, fw_off, SEEK_SET);
if (len > maxlen) {
printf("file too big\n");
return -1;
}
printf("flash file len %u, compare to %08x in flash\n", len, addr);
for (j = 0; j < len; j += bl, addr += bl) {
if (len - j < bl)
bl = len - j;
flashread(ddf->fd, buf, addr, bl);
rlen = read(fs, buf2, bl);
if (rlen < 0 || rlen != bl) {
printf("read error\n");
return -1;
}
if (memcmp(buf, buf2, bl)) {
printf("flash differs at %08x (offset %u)\n", addr, j);
dump(buf, 32);
dump(buf2, 32);
return addr;
}
}
printf("flash same as file\n");
return -2;
}
static int flash_detect(struct ddflash *ddf)
{
uint8_t cmd = 0x9F;
uint8_t id[3];
int r = flashio(ddf->fd, &cmd, 1, id, 3);
if (r < 0)
return r;
if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x41) {
ddf->flash_type = SSTI_SST25VF016B;
printf("Flash: SSTI SST25VF016B 16 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x200000;
} else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4A) {
ddf->flash_type = SSTI_SST25VF032B;
printf("Flash: SSTI SST25VF032B 32 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x400000;
} else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4B) {
ddf->flash_type = SSTI_SST25VF064C;
printf("Flash: SSTI SST25VF064C 64 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x800000;
} else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x15) {
ddf->flash_type = SPANSION_S25FL116K;
printf("Flash: SPANSION S25FL116K 16 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x200000;
} else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x16) {
ddf->flash_type = SPANSION_S25FL132K;
printf("Flash: SPANSION S25FL132K 32 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x400000;
} else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x17) {
ddf->flash_type = SPANSION_S25FL164K;
printf("Flash: SPANSION S25FL164K 64 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x800000;
} else if (id[0] == 0x1F && id[1] == 0x28) {
ddf->flash_type = ATMEL_AT45DB642D;
printf("Flash: Atmel AT45DB642D 64 MBit\n");
ddf->sector_size = 1024;
ddf->size = 0x800000;
} else {
printf("Unknown Flash Flash ID = %02x %02x %02x\n", id[0], id[1], id[2]);
return -1;
}
if (ddf->sector_size) {
ddf->buffer = malloc(ddf->sector_size);
printf("allocated buffer %08x@%08x\n", ddf->sector_size, (uint32_t) ddf->buffer);
if (!ddf->buffer)
return -1;
}
return 0;
}
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];
if (ioctl(ddf->fd, IOCTL_DDB_ID, &ddf->id) < 0)
return -1;
#if 1
printf("%04x %04x %04x %04x %08x %08x\n",
ddf->id.vendor, ddf->id.device,
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;
}
static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off)
{
int fd, fsize, ret = 0;
off_t off;
uint32_t p, i;
uint8_t *buf;
uint8_t hdr[256];
unsigned int devid, version, length;
unsigned int cid[8];
int cids = 0;
uint32_t maxlen = 1024 * 1024;
fd = open(fn, O_RDONLY);
if (fd < 0) {
printf("%s: not found\n", fn);
return -1;
}
off = lseek(fd, 0, SEEK_END);
if (off < 0)
return -1;
fsize = off;
if (fsize > maxlen) {
close(fd);
return -1;
}
lseek(fd, 0, SEEK_SET);
buf = malloc(fsize);
if (!buf)
return -1;
read(fd, buf, fsize);
close(fd);
for (p = 0; p < fsize && buf[p]; p++) {
char *key = &buf[p], *val = NULL;
for (; p < fsize && buf[p] != 0x0a; p++) {
if (buf[p] == ':') {
buf[p] = 0;
val = &buf[p + 1];
}
}
if (val == NULL || p == fsize)
break;
buf[p] = 0;
//printf("%-20s:%s\n", key, val);
if (!strcasecmp(key, "Devid")) {
sscanf(val, "%x", &devid);
} else if (!strcasecmp(key, "Compat")) {
cids = sscanf(val, "%x,%x,%x,%x,%x,%x,%x,%x",
&cid[0], &cid[1], &cid[2], &cid[3],
&cid[4], &cid[5], &cid[6], &cid[7]);
if (cids < 1)
break;
for (i = 0; i < cids; i++)
if (cid[i] == ddf->id.device)
break;
if (i == cids) {
printf("%s: no compatible id\n", fn);
ret = -2; /* no compatible ID */
goto out;
}
} else if (!strcasecmp(key, "Version")) {
sscanf(val, "%x", &version);
} else if (!strcasecmp(key, "Length")) {
sscanf(val, "%u", &length);
}
}
p++;
*fw_off = p;
printf("devid = %04x\n", devid);
printf("version = %08x %08x\n", version, ddf->id.hw);
printf("length = %u\n", length);
printf("fsize = %u, p = %u, f-p = %u\n", fsize, p, fsize - p);
if (devid == ddf->id.device) {
if (version <= (ddf->id.hw & 0xffffff)) {
printf("%s: old version\n", fn);
ret = -3; /* same id but no newer version */
}
} else
ret = 1;
out:
free(buf);
printf("check_fw = %d\n", ret);
return ret;
}
static int update_image(struct ddflash *ddf, char *fn,
uint32_t adr, uint32_t len,
int has_header, int no_change)
{
int fs, res = 0;
uint32_t fw_off = 0;
printf("Check %s\n", fn);
if (has_header) {
int ck;
ck = check_fw(ddf, fn, &fw_off);
if (ck < 0)
return ck;
if (ck == 1 && no_change)
return 0;
}
fs = open(fn, O_RDONLY);
if (fs < 0 ) {
printf("File %s not found \n", fn);
return -1;
}
res = flashcmp(ddf, fs, adr, len, fw_off);
if (res == -2) {
printf("%s: same as flash\n", fn);
}
if (res < 0)
goto out;
res = flashwrite(ddf, fs, adr, len, fw_off);
if (res == 0)
res = 1;
out:
close(fs);
return res;
}
static int fexists(char *fn)
{
struct stat b;
return (!stat(fn, &b));
}
static int update_flash(struct ddflash *ddf)
{
@ -65,40 +852,18 @@ static int update_flash(struct ddflash *ddf)
if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 0)) == 1)
stat |= 1;
} else {
if (ddf->id.device == 0x0307) {
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)
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";
@ -107,13 +872,6 @@ 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;
}
@ -178,7 +936,6 @@ int main(int argc, char **argv)
return -1;
}
}
ddf.link = 0;
flash = flash_detect(&ddf);
if (flash < 0)
return -1;

View File

@ -1,4 +1,3 @@
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@ -10,10 +9,10 @@
#include <string.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <errno.h>
#include "flash.h"
#include "flash.c"
static uint32_t linknr = 0;
typedef int (*COMMAND_FUNCTION)(int dev, int argc, char* argv[], uint32_t Flags);
@ -22,6 +21,17 @@ 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;
@ -32,37 +42,102 @@ 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, &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, &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, S_IRWXU);
if (fd < 0) {
printf("Could not open file %s\n", argv[2]);
return -1;
}
}
Buffer = malloc(Len);
if (flashread(ddb, linknr, Buffer, Start, Len) < 0) {
if (flashread(ddb, Buffer, Start, Len) < 0) {
printf("flashread error\n");
free(Buffer);
return 0;
}
if (argc == 3) {
write(fd, Buffer, Len);
close(fd);
} else
Dump(Buffer,Start,Len);
free(Buffer);
@ -70,32 +145,62 @@ int ReadFlash(int ddb, int argc, char *argv[], uint32_t Flags)
}
int ReadSave(int ddb, int argc, char *argv[], uint32_t Flags)
int FlashDetect(int dev)
{
uint32_t Start;
uint32_t Len;
uint8_t *Buffer;
int fd;
uint8_t Cmd = 0x9F;
uint8_t Id[3];
if (argc < 3 )
return -1;
Start = strtoul(argv[0],NULL,16);
Len = strtoul(argv[1],NULL,16);
int r = FlashIO(dev, &Cmd, 1, Id, 3);
if (r < 0)
return r;
Buffer = malloc(Len);
if (flashread(ddb, linknr, Buffer, Start, Len) < 0) {
printf("flashread error\n");
free(Buffer);
return 0;
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;
}
free(Buffer);
return 0;
return r;
}
int FlashChipEraseAtmel(int dev)
{
int err = 0;
@ -110,12 +215,12 @@ int FlashChipEraseAtmel(int dev)
Cmd[1] = ( (( i ) >> 16) & 0xFF );
Cmd[2] = ( (( i ) >> 8) & 0xFF );
Cmd[3] = 0x00;
err = flashio(dev,linknr, 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,linknr, Cmd,1,&Cmd[0],1);
err = FlashIO(dev,Cmd,1,&Cmd[0],1);
if( err < 0 ) break;
if( (Cmd[0] & 0x80) == 0x80 ) break;
}
@ -133,25 +238,25 @@ int FlashChipEraseSSTI(int dev)
do {
Cmd[0] = 0x50; // EWSR
err = flashio(dev, linknr, 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, linknr, Cmd,2,NULL,0);
err = FlashIO(dev,Cmd,2,NULL,0);
if( err < 0 ) break;
Cmd[0] = 0x06; // WREN
err = flashio(dev, linknr, Cmd,1,NULL,0);
err = FlashIO(dev,Cmd,1,NULL,0);
if( err < 0 ) break;
Cmd[0] = 0x60; // CHIP Erase
err = flashio(dev, linknr, Cmd,1,NULL,0);
err = FlashIO(dev,Cmd,1,NULL,0);
if( err < 0 ) break;
while(1) {
Cmd[0] = 0x05; // RDRS
err = flashio(dev, linknr, Cmd,1,&Cmd[0],1);
err = FlashIO(dev,Cmd,1,&Cmd[0],1);
if( err < 0 ) break;
if( (Cmd[0] & 0x01) == 0 ) break;
}
@ -159,12 +264,12 @@ int FlashChipEraseSSTI(int dev)
break;
Cmd[0] = 0x50; // EWSR
err = flashio(dev, linknr, 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, linknr, Cmd,2,NULL,0);
err = FlashIO(dev,Cmd,2,NULL,0);
}
while(0);
@ -174,6 +279,286 @@ 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)
{
@ -309,7 +694,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;
@ -334,7 +719,7 @@ int flashioc(int dev,int argc, char* argv[],uint32_t Flags)
Buffer[i] = (uint8_t) tmp;
}
if( flashio(dev, linknr, Buffer,WriteLen,Buffer,ReadLen) < 0 )
if( FlashIO(dev,Buffer,WriteLen,Buffer,ReadLen) < 0 )
{
return 0;
}
@ -380,14 +765,15 @@ uint32_t GetFPGA_ID(uint8_t * Buffer)
}
int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
{
uint8_t * Buffer = NULL;
int BufferSize = 0;
int BlockErase = 0;
uint32_t FlashOffset = 0x10000;
uint32_t SectorSize = 0;
uint32_t FlashSize = 0;
int SectorSize = 0;
int FlashSize = 0;
int ValidateFPGAType = 1;
int Flash;
uint32_t Id1, Id2;
@ -404,10 +790,6 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
case SPANSION_S25FL116K: SectorSize = 4096; FlashSize = 0x200000; break;
case SPANSION_S25FL132K: SectorSize = 4096; FlashSize = 0x400000; break;
case SPANSION_S25FL164K: SectorSize = 4096; FlashSize = 0x800000; break;
case WINBOND_W25Q16JV: SectorSize = 4096; FlashSize = 0x200000; break;
case WINBOND_W25Q32JV: SectorSize = 4096; FlashSize = 0x400000; break;
case WINBOND_W25Q64JV: SectorSize = 4096; FlashSize = 0x800000; break;
case WINBOND_W25Q128JV: SectorSize = 4096; FlashSize = 0x1000000; break;
}
if (SectorSize == 0)
return 0;
@ -482,7 +864,7 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
int fsize = lseek(fh,0,SEEK_END);
if( fsize > 5000000 || fsize < SectorSize )
if( fsize > 4000000 || fsize < SectorSize )
{
close(fh);
printf("Invalid File Size \n");
@ -538,7 +920,7 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
printf("out of memory\n");
return 0;
}
if (flashread(dev, linknr, CmpBuffer, FlashOffset, 0x10000)<0) {
if (flashread(dev, CmpBuffer, FlashOffset, 0x10000)<0) {
printf("Ioctl returns error\n");
free(Buffer);
free(CmpBuffer);
@ -577,10 +959,6 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
case SPANSION_S25FL116K:
case SPANSION_S25FL132K:
case SPANSION_S25FL164K:
case WINBOND_W25Q16JV:
case WINBOND_W25Q32JV:
case WINBOND_W25Q64JV:
case WINBOND_W25Q128JV:
err = FlashWritePageMode(dev,FlashOffset,Buffer,BufferSize,0x1C); break;
}
@ -668,7 +1046,7 @@ int FlashVerify(int dev,int argc, char* argv[],uint32_t Flags)
// Place our own header
}
#endif
if (flashread(dev, linknr, Buffer2, FlashOffset, BufferSize)<0) {
if (flashread(dev, Buffer2, FlashOffset, BufferSize)<0) {
printf("Ioctl returns error\n");
free(Buffer);
free(Buffer2);
@ -732,7 +1110,6 @@ 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) {
@ -750,23 +1127,6 @@ 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;
}
@ -1120,7 +1480,7 @@ char *GetSerNbr(int dev)
int i;
memset(Buffer,0,sizeof(Buffer));
if (flashread(dev, linknr, Buffer, Start, sizeof(Buffer) - 1))
if (flashread(dev, Buffer, Start, sizeof(Buffer) - 1))
{
printf("Ioctl returns error\n");
return NULL;
@ -1292,192 +1652,6 @@ int lic_erase(int dev, int argc, char* argv[], uint32_t Flags)
return err;
}
static int read_sfpd(int dev, uint8_t adr, uint8_t *val)
{
uint8_t cmd[5] = { 0x5a, 0, 0, adr, 0 };
int r;
r = flashio(dev, linknr, cmd, 5, val, 1);
if (r < 0)
return r;
return 0;
}
static int read_sst_id(int dev, uint8_t *id)
{
uint8_t cmd[2] = { 0x88, 0 };
uint8_t buf[9];
int r;
r = flashio(dev, linknr, cmd, 2, buf, 9);
if (r < 0)
return r;
memcpy(id, buf + 1, 8);
return 0;
}
static int read_winbd(int dev, uint8_t *val)
{
uint8_t cmd[5] = { 0x4b, 0, 0, 0, 0 };
int r;
r = flashio(dev, linknr, cmd, 5, val, 8);
if (r < 0)
return r;
return 0;
}
int read_id(int dev, int argc, char* argv[], uint32_t Flags)
{
int Flash = FlashDetect(dev);
uint8_t Cmd;;
uint8_t Id[8];
uint32_t len, i, adr;
switch(Flash) {
case WINBOND_W25Q16JV:
case WINBOND_W25Q32JV:
case WINBOND_W25Q64JV:
case WINBOND_W25Q128JV:
read_winbd(dev, Id);
len = 8;
break;
case SPANSION_S25FL116K:
case SPANSION_S25FL132K:
case SPANSION_S25FL164K:
for (i = 0; i < 8; i++)
read_sfpd(dev, 0xf8 + i, &Id[i]);
len = 8;
break;
case SSTI_SST25VF064C:
read_sst_id(dev, Id);
len = 8;
break;
default:
printf("Unsupported Flash\n");
return -1;
}
printf("ID: ");
for (i = 0; i < len; i++)
printf("%02x ", Id[i]);
printf("\n");
return 0;
}
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[] =
{
@ -1486,13 +1660,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> [<Filename>]" },
{ "flashio", flashioc, 1, "Flash IO : flashio <write data>.. <read count>" },
{ "flashread", ReadFlash, 1, "Read Flash : flashread <start> <count>" },
{ "flashio", FlashIO, 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" },
@ -1502,9 +1676,6 @@ struct SCommand CommandTable[] =
{ "licimport", lic_import, 1, "License Import : licimport" },
{ "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 }
};

View File

@ -1,295 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include "flash.h"
#include "flash.c"
static int verbose = 0;
static int yesno()
{
char c;
printf("\n\nNew firmware available\nReally flash now? y/n\n");
fflush(0);
c = getchar();
if (c!='y') {
printf("\nFlashing aborted.\n\n");
return 0;
}
printf("\nStarting to flash\n\n");
return 1;
}
static int update_flash(struct ddflash *ddf)
{
char *fname, *default_fname;
int res, stat = 0;
char *name = 0, *dname;
uint32_t imgadr = 0x10000;
switch (ddf->id.device) {
case 0x300:
case 0x301:
case 0x302:
case 0x307:
if ((res = update_image(ddf, "/boot/bs.img", 0x4000, 0x1000, 0, 0)) == 1)
stat |= 4;
if ((res = update_image(ddf, "/boot/uboot.img", 0xb0000, 0xb0000, 0, 0)) == 1)
stat |= 2;
if (fexists("/config/gtl.enabled")) {
if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x10000, 0xa0000, 1, 0)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x10000, 0xa0000, 1, 0)) == 1)
stat |= 1;
} else if (fexists("/config/gtl.disabled")) {
if ((res = update_image(ddf, "/config/fpga.img", 0x10000, 0xa0000, 1, 0)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 0)) == 1)
stat |= 1;
} else {
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";
fname="/boot/fpga.img";
if ((res = update_image(ddf, fname, 0x10000, 0x100000, 1, 0)) == 1)
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:
{
uint32_t val;
if (!readreg(ddf->fd, (ddf->link << 28) | 0x10, &val)) {
//printf("reg0x10=%08x\n", val);
if ((val >> 24) == 5)
imgadr = 0;
}
}
fname = ddf->fname;
default_fname = devid2fname(ddf->id.device, &name);
if (!fname)
fname = default_fname;
if (name)
printf("Card: %s\n", name);
if (ddf->flash_name)
printf("Flash: %s\n", ddf->flash_name);
printf("Version: %08x\n", ddf->id.hw);
printf("REGMAP : %08x\n", ddf->id.regmap);
printf("Address: %08x\n", imgadr);
if ((res = update_image(ddf, fname, imgadr, ddf->size / 2, 1, 0)) == 1)
stat |= 1;
return stat;
}
return stat;
}
static int update_link(struct ddflash *ddf)
{
int ret;
ret = flash_detect(ddf);
if (ret < 0)
return ret;
ret = update_flash(ddf);
if (ddf->buffer)
free(ddf->buffer);
return ret;
}
static int update_card(int ddbnum, char *fname, int force)
{
struct ddflash ddf;
char ddbname[80];
struct ddb_id ddbid;
int ddb, ret, link, links;
sprintf(ddbname, "/dev/ddbridge/card%d", ddbnum);
ddb = open(ddbname, O_RDWR);
if (ddb < 0)
return -3;
ddf.fd = ddb;
ddf.link = 0;
ddf.fname = fname;
ddf.force = force;
links = 1;
for (link = 0; link < links; link++) {
ddf.link = link;
if (verbose >= 2)
printf("Get id card %u link %u\n", ddbnum, link);
ret = get_id(&ddf);
if (ret < 0)
goto out;
if (!link) {
switch (ddf.id.device) {
case 0x20:
links = 4;
break;
case 0x300:
case 0x301:
case 0x307:
links = 2;
break;
default:
break;
}
}
//printf("%08x %08x\n", ddf.id.device, ddf.id.subdevice);
if (ddf.id.device) {
printf("\n\nUpdate card %s link %u:\n", ddbname, link);
ret = update_link(&ddf);
//if (ret < 0)
// break;
}
}
out:
close(ddb);
return ret;
}
static int usage()
{
printf("ddupdate [OPTION]\n\n"
"-n N\n only update card N (default with N=0)\n\n"
"-a \n update all cards\n\n"
"-b file\n fpga image file override (ignored if -a is used)\n\n"
"-f \n force update\n\n"
"-v \n more verbose (up to -v -v -v)\n\n"
);
}
int main(int argc, char **argv)
{
int ddbnum = -1, all = 0, i, force = 0, reboot_len = -1;
char *fname = 0;
int ret;
while (1) {
int option_index = 0;
int c;
static struct option long_options[] = {
{"reboot", optional_argument , NULL, 'r'},
{"help", no_argument , NULL, 'h'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"n:havfb:r::",
long_options, &option_index);
if (c==-1)
break;
switch (c) {
case 'b':
fname = optarg;
break;
case 'n':
ddbnum = strtol(optarg, NULL, 0);
break;
case 'a':
all = 1;
break;
case 'f':
force = 1;
break;
case 'v':
verbose++;
break;
case 'r':
if (optarg)
reboot_len = strtol(optarg, NULL, 0);
else
reboot_len = 40;
if (!reboot_len)
reboot(40);
break;
case 'h':
usage();
return 0;
default:
break;
}
}
if (optind < argc) {
printf("Warning: unused arguments\n");
}
if (!all && (ddbnum < 0)) {
printf("Select card number or all cards\n\n");
usage();
return -1;
}
if (!all)
ret = update_card(ddbnum, fname, force);
else
for (i = 0; i < 100; i++) {
ret = update_card(i, 0, 0);
if (ret == -3) /* could not open, no more cards! */
break;
if (ret < 0)
return i; /* fatal error */
if (verbose >= 1)
printf("card %d up to date\n", i);
}
if (reboot_len > 0)
reboot(reboot_len);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -61,47 +61,3 @@ 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)
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,
WINBOND_W25Q16JV = 8,
WINBOND_W25Q32JV = 9,
WINBOND_W25Q64JV = 10,
WINBOND_W25Q128JV = 11,
};
struct flash_info {
uint8_t id[3];
uint32_t type;
uint32_t ssize;
uint32_t fsize;
char *name;
};
struct ddflash {
int fd;
uint32_t link;
char *fname;
int force;
struct ddb_id id;
uint32_t version;
char *flash_name;
uint32_t flash_type;
uint32_t sector_size;
uint32_t size;
uint32_t bufsize;
uint32_t block_erase;
uint8_t *buffer;
};

View File

@ -1,165 +0,0 @@
#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 <getopt.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 argc, char*argv[])
{
int fd;
struct dvb_mod_params mp;
struct dvb_mod_channel_params mc;
uint32_t data;
int32_t adapter = 0, channel = 0, gain = -1, att=-1, mod=-1;
int32_t base = -1, freq = -1, rate = -1, srate = -1;
char mod_name[128];
while (1) {
int cur_optind = optind ? optind : 1;
int option_index = 0;
int c;
static struct option long_options[] = {
{"adapter", required_argument, 0, 'a'},
{"channel", required_argument, 0, 'c'},
{"att", required_argument, 0, 't'},
{"gain", required_argument, 0, 'g'},
{"base", required_argument, 0, 'b'},
{"frequency", required_argument, 0, 'f'},
{"rate", required_argument, 0, 'r'},
{"modulation", required_argument, 0, 'm'},
{"symbolrate", required_argument, 0, 's'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"a:c:g:b:f:r:t:m:s:",
long_options, &option_index);
if (c==-1)
break;
switch (c) {
case 'a':
adapter = strtoul(optarg, NULL, 0);
break;
case 'c':
channel = strtoul(optarg, NULL, 0);
break;
case 'g':
gain = strtoul(optarg, NULL, 0);
break;
case 't':
att = strtoul(optarg, NULL, 0);
break;
case 'b':
base = strtoul(optarg, NULL, 0);
break;
case 'f':
freq = strtoul(optarg, NULL, 0);
break;
case 'm':
mod = strtoul(optarg, NULL, 0);
break;
case 's':
srate = strtoul(optarg, NULL, 0);
break;
case 'r':
if (!strcmp(optarg, "DVBT_8"))
rate = SYS_DVBT_8;
else if (!strcmp(optarg, "DVBT_7"))
rate = SYS_DVBT_7;
else if (!strcmp(optarg, "DVBT_6"))
rate = SYS_DVBT_6;
else if (!strcmp(optarg, "ISDBT_6"))
rate = SYS_ISDBT_6;
else rate = strtoul(optarg, NULL, 0);
break;
default:
break;
}
}
if (optind < argc) {
printf("too many arguments\n");
exit(1);
}
snprintf(mod_name, 127, "/dev/dvb/adapter%d/mod%d", adapter, channel);
fd = open(mod_name, O_RDONLY);
if (fd < 0) {
printf("Could not open modulator device.\n");
exit(1);
}
/* 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_ATTENUATOR, &data);
//printf("Modulator attenuator = %u\n", data);
if (att >= 0)
set_property(fd, MODULATOR_ATTENUATOR, att);
if (gain >= 0)
set_property(fd, MODULATOR_GAIN, gain);
if (base > 0)
set_property(fd, MODULATOR_BASE_FREQUENCY, base);
if (freq > 0)
set_property(fd, MODULATOR_FREQUENCY, freq);
if (rate > 0)
set_property(fd, MODULATOR_OUTPUT_RATE, rate);
if (mod >= 0)
set_property(fd, MODULATOR_MODULATION, mod);
if (srate > 0)
set_property(fd, MODULATOR_SYMBOL_RATE, srate);
close(fd);
}

View File

@ -1,15 +1,8 @@
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 -DCONFIG_DVB_TDA18271C2DD
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 dvb_netstream.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 dvb_netstream.o
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
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
ifneq ($(KERNEL_DVB_CORE),y)
obj-$(CONFIG_DVB_OCTONET) += octonet.o
endif
#EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends
#EXTRA_CFLAGS += -Idrivers/media/common/tuners
#NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends
EXTRA_CFLAGS += -Idrivers/media/common/tuners
NOSTDINC_FLAGS += -I$(SUBDIRS)/frontends -I$(SUBDIRS)/include -I$(SUBDIRS)/dvb-core

View File

@ -1,46 +0,0 @@
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.

View File

@ -1,13 +1,19 @@
#
# Makefile for the ddbridge device driver
#
KDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
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 dvb_netstream.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 dvb_netstream.o
MODDEFS := CONFIG_DVB_DDBRIDGE=m
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
obj-$(CONFIG_DVB_OCTONET) += octonet.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*
ccflags-y += -Idrivers/media/dvb-frontends/
ccflags-y += -Idrivers/media/tuners/

View File

@ -1,15 +0,0 @@
#
# 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 dvb_netstream.o
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.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/
ccflags-y += --include=dd_compat.h

View File

@ -1,349 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-ci.c: Digital Devices bridge and DuoFlex CI driver
*
* Copyright (C) 2010-2017 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, see <https://www.gnu.org/licenses/>.
*/
#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)) & 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 off = (address >> 1) & (CI_BUFFER_SIZE - 1);
u8 val;
if (address > CI_BUFFER_SIZE)
return -1;
ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address,
CI_DO_READ_ATTRIBUTES(ci));
wait_ci_ready(ci);
ddbcpyfrom(ci->port->dev, &val, CI_BUFFER(ci->nr) + off, 1);
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));
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));
ndelay(500);
do {
res = ddbreadl(ci->port->dev, CI_READDATA(ci));
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));
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));
msleep(300);
ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM,
CI_CONTROL(ci));
ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM,
CI_CONTROL(ci));
msleep(20);
ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON,
CI_CONTROL(ci));
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));
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));
ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE,
CI_CONTROL(ci));
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));
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;
const struct ddb_info *info = port->dev->link[port->lnr].info;
u32 off = info->ci_base ? info->ci_base : 0x400;
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;
ci->regs = DDB_LINK_TAG(port->lnr) | (off + 32 * ci->nr);
}
/* 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, 0x00, 0x01);
msleep(300);
write_creg(ci, 0x01, 0x01);
write_creg(ci, 0x04, 0x04);
msleep(300);
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

View File

@ -1,985 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* 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, see <https://www.gnu.org/licenses/>.
*/
#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 max_mci = {
.base = 0x500,
.num = 0x01,
.size = 0x04,
};
static const struct ddb_regset max_mci_buf = {
.base = 0x600,
.num = 0x01,
.size = 0x100,
};
static const struct ddb_regset sdr_mci = {
.base = 0x260,
.num = 0x01,
.size = 0x04,
};
static const struct ddb_regset sdr_mci_buf = {
.base = 0x300,
.num = 0x01,
.size = 0x100,
};
/****************************************************************************/
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_regset gtl_mini_input = {
.base = 0x400,
.num = 0x14,
.size = 0x10,
};
static const struct ddb_regset gtl_mini_idma = {
.base = 0x800,
.num = 0x40,
.size = 0x10,
};
static const struct ddb_regset gtl_mini_idma_buf = {
.base = 0x4000,
.num = 0x40,
.size = 0x100,
};
static const struct ddb_regset gtl_mini_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 octopus_mci_map = {
.irq_version = 1,
.irq_base_i2c = 0,
.irq_base_idma = 8,
.irq_base_odma = 16,
.irq_base_mci = 0,
.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,
.mci = &max_mci,
.mci_buf = &max_mci_buf,
};
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,
.irq_base_mci = 10,
.output = &octopus_output,
.odma = &octopus_mod_2_odma,
.odma_buf = &octopus_mod_2_odma_buf,
.channel = &octopus_mod_2_channel,
.mci = &sdr_mci,
.mci_buf = &sdr_mci_buf,
};
static const struct ddb_regmap octopus_sdr_map = {
.irq_version = 2,
.irq_base_odma = 64,
.irq_base_rate = 32,
.irq_base_mci = 10,
.output = &octopus_sdr_output,
.odma = &octopus_mod_2_odma,
.odma_buf = &octopus_mod_2_odma_buf,
.channel = &octopus_mod_2_channel,
.mci = &sdr_mci,
.mci_buf = &sdr_mci_buf,
};
static const struct ddb_regmap gtl_mini = {
.irq_version = 2,
.irq_base_i2c = 32,
.irq_base_idma = 64,
.irq_base_odma = 128,
.irq_base_gtl = 8,
.idma = &gtl_mini_idma,
.idma_buf = &gtl_mini_idma_buf,
.input = &gtl_mini_input,
.gtl = &gtl_mini_gtl,
};
/****************************************************************************/
/****************************************************************************/
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,
.name = "Digital Devices Octopus CI",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x03,
.ci_mask = 0x0c,
};
static const struct ddb_info ddb_cis = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus CI single",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x03,
.ci_mask = 0x04,
};
static const struct ddb_info ddb_ci_s2_pro = {
.type = DDB_OCTOPUS,
.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,
.ci_mask = 0x0c,
};
static const struct ddb_info ddb_ci_s2_pro_a = {
.type = DDB_OCTOPUS,
.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,
.ci_mask = 0x0c,
};
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-4",
.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_mod_fsm = {
.type = DDB_MOD,
.name = "Digital Devices DVB-C FSM",
.version = 2,
.regmap = &octopus_mod_2_map,
.port_num = 0,
.temp_num = 1,
.tempmon_irq = 8,
.lostlock_irq = 9,
};
static const struct ddb_info ddb_sdr_atv = {
.type = DDB_MOD,
.name = "Digital Devices SDR ATV",
.version = 16,
.regmap = &octopus_sdr_map,
.port_num = 16,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_sdr_iq = {
.type = DDB_MOD,
.name = "Digital Devices SDR IQ",
.version = 17,
.regmap = &octopus_sdr_map,
.port_num = 16,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_sdr_iq2 = {
.type = DDB_MOD,
.name = "Digital Devices SDR IQ2",
.version = 17,
.regmap = &octopus_sdr_map,
.port_num = 4,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_sdr_dvbt = {
.type = DDB_MOD,
.name = "Digital Devices DVBT",
.version = 18,
.regmap = &octopus_sdr_map,
.port_num = 14,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_sdr_dvbt_16 = {
.type = DDB_MOD,
.name = "Digital Devices DVBT",
.version = 18,
.regmap = &octopus_sdr_map,
.port_num = 16,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_s2_48 = {
.type = DDB_OCTOPUS_MAX,
.name = "Digital Devices MAX S8 4/8",
.regmap = &octopus_mci_map,
.port_num = 4,
.i2c_mask = 0x01,
.board_control = 1,
.tempmon_irq = 24,
.lnb_base = 0x400,
};
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_mci_map,
.port_num = 4,
.i2c_mask = 0x00,
.tempmon_irq = 24,
.mci_ports = 4,
.mci_type = DDB_TUNER_MCI_SX8,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_s2x_48_b = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX SX8 Basic",
.regmap = &octopus_mci_map,
.port_num = 4,
.i2c_mask = 0x00,
.tempmon_irq = 24,
.mci_ports = 4,
.mci_type = DDB_TUNER_MCI_SX8,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_m4 = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX M4",
.regmap = &octopus_mci_map,
.port_num = 2,
.i2c_mask = 0x00,
.tempmon_irq = 24,
.mci_ports = 2,
.mci_type = DDB_TUNER_MCI_M4,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_m8 = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX M8",
.regmap = &octopus_mci_map,
.port_num = 4,
.i2c_mask = 0x00,
.tempmon_irq = 24,
.mci_ports = 4,
.mci_type = DDB_TUNER_MCI_M8,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_m8a = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX M8A",
.regmap = &octopus_mci_map,
.port_num = 4,
.tempmon_irq = 24,
.mci_ports = 4,
.mci_type = DDB_TUNER_MCI_M8A,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_m8e = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX M8E",
.regmap = &octopus_mci_map,
.port_num = 4,
.tempmon_irq = 24,
.mci_ports = 4,
.mci_type = DDB_TUNER_MCI_M8E,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_ci_m2 = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices Octopus CI M2",
.regmap = &octopus_mci_map,
.port_num = 4,
.tempmon_irq = 24,
.mci_ports = 1,
.mci_type = DDB_TUNER_MCI_M2,
.temp_num = 1,
.ci_mask = 0x0c,
.ci_base = 0x400,
.lnb_base = 0x480,
};
static const struct ddb_info ddb_m2 = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices Octopus M2",
.regmap = &octopus_mci_map,
.port_num = 4,
.tempmon_irq = 24,
.mci_ports = 1,
.mci_type = DDB_TUNER_MCI_M2,
.temp_num = 1,
.lnb_base = 0x480,
};
/****************************************************************************/
static const struct ddb_info ddb_gtl_mini = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus GT Mini",
.regmap = &gtl_mini,
.port_num = 0,
.i2c_mask = 0x00,
.ns_num = 0,
};
/****************************************************************************/
/****************************************************************************/
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(0x000b, 0x0026, ddb_s2x_48_b),
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),
DDB_DEVID(0x0014, 0x0045, ddb_ci_m2),
DDB_DEVID(0x0020, 0x0012, ddb_gtl_mini),
DDB_DEVID(0x0022, 0x0052, ddb_m8),
DDB_DEVID(0x0024, 0x0053, ddb_m8a),
DDB_DEVID(0x0025, 0x0054, ddb_m2),
DDB_DEVID(0x0026, 0x0055, ddb_m8e),
/* 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, 0x0004, ddb_mod_fsm), /* dummy entry ! */
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_atv),
DDB_DEVID(0x0221, 0x0001, ddb_sdr_iq),
DDB_DEVID(0x0222, 0x0001, ddb_sdr_dvbt),
DDB_DEVID(0x0222, 0x0002, ddb_sdr_dvbt_16), /* dummy entry ! */
DDB_DEVID(0x0223, 0x0001, ddb_sdr_iq2),
DDB_DEVID(0xffff, 0xffff, ddb_none),
};
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 ||
id->subvendor == 0xffff) &&
(subdevice == id->subdevice ||
id->subdevice == 0xffff))
return id->info;
}
return &ddb_none;
}

View File

@ -1,12 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-i2c.c: Digital Devices bridge i2c driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* 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.
@ -19,11 +17,93 @@
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* 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 "ddbridge.h"
#include "ddbridge-io.h"
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 = &reg, .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 = &reg, .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);
}
static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
{
@ -35,12 +115,13 @@ 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);
#if 1
{
u32 istat = ddbreadl(dev, INTERRUPT_STATUS);
dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n",
dev->nr, i2c->nr, i2c->link);
dev_err(dev->dev, "DDBridge IRS %08x\n", istat);
if (i2c->link) {
u32 listat =
ddbreadl(dev,
@ -59,12 +140,11 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n",
val, mon);
}
}
#endif
return -EIO;
}
val &= 0x70000;
if (val == 0x20000)
dev_err(dev->dev, "I2C bus error\n");
if (val)
if (val & 0x70000)
return -EIO;
return 0;
}
@ -76,43 +156,38 @@ static int ddb_i2c_master_xfer(struct i2c_adapter *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;
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 (num == 2 && msg[1].flags & I2C_M_RD &&
!(msg[0].flags & I2C_M_RD)) {
if (msg[1].len > i2c->bsize)
break;
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))
break;
if (!ddb_i2c_cmd(i2c, addr, 1)) {
ddbcpyfrom(dev, msg[1].buf,
i2c->rbuf,
msg[1].len);
return num;
default:
break;
}
}
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)) {
ddbcpyfrom(dev, msg[0].buf,
i2c->rbuf, msg[0].len);
return num;
}
}
return -EIO;
}
@ -127,7 +202,7 @@ struct i2c_algorithm ddb_i2c_algo = {
.functionality = ddb_i2c_functionality,
};
void ddb_i2c_release(struct ddb *dev)
static void ddb_i2c_release(struct ddb *dev)
{
int i;
struct ddb_i2c *i2c;
@ -138,7 +213,7 @@ void ddb_i2c_release(struct ddb *dev)
}
}
static void i2c_handler(void *priv)
static void i2c_handler(unsigned long priv)
{
struct ddb_i2c *i2c = (struct ddb_i2c *) priv;
@ -146,8 +221,7 @@ static void i2c_handler(void *priv)
}
static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c,
const struct ddb_regmap *regmap,
int link, int i, int num)
struct ddb_regmap *regmap, int link, int i, int num)
{
struct i2c_adapter *adap;
@ -173,21 +247,20 @@ static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c,
adap->class = I2C_CLASS_TV_ANALOG;
#endif
#endif
snprintf(adap->name, I2C_NAME_SIZE, "ddbridge_%02x.%x.%x",
dev->nr, i2c->link, i);
strcpy(adap->name, "ddbridge");
adap->algo = &ddb_i2c_algo;
adap->algo_data = (void *)i2c;
adap->dev.parent = dev->dev;
return i2c_add_adapter(adap);
}
int ddb_i2c_init(struct ddb *dev)
static int ddb_i2c_init(struct ddb *dev)
{
int stat = 0;
u32 i, j, num = 0, l, base;
u32 i, j, num = 0, l;
struct ddb_i2c *i2c;
struct i2c_adapter *adap;
const struct ddb_regmap *regmap;
struct ddb_regmap *regmap;
for (l = 0; l < DDB_MAX_LINK; l++) {
if (!dev->link[l].info)
@ -195,12 +268,12 @@ int ddb_i2c_init(struct ddb *dev)
regmap = dev->link[l].info->regmap;
if (!regmap || !regmap->i2c)
continue;
base = regmap->irq_base_i2c;
for (i = 0; i < regmap->i2c->num; i++) {
if (!(dev->link[l].info->i2c_mask & (1 << i)))
continue;
i2c = &dev->i2c[num];
ddb_irq_set(dev, l, i + base, i2c_handler, i2c);
dev->handler_data[i + l * 32] = (unsigned long) i2c;
dev->handler[i + l * 32] = i2c_handler;
stat = ddb_i2c_add(dev, i2c, regmap, l, i, num);
if (stat)
break;
@ -213,9 +286,8 @@ int ddb_i2c_init(struct ddb *dev)
adap = &i2c->adap;
i2c_del_adapter(adap);
}
} else {
} else
dev->i2c_num = num;
}
return stat;
}

View File

@ -1,11 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ddbridge-i2c.h: Digital Devices bridge i2c driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Copyright (C) 2010-2015 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
@ -19,7 +17,10 @@
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/
#ifndef _DDBRIDGE_I2C_H_

View File

@ -1,188 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* 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];
if (!link->regs)
return 0;
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];
if (!link->regs)
return;
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 & ~3) >> (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)
{
return gtlcpyfrom(dev, dst, adr, count);
/* The possible 64 bit read in memcpy_fromio produces errors
on some platforms, i.e. arm64 rpi4
if (unlikely(adr & 0xf0000000))
return gtlcpyfrom(dev, dst, adr, count);
return memcpy_fromio(dst, dev->regs + adr, count);
*/
}

View File

@ -1,98 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* 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);
}
#ifdef DEBUG_GTLW
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

View File

@ -1,74 +0,0 @@
#ifndef _DDBRIDGE_IOCTL_H_
#define _DDBRIDGE_IOCTL_H_
#define DDB_MAGIC 'd'
struct ddb_flashio {
__u8 *write_buf;
__u32 write_len;
__u8 *read_buf;
__u32 read_len;
__u32 link;
};
struct ddb_gpio {
__u32 mask;
__u32 data;
};
struct ddb_id {
__u16 vendor;
__u16 device;
__u16 subvendor;
__u16 subdevice;
__u32 hw;
__u32 regmap;
};
struct ddb_reg {
__u32 reg;
__u32 val;
};
struct ddb_mem {
__u32 off;
__u8 *buf;
__u32 len;
};
struct ddb_mdio {
__u8 adr;
__u8 reg;
__u16 val;
};
struct ddb_i2c_msg {
__u8 bus;
__u8 adr;
__u8 *hdr;
__u32 hlen;
__u8 *msg;
__u32 mlen;
};
struct ddb_mci_msg {
__u32 link;
struct mci_command cmd;
struct mci_result res;
};
#define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio)
#define IOCTL_DDB_GPIO_IN _IOWR(DDB_MAGIC, 0x01, struct ddb_gpio)
#define IOCTL_DDB_GPIO_OUT _IOWR(DDB_MAGIC, 0x02, struct ddb_gpio)
#define IOCTL_DDB_ID _IOR(DDB_MAGIC, 0x03, struct ddb_id)
#define IOCTL_DDB_READ_REG _IOWR(DDB_MAGIC, 0x04, struct ddb_reg)
#define IOCTL_DDB_WRITE_REG _IOW(DDB_MAGIC, 0x05, struct ddb_reg)
#define IOCTL_DDB_READ_MEM _IOWR(DDB_MAGIC, 0x06, struct ddb_mem)
#define IOCTL_DDB_WRITE_MEM _IOR(DDB_MAGIC, 0x07, struct ddb_mem)
#define IOCTL_DDB_READ_MDIO _IOWR(DDB_MAGIC, 0x08, struct ddb_mdio)
#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)
#define IOCTL_DDB_MCI_CMD _IOWR(DDB_MAGIC, 0x0c, struct ddb_mci_msg)
#endif

View File

@ -1,666 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* 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-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;
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 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 = 0;
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;
if (p->stream_id != NO_STREAM_ID_FILTER)
cmd.dvbs2_search.input_stream_id = p->stream_id;
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_c(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
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;
if (p->bandwidth_hz <= 6000000)
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_6MHZ;
else if (p->bandwidth_hz <= 7000000)
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_7MHZ;
else
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_8MHZ;
cmd.dvbc_search.retry = 0;
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 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 = 0;
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_isdbs(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
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_ISDBS;
cmd.isdbs_search.retry = 0;
if (p->stream_id != NO_STREAM_ID_FILTER) {
cmd.isdbs_search.flags = (p->stream_id & 0xffff0000) ? 0 : 1;
cmd.isdbs_search.tsid = p->stream_id;
}
cmd.isdbs_search.frequency = p->frequency * 1000;
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_isdbc(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
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_ISDBC;
cmd.isdbc_search.retry = 0;
if (p->stream_id != NO_STREAM_ID_FILTER) {
cmd.isdbc_search.flags = (p->stream_id & 0xffff0000) ? 0 : 1;
cmd.isdbc_search.tsid = p->stream_id;
cmd.isdbc_search.onid = (p->stream_id & 0x10000) >> 16;
}
cmd.isdbc_search.bandwidth = MCI_BANDWIDTH_6MHZ;
cmd.isdbc_search.frequency = p->frequency;
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_j83b(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
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_J83B;
cmd.j83b_search.flags = 0;
cmd.j83b_search.retry = 0;
cmd.j83b_search.bandwidth = MCI_BANDWIDTH_6MHZ;
if (p->symbol_rate > 5500000)
cmd.j83b_search.bandwidth |= MCI_BANDWIDTH_EXTENSION;
cmd.j83b_search.frequency = p->frequency;
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_t2(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
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_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 = 0;
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 dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
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 = 0;
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 dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
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 = 0;
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;
//struct dtv_frontend_properties *p = &fe->dtv_property_cache;
stop(fe);
state->t2_signalling_valid = 0;
state->iq_constellation_point = 0;
state->iq_constellation_point_max = 0;
state->iq_constellation_tap = 0;
//printk("bw = %u\n", p->bandwidth_hz);
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_DVBC_ANNEX_B:
res = search_j83b(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;
case SYS_ISDBS:
res = search_isdbs(fe);
break;
case SYS_DVBC_ANNEX_C:
case SYS_ISDBC:
res = search_isdbc(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;
*status = 0x00;
if (!state->started)
return 0;
stat = ddb_mci_get_status(&state->mci, &res);
if (stat)
return stat;
stat = ddb_mci_get_info(&state->mci);
if (stat)
return stat;
ddb_mci_get_strength(fe);
if (res.status == MCI_DEMOD_WAIT_SIGNAL)
*status = 0x01;
else if (res.status == MX_DEMOD_WAIT_TS)
*status = 0x03;
else if (res.status == MCI_DEMOD_TIMEOUT)
*status = FE_TIMEDOUT;
else if (res.status == MCI_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);
#ifdef CONFIG_MEDIA_ATTACH
__module_get(THIS_MODULE);
#endif
}
static enum dvbfe_algo 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_DVBC_ANNEX_B, SYS_DVBC_ANNEX_C,
SYS_DVBC2, SYS_DVBT, SYS_DVBT2, SYS_DVBS, SYS_DVBS2,
#ifndef KERNEL_DVB_CORE
SYS_ISDBC, SYS_ISDBS, SYS_ISDBT,
#endif
},
.info = {
.name = "M4",
.frequency_min_hz = 47125000, /* DVB-T: 47125000 */
.frequency_max_hz = 2150000000, /* DVB-C: 862000000 */
.symbol_rate_min = 100000,
.symbol_rate_max = 100000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 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;
}
static 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,
};
static struct dvb_frontend_ops m_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_B, SYS_DVBC_ANNEX_C,
SYS_DVBT, SYS_DVBT2, SYS_DVBS, SYS_DVBS2,
#ifndef KERNEL_DVB_CORE
SYS_ISDBC, SYS_ISDBS, SYS_ISDBT,
#endif
},
.info = {
.name = "M_AS",
.frequency_min_hz = 47125000, /* DVB-T: 47125000 */
.frequency_max_hz = 2150000000, /* DVB-C: 862000000 */
.symbol_rate_min = 100000,
.symbol_rate_max = 100000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 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 struct mci_cfg ddb_max_m_cfg = {
.type = 0,
.fe_ops = &m_ops,
.base_size = sizeof(struct m4_base),
.state_size = sizeof(struct m4),
.init = init,
.base_init = base_init,
};
static struct dvb_frontend_ops m_s_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2, SYS_ISDBS },
.info = {
.name = "M_S",
.frequency_min_hz = 47125000, /* DVB-T: 47125000 */
.frequency_max_hz = 2150000000, /* DVB-C: 862000000 */
.symbol_rate_min = 100000,
.symbol_rate_max = 100000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 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 struct mci_cfg ddb_max_m_s_cfg = {
.type = 0,
.fe_ops = &m_s_ops,
.base_size = sizeof(struct m4_base),
.state_size = sizeof(struct m4),
.init = init,
.base_init = base_init,
};
static struct dvb_frontend_ops m_a_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_B, SYS_DVBC_ANNEX_C,
SYS_ISDBC,
SYS_DVBT, SYS_DVBT2, SYS_ISDBT,
},
.info = {
.name = "M_A",
.frequency_min_hz = 47125000, /* DVB-T: 47125000 */
.frequency_max_hz = 2150000000, /* DVB-C: 862000000 */
.symbol_rate_min = 100000,
.symbol_rate_max = 100000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 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 struct mci_cfg ddb_max_m_a_cfg = {
.type = 0,
.fe_ops = &m_a_ops,
.base_size = sizeof(struct m4_base),
.state_size = sizeof(struct m4),
.init = init,
.base_init = base_init,
};
static struct mci_cfg *ddb_max_cfgs [] = {
&ddb_max_m4_cfg,
&ddb_max_m_a_cfg,
&ddb_max_m_s_cfg,
&ddb_max_m_cfg,
};
struct dvb_frontend *ddb_mx_attach(struct ddb_input *input, int nr, int tuner, int type)
{
return ddb_mci_attach(input, ddb_max_cfgs[type & 3], nr, tuner);
}
EXPORT_SYMBOL(ddb_mx_attach);

View File

@ -1,512 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* 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, see <https://www.gnu.org/licenses/>.
*/
#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 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 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_clear_master(pdev);
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 {
stat = request_irq(pci_irq_vector(dev->pdev, 0),
ddb_irq_handler,
irq_flag, "ddbridge", (void *)dev);
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 (KERNEL_VERSION(5, 18, 0) <= LINUX_VERSION_CODE)
if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)))
if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
#else
if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
} else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
} else
#endif
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].ids.revision = pdev->revision;
dev->link[0].dev = dev;
dev->link[0].info = get_ddb_info(id->vendor, id->device,
id->subvendor, pdev->subsystem_device);
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);
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) {
if (dev->link[0].ids.revision == 1)
dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0004);
else if ((ddbreadl(dev, 0x1c) & 7) != 7)
dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0004);
}
dev_info(dev->dev, "%s\n", dev->link[0].info->name);
dev_info(dev->dev, "HW %08x REGMAP %08x FW %u.%u\n",
dev->link[0].ids.hwid, dev->link[0].ids.regmapid,
(dev->link[0].ids.hwid & 0xff0000) >> 16,
dev->link[0].ids.hwid & 0xffff);
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 stat;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
#ifndef PCI_DEVICE_SUB
#define PCI_DEVICE_SUB(vend, dev, subvend, subdev) \
.vendor = (vend), .device = (dev), \
.subvendor = (subvend), .subdevice = (subdev)
#endif
#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(0x000b),
DDB_DEVICE_ANY(0x0011),
DDB_DEVICE_ANY(0x0012),
DDB_DEVICE_ANY(0x0013),
DDB_DEVICE_ANY(0x0014),
DDB_DEVICE_ANY(0x0020),
DDB_DEVICE_ANY(0x0022),
DDB_DEVICE_ANY(0x0024),
DDB_DEVICE_ANY(0x0025),
DDB_DEVICE_ANY(0x0026),
DDB_DEVICE_ANY(0x0201),
DDB_DEVICE_ANY(0x0203),
DDB_DEVICE_ANY(0x0210),
DDB_DEVICE_ANY(0x0220),
DDB_DEVICE_ANY(0x0221),
DDB_DEVICE_ANY(0x0222),
DDB_DEVICE_ANY(0x0223),
{0}
};
MODULE_DEVICE_TABLE(pci, ddb_id_table);
static pci_ers_result_t ddb_pci_slot_reset(struct pci_dev *dev)
{
pr_info("pci_slot_reset\n");
return PCI_ERS_RESULT_RECOVERED;
}
static void ddb_pci_resume(struct pci_dev *dev)
{
pr_info("pci_resume\n");
}
static pci_ers_result_t ddb_pci_mmio_enabled(struct pci_dev *pdev)
{
pr_info("pci_mmio_enabled\n");
return PCI_ERS_RESULT_NEED_RESET;
}
static pci_ers_result_t ddb_pci_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
switch (state) {
case pci_channel_io_frozen:
return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_perm_failure:
return PCI_ERS_RESULT_DISCONNECT;
case pci_channel_io_normal:
default:
break;
}
return PCI_ERS_RESULT_NEED_RESET;
}
static const struct pci_error_handlers ddb_error = {
.error_detected = ddb_pci_error_detected,
.mmio_enabled = ddb_pci_mmio_enabled,
.slot_reset = ddb_pci_slot_reset,
.resume = ddb_pci_resume,
};
static struct pci_driver ddb_pci_driver = {
.name = "ddbridge",
.id_table = ddb_id_table,
.probe = ddb_probe,
.remove = ddb_remove,
.err_handler = &ddb_error,
};
static __init int module_init_ddbridge(void)
{
int stat;
pr_info("Digital Devices PCIE bridge driver "
DDBRIDGE_VERSION
", Copyright (C) 2010-19 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);

View File

@ -1,615 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* 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 delmode;
module_param(delmode, int, 0444);
MODULE_PARM_DESC(delmode, "frontend delivery system mode");
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 ");
static int no_voltage;
module_param(no_voltage, int, 0444);
MODULE_PARM_DESC(no_voltage, "Do not enable voltage on LNBH (will also disable 22KHz tone).");
static u8 input_diseqc_sequence[6] = { 0x00 };
static int input_diseqc_sequence_length = 1;
module_param_array(input_diseqc_sequence, byte, &input_diseqc_sequence_length, 0444);
MODULE_PARM_DESC(input_diseqc_sequence, "DiSEqC sequence to select input. Last byte & 15 selects input.");
/* 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);
u32 base = dev->link[link].info->lnb_base;
v = LNB_TONE & (dev->link[link].lnb.tone << (15 - lnb));
ddbwritel(dev, cmd | v, tag | base | LNB_CONTROL(lnb));
for (c = 0; c < 10; c++) {
v = ddbreadl(dev, tag | base | LNB_CONTROL(lnb));
if ((v & LNB_BUSY) == 0)
break;
msleep(20);
}
if (c == 10)
dev_info(dev->dev,
"%s lnb = %08x cmd = %08x timed out\n",
__func__, lnb, cmd | v);
return 0;
}
static int max_set_input(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(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);
u32 base = dev->link[port->lnr].info->lnb_base;
int i;
u32 fmode = dev->link[port->lnr].lnb.fmode;
if (fmode == 2 || fmode == 1)
return 0;
if (fmode == 4)
if (!max_emulate_switch(fe, cmd->msg, cmd->msg_len))
return 0;
if (cmd->msg_len &&
cmd->msg_len == input_diseqc_sequence_length &&
!memcmp(cmd->msg, input_diseqc_sequence, cmd->msg_len - 1))
return max_set_input(fe, cmd->msg[cmd->msg_len - 1] & 0x0f);
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 | base | LNB_BUF_LEVEL(dvb->input));
for (i = 0; i < cmd->msg_len; i++)
ddbwritel(dev, cmd->msg[i], tag | base | 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);
u32 base = dev->link[link].info->lnb_base;
int i;
ddbwritel(dev, 0, tag | base | LNB_BUF_LEVEL(input));
for (i = 0; i < cmd->msg_len; i++)
ddbwritel(dev, cmd->msg[i], tag | base | 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 (no_voltage)
voltage = SEC_VOLTAGE_OFF;
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)
{
struct ddb_input *input = fe->sec_priv;
struct ddb_port *port = input->port;
struct ddb *dev = port->dev;
u32 tag = DDB_LINK_TAG(port->lnr);
u32 base = dev->link[port->lnr].info->lnb_base;
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
u32 fmode = dev->link[port->lnr].lnb.fmode;
mutex_lock(&dev->link[port->lnr].lnb.lock);
switch (fmode) {
default:
case 0:
case 3:
ddbwritel(dev, arg ? 0x34 : 0x01, tag | base | LNB_CONTROL(dvb->input));
break;
case 1:
case 2:
ddbwritel(dev, arg ? 0x34 : 0x01, tag | base | LNB_CONTROL(0));
ddbwritel(dev, arg ? 0x34 : 0x01, tag | base | LNB_CONTROL(1));
ddbwritel(dev, arg ? 0x34 : 0x01, tag | base | LNB_CONTROL(2));
ddbwritel(dev, arg ? 0x34 : 0x01, tag | base | LNB_CONTROL(3));
break;
}
mutex_unlock(&dev->link[port->lnr].lnb.lock);
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;
#ifdef CONFIG_MEDIA_ATTACH
dvb->fe = dvb_attach(mxl5xx_attach, i2c, &cfg,
demod, tuner, &dvb->set_input);
#else
dvb->fe = mxl5xx_attach(i2c, &cfg, demod, tuner, &dvb->set_input);
#endif
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;
#ifndef KERNEL_DVB_CORE
dvb->fe->ops.set_input = max_set_input;
#endif
dvb->input = tuner;
return 0;
}
/* MAX MCI related functions */
struct dvb_frontend *ddb_sx8_attach(struct ddb_input *input, int nr, int tuner,
int (**fn_set_input)(struct dvb_frontend *fe, int input));
struct dvb_frontend *ddb_mx_attach(struct ddb_input *input, int nr, int tuner, int type);
int ddb_fe_attach_mci(struct ddb_input *input, u32 type)
{
struct ddb *dev = input->port->dev;
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;
int fm = fmode;
demod = input->nr;
tuner = demod & 3;
switch (type) {
case DDB_TUNER_MCI_SX8:
if (fm >= 3)
tuner = 0;
dvb->fe = ddb_sx8_attach(input, demod, tuner, &dvb->set_input);
dvb->input = tuner;
break;
case DDB_TUNER_MCI_M4:
fm = 0;
dvb->fe = ddb_mx_attach(input, demod, tuner, 0);
dvb->input = tuner;
break;
case DDB_TUNER_MCI_M8:
fm = 3;
if (!demod)
ddb_mci_cmd_link_simple(link, MCI_CMD_SET_INPUT_CONFIG,
0xff, (delmode & 0x10) | 3);
dvb->fe = ddb_mx_attach(input, demod, tuner, 3);
dvb->input = 0;
break;
case DDB_TUNER_MCI_M8A:
case DDB_TUNER_MCI_M8E:
fm = 3;
dvb->fe = ddb_mx_attach(input, demod, tuner, 3);
dvb->input = 0;
break;
case DDB_TUNER_MCI_M2:
{
u32 mode, mmode;
// delmode: 0 - sat,sat 1-cable,cable/sat
switch (delmode & 1) {
case 0:
mode = 2;
mmode = 2; /* M_S */
break;
case 1:
mode = 1;
mmode = demod ? 3 : 1; /* demod 1=M/0=M_A */
break;
}
if (!demod)
ddb_mci_cmd_link_simple(link, MCI_CMD_SET_INPUT_CONFIG,
0xff, mode | (delmode & 0x10));
dvb->fe = ddb_mx_attach(input, demod, tuner, mmode);
dvb->input = tuner;
fm = 0;
break;
}
default:
return -EINVAL;
}
if (!dvb->fe) {
dev_err(dev->dev, "No MCI card found!\n");
return -ENODEV;
}
if (!input->nr || (input->nr < 4 && type != DDB_TUNER_MCI_M8)) {
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;
if (type == DDB_TUNER_MCI_SX8) {
#ifndef KERNEL_DVB_CORE
dvb->fe->ops.set_input = max_set_input;
#endif
}
return 0;
}

View File

@ -1,468 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* 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 ddb_link *link)
{
const struct ddb_regmap *regmap = link->info->regmap;
u32 control;
u32 status = 0;
u32 timeout = 40;
union {
u32 u[4];
char s[16];
} version;
u32 vaddr;
if (!regmap || !regmap->mci)
return -EINVAL;
control = regmap->mci->base;
vaddr = regmap->mci_buf->base + 0xf0;
if ((link->info->type == DDB_OCTOPUS_MCI) &&
(ddblreadl(link, control) & MCI_CONTROL_START_COMMAND)) {
ddblwritel(link, MCI_CONTROL_RESET, control);
ddblwritel(link, 0, control + 4); /* 1= no internal init */
msleep(300);
}
ddblwritel(link, 0, control);
while (1) {
status = ddblreadl(link, control);
if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY)
break;
if (--timeout == 0)
break;
msleep(50);
}
dev_info(link->dev->dev, "MCI control port @ %08x\n", control);
if ((status & MCI_CONTROL_READY) == 0) {
dev_err(link->dev->dev, "MCI init failed!\n");
return -1;
}
version.u[0] = ddblreadl(link, vaddr);
version.u[1] = ddblreadl(link, vaddr + 4);
version.u[2] = ddblreadl(link, vaddr + 8);
version.u[3] = ddblreadl(link, vaddr + 12);
dev_info(link->dev->dev, "MCI port OK, init time %u msecs\n", (40 - timeout) * 50);
dev_info(link->dev->dev, "MCI firmware version %s.%d\n", version.s, version.s[15]);
return 0;
}
static int ddb_mci_cmd_raw_unlocked(struct ddb_link *link,
u32 *cmd, u32 cmd_len,
u32 *res, u32 res_len)
{
const struct ddb_regmap *regmap = link->info->regmap;
u32 control, command, result;
u32 i, val;
unsigned long stat;
if (!regmap || ! regmap->mci)
return -EINVAL;
control = regmap->mci->base;
command = regmap->mci_buf->base;
result = command + MCI_COMMAND_SIZE;
val = ddblreadl(link, 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], command + i * 4);
val |= (MCI_CONTROL_START_COMMAND |
MCI_CONTROL_ENABLE_DONE_INTERRUPT);
ddblwritel(link, val, control);
stat = wait_for_completion_timeout(&link->mci_completion, HZ);
if (stat == 0) {
u32 istat = ddblreadl(link, INTERRUPT_STATUS);
dev_err(link->dev->dev, "MCI timeout\n");
val = ddblreadl(link, control);
if (val == 0xffffffff) {
dev_err(link->dev->dev,
"Lost PCIe link!\n");
return -EIO;
} else {
dev_err(link->dev->dev,
"DDBridge IRS %08x link %u\n",
istat, link->nr);
if (istat & 1)
ddblwritel(link, istat, INTERRUPT_ACK);
if (link->nr)
ddbwritel(link->dev,
0xffffff, INTERRUPT_ACK);
}
}
//print_hex_dump(KERN_INFO, "MCI", DUMP_PREFIX_OFFSET, 16, 1, cmd, cmd_len, false);
if (res && res_len)
for (i = 0; i < res_len; i++)
res[i] = ddblreadl(link, result + i * 4);
return 0;
}
int ddb_mci_cmd_link(struct ddb_link *link,
struct mci_command *command,
struct mci_result *result)
{
struct mci_result res;
int stat;
if (!link->mci_ok)
return -EFAULT;
if (!result)
result = &res;
mutex_lock(&link->mci_lock);
stat = ddb_mci_cmd_raw_unlocked(link,
(u32 *)command,
sizeof(*command)/sizeof(u32),
(u32 *)result,
sizeof(*result)/sizeof(u32));
mutex_unlock(&link->mci_lock);
if (command && result && (result->status & 0x80))
dev_warn(link->dev->dev,
"mci_command 0x%02x, error=0x%02x\n",
command->command, result->status);
return stat;
}
int ddb_mci_cmd_link_simple(struct ddb_link *link, u8 command, u8 demod, u8 value)
{
struct mci_command cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.command = command;
cmd.demod = demod;
cmd.params8[0] = value;
return ddb_mci_cmd_link(link, &cmd, 0);
}
static void mci_handler(void *priv)
{
struct ddb_link *link = (struct ddb_link *) priv;
complete(&link->mci_completion);
}
int mci_init(struct ddb_link *link)
{
int result;
mutex_init(&link->mci_lock);
init_completion(&link->mci_completion);
result = mci_reset(link);
if (result < 0)
return result;
if (link->ids.device == 0x0009 || link->ids.device == 0x000b)
ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG);
ddb_irq_set(link->dev, link->nr,
link->info->regmap->irq_base_mci,
mci_handler, link);
link->mci_ok = 1;
return result;
}
int mci_cmd_val(struct ddb_link *link, uint32_t cmd, uint32_t val)
{
struct mci_result result;
struct mci_command command;
command.command_word = cmd;
command.params[0] = val;
return ddb_mci_cmd_link(link, &command, &result);
}
/****************************************************************************/
/****************************************************************************/
int ddb_mci_cmd(struct mci *state,
struct mci_command *command,
struct mci_result *result)
{
return ddb_mci_cmd_link(state->base->link, command, result);
}
static int ddb_mci_cmd_raw(struct mci *state,
struct mci_command *command, u32 command_len,
struct mci_result *result, u32 result_len)
{
struct ddb_link *link = state->base->link;
int stat;
mutex_lock(&link->mci_lock);
stat = ddb_mci_cmd_raw_unlocked(link,
(u32 *)command, command_len,
(u32 *)result, result_len);
mutex_unlock(&link->mci_lock);
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_7_8, 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;
p->symbol_rate =
mci->signal_info.dvbs2_signal_info.symbol_rate;
switch (p->delivery_system) {
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;
p->inversion = (mci->signal_info.dvbs2_signal_info.roll_off & 0x80) ?
INVERSION_ON : INVERSION_OFF;
if (mci->signal_info.dvbs2_signal_info.standard == 2) {
u32 modcod;
p->delivery_system = SYS_DVBS2;
p->transmission_mode = pls_code;
p->rolloff =
ro_lut[mci->signal_info.dvbs2_signal_info.roll_off & 7];
p->pilot = (pls_code & 1) ? PILOT_ON : PILOT_OFF;
if (pls_code & 0x80) {
/* no suitable values defined in Linux DVB API yet */
/* modcod = (0x7f & pls_code) >> 1; */
p->fec_inner = FEC_NONE;
p->modulation = 0;
if (pls_code >= 250)
p->pilot = PILOT_ON;
} else {
modcod = (0x7c & pls_code) >> 2;
p->fec_inner = modcod2fec[modcod];
p->modulation = modcod2mod[modcod];
}
} 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:
p->modulation =
mci->signal_info.dvbc_signal_info.constellation + 1;
break;
case SYS_DVBT:
break;
case SYS_DVBT2:
break;
case SYS_DVBC2:
break;
case SYS_ISDBT:
break;
default:
break;
}
/* post is correct, we cannot provide both pre and post at the same time */
/* set pre and post the same for now */
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->post_bit_error.len = 1;
p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
p->post_bit_error.stat[0].uvalue =
mci->signal_info.dvbs2_signal_info.ber_numerator;
p->post_bit_count.len = 1;
p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
p->post_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 = (s64)
mci->signal_info.dvbs2_signal_info.channel_power * 10;
}
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;
}
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;
link->mci_base = base;
mutex_init(&base->tuner_lock);
state->base = base;
if (!link->mci_ok) {
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;
state->input = input;
if (cfg->init)
cfg->init(state);
return &state->fe;
fail:
kfree(state);
return NULL;
}

File diff suppressed because it is too large Load Diff

1152
ddbridge/ddbridge-mod.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
/*
* ddbridge-ns.c: Digital Devices PCIe bridge driver net streaming
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Copyright (C) 2010-2015 Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
* 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
@ -17,12 +17,14 @@
*
*
* 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
* 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 "ddbridge.h"
#include "ddbridge-io.h"
static int ddb_dvb_ns_input_start(struct ddb_input *input);
static int ddb_dvb_ns_input_stop(struct ddb_input *input);
static u16 calc_pcs(struct dvb_ns_params *p)
{
@ -44,7 +46,7 @@ static u16 calc_pcs16(struct dvb_ns_params *p, int ipv)
u32 sum = 0, i;
u16 pcs;
for (i = 0; i < (ipv ? 16 : 4); i += 2) {
for (i = 0; i < ipv ? 16 : 4; i += 2) {
sum += (p->sip[i] << 8) | p->sip[i + 1];
sum += (p->dip[i] << 8) | p->dip[i + 1];
}
@ -85,6 +87,7 @@ 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);
@ -115,9 +118,8 @@ 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;
}
@ -152,12 +154,12 @@ static int ns_set_pid(struct dvbnss *nss, u16 pid)
else
ddbmemset(dev, off, 0x00, 0x400);
} else {
u8 val = ddbreadb0(dev, off + byte);
u8 val = ddbreadb(dev, off + byte);
if (pid & 0x8000)
ddbwriteb0(dev, val | bit, off + byte);
ddbwriteb(dev, val | bit, off + byte);
else
ddbwriteb0(dev, val & ~bit, off + byte);
ddbwriteb(dev, val & ~bit, off + byte);
}
}
#else
@ -196,13 +198,13 @@ static int ns_set_ci(struct dvbnss *nss, u8 ci)
if (ciport < 0)
return -EINVAL;
dev_info(dev->dev, "DDBridge: input %d.%d to ci %d at port %d\n",
pr_info("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));
TS_OUTPUT_CONTROL(ciport));
usleep_range(1, 5);
ddbwritel(dev, (input->port->lnr << 21) | (input->nr << 16) | 0x1d,
TS_CONTROL(dev->port[ciport].output));
TS_OUTPUT_CONTROL(ciport));
dns->fe = dev->port[ciport].input[0];
return 0;
}
@ -441,11 +443,13 @@ static int ns_start(struct dvbnss *nss)
reg |= 0x40;
if (nss->params.flags & DVB_NS_IPV6)
reg |= 0x80;
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
STREAM_CONTROL(dns->nr));
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;
}
@ -463,7 +467,7 @@ static int ns_stop(struct dvbnss *nss)
return 0;
}
int netstream_init(struct ddb_input *input)
static int netstream_init(struct ddb_input *input)
{
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
struct dvb_adapter *adap = dvb->adap;

View File

@ -1,7 +1,7 @@
/*
* ddbridge-regs.h: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Copyright (C) 2010-2015 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,22 +15,20 @@
*
*
* 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
* 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
*/
/* Register Definitions */
#define CUR_REGISTERMAP_VERSION 0x10004
#define CUR_REGISTERMAP_VERSION_0007 0x10002
#define CUR_REGISTERMAP_VERSION_0008 0x10002
#define CUR_REGISTERMAP_VERSION 0x10003
#define CUR_REGISTERMAP_VERSION_CI 0x10000
#define CUR_REGISTERMAP_VERSION_CI_PRO 0x10000
#define CUR_REGISTERMAP_VERSION_MOD 0x10000
#define HARDWARE_VERSION 0x0000
#define REGISTERMAP_VERSION 0x0004
#define DEVICE_ID 0x0008
#define BOARD_ID 0x000C
#define HARDWARE_VERSION 0x00
#define REGISTERMAP_VERSION 0x04
/* ------------------------------------------------------------------------- */
/* SPI Controller */
@ -48,10 +46,10 @@
/* ------------------------------------------------------------------------- */
/* MDIO */
#define MDIO_CTRL_OFF 0x00
#define MDIO_ADR_OFF 0x04
#define MDIO_REG_OFF 0x08
#define MDIO_VAL_OFF 0x0C
#define MDIO_CTRL 0x20
#define MDIO_ADR 0x24
#define MDIO_REG 0x28
#define MDIO_VAL 0x2C
/* ------------------------------------------------------------------------- */
@ -60,8 +58,8 @@
/* ------------------------------------------------------------------------- */
/* 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)
@ -78,8 +76,6 @@
#define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20)
#define INTERRUPT_ACK (INTERRUPT_BASE + 0x20)
#define INTERRUPT_ACK1 (INTERRUPT_BASE + 0x24)
#define INTERRUPT_ACK2 (INTERRUPT_BASE + 0x28)
#define INTMASK_CLOCKGEN (0x00000001)
#define INTMASK_TEMPMON (0x00000002)
@ -108,23 +104,7 @@
#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)
#define INTERRUPT_V2_ENABLE_3 (INTERRUPT_BASE + 0x0c)
#define INTERRUPT_V2_ENABLE_4 (INTERRUPT_BASE + 0x10)
#define INTERRUPT_V2_ENABLE_5 (INTERRUPT_BASE + 0x14)
#define INTERRUPT_V2_ENABLE_6 (INTERRUPT_BASE + 0x18)
#define INTERRUPT_V2_ENABLE_7 (INTERRUPT_BASE + 0x1c)
#define INTERRUPT_V2_STATUS (INTERRUPT_BASE + 0x20)
#define INTERRUPT_V2_STATUS_1 (INTERRUPT_BASE + 0x24)
#define INTERRUPT_V2_STATUS_2 (INTERRUPT_BASE + 0x28)
#define INTERRUPT_V2_STATUS_3 (INTERRUPT_BASE + 0x2c)
#define INTERRUPT_V2_STATUS_4 (INTERRUPT_BASE + 0x30)
#define INTERRUPT_V2_STATUS_5 (INTERRUPT_BASE + 0x34)
#define INTERRUPT_V2_STATUS_6 (INTERRUPT_BASE + 0x38)
#define INTERRUPT_V2_STATUS_7 (INTERRUPT_BASE + 0x3c)
/* Modulator registers */
@ -146,63 +126,25 @@
#define DAC_CONTROL_RESET (0x200)
/* Temperature Monitor ( 2x LM75A @ 0x90,0x92 I2c ) */
#define TEMPMON_BASE (0x1c0)
#define TEMPMON_BASE (0xA0)
#define TEMPMON_CONTROL (TEMPMON_BASE + 0x00)
#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)
/* Temperature in C x 256 */
/* SHORT 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_INTERRUPT_V1 (24)
#define TEMPMON_INTERRUPT_V1_MASK (1<<24)
/* 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 )
*/
/* 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)
/* ------------------------------------------------------------------------- */
/* I2C Master Controller */
#define I2C_BASE (0x80) /* Byte offset */
#define I2C_COMMAND (0x00)
#define I2C_TIMING (0x04)
#define I2C_TASKLENGTH (0x08) /* High read, low write */
#define I2C_TASKADDRESS (0x0C) /* High read, low write */
#define I2C_MONITOR (0x1C)
#define I2C_SPEED_666 (0x02010202)
#define I2C_SPEED_400 (0x04030404)
#define I2C_SPEED_200 (0x09080909)
@ -211,6 +153,7 @@
#define I2C_SPEED_77 (0x19181919)
#define I2C_SPEED_50 (0x27262727)
/* ------------------------------------------------------------------------- */
/* DMA Controller */
@ -230,25 +173,32 @@
#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_STAT(_io) ((_io)->regs + 0x08)
#define TS_INPUT_BASE (0x200)
#define TS_INPUT_CONTROL(i) (TS_INPUT_BASE + (i) * 0x10 + 0x00)
#define TS_INPUT_CONTROL2(i) (TS_INPUT_BASE + (i) * 0x10 + 0x04)
#define TS_INPUT_CONTROL_ENABLE (0x00000001)
#define TS_INPUT_CONTROL_RESET (0x00000002)
#define TS_INPUT_CONTROL_SKIPERROR (0x00000008)
#define TS_OUTPUT_BASE (0x280)
#define TS_OUTPUT_CONTROL(i) (TS_OUTPUT_BASE + (i) * 0x10 + 0x00)
#define TS_OUTPUT_CONTROL2(i) (TS_OUTPUT_BASE + (i) * 0x10 + 0x04)
/* ------------------------------------------------------------------------- */
/* 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_BASE (0x300)
#define DMA_BUFFER_CONTROL(i) (DMA_BUFFER_BASE + (i) * 0x10 + 0x00)
#define DMA_BUFFER_ACK(i) (DMA_BUFFER_BASE + (i) * 0x10 + 0x04)
#define DMA_BUFFER_CURRENT(i) (DMA_BUFFER_BASE + (i) * 0x10 + 0x08)
#define DMA_BUFFER_SIZE(i) (DMA_BUFFER_BASE + (i) * 0x10 + 0x0c)
#define DMA_BASE_ADDRESS_TABLE (0x2000)
#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512)
/* ------------------------------------------------------------------------- */
#define LNB_CONTROL(i) ((i) * 0x20 + 0x00)
#define LNB_BASE (0x400)
#define LNB_CONTROL(i) (LNB_BASE + (i) * 0x20 + 0x00)
#define LNB_CMD (7ULL << 0)
#define LNB_CMD_NOP 0
#define LNB_CMD_INIT 1
@ -257,33 +207,27 @@
#define LNB_CMD_HIGH 4
#define LNB_CMD_OFF 5
#define LNB_CMD_DISEQC 6
#define LNB_CMD_SCIF 7
#define LNB_CMD_UNI 7
#define LNB_BUSY (1ULL << 4)
#define LNB_TONE (1ULL << 15)
#define LNB_INTERRUPT_BASE 4
#define LNB_STATUS(i) ((i) * 0x20 + 0x04)
#define LNB_VOLTAGE(i) ((i) * 0x20 + 0x08)
#define LNB_CONFIG(i) ((i) * 0x20 + 0x0c)
#define LNB_BUF_LEVEL(i) ((i) * 0x20 + 0x10)
#define LNB_BUF_WRITE(i) ((i) * 0x20 + 0x14)
#define LNB_SETTING(i) ((i) * 0x20 + 0x0c)
#define LNB_FIFO_LEVEL(i) ((i) * 0x20 + 0x10)
#define LNB_RESET_FIFO(i) ((i) * 0x20 + 0x10)
#define LNB_WRITE_FIFO(i) ((i) * 0x20 + 0x14)
#define LNB_STATUS(i) (LNB_BASE + (i) * 0x20 + 0x04)
#define LNB_VOLTAGE(i) (LNB_BASE + (i) * 0x20 + 0x08)
#define LNB_CONFIG(i) (LNB_BASE + (i) * 0x20 + 0x0c)
#define LNB_BUF_LEVEL(i) (LNB_BASE + (i) * 0x20 + 0x10)
#define LNB_BUF_WRITE(i) (LNB_BASE + (i) * 0x20 + 0x14)
/* ------------------------------------------------------------------------- */
/* CI Interface (only CI-Bridge) */
#define CI_CONTROL(_ci) ((_ci)->regs + 0x00)
#define CI_BASE (0x400)
#define CI_CONTROL(i) (CI_BASE + (i) * 32 + 0x00)
#define CI_DO_ATTRIBUTE_RW(_ci) ((_ci)->regs + 0x04)
#define CI_DO_IO_RW(_ci) ((_ci)->regs + 0x08)
#define CI_READDATA(_ci) ((_ci)->regs + 0x0c)
#define CI_DO_READ_ATTRIBUTES(_ci) ((_ci)->regs + 0x10)
#define CI_DO_ATTRIBUTE_RW(i) (CI_BASE + (i) * 32 + 0x04)
#define CI_DO_IO_RW(i) (CI_BASE + (i) * 32 + 0x08)
#define CI_READDATA(i) (CI_BASE + (i) * 32 + 0x0c)
#define CI_DO_READ_ATTRIBUTES(i) (CI_BASE + (i) * 32 + 0x10)
#define CI_RESET_CAM (0x00000001)
#define CI_POWER_ON (0x00000002)
@ -294,7 +238,6 @@
#define CI_CAM_READY (0x00010000)
#define CI_CAM_DETECT (0x00020000)
#define CI_POWER_ERROR (0x00100000)
#define CI_READY (0x80000000)
#define CI_BLOCKIO_ACTIVE (0x40000000)
#define CI_BLOCKIO_RCVDATA (0x20000000)
@ -304,8 +247,8 @@
#define CI_READ_CMD (0x40000000)
#define CI_WRITE_CMD (0x80000000)
#define CI_BLOCKIO_SEND(_ci) ((_ci)->regs + 0x14)
#define CI_BLOCKIO_RECEIVE(_ci) ((_ci)->regs + 0x18)
#define CI_BLOCKIO_SEND(i) (CI_BASE + (i) * 32 + 0x14)
#define CI_BLOCKIO_RECEIVE(i) (CI_BASE + (i) * 32 + 0x18)
#define CI_BLOCKIO_SEND_COMMAND (0x80000000)
#define CI_BLOCKIO_SEND_COMPLETE_ACK (0x40000000)
@ -320,8 +263,6 @@
#define CI_BLOCKIO_SEND_BUFFER(i) \
(CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE + CI_BLOCKIO_BUFFER_SIZE)
/* V1 */
#define VCO1_BASE (0xC0)
#define VCO1_CONTROL (VCO1_BASE + 0x00)
#define VCO1_DATA (VCO1_BASE + 0x04) /* 24 Bit */
@ -352,81 +293,13 @@
/* Muxout from VCO (usually = Lock) */
#define VCO3_CONTROL_MUXOUT (0x00000004)
/* V2 */
#define MAX2871_BASE (0xC0)
#define MAX2871_CONTROL (MAX2871_BASE + 0x00)
#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)
#define FSM_CONTROL_ENABLE (0x00000100)
#define FSM_CMD_MASK (0x00000087)
#define FSM_CMD_STATUS (0x00000080)
#define FSM_CMD_RESET (0x00000080)
#define FSM_CMD_POWERDOWN (0x00000081)
#define FSM_CMD_SETUP (0x00000082)
#define FSM_STATUS (FSM_BASE + 0x00)
#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_GAIN (FSM_BASE + 0x10)
#define FSM_GAINMASK (0x000000FF)
#define FSM_GAIN_N1 (0x000000FE)
#define FSM_GAIN_N2 (0x000000A1)
#define FSM_GAIN_N4 (0x00000066)
#define FSM_GAIN_N8 (0x00000048)
#define FSM_GAIN_N16 (0x0000002D)
#define FSM_GAIN_N24 (0x00000029)
#define FSM_GAIN_N96 (0x00000011)
/* Attenuator/VGA */
#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)
#define RF_VGA_GAIN_N24 (122)
#define RF_VGA_GAIN_MAX (200)
/* V1 only */
#define RF_POWER (0xE0)
#define RF_POWER_BASE (0xE0)
#define RF_POWER_CONTROL (RF_POWER_BASE + 0x00)
@ -437,8 +310,9 @@
#define RF_POWER_CONTROL_VALIDMASK (0x00000700)
#define RF_POWER_CONTROL_VALID (0x00000500)
/*
* Output control
/* --------------------------------------------------------------------------
Output control
*/
#define IQOUTPUT_BASE (0x240)
@ -468,7 +342,8 @@
#define IQOUTPUT_CONTROL_ENABLE_PEAK (0x00000008)
#define IQOUTPUT_CONTROL_BYPASS_EQUALIZER (0x00000010)
/* Modulator Base V1 */
/* Modulator Base */
#define MODULATOR_BASE (0x200)
#define MODULATOR_CONTROL (MODULATOR_BASE)
@ -483,13 +358,12 @@
#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
#define CHANNEL_BASE (0x400)
#define CHANNEL_CONTROL(i) (CHANNEL_BASE + (i) * 64 + 0x00)
#define CHANNEL_SETTINGS(i) (CHANNEL_BASE + (i) * 64 + 0x04)
#define CHANNEL_SETTINGS2(i) (CHANNEL_BASE + (i) * 64 + 0x08)
#define CHANNEL_RATE_INCR(i) (CHANNEL_BASE + (i) * 64 + 0x0C)
#define CHANNEL_PCR_ADJUST_OUTL(i) (CHANNEL_BASE + (i) * 64 + 0x10)
#define CHANNEL_PCR_ADJUST_OUTH(i) (CHANNEL_BASE + (i) * 64 + 0x14)
@ -499,8 +373,6 @@
#define CHANNEL_PCR_ADJUST_ACCUH(i) (CHANNEL_BASE + (i) * 64 + 0x24)
#define CHANNEL_PKT_COUNT_OUT(i) (CHANNEL_BASE + (i) * 64 + 0x28)
#define CHANNEL_PKT_COUNT_IN(i) (CHANNEL_BASE + (i) * 64 + 0x2C)
#define CHANNEL_KF(i) (CHANNEL_BASE + (i) * 64 + 0x30)
#define CHANNEL_LF(i) (CHANNEL_BASE + (i) * 64 + 0x34)
#define CHANNEL_CONTROL_RESET (0x00000001)
#define CHANNEL_CONTROL_ENABLE_DVB (0x00000002)
@ -509,17 +381,8 @@
#define CHANNEL_CONTROL_ENABLE_PCRADJUST (0x00000010)
#define CHANNEL_CONTROL_FREEZE_STATUS (0x00000100)
#define CHANNEL_CONTROL_CMD_MASK (0x0000F000)
#define CHANNEL_CONTROL_CMD_STATUS (0x00008000)
#define CHANNEL_CONTROL_CMD_FREE (0x00008000)
#define CHANNEL_CONTROL_CMD_SETUP (0x00009000)
#define CHANNEL_CONTROL_CMD_MUTE (0x0000A000)
#define CHANNEL_CONTROL_CMD_UNMUTE (0x0000B000)
#define CHANNEL_CONTROL_RESET_ERROR (0x00010000)
#define CHANNEL_CONTROL_ACTIVE (0x00400000)
#define CHANNEL_CONTROL_BUSY (0x00800000)
#define CHANNEL_CONTROL_ERROR_CMD (0x10000000)
#define CHANNEL_CONTROL_BUSY (0x01000000)
#define CHANNEL_CONTROL_ERROR_SYNC (0x20000000)
#define CHANNEL_CONTROL_ERROR_UNDERRUN (0x40000000)
#define CHANNEL_CONTROL_ERROR_FATAL (0x80000000)
@ -531,13 +394,6 @@
#define CHANNEL_SETTINGS_QAM128 (0x00000003)
#define CHANNEL_SETTINGS_QAM256 (0x00000004)
#define CHANNEL_SETTINGS2_OUTPUT_MASK (0x0000007F)
#define KFLF_MAX (0x07FFFFFFUL)
#define KF_INIT(_symbol_rate) (_symbol_rate)
#define LF_INIT(_symbol_rate) (9000000UL)
#define MIN_SYMBOLRATE (1000000)
#define MAX_SYMBOLRATE (7100000)
/* OCTONET */
@ -575,77 +431,5 @@
#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 \
)
/* SDR_CONTROL */
#define SDR_CONTROL (0xd0)
#define SDR_GAIN_SMA (0xd4)
#define SDR_ATTENUATER (0xd8)
#define SDR_GAIN_F (0xdc)

View File

@ -1,663 +0,0 @@
/*
* 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-mci.h"
static int default_mod = 3;
module_param(default_mod, int, 0444);
MODULE_PARM_DESC(default_mod, "default modulations enabled, default is 3 (1 = QPSK, 2 = 8PSK, 4 = 16APSK, ...)");
static int direct_mode;
module_param(direct_mode, int, 0444);
MODULE_PARM_DESC(direct_mode, "Ignore LDPC limits and assign high speed demods according to needed symbolrate.");
static u32 sx8_tuner_flags;
module_param(sx8_tuner_flags, int, 0664);
MODULE_PARM_DESC(sx8_tuner_flags, "Change SX8 tuner flags.");
static u32 sx8_tuner_gain;
module_param(sx8_tuner_gain, int, 0664);
MODULE_PARM_DESC(sx8_tuner_gain, "Change SX8 tuner gain.");
static const u32 MCLK = (1550000000 / 12);
/* Add 2MBit/s overhead allowance (minimum factor is 90/32400 for QPSK w/o Pilots) */
static const u32 MAX_LDPC_BITRATE = (720000000 + 2000000);
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 used_ldpc_bitrate[SX8_DEMOD_NUM];
u8 demod_in_use[SX8_DEMOD_NUM];
u32 iq_mode;
};
struct sx8 {
struct mci mci;
struct mutex lock;
int first_time_lock;
int started;
int iq_started;
};
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);
#ifdef CONFIG_MEDIA_ATTACH
__module_get(THIS_MODULE);
#endif
}
static int ddb_mci_tsconfig(struct mci *state, u32 config)
{
struct ddb_link *link = state->base->link;
if (link->ids.device != 0x0009 && link->ids.device != 0x000b)
return -EINVAL;
ddblwritel(link, config, SX8_TSCONFIG);
return 0;
}
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{
int stat = 0;
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;
*status = 0x00;
mutex_lock(&state->lock);
if (!state->started && !state->iq_started)
goto unlock;
stat = ddb_mci_get_status(&state->mci, &res);
if (stat)
goto unlock;
ddb_mci_get_info(&state->mci);
if (stat)
goto unlock;
if (res.status == MCI_DEMOD_LOCKED || res.status == SX8_DEMOD_IQ_MODE) {
//if (res.status == MCI_DEMOD_LOCKED || sx8_base->iq_mode) {
*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI |
FE_HAS_CARRIER | FE_HAS_SIGNAL;
if (res.status == MCI_DEMOD_LOCKED) {
mutex_lock(&mci_base->tuner_lock);
if (state->first_time_lock && state->started) {
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;
state->first_time_lock = 0;
}
mutex_unlock(&mci_base->tuner_lock);
}
} else if (res.status == MCI_DEMOD_TIMEOUT)
*status = FE_TIMEDOUT;
else if (res.status >= SX8_DEMOD_WAIT_MATYPE) {
*status = FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
if (sx8_base->iq_mode)
*status |= FE_HAS_LOCK;
}
unlock:
mutex_unlock(&state->lock);
return stat;
}
static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on,
u8 flags, u8 gain)
{
struct sx8 *state = fe->demodulator_priv;
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 = flags;
cmd.sx8_input_enable.rf_gain = gain;
return ddb_mci_cmd(&state->mci, &cmd, NULL);
}
static int stop_iq(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->iq_started)
return -1;
memset(&cmd, 0, sizeof(cmd));
cmd.command = SX8_CMD_STOP_IQ;
cmd.demod = state->mci.demod;
ddb_mci_cmd(&state->mci, &cmd, NULL);
ddb_mci_tsconfig(&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, 0, 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;
mutex_unlock(&mci_base->tuner_lock);
sx8_base->iq_mode = 0;
state->iq_started = 0;
return 0;
}
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;
input = state->mci.tuner;
if (!state->started)
return -1;
if (state->mci.demod != SX8_DEMOD_NONE) {
memset(&cmd, 0, sizeof(cmd));
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_tsconfig(&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, 0, 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;
state->started = 0;
mutex_unlock(&mci_base->tuner_lock);
return 0;
}
static const u8 ro_lut[8] = {
8 | SX8_ROLLOFF_35, 8 | SX8_ROLLOFF_20, 8 | SX8_ROLLOFF_25, 0,
8 | SX8_ROLLOFF_15, 8 | SX8_ROLLOFF_10, 8 | SX8_ROLLOFF_05, 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;
struct ddb_link *link = state->mci.base->link;
if (link->ids.device == 0x000b) {
/* Mask out higher modulations and MIS for Basic
or search command will fail */
modmask &= 3;
p->stream_id = NO_STREAM_ID_FILTER;
}
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 (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++;
}
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_tuner_flags, sx8_tuner_gain);
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 = p->stream_id & 0x0f;
ddb_mci_cmd(&state->mci, &cmd, NULL);
ddb_mci_tsconfig(&state->mci, ts_config);
}
if (p->stream_id != NO_STREAM_ID_FILTER && !(p->stream_id & 0xf0000000))
flags |= 0x80;
//printk("bw %u\n", p->bandwidth_hz);
if (p->bandwidth_hz && (p->bandwidth_hz < 20000)) {
flags |= 0x40;
/* +/- range, so multiply bandwidth_hz (actually in kHz) by 500 */
cmd.dvbs2_search.frequency_range = p->bandwidth_hz * 500;
//printk("range %u\n", cmd.dvbs2_search.frequency_range);
}
cmd.command = MCI_CMD_SEARCH_DVBS;
cmd.dvbs2_search.flags = flags;
cmd.dvbs2_search.s2_modulation_mask = modmask;
cmd.dvbs2_search.rsvd1 = ro_lut[p->rolloff & 7];
cmd.dvbs2_search.retry = 2;
if (sx8_base->iq_mode)
cmd.dvbs2_search.retry = 255;
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 != NO_STREAM_ID_FILTER) &&
(p->stream_id & 0x80000000))
cmd.output |= 0x80;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
state->started = 1;
state->first_time_lock = 1;
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
if (stat)
stop(fe);
return stat;
}
static int start_iq(struct dvb_frontend *fe, u32 flags,
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 (!state->iq_started) {
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;
sx8_base->tuner_use_count[input]++;
sx8_base->iq_mode = 2;
mci_set_tuner(fe, input, 1, flags & 0xff, 0x40);
} else {
if ((state->iq_started & 0x07) != state->mci.nr) {
stat = -EBUSY;
goto unlock;
}
}
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 >> 16) & 0xff;
cmd.sx8_start_iq.roll_off = 5;
//cmd.sx8_start_iq.roll_off = ro_lut[p->rolloff & 7];
cmd.sx8_start_iq.frequency = p->frequency * 1000;
cmd.sx8_start_iq.symbol_rate = p->symbol_rate;
cmd.sx8_start_iq.gain = (flags >> 8) & 0xff;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
state->iq_started = 8 | state->mci.nr;
state->first_time_lock = 1;
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
if (stat)
stop_iq(fe);
ddb_mci_tsconfig(&state->mci, ts_config);
return stat;
}
static int set_lna(struct dvb_frontend *fe)
{
printk("set_lna\n");
return 0;
}
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, ts_mode = 0;
isi = p->stream_id;
if (isi != NO_STREAM_ID_FILTER) {
iq_mode = (isi & 0x30000000) >> 28;
ts_mode = (isi & 0x03000000) >> 24;
}
state->mci.input->con = ts_mode << 8;
if (iq_mode)
ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
mutex_lock(&state->lock);
stop(fe);
if (iq_mode < 2) {
u32 mask;
stop_iq(fe);
switch (p->modulation) {
case APSK_256:
case APSK_256_L:
mask = 0x7f;
break;
case APSK_128:
mask = 0x3f;
break;
case APSK_64:
case APSK_64_L:
mask = 0x1f;
break;
case APSK_32:
mask = 0x0f;
break;
case APSK_16:
case APSK_16_L:
mask = 0x07;
break;
default:
mask = default_mod;
break;
}
stat = start(fe, 3, mask, ts_config);
} else {
stat = start_iq(fe, isi & 0xffffff, ts_config);
}
mutex_unlock(&state->lock);
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 enum dvbfe_algo 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;
#ifndef KERNEL_DVB_CORE
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
#endif
if (input >= SX8_TUNER_NUM)
return -EINVAL;
if (state->mci.tuner == input)
return 0;
mutex_lock(&state->lock);
stop_iq(fe);
stop(fe);
state->mci.tuner = input;
#ifndef KERNEL_DVB_CORE
p->input = input;
#endif
mutex_unlock(&state->lock);
return 0;
}
static int sleep(struct dvb_frontend *fe)
{
struct sx8 *state = fe->demodulator_priv;
mutex_lock(&state->lock);
stop_iq(fe);
stop(fe);
mutex_unlock(&state->lock);
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 },
.info = {
.name = "DVB-S/S2X",
.frequency_min_hz = 950000000,
.frequency_max_hz = 2150000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 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,
#ifndef KERNEL_DVB_CORE
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
.set_input = set_input,
#endif
.set_lna = set_lna,
.sleep = sleep,
};
static int init(struct mci *mci)
{
struct sx8 *state = (struct sx8 *) mci;
state->mci.demod = SX8_DEMOD_NONE;
#ifndef KERNEL_DVB_CORE
mci->fe.ops.xbar[1] = mci->nr;
mci->fe.dtv_property_cache.input = mci->tuner;
#endif
mutex_init(&state->lock);
return 0;
}
static int base_init(struct mci_base *mci_base)
{
//struct sx8_base *base = (struct sx8_base *) mci_base;
return 0;
}
static 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,
};
struct dvb_frontend *ddb_sx8_attach(struct ddb_input *input, int nr, int tuner,
int (**fn_set_input)(struct dvb_frontend *fe, int input))
{
*fn_set_input = set_input;
return ddb_mci_attach(input, &ddb_max_sx8_cfg, nr, tuner);
}

554
ddbridge/ddbridge.c Normal file
View File

@ -0,0 +1,554 @@
/*
* 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_ALT_DMA*/
#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_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);
ddbwritel(dev, 0, INTERRUPT_ENABLE);
ddbwritel(dev, 0, MSI1_ENABLE);
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
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_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct ddb *dev;
int stat = 0;
int irq_flag = IRQF_SHARED;
if (pci_enable_device(pdev) < 0)
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) {
int i;
ddbwritel(dev, 0, ETHER_CONTROL);
for (i = 0; i < 16; i++)
ddbwritel(dev, 0x00, TS_OUTPUT_CONTROL(i));
usleep_range(5000, 6000);
}
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);
#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, 2);
if (stat >= 1) {
dev->msi = stat;
pr_info("DDBridge: using %d MSI interrupt(s)\n",
dev->msi);
irq_flag = 0;
} else
pr_info("DDBridge: MSI not available.\n");
#else
stat = pci_enable_msi_block(dev->pdev, 2);
if (stat == 0) {
dev->msi = 1;
pr_info("DDBridge: using 2 MSI interrupts\n");
}
if (stat == 1)
stat = pci_enable_msi(dev->pdev);
if (stat < 0) {
pr_info("DDBridge: MSI not available.\n");
} else {
irq_flag = 0;
dev->msi++;
}
#endif
}
if (dev->msi == 2) {
stat = request_irq(dev->pdev->irq, irq_handler0,
irq_flag, "ddbridge", (void *) dev);
if (stat < 0)
goto fail0;
stat = request_irq(dev->pdev->irq + 1, irq_handler1,
irq_flag, "ddbridge", (void *) dev);
if (stat < 0) {
free_irq(dev->pdev->irq, dev);
goto fail0;
}
} 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)
goto fail0;
}
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;
}
/*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);
}
if (ddb_init(dev) == 0)
return 0;
ddbwritel(dev, 0, INTERRUPT_ENABLE);
ddbwritel(dev, 0, MSI1_ENABLE);
free_irq(dev->pdev->irq, dev);
if (dev->msi == 2)
free_irq(dev->pdev->irq + 1, 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_regset octopus_i2c = {
.base = 0x80,
.num = 0x04,
.size = 0x20,
};
static struct ddb_regset octopus_i2c_buf = {
.base = 0x1000,
.num = 0x04,
.size = 0x200,
};
/****************************************************************************/
static struct ddb_regmap octopus_map = {
.i2c = &octopus_i2c,
.i2c_buf = &octopus_i2c_buf,
};
static struct ddb_regmap octopus_net_map = {
.i2c = &octopus_i2c,
.i2c_buf = &octopus_i2c_buf,
};
static struct ddb_regmap octopus_mod_map = {
};
/****************************************************************************/
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_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,
};
static struct ddb_info ddb_ct_8 = {
.type = DDB_OCTOPUS_MAX_CT,
.name = "Digital Devices MAX CT8",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 0x0ff,
.board_control_2 = 0xf00,
.ts_quirks = TS_QUIRK_SERIAL,
};
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_octopus_net = {
.type = DDB_OCTONET,
.name = "Digital Devices OctopusNet network DVB adapter",
.regmap = &octopus_net_map,
.port_num = 10,
.i2c_mask = 0x3ff,
.ns_num = 12,
.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_ct_8),
DDB_ID(DDVID, 0x0008, DDVID, 0x0035, ddb_ct_8),
DDB_ID(DDVID, 0x0008, DDVID, 0x0036, ddb_ct_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, 0x0320, PCI_ANY_ID, PCI_ANY_ID, ddb_octopus_net),
/* 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-15 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);

View File

@ -1,10 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ddbridge.h: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
* Copyright (C) 2010-2015 Digital Devices GmbH
* Ralph Metzler <rmetzler@digitaldevices.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -16,8 +14,12 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/
#ifndef _DDBRIDGE_H_
@ -25,7 +27,7 @@
#include <linux/version.h>
#if (KERNEL_VERSION(3, 8, 0) <= LINUX_VERSION_CODE)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
#define __devexit
#define __devinit
#define __devinitconst
@ -53,24 +55,27 @@
#include <linux/completion.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/dvb/ca.h>
#include <linux/socket.h>
#include <linux/device.h>
#include <linux/io.h>
#include "dvb_netstream.h"
#include <media/dmxdev.h>
#include <media/dvbdev.h>
#include <media/dvb_demux.h>
#include <media/dvb_frontend.h>
#include <media/dvb_ringbuffer.h>
#include <media/dvb_ca_en50221.h>
#include <media/dvb_net.h>
#include "dmxdev.h"
#include "dvbdev.h"
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include "dvb_ringbuffer.h"
#include "dvb_ca_en50221.h"
#include "dvb_net.h"
#include "tda18271c2dd.h"
#include "stv6110x.h"
@ -86,17 +91,14 @@
#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
#define DDB_MAX_OUTPUT 32
#define DDB_MAX_I2C 16
#define DDB_MAX_PORT 16
#define DDB_MAX_INPUT 44
#define DDB_MAX_OUTPUT 10
#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;
@ -104,30 +106,25 @@ struct ddb_regset {
u32 size;
};
struct ddb_ports {
u32 base;
u32 num;
u32 size;
};
struct ddb_regmap {
u32 irq_version;
u32 irq_base_i2c;
u32 irq_base_idma;
u32 irq_base_odma;
u32 irq_base_gtl;
u32 irq_base_rate;
u32 irq_base_mci;
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;
const struct ddb_regset *input;
const struct ddb_regset *output;
const struct ddb_regset *channel;
const struct ddb_regset *gtl;
const struct ddb_regset *mci;
const struct ddb_regset *mci_buf;
struct ddb_ports *bc;
struct ddb_regset *i2c;
struct ddb_regset *i2c_buf;
struct ddb_regset *dma;
struct ddb_regset *dma_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_ids {
@ -140,81 +137,73 @@ struct ddb_ids {
u32 regmapid;
u32 devid;
u32 mac;
u8 revision;
};
struct ddb_info {
u32 type;
int 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_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
#define TS_QUIRK_ALT_OSC 8
u8 mci_ports;
u8 mci_type;
u8 ci_mask;
u32 tempmon_irq;
u32 lostlock_irq;
u32 mdio_base;
u32 hw_min;
u32 ci_base;
u32 lnb_base;
const struct ddb_regmap *regmap;
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 */
#define OUTPUT_DMA_BUFS_SDR 32
#define OUTPUT_DMA_SIZE_SDR (256 * 1024)
#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
struct ddb;
struct ddb_port;
struct ddb_dma {
void *io;
u32 regs;
u32 bufregs;
u32 nr;
dma_addr_t pbuf[DMA_MAX_BUFS];
u8 *vbuf[DMA_MAX_BUFS];
u32 num;
u32 size;
u32 div;
u32 bufval;
u32 bufreg;
#ifdef DDB_USE_WORK
struct work_struct work;
#else
struct tasklet_struct tasklet;
spinlock_t lock; /* DMA lock */
#endif
spinlock_t lock;
wait_queue_head_t wq;
int running;
u32 stat;
u32 ctrl;
u32 cbuf;
u32 coff;
u32 stall_count;
u32 packet_loss;
u32 unaligned;
};
struct ddb_dvb {
@ -233,12 +222,11 @@ struct ddb_dvb {
u32 attached;
u8 input;
enum fe_sec_tone_mode tone;
enum fe_sec_voltage voltage;
fe_sec_tone_mode_t tone;
fe_sec_voltage_t voltage;
int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int val);
int (*set_voltage)(struct dvb_frontend *fe,
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_input)(struct dvb_frontend *fe, int input);
int (*diseqc_send_master_cmd)(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd);
@ -248,14 +236,12 @@ struct ddb_ci {
struct dvb_ca_en50221 en;
struct ddb_port *port;
u32 nr;
u32 regs;
struct mutex lock;
};
struct ddb_io {
struct ddb_port *port;
u32 nr;
u32 regs;
u32 con;
struct ddb_dma *dma;
struct ddb_io *redo;
struct ddb_io *redi;
@ -283,7 +269,7 @@ struct ddb_port {
u32 regs;
u32 lnr;
struct ddb_i2c *i2c;
struct mutex i2c_gate_lock; /* I2C access lock */
struct mutex i2c_gate_lock;
u32 class;
#define DDB_PORT_NONE 0
#define DDB_PORT_CI 1
@ -293,7 +279,6 @@ 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
@ -309,7 +294,6 @@ 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)
@ -317,15 +301,7 @@ 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_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)
#define DDB_TUNER_MCI_M8 (DDB_TUNER_MCI + 2)
#define DDB_TUNER_MCI_M8A (DDB_TUNER_MCI + 3)
#define DDB_TUNER_MCI_M2 (DDB_TUNER_MCI + 4)
#define DDB_TUNER_MCI_M8E (DDB_TUNER_MCI + 5)
#define DDB_TUNER_DVBC2T2_ST (DDB_TUNER_XO2 + 5)
struct ddb_input *input[2];
struct ddb_output *output;
@ -340,17 +316,10 @@ struct mod_base {
u32 frequency;
u32 flat_start;
u32 flat_end;
u32 attenuation;
u32 gain;
};
struct ddb_mod {
struct ddb_port *port;
u32 frequency;
struct mod_state {
u32 modulation;
u32 symbolrate;
u64 obitrate;
u64 ibitrate;
u32 pcr_correction;
@ -404,38 +373,24 @@ struct ddb_ns {
};
struct ddb_lnb {
struct mutex lock; /* lock lnb access */
struct mutex lock;
u32 tone;
enum fe_sec_voltage oldvoltage[4];
fe_sec_voltage_t oldvoltage[4];
u32 voltage[4];
u32 voltages;
u32 fmode;
};
struct ddb_irq {
void (*handler)(void *data);
void *data;
};
struct ddb_link {
struct ddb *dev;
const struct ddb_info *info;
struct ddb_info *info;
u32 nr;
u32 regs;
spinlock_t lock; /* lock link access */
struct mutex flash_mutex; /* lock flash access */
spinlock_t lock;
struct mutex flash_mutex;
struct ddb_lnb lnb;
struct tasklet_struct tasklet;
struct ddb_ids ids;
spinlock_t temp_lock; /* lock temp chip access */
int over_temperature_error;
u8 temp_tab[11];
struct ddb_irq irq[256];
struct mci_base *mci_base;
struct completion mci_completion;
struct mutex mci_lock;
int mci_ok;
};
struct ddb {
@ -458,11 +413,13 @@ struct ddb {
struct ddb_input input[DDB_MAX_INPUT];
struct ddb_output output[DDB_MAX_OUTPUT];
struct dvb_adapter adap[DDB_MAX_INPUT];
struct ddb_dma idma[DDB_MAX_INPUT];
struct ddb_dma odma[DDB_MAX_OUTPUT];
struct ddb_dma dma[DDB_MAX_INPUT + DDB_MAX_OUTPUT];
void (*handler[128])(unsigned long);
unsigned long handler_data[128];
struct device *ddb_dev;
atomic_t ddb_dev_users;
u32 ddb_dev_users;
u32 nr;
u8 iobuf[1028];
@ -473,16 +430,228 @@ struct ddb {
int ns_num;
struct ddb_ns ns[DDB_NS_MAX];
int vlan;
struct mutex mutex; /* lock accces to global ddb array */
struct mutex mutex;
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 */
struct mod_state mod[10];
};
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))
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
@ -535,56 +704,16 @@ 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.41"
/* 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(void *data);
void ddbridge_mod_output_start(struct ddb_output *output);
void ddbridge_mod_rate_handler(unsigned long data);
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 ddb_i2c_init(struct ddb *dev);
void ddb_i2c_release(struct ddb *dev);
int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
int ddb_ci_attach(struct ddb_port *port, u32 bitrate);
#define DDBRIDGE_VERSION "0.9.23"
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);
struct dvb_frontend *ddb_sx8_attach(struct ddb_input *input, int nr, int tuner,
int (**fn_set_input)(struct dvb_frontend *fe, int input));
struct dvb_frontend *ddb_mx_attach(struct ddb_input *input, int nr, int tuner, int type);
int ddb_dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
int (*func)(struct file *file, unsigned int cmd, void *arg));
#endif

View File

@ -1,76 +0,0 @@
#ifndef _UAPI_DVBNS_H_
#define _UAPI_DVBNS_H_
#include <linux/types.h>
struct dvb_ns_params {
__u8 smac[6];
__u8 dmac[6];
__u8 sip[16];
__u8 dip[16];
__u16 sport;
__u16 dport;
__u16 sport2;
__u16 dport2;
__u8 ssrc[8];
__u8 flags;
__u8 qos;
__u16 vlan;
__u8 ttl;
};
#define DVB_NS_IPV6 0x01
#define DVB_NS_RTP 0x02
#define DVB_NS_RTCP 0x04
#define DVB_NS_RTP_TO 0x08
#define DVB_NS_VLAN 0x10
struct dvb_ns_rtcp {
__u8 *msg;
__u16 len;
};
struct dvb_ns_packet {
__u8 *buf;
__u8 count;
};
struct dvb_nsd_ts {
__u16 pid;
__u16 num;
__u16 input;
__u16 timeout;
__u16 len;
__u8 *ts;
__u8 mode;
__u8 table;
__u8 filter_mask;
__u8 section;
__u16 section_id;
};
struct dvb_ns_cap {
__u8 streams_max;
__u8 reserved[127];
};
#define NS_SET_NET _IOW('o', 192, struct dvb_ns_params)
#define NS_START _IO('o', 193)
#define NS_STOP _IO('o', 194)
#define NS_SET_PID _IOW('o', 195, __u16)
#define NS_SET_PIDS _IOW('o', 196, __u8 *)
#define NS_SET_RTCP_MSG _IOW('o', 197, struct dvb_ns_rtcp)
#define NSD_START_GET_TS _IOWR('o', 198, struct dvb_nsd_ts)
#define NSD_STOP_GET_TS _IOWR('o', 199, struct dvb_nsd_ts)
#define NSD_CANCEL_GET_TS _IO('o', 200)
#define NSD_POLL_GET_TS _IOWR('o', 201, struct dvb_nsd_ts)
#define NS_SET_PACKETS _IOW('o', 202, struct dvb_ns_packet)
#define NS_INSERT_PACKETS _IOW('o', 203, __u8)
#define NS_SET_CI _IOW('o', 204, __u8)
#define NS_GET_CAP _IOR('o', 204, struct dvb_ns_cap))
#endif /*_UAPI_DVBNS_H_*/

View File

@ -1,7 +1,7 @@
/*
* octonet.c: Digital Devices network tuner driver
*
* Copyright (C) 2012-17 Digital Devices GmbH
* Copyright (C) 2012-15 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
@ -17,18 +17,97 @@
*
*
* 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
* 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 "ddbridge.h"
#include "ddbridge-io.h"
#include "ddbridge-regs.h"
#include <asm-generic/pci-dma-compat.h>
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_regset octopus_i2c = {
.base = 0x80,
.num = 0x04,
.size = 0x20,
};
static struct ddb_regset octopus_i2c_buf = {
.base = 0x1000,
.num = 0x04,
.size = 0x200,
};
static struct ddb_regmap octopus_net_map = {
.i2c = &octopus_i2c,
.i2c_buf = &octopus_i2c_buf,
};
static struct ddb_regset octopus_gtl = {
.base = 0x180,
.num = 0x01,
.size = 0x20,
};
static struct ddb_regmap octopus_net_gtl = {
.i2c = &octopus_i2c,
.i2c_buf = &octopus_i2c_buf,
.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);
}
#if (KERNEL_VERSION(6, 11, 0) > LINUX_VERSION_CODE)
static int __exit octonet_remove(struct platform_device *pdev)
#else
static void __exit octonet_remove(struct platform_device *pdev)
#endif
{
struct ddb *dev;
@ -45,11 +124,9 @@ static void __exit octonet_remove(struct platform_device *pdev)
free_irq(platform_get_irq(dev->pfdev, 0), dev);
ddb_ports_release(dev);
ddb_unmap(dev);
octonet_unmap(dev);
platform_set_drvdata(pdev, 0);
#if (KERNEL_VERSION(6, 11, 0) > LINUX_VERSION_CODE)
return 0;
#endif
}
static int __init octonet_probe(struct platform_device *pdev)
@ -57,8 +134,9 @@ static int __init octonet_probe(struct platform_device *pdev)
struct ddb *dev;
struct resource *regs;
int irq;
int i;
dev = vzalloc(sizeof(*dev));
dev = vzalloc(sizeof(struct ddb));
if (!dev)
return -ENOMEM;
platform_set_drvdata(pdev, dev);
@ -90,23 +168,31 @@ 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;
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",
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);
dev_info(dev->dev, "DDBridge: MAC %08x DEVID %08x\n",
pr_info("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);
ddbwritel(dev, 0xffffffff, INTERRUPT_STATUS);
ddb_reset_ios(dev);
for (i = 0; i < 16; i++)
ddbwritel(dev, 0x00, TS_OUTPUT_CONTROL(i));
usleep_range(5000, 6000);
irq = platform_get_irq(dev->pfdev, 0);
if (irq < 0)
goto fail;
if (request_irq(irq, ddb_irq_handler,
if (request_irq(irq, irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"octonet-dvb", (void *) dev) < 0)
goto fail;
@ -119,7 +205,7 @@ fail:
dev_err(dev->dev, "fail\n");
ddbwritel(dev, 0, ETHER_CONTROL);
ddbwritel(dev, 0, INTERRUPT_ENABLE);
ddb_unmap(dev);
octonet_unmap(dev);
platform_set_drvdata(pdev, 0);
return -1;
}
@ -133,7 +219,7 @@ static const struct of_device_id octonet_dt_ids[] = {
MODULE_DEVICE_TABLE(of, octonet_dt_ids);
#endif
static struct platform_driver octonet_driver __refdata = {
static struct platform_driver octonet_driver = {
.remove = __exit_p(octonet_remove),
.probe = octonet_probe,
.driver = {
@ -147,23 +233,25 @@ static struct platform_driver octonet_driver __refdata = {
static __init int init_octonet(void)
{
int stat;
int res;
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;
pr_info("Digital Devices OctopusNet driver " DDBRIDGE_VERSION
", Copyright (C) 2010-15 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;
}
static __exit void exit_octonet(void)
{
platform_driver_unregister(&octonet_driver);
ddb_exit_ddbridge(0, 0);
ddb_class_destroy();
}
module_init(init_octonet);
@ -171,5 +259,5 @@ module_exit(exit_octonet);
MODULE_DESCRIPTION("GPL");
MODULE_AUTHOR("Marcus and Ralph Metzler, Metzler Brothers Systementwicklung GbR");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(DDBRIDGE_VERSION);
MODULE_LICENSE("GPL");
MODULE_VERSION("0.6");

View File

@ -1,104 +0,0 @@
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:
cineS2 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.

22
docs/ci
View File

@ -1,5 +1,3 @@
- General Information
The caX device associated with a CI device behaves just like any other
caX interface. You usually use it through a library like libdvben50221
which is part of the dvb-apps package available at linuxtv.org.
@ -28,24 +26,6 @@ use the new interface.
See docs/redirect for more info.
- Clock Speed
The normal clock speed for the TS output is 72 MHz wich is the standard
speed used for CI.
Packets are sent with an adjustable gap between the packets.
The gap size is (gap value * 2) + 4 or 0 if the gap is disabled.
So, the standard gap value of 4 leads to a gap of 12 bytes which means
that the effective data rate is (72*188)/200 = 67.68 MBits/s.
Depending on the hardware, the clock speed can be changed with the
ci_bitrate module parameter:
- Octopus CI, Octopus CI S2 Pro : supported
- old CI single flex modules: supported
- new dual CI flex module: not yet supported, use the standard 72000 kHz
Valid ranges for are from ... to 96000 KHz.

View File

@ -1,13 +0,0 @@
Firmware update:
Copy the firmware file to the dddvb/apps/ directory and
execute "./flashprog".
The program will try to identify the card version and
check if it finds the corresponding firmware file.
It will then prompt you to confirm to proceed
with the flashing procedure.
After the update the system needs a power cycle.

View File

@ -1,27 +0,0 @@
~The Max SX8 can provide IQ samples in real time.
They are 8 bit signed values embedded in TS packets with PID 0x200.
API:
Currently DTV_STREAM_ID is misused.
0x10000000 - symbols (locked and tracked) at symbol rate
0x20000000 - samples at symbol rate
(fixed at ADC rate (1550/24=64.583... MHz) if 0x00010000 is set)
Max. sample rate is 64.583333 MHz.
0x00xx0000 - flags
Bit 0 : 0 = VTM/SDR, 1 = SCAN,
Bit 1: 1 = Disable channel AGC,
Bit 2: 1 = Set Gain.
0x0000xx00 - xx=gain
0x000000xx - xx=flags
Bit 0:1 Preamp Mode; 0 = Preamp AGC, 1 == Minimum (~ -17dB) ,
2 = Medium, 3 = Maximum gain {~ 15dB}
Bit 2: Bypass Input LNA (6 dB less gain) (Note this is after Preamp)
Bit 4: Set RF Gain
Bit 5: Freeze RF Gain (Turn AGC off at current gain, only when already enabled)
Bit 7: Optimize RF Gain and freeze for FFT

View File

@ -27,120 +27,3 @@ 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.
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:
THIS FEATURE ONLY WORKS FOR DVB-C MODULATORS
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
FOR DVB-T MODULATORS THIS FEATURE DOES NOT WORK
You should write a steady stream of transport packets with the
rate given by the modulation. The easiest way to keep a steady rate
is to write as much as the device will receive until it blocks. In that
way you ensure that the device will not get an underrun of data and
you can use the acceptance rate as a guide for you input rate.
All you should do is to correct the PCR of your transport stream according
to the calculated packet rate and use a buffer that assures that you are
always ready to write as sson as the modulator device allows it.
E.g you have a circular output buffer that you fill to say 50% and than start
writing into the device in a seperate thread. You feed the output buffer
with you input TS and see that it does not underrun, you may need to insert
empty packets to do that. The output thread should always have enough data
to write to the device as soon as it no longer blocks.
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.

View File

@ -1,181 +0,0 @@
MCI API for modulators:
Notes:
The API is not meant to be used directly but via the app/modconfig command.
Example config files for DVB-T and DVB-C are in apps/modulator.conf and
apps/modulator-c.conf, respectively.
stream - refers to one modulator slot which take a TS and modulates it
e.g. the FSM16 has 16 streams
channel - an actual frequency the stream is sent on
the FSM cards in default config have 96 channels at 114 MHz + X * 8 MHz (X=0-95)
MCI commands can be sent to modulators with the IOCTL_DDB_MCI_CMD:
#define IOCTL_DDB_MCI_CMD _IOWR(DDB_MAGIC, 0x0c, struct ddb_mci_msg)
with
struct ddb_mci_msg {
__u32 link;
struct mci_command cmd;
struct mci_result res;
};
link is always 0 for modulators.
mci_command with the entries relevant to modulators looks like this:
struct mci_command {
union {
u32 command_word;
struct {
u8 command;
u8 tuner;
u8 demod;
u8 output;
};
struct {
u8 mod_command;
u8 mod_channel;
u8 mod_stream;
u8 mod_rsvd1;
};
};
union {
...
struct mod_setup_channels mod_setup_channels[4];
struct mod_setup_stream mod_setup_stream;
struct mod_setup_output mod_setup_output;
...
};
};
mci_result like this:
struct mci_result {
union {
u32 status_word;
struct {
u8 status;
u8 mode;
u16 time;
};
};
...
};
mci_command.command can be one of:
#define MOD_SETUP_CHANNELS (0x60)
#define MOD_SETUP_OUTPUT (0x61)
#define MOD_SETUP_STREAM (0x62)
which use the following corresponding structs in mci_command:
MOD_SETUP_CHANNELS:
mod_command = MOD_SETUP_CHANNELS
mod_channel and mod_stream are not used
struct mod_setup_channels {
u8 flags;
u8 standard;
u8 num_channels;
u8 rsvd;
u32 frequency;
u32 offset; /* used only when Standard == 0 */
u32 bandwidth; /* used only when Standard == 0 */
};
You can set up to 4 regions of channels.
flags:
#define MOD_SETUP_FLAG_FIRST (0x01)
#define MOD_SETUP_FLAG_LAST (0x02)
#define MOD_SETUP_FLAG_VALID (0x80)
Set first/last if this is the first and/or last region you define.
Set valid if you actually want to set it.
standard:
see MOD_STANDARD_* defines in ddbridge-mci.h
for FSM cards only MOD_STANDARD_DVBC_6/7/8 are relevant
num_channels:
number of channels in this channel region
frequency:
start frquency of this region
frequency offset between channels depends on standard (e.g. 8MHz for DVBC_8)
offset/bandwidth: set offsets between channels and bandwidth by hand (not for FSM cards)
NOTE: After changing the channel setup you have to set the streams you want to use at least once
before you use them. Otherwise, they will not have the new channel frequency.
MOD_SETUP_OUTPUT:
set mod_command to MOD_SETUP_OUTPUT
mod_channel and mod_stream are not used
struct mod_setup_output {
u8 connector; /* 0 = OFF, 1 = F, 2 = SMA */
u8 num_channels; /* max active channels, determines max power for each channel. */
u8 unit; /* 0 = dBµV, 1 = dBm, */
u8 rsvd;
s16 channel_power;
};
connector: use the F- or SMA-connector (the FSM cards only has F)
num_channels: how many channels will have actually have a stream using it (has to be less or equal to card stream capability)
This influences internal multipliers. Setting it lower improves signal quality.
unit: determines unit of channel_power (0 = dBµV, 1 = dBm)
channel_power: set channel power of output to X dBµV or dBm.
MOD_SETUP_STREAM:
mod_command = MOD_SETUP_STREAM
mod_stream = stream you want to configure
mod_channel = channel the stream is to be sent on
struct mod_setup_stream {
u8 standard;
u8 stream_format;
u8 rsvd1[2];
u32 symbol_rate; /* only used when Standard doesn't define a fixed symbol rate */
union {
struct mod_ofdm_parameter ofdm;
struct mod_qam_parameter qam;
};
};

View File

@ -1,9 +1,9 @@
- NAND flash
0x00000000 - 0x0007ffff spl 512K
0x00080000 - 0x0047ffff uboot 4M
0x00480000 - 0x004fffff env 512K
0x00500000 - 0x00ffffff spare 11M
0x01000000 - 0x01ffffff recovery 16M
0x02000000 - 0x1fffffff ubi -
0x00000000 - 0x0025ffff U-boot
0x00260000 - 0x0027ffff ENV
0x00300000 - 0x00ffffff Linux image
0x01000000 - 0x01ffffff Linux recovery
0x02000000 - 0x1fffffff Linux UBI

View File

@ -28,7 +28,3 @@ devices in any way.
adapter_alloc=3 is rcommended when using redirect
The ci device will then show up in the same adapter directory and most
software will then assume it belongs to the frontend in the same directory.
Redirect between cards in different IOMMU groups will not work!
Disable IOMMU if you have this problem.

View File

@ -1,80 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# DVB device configuration
#
config DVB_MMAP
bool "Enable DVB memory-mapped API (EXPERIMENTAL)"
depends on DVB_CORE
depends on VIDEO_DEV=y || VIDEO_DEV=DVB_CORE
select VIDEOBUF2_VMALLOC
help
This option enables DVB experimental memory-mapped API, which
reduces the number of context switches to read DVB buffers, as
the buffers can use mmap() syscalls.
Support for it is experimental. Use with care. If unsure,
say N.
config DVB_NET
bool "DVB Network Support"
default (NET && INET)
depends on NET && INET && DVB_CORE
help
This option enables DVB Network Support which is a part of the DVB
standard. It is used, for example, by automatic firmware updates used
on Set-Top-Boxes. It can also be used to access the Internet via the
DVB card, if the network provider supports it.
You may want to disable the network support on embedded devices. If
unsure say Y.
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 y
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
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.
config DVB_ULE_DEBUG
bool "Enable DVB net ULE packet debug messages"
depends on DVB_CORE
help
Enable extra log messages meant to detect problems while
handling DVB network ULE 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.

View File

@ -1,15 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the kernel DVB device drivers.
#
dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.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-vb2-y) dvb_math.o
dvb_net.o dvb_ringbuffer.o dvb_math.o dvb_netstream.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o
EXTRA_CFLAGS += -DCONFIG_DVB_DYNAMIC_MINORS -DCONFIG_DVB_NET
NOSTDINC_FLAGS += -I$(SUBDIRS)/include -I$(SUBDIRS)/dvb-core

View File

@ -1,14 +0,0 @@
#
# 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_ca_en50221.o dvb_frontend.o \
$(dvb-net-y) dvb_ringbuffer.o dvb_math.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o
ccflags-y += -Idrivers/media/dvb-core/
ccflags-y += --include=dd_compat.h

241
dvb-core/demux.h Normal file
View File

@ -0,0 +1,241 @@
/*
* demux.h
*
* Copyright (c) 2002 Convergence GmbH
*
* based on code:
* Copyright (c) 2000 Nokia Research Center
* Tampere, FINLAND
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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
#define __DEMUX_H
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/time.h>
#include <linux/dvb/dmx.h>
/*--------------------------------------------------------------------------*/
/* Common definitions */
/*--------------------------------------------------------------------------*/
/*
* DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
*/
#ifndef DMX_MAX_FILTER_SIZE
#define DMX_MAX_FILTER_SIZE 18
#endif
/*
* DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
*/
#ifndef DMX_MAX_SECTION_SIZE
#define DMX_MAX_SECTION_SIZE 4096
#endif
#ifndef DMX_MAX_SECFEED_SIZE
#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
#endif
/*
* enum dmx_success: Success codes for the Demux Callback API.
*/
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 */
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);
};
/*--------------------------------------------------------------------------*/
/* Section reception */
/*--------------------------------------------------------------------------*/
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 */
};
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 check_crc;
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);
};
/*--------------------------------------------------------------------------*/
/* Callback functions */
/*--------------------------------------------------------------------------*/
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 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 */
/*--------------------------------------------------------------------------*/
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 {
struct list_head connectivity_list; /* List of front-ends that can
be connected to a particular
demux */
enum dmx_frontend_source source;
};
/*--------------------------------------------------------------------------*/
/* MPEG-2 TS Demux */
/*--------------------------------------------------------------------------*/
/*
* Flags OR'ed in the capabilities field of struct dmx_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
/*
* 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)
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);
int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids);
int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps);
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);
};
#endif /* #ifndef __DEMUX_H */

View File

@ -1,14 +1,25 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* dmxdev.c - DVB demultiplexer device
*
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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/version.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@ -17,22 +28,15 @@
#include <linux/poll.h>
#include <linux/ioctl.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <media/dmxdev.h>
#ifdef CONFIG_DVB_MMAP
#include <media/dvb_vb2.h>
#endif
#include <asm/uaccess.h>
#include "dmxdev.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
#define dprintk(fmt, arg...) do { \
if (debug) \
printk(KERN_DEBUG pr_fmt("%s: " fmt), \
__func__, ##arg); \
} while (0)
#define dprintk if (debug) printk
static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
const u8 *src, size_t len)
@ -46,7 +50,7 @@ static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
free = dvb_ringbuffer_free(buf);
if (len > free) {
dprintk("buffer overflow\n");
dprintk("dmxdev: buffer overflow\n");
return -EOVERFLOW;
}
@ -121,9 +125,8 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
struct dmx_frontend *front;
bool need_ringbuffer = false;
dprintk("%s\n", __func__);
dprintk("function : %s\n", __func__);
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
@ -133,35 +136,15 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
return -ENODEV;
}
dmxdev->may_do_mmap = 0;
/*
* The logic here is a little tricky due to the ifdef.
*
* The ringbuffer is used for both read and mmap.
*
* It is not needed, however, on two situations:
* - Write devices (access with O_WRONLY);
* - For duplex device nodes, opened with O_RDWR.
*/
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
need_ringbuffer = true;
else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
if ((file->f_flags & O_ACCMODE) == O_RDWR) {
if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
#ifdef CONFIG_DVB_MMAP
dmxdev->may_do_mmap = 1;
need_ringbuffer = true;
#else
mutex_unlock(&dmxdev->mutex);
return -EOPNOTSUPP;
#endif
}
}
if (need_ringbuffer) {
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
void *mem;
if (!dvbdev->readers) {
mutex_unlock(&dmxdev->mutex);
return -EBUSY;
@ -172,11 +155,6 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
return -ENOMEM;
}
dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
#ifdef CONFIG_DVB_MMAP
if (dmxdev->may_do_mmap)
dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr",
file->f_flags & O_NONBLOCK);
#endif
dvbdev->readers--;
}
@ -214,19 +192,10 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
dmxdev->demux->connect_frontend(dmxdev->demux,
dmxdev->dvr_orig_fe);
}
if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
dmxdev->may_do_mmap) {
#ifdef CONFIG_DVB_MMAP
if (dmxdev->may_do_mmap) {
if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx);
dvb_vb2_release(&dmxdev->dvr_vb2_ctx);
}
#endif
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
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;
@ -237,6 +206,8 @@ 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
@ -289,7 +260,7 @@ static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
void *newmem;
void *oldmem;
dprintk("%s\n", __func__);
dprintk("function : %s\n", __func__);
if (buf->size == size)
return 0;
@ -356,30 +327,6 @@ 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;
@ -404,22 +351,16 @@ 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,
u32 *buffer_flags)
enum dmx_success success)
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
int ret;
#ifdef CONFIG_DVB_MMAP
if (!dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx) &&
dmxdevfilter->buffer.error) {
#else
if (dmxdevfilter->buffer.error) {
#endif
wake_up(&dmxdevfilter->buffer.queue);
return 0;
}
@ -429,32 +370,13 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
return 0;
}
del_timer(&dmxdevfilter->timer);
dprintk("section callback %*ph\n", 6, buffer1);
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) {
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
buffer1, buffer1_len,
buffer_flags);
if (ret == buffer1_len)
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
buffer2, buffer2_len,
buffer_flags);
} else {
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
buffer1, buffer1_len);
if (ret == buffer1_len) {
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
buffer2, buffer2_len);
}
}
#else
dprintk("dmxdev: section callback %*ph\n", 6, buffer1);
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
buffer1_len);
if (ret == buffer1_len) {
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
buffer2_len);
}
#endif
if (ret < 0)
dmxdevfilter->buffer.error = ret;
if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
@ -467,13 +389,10 @@ 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,
u32 *buffer_flags)
enum dmx_success success)
{
struct dmxdev_filter *dmxdevfilter = feed->priv;
struct dvb_ringbuffer *buffer;
#ifdef CONFIG_DVB_MMAP
struct dvb_vb2_ctx *ctx;
#endif
int ret;
spin_lock(&dmxdevfilter->dev->lock);
@ -482,28 +401,11 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
return 0;
}
if (dmxdevfilter->params.pes.output == DMX_OUT_TAP ||
dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
|| dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
buffer = &dmxdevfilter->buffer;
#ifdef CONFIG_DVB_MMAP
ctx = &dmxdevfilter->vb2_ctx;
#endif
} else {
else
buffer = &dmxdevfilter->dev->dvr_buffer;
#ifdef CONFIG_DVB_MMAP
ctx = &dmxdevfilter->dev->dvr_vb2_ctx;
#endif
}
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(ctx)) {
ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len,
buffer_flags);
if (ret == buffer1_len)
ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len,
buffer_flags);
} else {
#endif
if (buffer->error) {
spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&buffer->queue);
@ -511,11 +413,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
}
ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
if (ret == buffer1_len)
ret = dvb_dmxdev_buffer_write(buffer,
buffer2, buffer2_len);
#ifdef CONFIG_DVB_MMAP
}
#endif
ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
if (ret < 0)
buffer->error = ret;
spin_unlock(&dmxdevfilter->dev->lock);
@ -662,9 +560,9 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
struct dmxdev_filter *filter,
struct dmxdev_feed *feed)
{
ktime_t timeout = ktime_set(0, 0);
struct timespec timeout = { 0 };
struct dmx_pes_filter_params *para = &filter->params.pes;
enum dmx_output otype;
dmx_output_t otype;
int ret;
int ts_type;
enum dmx_ts_pes ts_pes;
@ -695,7 +593,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, timeout);
ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
if (ret < 0) {
dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
return ret;
@ -760,16 +658,16 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
secfeed,
dvb_dmxdev_section_callback);
if (!*secfeed) {
pr_err("DVB (%s): could not alloc feed\n",
if (ret < 0) {
printk("DVB (%s): could not alloc feed\n",
__func__);
return ret;
}
ret = (*secfeed)->set(*secfeed, para->pid,
ret = (*secfeed)->set(*secfeed, para->pid, 32768,
(para->flags & DMX_CHECK_CRC) ? 1 : 0);
if (ret < 0) {
pr_err("DVB (%s): could not set feed\n",
printk("DVB (%s): could not set feed\n",
__func__);
dvb_dmxdev_feed_restart(filter);
return ret;
@ -840,11 +738,6 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
if (dmxdev->exit) {
mutex_unlock(&dmxdev->mutex);
return -ENODEV;
}
for (i = 0; i < dmxdev->filternum; i++)
if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
break;
@ -858,24 +751,10 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
mutex_init(&dmxdevfilter->mutex);
file->private_data = dmxdevfilter;
#ifdef CONFIG_DVB_MMAP
dmxdev->may_do_mmap = 1;
#else
dmxdev->may_do_mmap = 0;
#endif
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
#ifdef CONFIG_DVB_MMAP
dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter",
file->f_flags & O_NONBLOCK);
#endif
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++;
@ -888,11 +767,6 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
{
mutex_lock(&dmxdev->mutex);
mutex_lock(&dmxdevfilter->mutex);
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
dvb_vb2_stream_off(&dmxdevfilter->vb2_ctx);
dvb_vb2_release(&dmxdevfilter->vb2_ctx);
#endif
dvb_dmxdev_filter_stop(dmxdevfilter);
dvb_dmxdev_filter_reset(dmxdevfilter);
@ -913,7 +787,7 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
return 0;
}
static inline void invert_mode(struct dmx_filter *filter)
static inline void invert_mode(dmx_filter_t *filter)
{
int i;
@ -974,7 +848,7 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter,
struct dmx_sct_filter_params *params)
{
dprintk("%s: PID=0x%04x, flags=%02x, timeout=%d\n",
dprintk("function : %s, PID=0x%04x, flags=%02x, timeout=%d\n",
__func__, params->pid, params->flags, params->timeout);
dvb_dmxdev_filter_stop(dmxdevfilter);
@ -1000,7 +874,7 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
dvb_dmxdev_filter_stop(dmxdevfilter);
dvb_dmxdev_filter_reset(dmxdevfilter);
if ((unsigned int)params->pes_type > DMX_PES_OTHER)
if ((unsigned)params->pes_type > DMX_PES_OTHER)
return -EINVAL;
dmxdevfilter->type = DMXDEV_TYPE_PES;
@ -1151,6 +1025,22 @@ 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;
@ -1180,56 +1070,8 @@ static int dvb_demux_do_ioctl(struct file *file,
mutex_unlock(&dmxdevfilter->mutex);
break;
#ifdef CONFIG_DVB_MMAP
case DMX_REQBUFS:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_reqbufs(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_QUERYBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_querybuf(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_EXPBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_expbuf(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_QBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_qbuf(&dmxdevfilter->vb2_ctx, parg);
if (ret == 0 && !dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
ret = dvb_vb2_stream_on(&dmxdevfilter->vb2_ctx);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_DQBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_dqbuf(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
#endif
default:
ret = -ENOTTY;
ret = -EINVAL;
break;
}
mutex_unlock(&dmxdev->mutex);
@ -1242,70 +1084,30 @@ static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0))
typedef unsigned int __poll_t;
#define EPOLLIN POLLIN
#define EPOLLERR POLLERR
#define EPOLLPRI POLLPRI
#define EPOLLRDNORM POLLRDNORM
#define EPOLLWRNORM POLLWRNORM
#define EPOLLOUT POLLOUT
#endif
static __poll_t dvb_demux_poll(struct file *file, poll_table *wait)
static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
__poll_t mask = 0;
unsigned int mask = 0;
if (!dmxdevfilter)
return -EINVAL;
poll_wait(file, &dmxdevfilter->buffer.queue, wait);
if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
return EPOLLERR;
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
return dvb_vb2_poll(&dmxdevfilter->vb2_ctx, file, wait);
#endif
if (dmxdevfilter->state != DMXDEV_STATE_GO &&
dmxdevfilter->state != DMXDEV_STATE_DONE &&
dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
return 0;
if (dmxdevfilter->buffer.error)
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
mask |= (POLLIN | POLLRDNORM | POLLPRI);
return mask;
}
#ifdef CONFIG_DVB_MMAP
static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev = dmxdevfilter->dev;
int ret;
if (!dmxdev->may_do_mmap)
return -ENOTTY;
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_mmap(&dmxdevfilter->vb2_ctx, vma);
mutex_unlock(&dmxdevfilter->mutex);
mutex_unlock(&dmxdev->mutex);
return ret;
}
#endif
static int dvb_demux_release(struct inode *inode, struct file *file)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
@ -1318,6 +1120,8 @@ 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;
mutex_unlock(&dmxdev->mutex);
wake_up(&dmxdev->dvbdev->wait_queue);
} else
@ -1330,23 +1134,16 @@ static const struct file_operations dvb_demux_fops = {
.owner = THIS_MODULE,
.read = dvb_demux_read,
.unlocked_ioctl = dvb_demux_ioctl,
.compat_ioctl = dvb_demux_ioctl,
.open = dvb_demux_open,
.release = dvb_demux_release,
.poll = dvb_demux_poll,
.llseek = default_llseek,
#ifdef CONFIG_DVB_MMAP
.mmap = dvb_demux_mmap,
#endif
};
static const struct dvb_device dvbdev_demux = {
static 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
};
@ -1366,31 +1163,8 @@ static int dvb_dvr_do_ioctl(struct file *file,
ret = dvb_dvr_set_buffer_size(dmxdev, arg);
break;
#ifdef CONFIG_DVB_MMAP
case DMX_REQBUFS:
ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg);
break;
case DMX_QUERYBUF:
ret = dvb_vb2_querybuf(&dmxdev->dvr_vb2_ctx, parg);
break;
case DMX_EXPBUF:
ret = dvb_vb2_expbuf(&dmxdev->dvr_vb2_ctx, parg);
break;
case DMX_QBUF:
ret = dvb_vb2_qbuf(&dmxdev->dvr_vb2_ctx, parg);
if (ret == 0 && !dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
ret = dvb_vb2_stream_on(&dmxdev->dvr_vb2_ctx);
break;
case DMX_DQBUF:
ret = dvb_vb2_dqbuf(&dmxdev->dvr_vb2_ctx, parg);
break;
#endif
default:
ret = -ENOTTY;
ret = -EINVAL;
break;
}
mutex_unlock(&dmxdev->mutex);
@ -1403,58 +1177,28 @@ static long dvb_dvr_ioctl(struct file *file,
return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
}
static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait)
static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
__poll_t mask = 0;
unsigned int mask = 0;
dprintk("%s\n", __func__);
dprintk("function : %s\n", __func__);
poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
if (dmxdev->exit)
return EPOLLERR;
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
return dvb_vb2_poll(&dmxdev->dvr_vb2_ctx, file, wait);
#endif
if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
dmxdev->may_do_mmap) {
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
if (dmxdev->dvr_buffer.error)
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
mask |= (POLLIN | POLLRDNORM | POLLPRI);
} else
mask |= (EPOLLOUT | EPOLLWRNORM | EPOLLPRI);
mask |= (POLLOUT | POLLWRNORM | POLLPRI);
return mask;
}
#ifdef CONFIG_DVB_MMAP
static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma)
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
int ret;
if (!dmxdev->may_do_mmap)
return -ENOTTY;
if (dmxdev->exit)
return -ENODEV;
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
ret = dvb_vb2_mmap(&dmxdev->dvr_vb2_ctx, vma);
mutex_unlock(&dmxdev->mutex);
return ret;
}
#endif
static const struct file_operations dvb_dvr_fops = {
.owner = THIS_MODULE,
.read = dvb_dvr_read,
@ -1464,34 +1208,23 @@ static const struct file_operations dvb_dvr_fops = {
.release = dvb_dvr_release,
.poll = dvb_dvr_poll,
.llseek = default_llseek,
#ifdef CONFIG_DVB_MMAP
.mmap = dvb_dvr_mmap,
#endif
};
static const struct dvb_device dvbdev_dvr = {
static 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, ret;
int i;
if (dmxdev->demux->open(dmxdev->demux) < 0)
return -EUSERS;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0))
dmxdev->filter = vmalloc(sizeof(struct dmxdev_filter) * dmxdev->filternum);
#else
dmxdev->filter = vmalloc(array_size(sizeof(struct dmxdev_filter),
dmxdev->filternum));
#endif
dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
if (!dmxdev->filter)
return -ENOMEM;
@ -1504,36 +1237,21 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
DMXDEV_STATE_FREE);
}
ret = dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
DVB_DEVICE_DEMUX, dmxdev->filternum);
if (ret < 0)
goto err_register_dvbdev;
ret = dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
dmxdev, DVB_DEVICE_DVR, dmxdev->filternum);
if (ret < 0)
goto err_register_dvr_dvbdev;
dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
DVB_DEVICE_DEMUX);
dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
dmxdev, DVB_DEVICE_DVR);
dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
return 0;
err_register_dvr_dvbdev:
dvb_unregister_device(dmxdev->dvbdev);
err_register_dvbdev:
vfree(dmxdev->filter);
dmxdev->filter = NULL;
return ret;
}
EXPORT_SYMBOL(dvb_dmxdev_init);
void dvb_dmxdev_release(struct dmxdev *dmxdev)
{
mutex_lock(&dmxdev->mutex);
dmxdev->exit=1;
mutex_unlock(&dmxdev->mutex);
if (dmxdev->dvbdev->users > 1) {
wait_event(dmxdev->dvbdev->wait_queue,
dmxdev->dvbdev->users==1);

119
dvb-core/dmxdev.h Normal file
View File

@ -0,0 +1,119 @@
/*
* dmxdev.h
*
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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_
#define _DMXDEV_H_
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/dvb/dmx.h>
#include "dvbdev.h"
#include "demux.h"
#include "dvb_ringbuffer.h"
enum dmxdev_type {
DMXDEV_TYPE_NONE,
DMXDEV_TYPE_SEC,
DMXDEV_TYPE_PES,
};
enum dmxdev_state {
DMXDEV_STATE_FREE,
DMXDEV_STATE_ALLOCATED,
DMXDEV_STATE_SET,
DMXDEV_STATE_GO,
DMXDEV_STATE_DONE,
DMXDEV_STATE_TIMEDOUT
};
struct dmxdev_feed {
u16 pid;
struct dmx_ts_feed *ts;
struct list_head next;
};
struct dmxdev_filter {
union {
struct dmx_section_filter *sec;
} filter;
union {
/* list of TS and PES feeds (struct dmxdev_feed) */
struct list_head ts;
struct dmx_section_feed *sec;
} feed;
union {
struct dmx_sct_filter_params sec;
struct dmx_pes_filter_params pes;
} params;
enum dmxdev_type type;
enum dmxdev_state state;
struct dmxdev *dev;
struct dvb_ringbuffer buffer;
struct mutex mutex;
/* only for sections */
struct timer_list timer;
int todo;
u8 secheader[3];
};
struct dmxdev {
struct dvb_device *dvbdev;
struct dvb_device *dvr_dvbdev;
struct dmxdev_filter *filter;
struct dmx_demux *demux;
int filternum;
int capabilities;
unsigned int exit:1;
#define DMXDEV_CAP_DUPLEX 1
struct dmx_frontend *dvr_orig_fe;
struct dvb_ringbuffer dvr_buffer;
#define DVR_BUFFER_SIZE (10*188*1024)
struct mutex mutex;
spinlock_t lock;
};
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *);
void dvb_dmxdev_release(struct dmxdev *dmxdev);
#endif /* _DMXDEV_H_ */

File diff suppressed because it is too large Load Diff

140
dvb-core/dvb_ca_en50221.h Normal file
View File

@ -0,0 +1,140 @@
/*
* dvb_ca.h: generic DVB functions for EN50221 CA interfaces
*
* Copyright (C) 2004 Andrew de Quincey
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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_
#define _DVB_CA_EN50221_H_
#include <linux/list.h>
#include <linux/dvb/ca.h>
#include "dvbdev.h"
#define DVB_CA_EN50221_POLL_CAM_PRESENT 1
#define DVB_CA_EN50221_POLL_CAM_CHANGED 2
#define DVB_CA_EN50221_POLL_CAM_READY 4
#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE 1
#define DVB_CA_EN50221_FLAG_IRQ_FR 2
#define DVB_CA_EN50221_FLAG_IRQ_DA 4
#define DVB_CA_EN50221_CAMCHANGE_REMOVED 0
#define DVB_CA_EN50221_CAMCHANGE_INSERTED 1
/* Structure describing a CA interface */
struct dvb_ca_en50221 {
/* the module owning this structure */
struct module* owner;
/* 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.
*/
/* 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);
/* 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);
/* 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);
/* 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);
/*
* 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;
};
/* ******************************************************************************** */
/* 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
*/
void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type);
/**
* A CAMREADY IRQ has occurred.
*
* @param ca CA instance.
* @param slot Slot concerned.
*/
void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot);
/**
* An FR or a DA IRQ has occurred.
*
* @param ca CA instance.
* @param slot Slot concerned.
*/
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot);
/* ******************************************************************************** */
/* Initialisation/shutdown functions */
/**
* Initialise a new DVB CA device.
*
* @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.
*
* @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);
/**
* Release a DVB CA device.
*
* @param ca The associated dvb_ca instance.
*/
extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca);
#endif

View File

@ -1,20 +1,27 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* dvb_demux.c - DVB kernel demux API
*
* Copyright (C) 2000-2001 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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>
@ -22,18 +29,16 @@
#include <linux/poll.h>
#include <linux/string.h>
#include <linux/crc32.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
#include <media/dvb_demux.h>
#include "dvb_demux.h"
#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
#define NOBUFS
/*
** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog
*/
// #define DVB_DEMUX_SECTION_LOSS_LOG
static int dvb_demux_tscheck;
module_param(dvb_demux_tscheck, int, 0644);
@ -50,23 +55,9 @@ 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(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)
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
# define dprintk_sect_loss(x...) dprintk(x)
#else
# define dprintk_sect_loss(x...)
#endif
#define set_buf_flags(__feed, __flag) \
do { \
(__feed)->buffer_flags |= (__flag); \
printk(x); \
} while (0)
/******************************************************************************
@ -118,30 +109,28 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
{
int count = payload(buf);
int p;
int ccok;
u8 cc;
//int ccok;
//u8 cc;
if (count == 0)
return -1;
p = 188 - count;
/*
cc = buf[3] & 0x0f;
ccok = ((feed->cc + 1) & 0x0f) == cc;
if (!ccok) {
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("missed packet: %d instead of %d!\n",
cc, (feed->cc + 1) & 0x0f);
}
feed->cc = cc;
if (!ccok)
printk("missed packet!\n");
*/
if (buf[1] & 0x40) // PUSI ?
feed->peslen = 0xfffa;
feed->peslen += count;
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts,
&feed->buffer_flags);
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
}
static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
@ -163,7 +152,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, &feed->buffer_flags);
NULL, 0, &f->filter, DMX_OK);
}
static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
@ -182,11 +171,9 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
if (sec->check_crc) {
section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
if (section_syntax_indicator &&
demux->check_crc32(feed, sec->secbuf, sec->seclen)) {
set_buf_flags(feed, DMX_BUFFER_FLAG_HAD_CRC32_DISCARD);
demux->check_crc32(feed, sec->secbuf, sec->seclen))
return -1;
}
}
do {
if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0)
@ -202,8 +189,9 @@ 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
if (sec->secbufp < sec->tsfeedp) {
int n = sec->tsfeedp - sec->secbufp;
int i, n = sec->tsfeedp - sec->secbufp;
/*
* Section padding is done with 0xff bytes entirely.
@ -211,13 +199,15 @@ 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) {
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("section ts padding loss: %d/%d\n",
printk("dvb_demux.c section ts padding loss: %d/%d\n",
n, sec->tsfeedp);
dprintk_sect_loss("pad data: %*ph\n", n, sec->secbuf);
printk("dvb_demux.c pad data:");
for (i = 0; i < n; i++)
printk(" %02x", sec->secbuf[i]);
printk("\n");
}
}
#endif
sec->tsfeedp = sec->secbufp = sec->seclen = 0;
sec->secbuf = sec->secbuf_base;
@ -236,26 +226,27 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
* when the second packet arrives.
*
* Fix:
* when demux is started, let feed->pusi_seen = false to
* when demux is started, let feed->pusi_seen = 0 to
* prevent initial feeding of garbage from the end of
* previous section. When you for the first time see PUSI=1
* then set feed->pusi_seen = true
* then set feed->pusi_seen = 1
*/
static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
const u8 *buf, u8 len)
{
struct dvb_demux *demux = feed->demux;
struct dmx_section_feed *sec = &feed->feed.sec;
u16 limit, seclen;
u16 limit, seclen, n;
if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
return 0;
if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("section buffer full loss: %d/%d\n",
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
printk("dvb_demux.c section buffer full loss: %d/%d\n",
sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
DMX_MAX_SECFEED_SIZE);
#endif
len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
}
@ -275,7 +266,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
/* to be sure always set secbuf */
sec->secbuf = sec->secbuf_base + sec->secbufp;
while (sec->secbufp + 2 < limit) {
for (n = 0; sec->secbufp + 2 < limit; n++) {
seclen = section_length(sec->secbuf);
if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
|| seclen + sec->secbufp > limit)
@ -283,13 +274,12 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
sec->seclen = seclen;
sec->crc_val = ~0;
/* dump [secbuf .. secbuf+seclen) */
if (feed->pusi_seen) {
if (feed->pusi_seen)
dvb_dmx_swfilter_section_feed(feed);
} else {
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("pusi not seen, discarding section data\n");
}
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
else
printk("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 */
}
@ -313,6 +303,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
cc = buf[3] & 0x0f;
ccok = ((feed->cc + 1) & 0x0f) == cc;
feed->cc = cc;
if (buf[3] & 0x20) {
/* adaption field present, check for discontinuity_indicator */
@ -321,34 +312,21 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
}
if (!ccok || dc_i) {
if (dc_i) {
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR);
dprintk_sect_loss("%d frame with disconnect indicator\n",
cc);
} else {
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("discontinuity: %d instead of %d. %d bytes lost\n",
cc, (feed->cc + 1) & 0x0f, count + 4);
}
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
printk("dvb_demux.c discontinuity detected %d bytes lost\n",
count);
/*
* those bytes under some circumstances will again be reported
* those bytes under sume circumstances will again be reported
* in the following dvb_dmx_swfilter_section_new
*/
#endif
/*
* Discontinuity detected. Reset pusi_seen to
* Discontinuity detected. Reset pusi_seen = 0 to
* stop feeding of suspicious data until next PUSI=1 arrives
*
* FIXME: does it make sense if the MPEG-TS is the one
* reporting discontinuity?
*/
feed->pusi_seen = false;
feed->pusi_seen = 0;
dvb_dmx_swfilter_section_new(feed);
}
feed->cc = cc;
if (buf[1] & 0x40) {
/* PUSI=1 (is set), section boundary is here */
@ -360,16 +338,16 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
dvb_dmx_swfilter_section_copy_dump(feed, before,
before_len);
/* before start of new section, set pusi_seen */
feed->pusi_seen = true;
/* before start of new section, set pusi_seen = 1 */
feed->pusi_seen = 1;
dvb_dmx_swfilter_section_new(feed);
dvb_dmx_swfilter_section_copy_dump(feed, after,
after_len);
} else if (count > 0) {
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("PUSI=1 but %d bytes lost\n", count);
}
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
else if (count > 0)
printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
#endif
} else {
/* PUSI=0 (is not set), no section boundary */
dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
@ -390,9 +368,8 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
dvb_dmx_swfilter_payload(feed, buf);
else
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
&feed->buffer_flags);
DMX_OK);
}
/* Used only on full-featured devices */
if (feed->ts_type & TS_DECODER)
if (feed->demux->write_to_decoder)
feed->demux->write_to_decoder(feed, buf, 188);
@ -422,25 +399,29 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
int dvr_done = 0;
if (dvb_demux_speedcheck) {
ktime_t cur_time;
struct timespec cur_time, delta_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 = ktime_get();
cur_time = current_kernel_time();
if (ktime_to_ns(demux->speed_last_time) != 0) {
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);
speed_bytes = (u64)demux->speed_pkts_cnt
* 188 * 8;
/* convert to 1024 basis */
speed_bytes = 1000 * div64_u64(speed_bytes,
1024);
speed_timedelta = ktime_ms_delta(cur_time,
demux->speed_last_time);
if (speed_timedelta)
dprintk("TS speed %llu Kbits/sec \n",
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));
}
@ -451,14 +432,10 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
}
if (buf[1] & 0x80) {
list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
continue;
set_buf_flags(feed, DMX_BUFFER_FLAG_TEI);
}
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 can't be trusted - drop it unless
/* data in this packet cant be trusted - drop it unless
* module option dvb_demux_feed_err_pkts is set */
if (!dvb_demux_feed_err_pkts)
return;
@ -471,13 +448,6 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
(demux->cnt_storage[pid] + 1) & 0xf;
if ((buf[3] & 0xf) != demux->cnt_storage[pid]) {
list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
continue;
set_buf_flags(feed,
DMX_BUFFER_PKT_COUNTER_MISMATCH);
}
dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n",
pid, demux->cnt_storage[pid],
buf[3] & 0xf);
@ -499,17 +469,14 @@ 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,
&feed->buffer_flags);
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
}
}
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
size_t count)
{
unsigned long flags;
spin_lock_irqsave(&demux->lock, flags);
spin_lock(&demux->lock);
while (count--) {
if (buf[0] == 0x47)
@ -517,7 +484,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
buf += 188;
}
spin_unlock_irqrestore(&demux->lock, flags);
spin_unlock(&demux->lock);
}
EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
@ -552,9 +519,8 @@ 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_irqsave(&demux->lock, flags);
spin_lock(&demux->lock);
if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
i = demux->tsbufp;
@ -598,7 +564,7 @@ static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
}
bailout:
spin_unlock_irqrestore(&demux->lock, flags);
spin_unlock(&demux->lock);
}
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
@ -615,22 +581,11 @@ EXPORT_SYMBOL(dvb_dmx_swfilter_204);
void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
{
unsigned long flags;
spin_lock(&demux->lock);
spin_lock_irqsave(&demux->lock, flags);
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
#if 1
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts,
&demux->feed->buffer_flags);
#else
struct dvb_demux_feed *feed;
list_for_each_entry(feed, &demux->feed_list, list_head) {
feed->cb.ts(buf, count, NULL, 0, &feed->feed.ts,
&feed->buffer_flags);
}
#endif
spin_unlock_irqrestore(&demux->lock, flags);
spin_unlock(&demux->lock);
}
EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
@ -681,7 +636,7 @@ static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
{
spin_lock_irq(&feed->demux->lock);
if (dvb_demux_feed_find(feed)) {
pr_err("%s: feed already in list (type=%x state=%x pid=%x)\n",
printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
__func__, feed->type, feed->state, feed->pid);
goto out;
}
@ -695,7 +650,7 @@ static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
{
spin_lock_irq(&feed->demux->lock);
if (!(dvb_demux_feed_find(feed))) {
pr_err("%s: feed not in list (type=%x state=%x pid=%x)\n",
printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
__func__, feed->type, feed->state, feed->pid);
goto out;
}
@ -706,7 +661,8 @@ out:
}
static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
enum dmx_ts_pes pes_type, ktime_t timeout)
enum dmx_ts_pes pes_type,
size_t circular_buffer_size, struct timespec timeout)
{
struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
struct dvb_demux *demux = feed->demux;
@ -736,10 +692,23 @@ 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);
@ -828,7 +797,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
feed->demux = demux;
feed->pid = 0xffff;
feed->peslen = 0xfffa;
feed->buffer_flags = 0;
feed->buffer = NULL;
(*ts_feed) = &feed->feed.ts;
(*ts_feed)->parent = dmx;
@ -865,6 +834,10 @@ 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;
@ -916,7 +889,8 @@ 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, int check_crc)
u16 pid, size_t circular_buffer_size,
int check_crc)
{
struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
@ -930,8 +904,19 @@ 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;
@ -948,14 +933,14 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
return;
do {
sf = &f->filter;
doneq = false;
doneq = 0;
for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
mode = sf->filter_mode[i];
mask = sf->filter_mask[i];
f->maskandmode[i] = mask & mode;
doneq |= f->maskandnotmode[i] = mask & ~mode;
}
f->doneq = doneq ? true : false;
f->doneq = doneq ? 1 : 0;
} while ((f = f->next));
}
@ -982,7 +967,6 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
dvbdmxfeed->feed.sec.secbufp = 0;
dvbdmxfeed->feed.sec.seclen = 0;
dvbdmxfeed->pusi_seen = false;
if (!dvbdmx->start_feed) {
mutex_unlock(&dvbdmx->mutex);
@ -1043,13 +1027,8 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
return -EINVAL;
}
if (feed->is_filtering) {
/* release dvbdmx->mutex as far as it is
acquired by stop_filtering() itself */
mutex_unlock(&dvbdmx->mutex);
if (feed->is_filtering)
feed->stop_filtering(feed);
mutex_lock(&dvbdmx->mutex);
}
spin_lock_irq(&dvbdmx->lock);
f = dvbdmxfeed->filter;
@ -1087,11 +1066,11 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
dvbdmxfeed->cb.sec = callback;
dvbdmxfeed->demux = dvbdmx;
dvbdmxfeed->pid = 0xffff;
dvbdmxfeed->buffer_flags = 0;
dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
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;
@ -1120,6 +1099,10 @@ 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);
@ -1259,25 +1242,12 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
dvbdemux->cnt_storage = NULL;
dvbdemux->users = 0;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0))
dvbdemux->filter = vmalloc(sizeof(struct dvb_demux_filter) *
dvbdemux->filternum);
dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
if (!dvbdemux->filter)
return -ENOMEM;
dvbdemux->feed = vmalloc(sizeof(struct dvb_demux_feed) *
dvbdemux->feednum);
#else
dvbdemux->filter = vmalloc(array_size(sizeof(struct dvb_demux_filter),
dvbdemux->filternum));
if (!dvbdemux->filter)
return -ENOMEM;
dvbdemux->feed = vmalloc(array_size(sizeof(struct dvb_demux_feed),
dvbdemux->feednum));
#endif
dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed));
if (!dvbdemux->feed) {
vfree(dvbdemux->filter);
dvbdemux->filter = NULL;
@ -1294,7 +1264,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
if (!dvbdemux->cnt_storage)
pr_warn("Couldn't allocate memory for TS/TEI check. Disabling it\n");
printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
INIT_LIST_HEAD(&dvbdemux->frontend_list);

151
dvb-core/dvb_demux.h Normal file
View File

@ -0,0 +1,151 @@
/*
* dvb_demux.h: DVB kernel demux API
*
* Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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_
#define _DVB_DEMUX_H_
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include "demux.h"
#define DMX_TYPE_TS 0
#define DMX_TYPE_SEC 1
#define DMX_TYPE_PES 2
#define DMX_STATE_FREE 0
#define DMX_STATE_ALLOCATED 1
#define DMX_STATE_SET 2
#define DMX_STATE_READY 3
#define DMX_STATE_GO 4
#define DVB_DEMUX_MASK_MAX 18
#define MAX_PID 0x1fff
#define SPEED_PKTS_INTERVAL 50000
struct dvb_demux_filter {
struct dmx_section_filter filter;
u8 maskandmode[DMX_MAX_FILTER_SIZE];
u8 maskandnotmode[DMX_MAX_FILTER_SIZE];
int doneq;
struct dvb_demux_filter *next;
struct dvb_demux_feed *feed;
int index;
int state;
int type;
u16 hw_handle;
struct timer_list timer;
};
#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
struct dvb_demux_feed {
union {
struct dmx_ts_feed ts;
struct dmx_section_feed sec;
} feed;
union {
dmx_ts_cb ts;
dmx_section_cb sec;
} cb;
struct dvb_demux *demux;
void *priv;
int type;
int state;
u16 pid;
u8 *buffer;
int buffer_size;
struct timespec timeout;
struct dvb_demux_filter *filter;
int ts_type;
enum dmx_ts_pes pes_type;
int cc;
int pusi_seen; /* prevents feeding of garbage from previous section */
u16 peslen;
struct list_head list_head;
unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */
};
struct dvb_demux {
struct dmx_demux dmx;
void *priv;
int filternum;
int feednum;
int (*start_feed)(struct dvb_demux_feed *feed);
int (*stop_feed)(struct dvb_demux_feed *feed);
int (*write_to_decoder)(struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
u32 (*check_crc32)(struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
const u8 *src, size_t len);
int users;
#define MAX_DVB_DEMUX_USERS 10
struct dvb_demux_filter *filter;
struct dvb_demux_feed *feed;
struct list_head frontend_list;
struct dvb_demux_feed *pesfilter[DMX_PES_OTHER];
u16 pids[DMX_PES_OTHER];
int playing;
int recording;
#define DMX_MAX_PID 0x2000
struct list_head feed_list;
u8 tsbuf[204];
int tsbufp;
struct mutex mutex;
spinlock_t lock;
uint8_t *cnt_storage; /* for TS continuity check */
struct timespec speed_last_time; /* for TS speed check */
uint32_t speed_pkts_cnt; /* for TS speed check */
};
int dvb_dmx_init(struct dvb_demux *dvbdemux);
void dvb_dmx_release(struct dvb_demux *dvbdemux);
void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
size_t count);
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
size_t count);
void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
size_t count);
#endif /* _DVB_DEMUX_H_ */

603
dvb-core/dvb_filter.c Normal file
View File

@ -0,0 +1,603 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include "dvb_filter.h"
#if 0
static unsigned int bitrates[3][16] =
{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}};
#endif
static u32 freq[4] = {480, 441, 320, 0};
static unsigned int ac3_bitrates[32] =
{32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640,
0,0,0,0,0,0,0,0,0,0,0,0,0};
static u32 ac3_frames[3][32] =
{{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024,
1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0},
{69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114,
1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0},
{96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344,
1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}};
#if 0
static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv,
void (*pes_write)(u8 *buf, int count, void *data),
void *priv)
{
dvb_filter_ipack_init(pa, IPACKS, pes_write);
dvb_filter_ipack_init(pv, IPACKS, pes_write);
pa->pid = pida;
pv->pid = pidv;
pa->data = priv;
pv->data = priv;
}
#endif
#if 0
static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188)
{
u8 off = 0;
if (!buf || !p ){
printk("NULL POINTER IDIOT\n");
return;
}
if (buf[1]&PAY_START) {
if (p->plength == MMAX_PLENGTH-6 && p->found>6){
p->plength = p->found-6;
p->found = 0;
send_ipack(p);
dvb_filter_ipack_reset(p);
}
}
if (buf[3] & ADAPT_FIELD) { // adaptation field?
off = buf[4] + 1;
if (off+4 > 187) return;
}
dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p);
}
#endif
#if 0
/* needs 5 byte input, returns picture coding type*/
static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr)
{
u8 pct;
if (pr) printk( "Pic header: ");
pic->temporal_reference[field] = (( headr[0] << 2 ) |
(headr[1] & 0x03) )& 0x03ff;
if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]);
pct = ( headr[1] >> 2 ) & 0x07;
pic->picture_coding_type[field] = pct;
if (pr) {
switch(pct){
case I_FRAME:
printk( " I-FRAME");
break;
case B_FRAME:
printk( " B-FRAME");
break;
case P_FRAME:
printk( " P-FRAME");
break;
}
}
pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) |
( (headr[3] & 0x1F) << 11) ) & 0xffff;
if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay);
pic->picture_header_parameter = ( headr[3] & 0xe0 ) |
((headr[4] & 0x80) >> 3);
if ( pct == B_FRAME ){
pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f;
}
if (pr) printk( " pic head param: 0x%x",
pic->picture_header_parameter);
return pct;
}
#endif
#if 0
/* needs 4 byte input */
static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr)
{
if (pr) printk("GOP header: ");
pic->time_code = (( headr[0] << 17 ) | ( headr[1] << 9) |
( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff;
if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F,
((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F),
((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F));
if ( ( headr[3] & 0x40 ) != 0 ){
pic->closed_gop = 1;
} else {
pic->closed_gop = 0;
}
if (pr) printk("closed: %d", pic->closed_gop);
if ( ( headr[3] & 0x20 ) != 0 ){
pic->broken_link = 1;
} else {
pic->broken_link = 0;
}
if (pr) printk(" broken: %d\n", pic->broken_link);
return 0;
}
#endif
#if 0
/* needs 8 byte input */
static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr)
{
int sw;
int form = -1;
if (pr) printk("Reading sequence header\n");
vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4);
vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]);
sw = (int)((headr[3]&0xF0) >> 4) ;
switch( sw ){
case 1:
if (pr)
printk("Videostream: ASPECT: 1:1");
vi->aspect_ratio = 100;
break;
case 2:
if (pr)
printk("Videostream: ASPECT: 4:3");
vi->aspect_ratio = 133;
break;
case 3:
if (pr)
printk("Videostream: ASPECT: 16:9");
vi->aspect_ratio = 177;
break;
case 4:
if (pr)
printk("Videostream: ASPECT: 2.21:1");
vi->aspect_ratio = 221;
break;
case 5 ... 15:
if (pr)
printk("Videostream: ASPECT: reserved");
vi->aspect_ratio = 0;
break;
default:
vi->aspect_ratio = 0;
return -1;
}
if (pr)
printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size);
sw = (int)(headr[3]&0x0F);
switch ( sw ) {
case 1:
if (pr)
printk(" FRate: 23.976 fps");
vi->framerate = 23976;
form = -1;
break;
case 2:
if (pr)
printk(" FRate: 24 fps");
vi->framerate = 24000;
form = -1;
break;
case 3:
if (pr)
printk(" FRate: 25 fps");
vi->framerate = 25000;
form = VIDEO_MODE_PAL;
break;
case 4:
if (pr)
printk(" FRate: 29.97 fps");
vi->framerate = 29970;
form = VIDEO_MODE_NTSC;
break;
case 5:
if (pr)
printk(" FRate: 30 fps");
vi->framerate = 30000;
form = VIDEO_MODE_NTSC;
break;
case 6:
if (pr)
printk(" FRate: 50 fps");
vi->framerate = 50000;
form = VIDEO_MODE_PAL;
break;
case 7:
if (pr)
printk(" FRate: 60 fps");
vi->framerate = 60000;
form = VIDEO_MODE_NTSC;
break;
}
vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03);
vi->vbv_buffer_size
= (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5);
if (pr){
printk(" BRate: %d Mbit/s",4*(vi->bit_rate)/10000);
printk(" vbvbuffer %d",16*1024*(vi->vbv_buffer_size));
printk("\n");
}
vi->video_format = form;
return 0;
}
#endif
#if 0
static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr)
{
u8 *headr;
int found = 0;
int c = 0;
while (found < 4 && c+4 < count){
u8 *b;
b = mbuf+c;
if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01
&& b[3] == 0xb3) found = 4;
else {
c++;
}
}
if (! found) return -1;
c += 4;
if (c+12 >= count) return -1;
headr = mbuf+c;
if (read_sequence_header(headr, vi, pr) < 0) return -1;
vi->off = c-4;
return 0;
}
#endif
#if 0
static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
{
u8 *headr;
int found = 0;
int c = 0;
int fr = 0;
while (found < 2 && c < count){
u8 b[2];
memcpy( b, mbuf+c, 2);
if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8)
found = 2;
else {
c++;
}
}
if (!found) return -1;
if (c+3 >= count) return -1;
headr = mbuf+c;
ai->layer = (headr[1] & 0x06) >> 1;
if (pr)
printk("Audiostream: Layer: %d", 4-ai->layer);
ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000;
if (pr){
if (ai->bit_rate == 0)
printk(" Bit rate: free");
else if (ai->bit_rate == 0xf)
printk(" BRate: reserved");
else
printk(" BRate: %d kb/s", ai->bit_rate/1000);
}
fr = (headr[2] & 0x0c ) >> 2;
ai->frequency = freq[fr]*100;
if (pr){
if (ai->frequency == 3)
printk(" Freq: reserved\n");
else
printk(" Freq: %d kHz\n",ai->frequency);
}
ai->off = c;
return 0;
}
#endif
int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
{
u8 *headr;
int found = 0;
int c = 0;
u8 frame = 0;
int fr = 0;
while ( !found && c < count){
u8 *b = mbuf+c;
if ( b[0] == 0x0b && b[1] == 0x77 )
found = 1;
else {
c++;
}
}
if (!found) return -1;
if (pr)
printk("Audiostream: AC3");
ai->off = c;
if (c+5 >= count) return -1;
ai->layer = 0; // 0 for AC3
headr = mbuf+c+2;
frame = (headr[2]&0x3f);
ai->bit_rate = ac3_bitrates[frame >> 1]*1000;
if (pr)
printk(" BRate: %d kb/s", (int) ai->bit_rate/1000);
ai->frequency = (headr[2] & 0xc0 ) >> 6;
fr = (headr[2] & 0xc0 ) >> 6;
ai->frequency = freq[fr]*100;
if (pr) printk (" Freq: %d Hz\n", (int) ai->frequency);
ai->framesize = ac3_frames[fr][frame >> 1];
if ((frame & 1) && (fr == 1)) ai->framesize++;
ai->framesize = ai->framesize << 1;
if (pr) printk (" Framesize %d\n",(int) ai->framesize);
return 0;
}
EXPORT_SYMBOL(dvb_filter_get_ac3info);
#if 0
static u8 *skip_pes_header(u8 **bufp)
{
u8 *inbuf = *bufp;
u8 *buf = inbuf;
u8 *pts = NULL;
int skip = 0;
static const int mpeg1_skip_table[16] = {
1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
};
if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */
if (buf[7] & PTS_ONLY)
pts = buf+9;
else pts = NULL;
buf = inbuf + 9 + inbuf[8];
} else { /* mpeg1 */
for (buf = inbuf + 6; *buf == 0xff; buf++)
if (buf == inbuf + 6 + 16) {
break;
}
if ((*buf & 0xc0) == 0x40)
buf += 2;
skip = mpeg1_skip_table [*buf >> 4];
if (skip == 5 || skip == 10) pts = buf;
else pts = NULL;
buf += mpeg1_skip_table [*buf >> 4];
}
*bufp = buf;
return pts;
}
#endif
#if 0
static void initialize_quant_matrix( u32 *matrix )
{
int i;
matrix[0] = 0x08101013;
matrix[1] = 0x10131616;
matrix[2] = 0x16161616;
matrix[3] = 0x1a181a1b;
matrix[4] = 0x1b1b1a1a;
matrix[5] = 0x1a1a1b1b;
matrix[6] = 0x1b1d1d1d;
matrix[7] = 0x2222221d;
matrix[8] = 0x1d1d1b1b;
matrix[9] = 0x1d1d2020;
matrix[10] = 0x22222526;
matrix[11] = 0x25232322;
matrix[12] = 0x23262628;
matrix[13] = 0x28283030;
matrix[14] = 0x2e2e3838;
matrix[15] = 0x3a454553;
for ( i = 16 ; i < 32 ; i++ )
matrix[i] = 0x10101010;
}
#endif
#if 0
static void initialize_mpg_picture(struct mpg_picture *pic)
{
int i;
/* set MPEG1 */
pic->mpeg1_flag = 1;
pic->profile_and_level = 0x4A ; /* MP@LL */
pic->progressive_sequence = 1;
pic->low_delay = 0;
pic->sequence_display_extension_flag = 0;
for ( i = 0 ; i < 4 ; i++ ){
pic->frame_centre_horizontal_offset[i] = 0;
pic->frame_centre_vertical_offset[i] = 0;
}
pic->last_frame_centre_horizontal_offset = 0;
pic->last_frame_centre_vertical_offset = 0;
pic->picture_display_extension_flag[0] = 0;
pic->picture_display_extension_flag[1] = 0;
pic->sequence_header_flag = 0;
pic->gop_flag = 0;
pic->sequence_end_flag = 0;
}
#endif
#if 0
static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic )
{
int16_t last_h_offset;
int16_t last_v_offset;
int16_t *p_h_offset;
int16_t *p_v_offset;
if ( pic->mpeg1_flag ){
pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE;
pic->top_field_first = 0;
pic->repeat_first_field = 0;
pic->progressive_frame = 1;
pic->picture_coding_parameter = 0x000010;
}
/* Reset flag */
pic->picture_display_extension_flag[field_type] = 0;
last_h_offset = pic->last_frame_centre_horizontal_offset;
last_v_offset = pic->last_frame_centre_vertical_offset;
if ( field_type == FIRST_FIELD ){
p_h_offset = pic->frame_centre_horizontal_offset;
p_v_offset = pic->frame_centre_vertical_offset;
*p_h_offset = last_h_offset;
*(p_h_offset + 1) = last_h_offset;
*(p_h_offset + 2) = last_h_offset;
*p_v_offset = last_v_offset;
*(p_v_offset + 1) = last_v_offset;
*(p_v_offset + 2) = last_v_offset;
} else {
pic->frame_centre_horizontal_offset[3] = last_h_offset;
pic->frame_centre_vertical_offset[3] = last_v_offset;
}
}
#endif
#if 0
static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type)
{
pic->picture_header = 0;
pic->sequence_header_data
= ( INIT_HORIZONTAL_SIZE << 20 )
| ( INIT_VERTICAL_SIZE << 8 )
| ( INIT_ASPECT_RATIO << 4 )
| ( INIT_FRAME_RATE );
pic->mpeg1_flag = 0;
pic->vinfo.horizontal_size
= INIT_DISP_HORIZONTAL_SIZE;
pic->vinfo.vertical_size
= INIT_DISP_VERTICAL_SIZE;
pic->picture_display_extension_flag[field_type]
= 0;
pic->pts_flag[field_type] = 0;
pic->sequence_gop_header = 0;
pic->picture_header = 0;
pic->sequence_header_flag = 0;
pic->gop_flag = 0;
pic->sequence_end_flag = 0;
pic->sequence_display_extension_flag = 0;
pic->last_frame_centre_horizontal_offset = 0;
pic->last_frame_centre_vertical_offset = 0;
pic->channel = chan;
}
#endif
void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
dvb_filter_pes2ts_cb_t *cb, void *priv)
{
unsigned char *buf=p2ts->buf;
buf[0]=0x47;
buf[1]=(pid>>8);
buf[2]=pid&0xff;
p2ts->cc=0;
p2ts->cb=cb;
p2ts->priv=priv;
}
EXPORT_SYMBOL(dvb_filter_pes2ts_init);
int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
int len, int payload_start)
{
unsigned char *buf=p2ts->buf;
int ret=0, rest;
//len=6+((pes[4]<<8)|pes[5]);
if (payload_start)
buf[1]|=0x40;
else
buf[1]&=~0x40;
while (len>=184) {
buf[3]=0x10|((p2ts->cc++)&0x0f);
memcpy(buf+4, pes, 184);
if ((ret=p2ts->cb(p2ts->priv, buf)))
return ret;
len-=184; pes+=184;
buf[1]&=~0x40;
}
if (!len)
return 0;
buf[3]=0x30|((p2ts->cc++)&0x0f);
rest=183-len;
if (rest) {
buf[5]=0x00;
if (rest-1)
memset(buf+6, 0xff, rest-1);
}
buf[4]=rest;
memcpy(buf+5+rest, pes, len);
return p2ts->cb(p2ts->priv, buf);
}
EXPORT_SYMBOL(dvb_filter_pes2ts);

246
dvb-core/dvb_filter.h Normal file
View File

@ -0,0 +1,246 @@
/*
* dvb_filter.h
*
* Copyright (C) 2003 Convergence GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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_FILTER_H_
#define _DVB_FILTER_H_
#include <linux/slab.h>
#include "demux.h"
typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *);
struct dvb_filter_pes2ts {
unsigned char buf[188];
unsigned char cc;
dvb_filter_pes2ts_cb_t *cb;
void *priv;
};
void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
dvb_filter_pes2ts_cb_t *cb, void *priv);
int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
int len, int payload_start);
#define PROG_STREAM_MAP 0xBC
#define PRIVATE_STREAM1 0xBD
#define PADDING_STREAM 0xBE
#define PRIVATE_STREAM2 0xBF
#define AUDIO_STREAM_S 0xC0
#define AUDIO_STREAM_E 0xDF
#define VIDEO_STREAM_S 0xE0
#define VIDEO_STREAM_E 0xEF
#define ECM_STREAM 0xF0
#define EMM_STREAM 0xF1
#define DSM_CC_STREAM 0xF2
#define ISO13522_STREAM 0xF3
#define PROG_STREAM_DIR 0xFF
#define DVB_PICTURE_START 0x00
#define DVB_USER_START 0xb2
#define DVB_SEQUENCE_HEADER 0xb3
#define DVB_SEQUENCE_ERROR 0xb4
#define DVB_EXTENSION_START 0xb5
#define DVB_SEQUENCE_END 0xb7
#define DVB_GOP_START 0xb8
#define DVB_EXCEPT_SLICE 0xb0
#define SEQUENCE_EXTENSION 0x01
#define SEQUENCE_DISPLAY_EXTENSION 0x02
#define PICTURE_CODING_EXTENSION 0x08
#define QUANT_MATRIX_EXTENSION 0x03
#define PICTURE_DISPLAY_EXTENSION 0x07
#define I_FRAME 0x01
#define B_FRAME 0x02
#define P_FRAME 0x03
/* Initialize sequence_data */
#define INIT_HORIZONTAL_SIZE 720
#define INIT_VERTICAL_SIZE 576
#define INIT_ASPECT_RATIO 0x02
#define INIT_FRAME_RATE 0x03
#define INIT_DISP_HORIZONTAL_SIZE 540
#define INIT_DISP_VERTICAL_SIZE 576
//flags2
#define PTS_DTS_FLAGS 0xC0
#define ESCR_FLAG 0x20
#define ES_RATE_FLAG 0x10
#define DSM_TRICK_FLAG 0x08
#define ADD_CPY_FLAG 0x04
#define PES_CRC_FLAG 0x02
#define PES_EXT_FLAG 0x01
//pts_dts flags
#define PTS_ONLY 0x80
#define PTS_DTS 0xC0
#define TS_SIZE 188
#define TRANS_ERROR 0x80
#define PAY_START 0x40
#define TRANS_PRIO 0x20
#define PID_MASK_HI 0x1F
//flags
#define TRANS_SCRMBL1 0x80
#define TRANS_SCRMBL2 0x40
#define ADAPT_FIELD 0x20
#define PAYLOAD 0x10
#define COUNT_MASK 0x0F
// adaptation flags
#define DISCON_IND 0x80
#define RAND_ACC_IND 0x40
#define ES_PRI_IND 0x20
#define PCR_FLAG 0x10
#define OPCR_FLAG 0x08
#define SPLICE_FLAG 0x04
#define TRANS_PRIV 0x02
#define ADAP_EXT_FLAG 0x01
// adaptation extension flags
#define LTW_FLAG 0x80
#define PIECE_RATE 0x40
#define SEAM_SPLICE 0x20
#define MAX_PLENGTH 0xFFFF
#define MMAX_PLENGTH (256*MAX_PLENGTH)
#ifndef IPACKS
#define IPACKS 2048
#endif
struct ipack {
int size;
int found;
u8 *buf;
u8 cid;
u32 plength;
u8 plen[2];
u8 flag1;
u8 flag2;
u8 hlength;
u8 pts[5];
u16 *pid;
int mpeg;
u8 check;
int which;
int done;
void *data;
void (*func)(u8 *buf, int size, void *priv);
int count;
int repack_subids;
};
struct dvb_video_info {
u32 horizontal_size;
u32 vertical_size;
u32 aspect_ratio;
u32 framerate;
u32 video_format;
u32 bit_rate;
u32 comp_bit_rate;
u32 vbv_buffer_size;
s16 vbv_delay;
u32 CSPF;
u32 off;
};
#define OFF_SIZE 4
#define FIRST_FIELD 0
#define SECOND_FIELD 1
#define VIDEO_FRAME_PICTURE 0x03
struct mpg_picture {
int channel;
struct dvb_video_info vinfo;
u32 *sequence_gop_header;
u32 *picture_header;
s32 time_code;
int low_delay;
int closed_gop;
int broken_link;
int sequence_header_flag;
int gop_flag;
int sequence_end_flag;
u8 profile_and_level;
s32 picture_coding_parameter;
u32 matrix[32];
s8 matrix_change_flag;
u8 picture_header_parameter;
/* bit 0 - 2: bwd f code
bit 3 : fpb vector
bit 4 - 6: fwd f code
bit 7 : fpf vector */
int mpeg1_flag;
int progressive_sequence;
int sequence_display_extension_flag;
u32 sequence_header_data;
s16 last_frame_centre_horizontal_offset;
s16 last_frame_centre_vertical_offset;
u32 pts[2]; /* [0] 1st field, [1] 2nd field */
int top_field_first;
int repeat_first_field;
int progressive_frame;
int bank;
int forward_bank;
int backward_bank;
int compress;
s16 frame_centre_horizontal_offset[OFF_SIZE];
/* [0-2] 1st field, [3] 2nd field */
s16 frame_centre_vertical_offset[OFF_SIZE];
/* [0-2] 1st field, [3] 2nd field */
s16 temporal_reference[2];
/* [0] 1st field, [1] 2nd field */
s8 picture_coding_type[2];
/* [0] 1st field, [1] 2nd field */
s8 picture_structure[2];
/* [0] 1st field, [1] 2nd field */
s8 picture_display_extension_flag[2];
/* [0] 1st field, [1] 2nd field */
/* picture_display_extenion() 0:no 1:exit*/
s8 pts_flag[2];
/* [0] 1st field, [1] 2nd field */
};
struct dvb_audio_info {
int layer;
u32 bit_rate;
u32 frequency;
u32 mode;
u32 mode_extension ;
u32 emphasis;
u32 framesize;
u32 off;
};
int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr);
#endif

File diff suppressed because it is too large Load Diff

441
dvb-core/dvb_frontend.h Normal file
View File

@ -0,0 +1,441 @@
/*
* dvb_frontend.h
*
* Copyright (C) 2001 convergence integrated media GmbH
* Copyright (C) 2004 convergence GmbH
*
* Written by Ralph Metzler
* Overhauled by Holger Waechtler
* Kernel I2C stuff by Michael Hunold <hunold@convergence.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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_FRONTEND_H_
#define _DVB_FRONTEND_H_
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/dvb/frontend.h>
#include "dvbdev.h"
/*
* Maximum number of Delivery systems per frontend. It
* should be smaller or equal to 32
*/
#define MAX_DELSYS 8
struct dvb_frontend_tune_settings {
int min_delay_ms;
int step_size;
int max_drift;
};
struct dvb_frontend;
struct dvb_tuner_info {
char name[128];
u32 frequency_min;
u32 frequency_max;
u32 frequency_step;
u32 bandwidth_min;
u32 bandwidth_max;
u32 bandwidth_step;
};
struct analog_parameters {
unsigned int frequency;
unsigned int mode;
unsigned int audmode;
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.
*
* 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.
*
* ALGO_RECOVERY: (Recovery Algorithm)
* ----------------------------------------------------------------
* These devices have AUTO recovery capabilities from LOCK failure
*/
enum dvbfe_algo {
DVBFE_ALGO_HW = (1 << 0),
DVBFE_ALGO_SW = (1 << 1),
DVBFE_ALGO_CUSTOM = (1 << 2),
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
*
* 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_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_ERROR
* The frontend search algorithm failed due to some error
*
* DVBFE_ALGO_SEARCH_AGAIN
* The frontend search algorithm was requested to search again
*/
enum dvbfe_search {
DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0),
DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1),
DVBFE_ALGO_SEARCH_FAILED = (1 << 2),
DVBFE_ALGO_SEARCH_INVALID = (1 << 3),
DVBFE_ALGO_SEARCH_AGAIN = (1 << 4),
DVBFE_ALGO_SEARCH_ERROR = (1 << 31),
};
struct dvb_tuner_ops {
struct dvb_tuner_info info;
int (*release)(struct dvb_frontend *fe);
int (*init)(struct dvb_frontend *fe);
int (*sleep)(struct dvb_frontend *fe);
/** This is for simple PLLs - set all parameters in one go. */
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);
int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency);
#define TUNER_STATUS_LOCKED 1
#define TUNER_STATUS_STEREO 2
int (*get_status)(struct dvb_frontend *fe, u32 *status);
int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
/** These are provided separately from set_params in order to facilitate silicon
* tuners which require sophisticated tuning loops, controlling each parameter separately. */
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
/*
* These are provided separately from set_params in order to facilitate silicon
* tuners which require sophisticated tuning loops, controlling each parameter separately.
*/
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);
};
struct analog_demod_info {
char *name;
};
struct analog_demod_ops {
struct analog_demod_info info;
void (*set_params)(struct dvb_frontend *fe,
struct analog_parameters *params);
int (*has_signal)(struct dvb_frontend *fe, u16 *signal);
int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
void (*tuner_status)(struct dvb_frontend *fe);
void (*standby)(struct dvb_frontend *fe);
void (*release)(struct dvb_frontend *fe);
int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
/** This is to allow setting tuner-specific configuration */
int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
};
struct dtv_frontend_properties;
struct dvb_frontend_ops {
struct dvb_frontend_info info;
u8 delsys[MAX_DELSYS];
void (*release)(struct dvb_frontend* fe);
void (*release_sec)(struct dvb_frontend* fe);
int (*init)(struct dvb_frontend* fe);
int (*sleep)(struct dvb_frontend* fe);
int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
/* if this is set, it overrides the default swzigzag */
int (*tune)(struct dvb_frontend* fe,
bool re_tune,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status);
/* get frontend tuning algorithm from the module */
enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
/* these two are only used for the swzigzag code */
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 (*read_status)(struct dvb_frontend* fe, fe_status_t* 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);
int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
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 (*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);
int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
int (*set_lna)(struct dvb_frontend *);
int (*set_input)(struct dvb_frontend *, int);
/* These callbacks are for devices that implement their own
* tuning algorithms, rather than a simple swzigzag
*/
enum dvbfe_search (*search)(struct dvb_frontend *fe);
struct dvb_tuner_ops tuner_ops;
struct analog_demod_ops analog_ops;
int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
u8 xbar[3];
};
#ifdef __DVB_CORE__
#define MAX_EVENT 8
struct dvb_fe_events {
struct dvb_frontend_event events[MAX_EVENT];
int eventw;
int eventr;
int overflow;
wait_queue_head_t wait_queue;
struct mutex mtx;
};
#endif
struct dtv_frontend_properties {
/* Cache State */
u32 state;
u32 frequency;
fe_modulation_t 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;
u32 bandwidth_hz; /* 0 = AUTO */
fe_guard_interval_t guard_interval;
fe_hierarchy_t hierarchy;
u32 symbol_rate;
fe_code_rate_t code_rate_HP;
fe_code_rate_t code_rate_LP;
fe_pilot_t pilot;
fe_rolloff_t rolloff;
fe_delivery_system_t delivery_system;
enum fe_interleaving interleaving;
/* ISDB-T specifics */
u8 isdbt_partial_reception;
u8 isdbt_sb_mode;
u8 isdbt_sb_subchannel;
u32 isdbt_sb_segment_idx;
u32 isdbt_sb_segment_count;
u8 isdbt_layer_enabled;
struct {
u8 segment_count;
fe_code_rate_t fec;
fe_modulation_t modulation;
u8 interleaving;
} layer[3];
/* Multistream specifics */
u32 stream_id;
/* ATSC-MH specifics */
u8 atscmh_fic_ver;
u8 atscmh_parade_id;
u8 atscmh_nog;
u8 atscmh_tnog;
u8 atscmh_sgn;
u8 atscmh_prc;
u8 atscmh_rs_frame_mode;
u8 atscmh_rs_frame_ensemble;
u8 atscmh_rs_code_mode_pri;
u8 atscmh_rs_code_mode_sec;
u8 atscmh_sccc_block_mode;
u8 atscmh_sccc_code_mode_a;
u8 atscmh_sccc_code_mode_b;
u8 atscmh_sccc_code_mode_c;
u8 atscmh_sccc_code_mode_d;
u32 lna;
s32 input;
/* statistics data */
struct dtv_fe_stats strength;
struct dtv_fe_stats cnr;
struct dtv_fe_stats pre_bit_error;
struct dtv_fe_stats pre_bit_count;
struct dtv_fe_stats post_bit_error;
struct dtv_fe_stats post_bit_count;
struct dtv_fe_stats block_error;
struct dtv_fe_stats block_count;
};
struct dvb_frontend {
struct dvb_frontend_ops ops;
struct dvb_adapter *dvb;
void *demodulator_priv;
void *tuner_priv;
void *frontend_priv;
void *sec_priv;
void *analog_demod_priv;
struct dtv_frontend_properties dtv_property_cache;
#define DVB_FRONTEND_COMPONENT_TUNER 0
#define DVB_FRONTEND_COMPONENT_DEMOD 1
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
int id;
};
extern int dvb_register_frontend(struct dvb_adapter *dvb,
struct dvb_frontend *fe);
extern int dvb_unregister_frontend(struct dvb_frontend *fe);
extern 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);
extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
#endif

View File

@ -1,4 +1,3 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* dvb-math provides some complex fixed-point math
* operations shared between the dvb related stuff
@ -14,14 +13,17 @@
* 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
*/
#if (KERNEL_VERSION(6, 6, 0) > LINUX_VERSION_CODE)
#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/bug.h>
#include <media/dvb_math.h>
#include "dvb_math.h"
static const unsigned short logtable[256] = {
0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
@ -141,6 +143,3 @@ unsigned int intlog10(u32 value)
return (log * 646456993) >> 31;
}
EXPORT_SYMBOL(intlog10);
#else
#include <linux/int_log.h>
#endif

View File

@ -13,6 +13,10 @@
* 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
@ -21,45 +25,33 @@
#include <linux/types.h>
/**
* intlog2 - computes log2 of a value; the result is shifted left by 24 bits
*
* @value: The value (must be != 0)
* computes log2 of a value; the result is shifted left by 24 bits
*
* to use rational values you can use the following method:
*
* intlog2(value) = intlog2(value * 2^x) - x * 2^24
*
* Some usecase examples:
* 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
*
* 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
* @param value The value (must be != 0)
* @return log2(value) * 2^24
*/
extern unsigned int intlog2(u32 value);
/**
* intlog10 - computes log10 of a value; the result is shifted left by 24 bits
*
* @value: The value (must be != 0)
* computes log10 of a value; the result is shifted left by 24 bits
*
* to use rational values you can use the following method:
*
* intlog10(value) = intlog10(value * 10^x) - x * 2^24
*
* An usecase example:
*
* intlog10(1000) will give 3 << 24 = 3 * 2^24
*
* 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
*
* return: log10(value) * 2^24
* @param value The value (must be != 0)
* @return log10(value) * 2^24
*/
extern unsigned int intlog10(u32 value);

File diff suppressed because it is too large Load Diff

67
dvb-core/dvb_net.h Normal file
View File

@ -0,0 +1,67 @@
/*
* dvb_net.h
*
* Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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_
#define _DVB_NET_H_
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include "dvbdev.h"
#define DVB_NET_DEVICES_MAX 10
#ifdef CONFIG_DVB_NET
struct dvb_net {
struct dvb_device *dvbdev;
struct net_device *device[DVB_NET_DEVICES_MAX];
int state[DVB_NET_DEVICES_MAX];
unsigned int exit:1;
struct dmx_demux *demux;
struct mutex ioctl_mutex;
};
void dvb_net_release(struct dvb_net *);
int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
#else
struct dvb_net {
struct dvb_device *dvbdev;
};
static inline void dvb_net_release(struct dvb_net *dvbnet)
{
}
static inline int dvb_net_init(struct dvb_adapter *adap,
struct dvb_net *dvbnet, struct dmx_demux *dmx)
{
return 0;
}
#endif /* ifdef CONFIG_DVB_NET */
#endif

View File

@ -26,9 +26,6 @@
#include <linux/net.h>
#include "dvb_netstream.h"
int ddb_dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
int (*func)(struct file *file, unsigned int cmd, void *arg));
static ssize_t ns_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
@ -214,7 +211,7 @@ static int do_ioctl(struct file *file, unsigned int cmd, void *parg)
static long ns_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return ddb_dvb_usercopy(file, cmd, arg, do_ioctl);
return dvb_usercopy(file, cmd, arg, do_ioctl);
}
static const struct file_operations ns_fops = {
@ -244,11 +241,11 @@ 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, 0);
DVB_DEVICE_NS);
INIT_LIST_HEAD(&ns->nssl);
return 0;
}
//EXPORT_SYMBOL(dvb_netstream_init);
EXPORT_SYMBOL(dvb_netstream_init);
void dvb_netstream_release(struct dvb_netstream *ns)
{
@ -259,4 +256,4 @@ void dvb_netstream_release(struct dvb_netstream *ns)
}
dvb_unregister_device(ns->dvbdev);
}
//EXPORT_SYMBOL(dvb_netstream_release);
EXPORT_SYMBOL(dvb_netstream_release);

View File

@ -36,9 +36,9 @@
#include <linux/socket.h>
#include <linux/in.h>
#include <asm/uaccess.h>
#include "ns.h"
#include <linux/dvb/ns.h>
#include <media/dvbdev.h>
#include "dvbdev.h"
#define DVBNS_MAXPIDS 32

View File

@ -18,6 +18,10 @@
* 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.
*/
@ -27,14 +31,9 @@
#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 <media/dvb_ringbuffer.h>
#include "dvb_ringbuffer.h"
#define PKT_READY 0
#define PKT_DISPOSED 1
@ -56,17 +55,7 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
{
#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/core-api/circular-buffers.rst
*/
return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
#endif
}
@ -75,16 +64,7 @@ ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
{
ssize_t free;
/* READ_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
free = rbuf->pread - rbuf->pwrite;
if (free <= 0)
free += rbuf->size;
return free-1;
@ -96,15 +76,7 @@ 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;
@ -114,33 +86,14 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
{
#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;
}
@ -166,25 +119,13 @@ 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 READ_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;
}
@ -198,24 +139,11 @@ 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 READ_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
}
@ -230,63 +158,10 @@ 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;
}
@ -391,9 +266,7 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t*
idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
}
consumed = (idx - rbuf->pread);
if (consumed < 0)
consumed += rbuf->size;
consumed = (idx - rbuf->pread) % rbuf->size;
while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
@ -424,4 +297,3 @@ 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);

186
dvb-core/dvb_ringbuffer.h Normal file
View File

@ -0,0 +1,186 @@
/*
*
* dvb_ringbuffer.h: ring buffer implementation for the dvb driver
*
* Copyright (C) 2003 Oliver Endriss
* Copyright (C) 2004 Andrew de Quincey
*
* based on code originally found in av7110.c & dvb_ci.c:
* Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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_
#define _DVB_RINGBUFFER_H_
#include <linux/spinlock.h>
#include <linux/wait.h>
struct dvb_ringbuffer {
u8 *data;
ssize_t size;
ssize_t pread;
ssize_t pwrite;
int error;
wait_queue_head_t queue;
spinlock_t lock;
};
#define DVB_RINGBUFFER_PKTHDRSIZE 3
/*
** 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 */
extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
/* return the 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 */
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
*/
extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf);
/* read routines & macros */
/* ---------------------- */
/* flush buffer */
extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
/* flush buffer protected by spinlock and wake-up waiting task(s) */
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]
/* advance read ptr by <num> bytes */
#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
*/
extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
u8 __user *buf, size_t len);
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
*/
extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
size_t len);
/**
* 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.
*/
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.
*
* <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.
*/
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.
*
* <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.
*
* <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);
#endif /* _DVB_RINGBUFFER_H_ */

View File

@ -1,448 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* dvb-vb2.c - dvb-vb2
*
* Copyright (C) 2015 Samsung Electronics
*
* Author: jh1009.sung@samsung.com
*/
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <media/dvbdev.h>
#include <media/dvb_vb2.h>
#define DVB_V2_MAX_SIZE (4096 * 188)
static int vb2_debug;
module_param(vb2_debug, int, 0644);
#define dprintk(level, fmt, arg...) \
do { \
if (vb2_debug >= level) \
pr_info("vb2: %s: " fmt, __func__, ## arg); \
} while (0)
static int _queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], struct device *alloc_devs[])
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vq);
ctx->buf_cnt = *nbuffers;
*nplanes = 1;
sizes[0] = ctx->buf_siz;
/*
* videobuf2-vmalloc allocator is context-less so no need to set
* alloc_ctxs array.
*/
dprintk(3, "[%s] count=%d, size=%d\n", ctx->name,
*nbuffers, sizes[0]);
return 0;
}
static int _buffer_prepare(struct vb2_buffer *vb)
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
unsigned long size = ctx->buf_siz;
if (vb2_plane_size(vb, 0) < size) {
dprintk(1, "[%s] data will not fit into plane (%lu < %lu)\n",
ctx->name, vb2_plane_size(vb, 0), size);
return -EINVAL;
}
vb2_set_plane_payload(vb, 0, size);
dprintk(3, "[%s]\n", ctx->name);
return 0;
}
static void _buffer_queue(struct vb2_buffer *vb)
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct dvb_buffer *buf = container_of(vb, struct dvb_buffer, vb);
unsigned long flags = 0;
spin_lock_irqsave(&ctx->slock, flags);
list_add_tail(&buf->list, &ctx->dvb_q);
spin_unlock_irqrestore(&ctx->slock, flags);
dprintk(3, "[%s]\n", ctx->name);
}
static int _start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vq);
dprintk(3, "[%s] count=%d\n", ctx->name, count);
return 0;
}
static void _stop_streaming(struct vb2_queue *vq)
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vq);
struct dvb_buffer *buf;
unsigned long flags = 0;
dprintk(3, "[%s]\n", ctx->name);
spin_lock_irqsave(&ctx->slock, flags);
while (!list_empty(&ctx->dvb_q)) {
buf = list_entry(ctx->dvb_q.next,
struct dvb_buffer, list);
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
list_del(&buf->list);
}
spin_unlock_irqrestore(&ctx->slock, flags);
}
static void _dmxdev_lock(struct vb2_queue *vq)
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vq);
mutex_lock(&ctx->mutex);
dprintk(3, "[%s]\n", ctx->name);
}
static void _dmxdev_unlock(struct vb2_queue *vq)
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vq);
if (mutex_is_locked(&ctx->mutex))
mutex_unlock(&ctx->mutex);
dprintk(3, "[%s]\n", ctx->name);
}
static const struct vb2_ops dvb_vb2_qops = {
.queue_setup = _queue_setup,
.buf_prepare = _buffer_prepare,
.buf_queue = _buffer_queue,
.start_streaming = _start_streaming,
.stop_streaming = _stop_streaming,
.wait_prepare = _dmxdev_unlock,
.wait_finish = _dmxdev_lock,
};
static void _fill_dmx_buffer(struct vb2_buffer *vb, void *pb)
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct dmx_buffer *b = pb;
b->index = vb->index;
b->length = vb->planes[0].length;
b->bytesused = vb->planes[0].bytesused;
b->offset = vb->planes[0].m.offset;
dprintk(3, "[%s]\n", ctx->name);
}
static int _fill_vb2_buffer(struct vb2_buffer *vb, struct vb2_plane *planes)
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
planes[0].bytesused = 0;
dprintk(3, "[%s]\n", ctx->name);
return 0;
}
static const struct vb2_buf_ops dvb_vb2_buf_ops = {
.fill_user_buffer = _fill_dmx_buffer,
.fill_vb2_buffer = _fill_vb2_buffer,
};
/*
* Videobuf operations
*/
int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int nonblocking)
{
struct vb2_queue *q = &ctx->vb_q;
int ret;
memset(ctx, 0, sizeof(struct dvb_vb2_ctx));
q->type = DVB_BUF_TYPE_CAPTURE;
/**only mmap is supported currently*/
q->io_modes = VB2_MMAP;
q->drv_priv = ctx;
q->buf_struct_size = sizeof(struct dvb_buffer);
q->min_queued_buffers = 1;
q->ops = &dvb_vb2_qops;
q->mem_ops = &vb2_vmalloc_memops;
q->buf_ops = &dvb_vb2_buf_ops;
ret = vb2_core_queue_init(q);
if (ret) {
ctx->state = DVB_VB2_STATE_NONE;
dprintk(1, "[%s] errno=%d\n", ctx->name, ret);
return ret;
}
mutex_init(&ctx->mutex);
spin_lock_init(&ctx->slock);
INIT_LIST_HEAD(&ctx->dvb_q);
strscpy(ctx->name, name, DVB_VB2_NAME_MAX);
ctx->nonblocking = nonblocking;
ctx->state = DVB_VB2_STATE_INIT;
dprintk(3, "[%s]\n", ctx->name);
return 0;
}
int dvb_vb2_release(struct dvb_vb2_ctx *ctx)
{
struct vb2_queue *q = (struct vb2_queue *)&ctx->vb_q;
if (ctx->state & DVB_VB2_STATE_INIT)
vb2_core_queue_release(q);
ctx->state = DVB_VB2_STATE_NONE;
dprintk(3, "[%s]\n", ctx->name);
return 0;
}
int dvb_vb2_stream_on(struct dvb_vb2_ctx *ctx)
{
struct vb2_queue *q = &ctx->vb_q;
int ret;
ret = vb2_core_streamon(q, q->type);
if (ret) {
ctx->state = DVB_VB2_STATE_NONE;
dprintk(1, "[%s] errno=%d\n", ctx->name, ret);
return ret;
}
ctx->state |= DVB_VB2_STATE_STREAMON;
dprintk(3, "[%s]\n", ctx->name);
return 0;
}
int dvb_vb2_stream_off(struct dvb_vb2_ctx *ctx)
{
struct vb2_queue *q = (struct vb2_queue *)&ctx->vb_q;
int ret;
ctx->state &= ~DVB_VB2_STATE_STREAMON;
ret = vb2_core_streamoff(q, q->type);
if (ret) {
ctx->state = DVB_VB2_STATE_NONE;
dprintk(1, "[%s] errno=%d\n", ctx->name, ret);
return ret;
}
dprintk(3, "[%s]\n", ctx->name);
return 0;
}
int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx)
{
return (ctx->state & DVB_VB2_STATE_STREAMON);
}
int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
const unsigned char *src, int len,
enum dmx_buffer_flags *buffer_flags)
{
unsigned long flags = 0;
void *vbuf = NULL;
int todo = len;
unsigned char *psrc = (unsigned char *)src;
int ll = 0;
/*
* normal case: This func is called twice from demux driver
* one with valid src pointer, second time with NULL pointer
*/
if (!src || !len)
return 0;
spin_lock_irqsave(&ctx->slock, flags);
if (buffer_flags && *buffer_flags) {
ctx->flags |= *buffer_flags;
*buffer_flags = 0;
}
while (todo) {
if (!ctx->buf) {
if (list_empty(&ctx->dvb_q)) {
dprintk(3, "[%s] Buffer overflow!!!\n",
ctx->name);
break;
}
ctx->buf = list_entry(ctx->dvb_q.next,
struct dvb_buffer, list);
ctx->remain = vb2_plane_size(&ctx->buf->vb, 0);
ctx->offset = 0;
}
if (!dvb_vb2_is_streaming(ctx)) {
vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_ERROR);
list_del(&ctx->buf->list);
ctx->buf = NULL;
break;
}
/* Fill buffer */
ll = min(todo, ctx->remain);
vbuf = vb2_plane_vaddr(&ctx->buf->vb, 0);
memcpy(vbuf + ctx->offset, psrc, ll);
todo -= ll;
psrc += ll;
ctx->remain -= ll;
ctx->offset += ll;
if (ctx->remain == 0) {
vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_DONE);
list_del(&ctx->buf->list);
ctx->buf = NULL;
}
}
if (ctx->nonblocking && ctx->buf) {
vb2_set_plane_payload(&ctx->buf->vb, 0, ll);
vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_DONE);
list_del(&ctx->buf->list);
ctx->buf = NULL;
}
spin_unlock_irqrestore(&ctx->slock, flags);
if (todo)
dprintk(1, "[%s] %d bytes are dropped.\n", ctx->name, todo);
else
dprintk(3, "[%s]\n", ctx->name);
dprintk(3, "[%s] %d bytes are copied\n", ctx->name, len - todo);
return (len - todo);
}
int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req)
{
int ret;
/* Adjust size to a sane value */
if (req->size > DVB_V2_MAX_SIZE)
req->size = DVB_V2_MAX_SIZE;
/* FIXME: round req->size to a 188 or 204 multiple */
ctx->buf_siz = req->size;
ctx->buf_cnt = req->count;
ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, 0, &req->count);
if (ret) {
ctx->state = DVB_VB2_STATE_NONE;
dprintk(1, "[%s] count=%d size=%d errno=%d\n", ctx->name,
ctx->buf_cnt, ctx->buf_siz, ret);
return ret;
}
ctx->state |= DVB_VB2_STATE_REQBUFS;
dprintk(3, "[%s] count=%d size=%d\n", ctx->name,
ctx->buf_cnt, ctx->buf_siz);
return 0;
}
int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
{
struct vb2_queue *q = &ctx->vb_q;
struct vb2_buffer *vb2 = vb2_get_buffer(q, b->index);
if (!vb2) {
dprintk(1, "[%s] invalid buffer index\n", ctx->name);
return -EINVAL;
}
vb2_core_querybuf(&ctx->vb_q, vb2, b);
dprintk(3, "[%s] index=%d\n", ctx->name, b->index);
return 0;
}
int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp)
{
struct vb2_queue *q = &ctx->vb_q;
int ret;
ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, q->bufs[exp->index],
0, exp->flags);
if (ret) {
dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,
exp->index, ret);
return ret;
}
dprintk(3, "[%s] index=%d fd=%d\n", ctx->name, exp->index, exp->fd);
return 0;
}
int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
{
struct vb2_queue *q = &ctx->vb_q;
struct vb2_buffer *vb2 = vb2_get_buffer(q, b->index);
int ret;
if (!vb2) {
dprintk(1, "[%s] invalid buffer index\n", ctx->name);
return -EINVAL;
}
ret = vb2_core_qbuf(&ctx->vb_q, vb2, b, NULL);
if (ret) {
dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,
b->index, ret);
return ret;
}
dprintk(5, "[%s] index=%d\n", ctx->name, b->index);
return 0;
}
int dvb_vb2_dqbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
{
unsigned long flags;
int ret;
ret = vb2_core_dqbuf(&ctx->vb_q, &b->index, b, ctx->nonblocking);
if (ret) {
dprintk(1, "[%s] errno=%d\n", ctx->name, ret);
return ret;
}
spin_lock_irqsave(&ctx->slock, flags);
b->count = ctx->count++;
b->flags = ctx->flags;
ctx->flags = 0;
spin_unlock_irqrestore(&ctx->slock, flags);
dprintk(5, "[%s] index=%d, count=%d, flags=%d\n",
ctx->name, b->index, ctx->count, b->flags);
return 0;
}
int dvb_vb2_mmap(struct dvb_vb2_ctx *ctx, struct vm_area_struct *vma)
{
int ret;
ret = vb2_mmap(&ctx->vb_q, vma);
if (ret) {
dprintk(1, "[%s] errno=%d\n", ctx->name, ret);
return ret;
}
dprintk(3, "[%s] ret=%d\n", ctx->name, ret);
return 0;
}
__poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx, struct file *file,
poll_table *wait)
{
dprintk(3, "[%s]\n", ctx->name);
return vb2_core_poll(&ctx->vb_q, file, wait);
}

File diff suppressed because it is too large Load Diff

150
dvb-core/dvbdev.h Normal file
View File

@ -0,0 +1,150 @@
/*
* dvbdev.h
*
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Lesser Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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_
#define _DVBDEV_H_
#include <linux/types.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/list.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
#endif
#define DVB_UNSET (-1)
#define DVB_DEVICE_VIDEO 0
#define DVB_DEVICE_AUDIO 1
#define DVB_DEVICE_SEC 2
#define DVB_DEVICE_FRONTEND 3
#define DVB_DEVICE_DEMUX 4
#define DVB_DEVICE_DVR 5
#define DVB_DEVICE_CA 6
#define DVB_DEVICE_NET 7
#define DVB_DEVICE_OSD 8
#define DVB_DEVICE_CI 9
#define DVB_DEVICE_MOD 10
#define DVB_DEVICE_NS 11
#define DVB_DEVICE_NSD 12
#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
static short adapter_nr[] = \
{[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \
module_param_array(adapter_nr, short, NULL, 0444); \
MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
struct dvb_frontend;
struct dvb_adapter {
int num;
struct list_head list_head;
struct list_head device_list;
const char *name;
u8 proposed_mac [6];
void* priv;
struct device *device;
struct module *module;
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 */
};
struct dvb_device {
struct list_head list_head;
const struct file_operations *fops;
struct dvb_adapter *adapter;
int type;
int minor;
u32 id;
/* in theory, 'users' can vanish now,
but I don't want to change too much now... */
int readers;
int writers;
int users;
wait_queue_head_t wait_queue;
/* don't really need those !? -- FIXME: use video_usercopy */
int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
void *priv;
};
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);
extern int dvb_register_device (struct dvb_adapter *adap,
struct dvb_device **pdvbdev,
const struct dvb_device *template,
void *priv,
int type);
extern void dvb_unregister_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,
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));
/** generic DVB attach function. */
#ifdef CONFIG_MEDIA_ATTACH
#define dvb_attach(FUNCTION, ARGS...) ({ \
void *__r = NULL; \
typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
if (__a) { \
__r = (void *) __a(ARGS); \
if (__r == NULL) \
symbol_put(FUNCTION); \
} else { \
printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
} \
__r; \
})
#else
#define dvb_attach(FUNCTION, ARGS...) ({ \
FUNCTION(ARGS); \
})
#endif
#endif /* #ifndef _DVBDEV_H_ */

View File

@ -1,838 +0,0 @@
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

View File

@ -9,14 +9,13 @@ EXTRA_CFLAGS += -DCONFIG_DVB_STV6110x
EXTRA_CFLAGS += -DCONFIG_DVB_STV0367DD
#EXTRA_CFLAGS += -DCONFIG_DVB_TDA18212
EXTRA_CFLAGS += -DCONFIG_DVB_TDA18212DD
EXTRA_CFLAGS += -DCONFIG_DVB_TDA18271C2DD
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2843
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
drxk-objs := drxk_hard.o
obj-$(CONFIG_DVB_DRXK) += drxk.o

View File

@ -1,124 +0,0 @@
#
# Makefile for the kernel DVB frontend device drivers.
#
ccflags-y += -I$(srctree)/drivers/media/dvb-core/
ccflags-y += -I$(srctree)/drivers/media/tuners/
ccflags-y += --include=dd_compat.h
# 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

View File

@ -22,9 +22,12 @@
* 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>
@ -33,9 +36,7 @@
#include "cxd2099.h"
static int buffermode;
module_param(buffermode, int, 0444);
MODULE_PARM_DESC(buffermode, "Enable use of the CXD2099AR buffer mode (default: disabled)");
//#define BUFFER_MODE 1
static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount);
@ -72,8 +73,7 @@ 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) {
dev_err(&adapter->dev,
"Failed to write to I2C register %02x@%02x!\n",
pr_err("Failed to write to I2C register %02x@%02x!\n",
reg, adr);
return -1;
}
@ -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) {
dev_err(&adapter->dev, "Failed to write to I2C!\n");
pr_err("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) {
dev_err(&adapter->dev, "error in i2c_read_reg\n");
pr_err("error in i2c_read_reg\n");
return -1;
}
return 0;
@ -116,7 +116,7 @@ static int i2c_read(struct i2c_adapter *adapter, u8 adr,
.buf = data, .len = n} };
if (i2c_transfer(adapter, msgs, 2) != 2) {
dev_err(&adapter->dev, "error in i2c_read\n");
pr_err("error in i2c_read\n");
return -1;
}
return 0;
@ -134,7 +134,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)
@ -151,6 +152,7 @@ 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;
@ -251,6 +253,7 @@ 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;
@ -260,14 +263,17 @@ 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)
@ -277,6 +283,7 @@ 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)
{
@ -311,7 +318,7 @@ static void cam_mode(struct cxd *ci, int mode)
if (!ci->en.read_data)
return;
ci->write_busy = 0;
dev_info(&ci->i2c->dev, "enable cam buffer mode\n");
pr_info("enable cam buffer mode\n");
write_reg(ci, 0x0d, 0x00);
write_reg(ci, 0x0e, 0x01);
write_regm(ci, 0x08, 0x40, 0x40);
@ -324,6 +331,8 @@ 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;
@ -331,140 +340,67 @@ static int init(struct cxd *ci)
mutex_lock(&ci->lock);
ci->mode = -1;
do {
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;
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));
/* TOSTRT = 8, Mode B (gated clock), falling Edge,
* Serial, POL=HIGH, MSB
*/
status = write_reg(ci, 0x0A, 0xA7);
if (status < 0)
break;
Serial, POL=HIGH, MSB */
CHK_ERROR(write_reg(ci, 0x0A, 0xA7));
status = write_reg(ci, 0x0B, 0x33);
if (status < 0)
break;
status = write_reg(ci, 0x0C, 0x33);
if (status < 0)
break;
CHK_ERROR(write_reg(ci, 0x0B, 0x33));
CHK_ERROR(write_reg(ci, 0x0C, 0x33));
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;
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));
if (ci->cfg.clock_mode == 2) {
/* bitrate*2^13/ 72000 */
u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000;
if (ci->cfg.polarity) {
status = write_reg(ci, 0x09, 0x6f);
if (status < 0)
break;
CHK_ERROR(write_reg(ci, 0x09, 0x6f));
} else {
status = write_reg(ci, 0x09, 0x6d);
if (status < 0)
break;
CHK_ERROR(write_reg(ci, 0x09, 0x6d));
}
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;
CHK_ERROR(write_reg(ci, 0x20, 0x08));
CHK_ERROR(write_reg(ci, 0x21, (reg >> 8) & 0xff));
CHK_ERROR(write_reg(ci, 0x22, reg & 0xff));
} else if (ci->cfg.clock_mode == 1) {
if (ci->cfg.polarity) {
status = write_reg(ci, 0x09, 0x6f); /* D */
if (status < 0)
break;
CHK_ERROR(write_reg(ci, 0x09, 0x6f)); /* D */
} else {
status = write_reg(ci, 0x09, 0x6d);
if (status < 0)
break;
CHK_ERROR(write_reg(ci, 0x09, 0x6d));
}
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;
CHK_ERROR(write_reg(ci, 0x20, 0x68));
CHK_ERROR(write_reg(ci, 0x21, 0x00));
CHK_ERROR(write_reg(ci, 0x22, 0x02));
} else {
if (ci->cfg.polarity) {
status = write_reg(ci, 0x09, 0x4f); /* C */
if (status < 0)
break;
CHK_ERROR(write_reg(ci, 0x09, 0x4f)); /* C */
} else {
status = write_reg(ci, 0x09, 0x4d);
if (status < 0)
break;
CHK_ERROR(write_reg(ci, 0x09, 0x4d));
}
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_reg(ci, 0x20, 0x28));
CHK_ERROR(write_reg(ci, 0x21, 0x00));
CHK_ERROR(write_reg(ci, 0x22, 0x07));
}
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;
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));
/* Put TS in bypass */
status = write_regm(ci, 0x09, 0x08, 0x08);
if (status < 0)
break;
CHK_ERROR(write_regm(ci, 0x09, 0x08, 0x08));
ci->cammode = -1;
cam_mode(ci, 0);
} while (0);
@ -568,16 +504,14 @@ 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++) {
usleep_range(10000, 11000);
msleep(20);
#if 0
read_reg(ci, 0x06, &val);
pr_info(KERN_INFO "%d:%02x\n", i, val);
@ -590,10 +524,7 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
}
}
mutex_unlock(&ci->lock);
/* Ensure cam stability after reset */
msleep(2000);
/* msleep(500); */
return 0;
}
@ -601,7 +532,7 @@ static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
{
struct cxd *ci = ca->data;
dev_info(&ci->i2c->dev, "%s\n", __func__);
pr_info("slot_shutdown\n");
if (ci->cammode)
read_data(ca, slot, ci->rbuf, 0);
mutex_lock(&ci->lock);
@ -631,6 +562,7 @@ static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
return 0;
}
static int campoll(struct cxd *ci)
{
u8 istat;
@ -644,7 +576,6 @@ static int campoll(struct cxd *ci)
ci->dr = 1;
if (istat & 0x20)
ci->write_busy = 0;
if (istat & 2) {
u8 slotstat;
@ -660,7 +591,7 @@ static int campoll(struct cxd *ci)
if (ci->slot_stat) {
ci->slot_stat = 0;
write_regm(ci, 0x03, 0x00, 0x08);
dev_info(&ci->i2c->dev, "NO CAM\n");
pr_info("NO CAM\n");
ci->ready = 0;
}
}
@ -673,6 +604,7 @@ 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;
@ -712,9 +644,21 @@ 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;
@ -729,6 +673,7 @@ 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,
@ -739,49 +684,43 @@ 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;
struct cxd *ci = 0;
u8 val;
if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) {
dev_info(&i2c->dev, "No CXD2099 detected at %02x\n", cfg->adr);
return NULL;
pr_info("No CXD2099 detected at %02x\n", cfg->adr);
return 0;
}
ci = kzalloc(sizeof(*ci), GFP_KERNEL);
ci = kzalloc(sizeof(struct cxd), GFP_KERNEL);
if (!ci)
return NULL;
return 0;
mutex_init(&ci->lock);
ci->cfg = *cfg;
memcpy(&ci->cfg, cfg, sizeof(struct cxd2099_cfg));
ci->i2c = i2c;
ci->lastaddress = 0xff;
ci->clk_reg_b = 0x4a;
ci->clk_reg_f = 0x1b;
ci->en = en_templ;
memcpy(&ci->en, &en_templ, sizeof(en_templ));
ci->en.data = ci;
init(ci);
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");
}
pr_info("Attached CXD2099AR at %02x\n", ci->cfg.adr);
return &ci->en;
}
EXPORT_SYMBOL_GPL(cxd2099_attach);
EXPORT_SYMBOL(cxd2099_attach);
MODULE_DESCRIPTION("cxd2099");
MODULE_AUTHOR("Ralph Metzler");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL");

View File

@ -25,7 +25,7 @@
#ifndef _CXD2099_H_
#define _CXD2099_H_
#include <media/dvb_ca_en50221.h>
#include <dvb_ca_en50221.h>
struct cxd2099_cfg {
u32 bitrate;
@ -36,18 +36,8 @@ 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

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,6 @@ struct cxd2843_cfg {
u8 adr;
u32 ts_clock;
u8 parallel;
u32 osc;
};
#if defined(CONFIG_DVB_CXD2843) || \

View File

@ -31,7 +31,7 @@
#include <linux/version.h>
#include <asm/div64.h>
#include <media/dvb_frontend.h>
#include "dvb_frontend.h"
#include "drxk.h"
#include "drxk_hard.h"
@ -62,6 +62,16 @@ static bool IsQAM(struct drxk_state *state)
state->m_OperationMode == OM_QAM_ITU_C;
}
bool IsA1WithPatchCode(struct drxk_state *state)
{
return state->m_DRXK_A1_PATCH_CODE;
}
bool IsA1WithRomCode(struct drxk_state *state)
{
return state->m_DRXK_A1_ROM_CODE;
}
#define NOA1ROM 0
#ifndef CHK_ERROR
@ -482,7 +492,7 @@ static int WriteBlock(struct drxk_state *state, u32 Address,
#define DRXK_MAX_RETRIES_POWERUP 20
#endif
static int PowerUpDevice(struct drxk_state *state)
int PowerUpDevice(struct drxk_state *state)
{
int status;
u8 data = 0;
@ -1556,7 +1566,7 @@ static int SetOperationMode(struct drxk_state *state, enum OperationMode oMode)
case OM_QAM_ITU_B:
status = -1;
break;
case OM_QAM_ITU_A:
case OM_QAM_ITU_A: /* fallthrough */
case OM_QAM_ITU_C:
CHK_ERROR(MPEGTSStop(state));
CHK_ERROR(PowerDownQAM(state));
@ -1579,7 +1589,7 @@ static int SetOperationMode(struct drxk_state *state, enum OperationMode oMode)
case OM_QAM_ITU_B:
status = -1;
break;
case OM_QAM_ITU_A:
case OM_QAM_ITU_A: /* fallthrough */
case OM_QAM_ITU_C:
state->m_OperationMode = oMode;
CHK_ERROR(SetQAMStandard(state,oMode));
@ -1755,7 +1765,7 @@ static int MPEGTSDtoSetup(struct drxk_state *state, enum OperationMode oMode)
fecOcRcnCtlRate = 0xC00000;
staticCLK = state->m_DVBTStaticCLK;
break;
case OM_QAM_ITU_A:
case OM_QAM_ITU_A: /* fallthrough */
case OM_QAM_ITU_C:
fecOcTmdMode = 0x0004;
fecOcRcnCtlRate = 0xD2B4EE; /* good for >63 Mb/s */
@ -2794,12 +2804,10 @@ static int DVBTScCommand(struct drxk_state *state,
case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
status = Write16_0(state, OFDM_SC_RA_RAM_PARAM1__A, param1);
/* All commands using 1 parameters */
fallthrough;
case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
case OFDM_SC_RA_RAM_CMD_USER_IO:
status = Write16_0(state, OFDM_SC_RA_RAM_PARAM0__A, param0);
/* All commands using 0 parameters */
fallthrough;
case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
case OFDM_SC_RA_RAM_CMD_NULL:
/* Write command */
@ -3207,8 +3215,7 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
case TRANSMISSION_MODE_AUTO:
default:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
/* try first guess DRX_FFTMODE_8K */
fallthrough;
/* fall through , try first guess DRX_FFTMODE_8K */
case TRANSMISSION_MODE_8K:
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
break;
@ -3226,8 +3233,7 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
default:
case GUARD_INTERVAL_AUTO:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
/* try first guess DRX_GUARD_1DIV4 */
fallthrough;
/* fall through , try first guess DRX_GUARD_1DIV4 */
case GUARD_INTERVAL_1_4:
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
break;
@ -3252,10 +3258,9 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
case HIERARCHY_NONE:
default:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M;
/* try first guess SC_RA_RAM_OP_PARAM_HIER_NO */
/* fall through , try first guess SC_RA_RAM_OP_PARAM_HIER_NO */
// transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO;
//break;
fallthrough;
case HIERARCHY_1:
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
break;
@ -3277,8 +3282,7 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
case QAM_AUTO:
default:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
/* try first guess DRX_CONSTELLATION_QAM64 */
fallthrough;
/* fall through , try first guess DRX_CONSTELLATION_QAM64 */
case QAM_64:
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
break;
@ -3301,7 +3305,7 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
WR16(devAddr, OFDM_EC_SB_PRIOR__A, OFDM_EC_SB_PRIOR_HI));
break;
case DRX_PRIORITY_UNKNOWN:
case DRX_PRIORITY_UNKNOWN : /* fall through */
default:
return (DRX_STS_INVALID_ARG);
break;
@ -3321,8 +3325,7 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
case FEC_AUTO:
default:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
/* try first guess DRX_CODERATE_2DIV3 */
fallthrough;
/* fall through , try first guess DRX_CODERATE_2DIV3 */
case FEC_2_3 :
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
break;
@ -4863,6 +4866,10 @@ static int drxk_set_parameters (struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
#endif
{
#ifndef USE_API3
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 delsys = p->delivery_system, old_delsys;
#endif
struct drxk_state *state = fe->demodulator_priv;
u32 IF;
@ -4889,14 +4896,14 @@ static int drxk_set_parameters (struct dvb_frontend *fe,
return 0;
}
static int drxk_c_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
static int drxk_c_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
{
//struct drxk_state *state = fe->demodulator_priv;
//printk("%s\n", __FUNCTION__);
return 0;
}
static int drxk_read_status(struct dvb_frontend *fe, enum fe_status *status)
static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct drxk_state *state = fe->demodulator_priv;
u32 stat;
@ -4983,7 +4990,7 @@ static int drxk_t_sleep(struct dvb_frontend* fe)
return 0;
}
static int drxk_t_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
static int drxk_t_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
{
//struct drxk_state *state = fe->demodulator_priv;
//printk("%s\n", __FUNCTION__);
@ -4991,12 +4998,12 @@ static int drxk_t_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_prop
}
static struct dvb_frontend_ops drxk_c_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_B, SYS_DVBC_ANNEX_C },
.info = {
.name = "DRXK DVB-C",
.frequency_stepsize_hz = 62500,
.frequency_min_hz = 47000000,
.frequency_max_hz = 862000000,
.type = FE_QAM,
.frequency_stepsize = 62500,
.frequency_min = 47000000,
.frequency_max = 862000000,
.symbol_rate_min = 870000,
.symbol_rate_max = 11700000,
.caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
@ -5019,13 +5026,13 @@ static struct dvb_frontend_ops drxk_c_ops = {
};
static struct dvb_frontend_ops drxk_t_ops = {
.delsys = { SYS_DVBT },
.info = {
.name = "DRXK DVB-T",
.frequency_min_hz = 47125000,
.frequency_max_hz = 865000000,
.frequency_stepsize_hz = 166667,
.frequency_tolerance_hz = 0,
.type = FE_OFDM,
.frequency_min = 47125000,
.frequency_max = 865000000,
.frequency_stepsize = 166667,
.frequency_tolerance = 0,
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
FE_CAN_FEC_AUTO |
@ -5085,6 +5092,6 @@ error:
MODULE_DESCRIPTION("DRX-K driver");
MODULE_AUTHOR("Ralph Metzler");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL_GPL(drxk_attach);
EXPORT_SYMBOL(drxk_attach);

View File

@ -30,7 +30,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <media/dvb_frontend.h>
#include "dvb_frontend.h"
#include "lnbh25.h"
struct lnbh25 {
@ -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,
enum fe_sec_voltage voltage)
fe_sec_voltage_t voltage)
{
struct lnbh25 *lnbh = (struct lnbh25 *) fe->sec_priv;
u8 oldreg0 = lnbh->reg[0];
@ -106,15 +106,13 @@ static int lnbh25_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
return 0;
}
#if 0
static int lnbh25_set_tone(struct dvb_frontend *fe,
enum fe_sec_tone_mode tone)
fe_sec_tone_mode_t tone)
{
/* struct lnbh25 *lnbh = (struct lnbh25 *) fe->sec_priv; */
return 0;
}
#endif
static int lnbh25_init(struct lnbh25 *lnbh)
{
@ -148,12 +146,12 @@ 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("LNBH25 on %02x\n", lnbh->adr);
pr_info("LNB25 on %02x\n", lnbh->adr);
return fe;
}
EXPORT_SYMBOL_GPL(lnbh25_attach);
EXPORT_SYMBOL(lnbh25_attach);
MODULE_DESCRIPTION("LNBH25");
MODULE_AUTHOR("Ralph Metzler");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL");

View File

@ -32,7 +32,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <media/dvb_frontend.h>
#include "dvb_frontend.h"
#include "lnbp21.h"
#include "lnbh24.h"
@ -45,7 +45,7 @@ struct lnbp21 {
};
static int lnbp21_set_voltage(struct dvb_frontend *fe,
enum fe_sec_voltage voltage)
fe_sec_voltage_t 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,
enum fe_sec_tone_mode tone)
fe_sec_tone_mode_t tone)
{
struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,
@ -178,7 +178,7 @@ struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
return lnbx2x_attach(fe, i2c, override_set, override_clear,
i2c_addr, LNBH24_TTX);
}
EXPORT_SYMBOL_GPL(lnbh24_attach);
EXPORT_SYMBOL(lnbh24_attach);
struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, u8 override_set,
@ -187,7 +187,7 @@ struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
return lnbx2x_attach(fe, i2c, override_set, override_clear,
0x08, LNBP21_ISEL);
}
EXPORT_SYMBOL_GPL(lnbp21_attach);
EXPORT_SYMBOL(lnbp21_attach);
MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24");
MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin");

View File

@ -39,11 +39,9 @@
#include <linux/mutex.h>
#include <linux/vmalloc.h>
#include <asm/div64.h>
#if (KERNEL_VERSION(6, 12, 0) > LINUX_VERSION_CODE)
#include <asm/unaligned.h>
#endif
#include <media/dvb_frontend.h>
#include "dvb_frontend.h"
#include "mxl5xx.h"
#include "mxl5xx_regs.h"
#include "mxl5xx_defs.h"
@ -100,6 +98,26 @@ struct mxl {
unsigned long tune_time;
};
static void le32_to_cpusn(u32 *data, u32 size)
{
u32 i;
for (i = 0; i < size; data++, i += 4)
le32_to_cpus(data);
}
static void flip_data_in_dword(u32 size, u8 *d)
{
u32 i;
u8 t;
for (i = 0; i < size; i += 4) {
t = d[i + 3]; d[i + 3] = d[i]; d[i] = t;
t = d[i + 2]; d[i + 2] = d[i + 1]; d[i + 1] = t;
}
}
static void convert_endian(u8 flag, u32 size, u8 *d)
{
u32 i;
@ -175,8 +193,7 @@ static int read_register_unlocked(struct mxl *state, u32 reg, u32 *val)
if (stat)
pr_err("i2c read error 1\n");
if (!stat)
stat = i2cread(state, (u8 *) val,
MXL_HYDRA_REG_SIZE_IN_BYTES);
stat = i2cread(state, (u8 *) val, MXL_HYDRA_REG_SIZE_IN_BYTES);
le32_to_cpus(val);
if (stat)
pr_err("i2c read error 2\n");
@ -201,8 +218,7 @@ static int send_command(struct mxl *state, u32 size, u8 *buf)
mutex_unlock(&state->base->i2c_lock);
usleep_range(1000, 2000);
mutex_lock(&state->base->i2c_lock);
read_register_unlocked(state, DMA_I2C_INTERRUPT_ADDR,
&val);
read_register_unlocked(state, DMA_I2C_INTERRUPT_ADDR, &val);
}
if (!count) {
pr_info("mxl5xx: send_command busy\n");
@ -231,9 +247,7 @@ static int write_register(struct mxl *state, u32 reg, u32 val)
return stat;
}
#if 0
static int write_register_block(struct mxl *state, u32 reg,
u32 size, u8 *data)
static int write_register_block(struct mxl *state, u32 reg, u32 size, u8 *data)
{
int stat;
u8 *buf = state->base->buf;
@ -255,7 +269,6 @@ static int write_register_block(struct mxl *state, u32 reg,
mutex_unlock(&state->base->i2c_lock);
return stat;
}
#endif
static int write_firmware_block(struct mxl *state,
u32 reg, u32 size, u8 *regDataPtr)
@ -295,8 +308,7 @@ static int read_register(struct mxl *state, u32 reg, u32 *val)
if (stat)
pr_err("i2c read error 1\n");
if (!stat)
stat = i2cread(state, (u8 *) val,
MXL_HYDRA_REG_SIZE_IN_BYTES);
stat = i2cread(state, (u8 *) val, MXL_HYDRA_REG_SIZE_IN_BYTES);
mutex_unlock(&state->base->i2c_lock);
le32_to_cpus(val);
if (stat)
@ -359,6 +371,17 @@ static int update_by_mnemonic(struct mxl *state,
return stat;
}
static void extract_from_mnemonic(u32 regAddr, u8 lsbPos, u8 width,
u32 *toAddr, u8 *toLsbPos, u8 *toWidth)
{
if (toAddr)
*toAddr = regAddr;
if (toLsbPos)
*toLsbPos = lsbPos;
if (toWidth)
*toWidth = width;
}
static int firmware_is_alive(struct mxl *state)
{
u32 hb0, hb1;
@ -368,10 +391,8 @@ static int firmware_is_alive(struct mxl *state)
msleep(20);
if (read_register(state, HYDRA_HEAR_BEAT, &hb1))
return 0;
if (hb1 == hb0) {
pr_warn("mxl5xx: Hydra FW not running!\n");
if (hb1 == hb0)
return 0;
}
return 1;
}
@ -394,27 +415,14 @@ static void release(struct dvb_frontend *fe)
kfree(state);
}
static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
static int get_algo(struct dvb_frontend *fe)
{
return DVBFE_ALGO_HW;
}
/* This should maybe go into dvb-core/dvb_math.c */
static u32 gold2root(u32 gold)
/*
static int cfg_scrambler(struct mxl *state)
{
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,
@ -423,15 +431,11 @@ static int cfg_scrambler(struct mxl *state, u32 gold)
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;
@ -439,25 +443,21 @@ static int CfgDemodAbortTune(struct mxl *state)
u8 cmdBuff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN];
abortTuneCmd.demodId = state->demod;
BUILD_HYDRA_CMD(MXL_HYDRA_ABORT_TUNE_CMD, MXL_CMD_WRITE,
cmdSize, &abortTuneCmd, cmdBuff);
return send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE,
&cmdBuff[0]);
BUILD_HYDRA_CMD(MXL_HYDRA_ABORT_TUNE_CMD, MXL_CMD_WRITE, cmdSize, &abortTuneCmd, cmdBuff);
return send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE, &cmdBuff[0]);
}
#if 0
static int reset_fec_counter(struct mxl *state)
{
MXL_HYDRA_DEMOD_ABORT_TUNE_T abortTuneCmd;
u32 demodIndex = (u32) state->demod;
u8 cmdSize = sizeof(u32);
u8 cmdBuff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN];
BUILD_HYDRA_CMD(MXL_HYDRA_DEMOD_RESET_FEC_COUNTER_CMD,
MXL_CMD_WRITE, cmdSize, &demodIndex, cmdBuff);
return send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE,
&cmdBuff[0]);
return send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE, &cmdBuff[0]);
}
#endif
static int send_master_cmd(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd)
@ -503,7 +503,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, p->scrambling_sequence_index);
//cfg_scrambler(state);
break;
default:
return -EINVAL;
@ -517,23 +517,21 @@ static int set_parameters(struct dvb_frontend *fe)
demodChanCfg.fecCodeRate = MXL_HYDRA_FEC_AUTO;
mutex_lock(&state->base->tune_lock);
if (time_after(jiffies + msecs_to_jiffies(200),
state->base->next_tune))
if (time_after(jiffies + msecs_to_jiffies(200), state->base->next_tune))
while (time_before(jiffies, state->base->next_tune))
msleep(10);
state->base->next_tune = jiffies + msecs_to_jiffies(100);
state->tuner_in_use = state->tuner;
BUILD_HYDRA_CMD(MXL_HYDRA_DEMOD_SET_PARAM_CMD, MXL_CMD_WRITE,
cmdSize, &demodChanCfg, cmdBuff);
stat = send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE,
&cmdBuff[0]);
stat = send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE, &cmdBuff[0]);
mutex_unlock(&state->base->tune_lock);
return stat;
}
static int get_stats(struct dvb_frontend *fe);
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
static int read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct mxl *state = fe->demodulator_priv;
@ -555,10 +553,10 @@ static int read_status(struct dvb_frontend *fe, enum fe_status *status)
static int tune(struct dvb_frontend *fe, bool re_tune,
unsigned int mode_flags,
unsigned int *delay, enum fe_status *status)
unsigned int *delay, fe_status_t *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;
@ -569,13 +567,17 @@ static int tune(struct dvb_frontend *fe, bool re_tune,
state->tune_time = jiffies;
return 0;
}
r = read_status(fe, status);
if (r)
return r;
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 (p->delivery_system == SYS_DVBS)
p->delivery_system = SYS_DVBS2;
else
@ -624,7 +626,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].svalue = 10 * (s64) *snr;
p->cnr.stat[0].uvalue = 10 * (s64) *snr;
return stat;
}
@ -643,8 +645,7 @@ static int read_ber(struct dvb_frontend *fe, u32 *ber)
HYDRA_DMD_STATUS_OFFSET(state->demod)),
(7 * sizeof(u32)),
(u8 *) &reg[0]);
stat = read_register_block(
state,
stat = read_register_block(state,
(HYDRA_DMD_DVBS_1ST_CORR_RS_ERRORS_ADDR_OFFSET +
HYDRA_DMD_STATUS_OFFSET(state->demod)),
(4 * sizeof(u32)),
@ -662,22 +663,16 @@ 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 = 8 * 188 * (u64) reg[6];
p->pre_bit_count.stat[0].uvalue = reg[6] * 188 * 8;
break;
case SYS_DVBS2:
p->block_error.len = 1;
p->block_error.stat[0].scale = FE_SCALE_COUNTER;
p->block_error.stat[0].uvalue = reg[1];
p->block_count.len = 1;
p->block_count.stat[0].scale = FE_SCALE_COUNTER;
p->block_count.stat[0].uvalue = reg[2];
break;
default:
break;
}
pr_debug("mxl5xx: ber %08x %08x %08x %08x %08x %08x %08x\n",
pr_info("mxl5xx: ber %08x %08x %08x %08x %08x %08x %08x\n",
reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6]);
pr_debug("mxl5xx: ber2 %08x %08x %08x %08x\n",
pr_info("mxl5xx: ber2 %08x %08x %08x %08x\n",
reg[0], reg[1], reg[2], reg[3]);
//pre_bit_error, pre_bit_count
//post_bit_error, post_bit_count;
@ -693,10 +688,6 @@ 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 +
@ -707,7 +698,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].svalue = 10 * (s64) (s16) (regData & 0xFFFF);
p->strength.stat[0].uvalue = 10 * (s64) (s16) (regData & 0xFFFF);
return stat;
}
@ -727,7 +718,7 @@ static int get_stats(struct dvb_frontend *fe)
return 0;
}
static enum fe_code_rate conv_fec(MXL_HYDRA_FEC_E fec)
static fe_code_rate_t conv_fec(MXL_HYDRA_FEC_E fec)
{
enum fe_code_rate fec2fec[11] = {
FEC_NONE, FEC_1_2, FEC_3_5, FEC_2_3,
@ -740,9 +731,10 @@ static enum fe_code_rate conv_fec(MXL_HYDRA_FEC_E fec)
return fec2fec[fec];
}
static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
static int get_frontend(struct dvb_frontend *fe)
{
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;
@ -763,7 +755,7 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod);
mutex_unlock(&state->base->status_lock);
pr_debug("mxl5xx: freq=%u delsys=%u srate=%u\n",
pr_info("mxl5xx: freq=%u delsys=%u srate=%u\n",
freq * 1000, regData[DMD_STANDARD_ADDR],
regData[DMD_SYMBOL_RATE_ADDR]);
p->symbol_rate = regData[DMD_SYMBOL_RATE_ADDR];
@ -777,8 +769,7 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
case SYS_DSS:
break;
case SYS_DVBS2:
switch ((MXL_HYDRA_PILOTS_E )
regData[DMD_DVBS2_PILOT_ON_OFF_ADDR]) {
switch ((MXL_HYDRA_PILOTS_E ) regData[DMD_DVBS2_PILOT_ON_OFF_ADDR]) {
case MXL_HYDRA_PILOTS_OFF:
p->pilot = PILOT_OFF;
break;
@ -788,10 +779,8 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
default:
break;
}
fallthrough;
case SYS_DVBS:
switch ((MXL_HYDRA_MODULATION_E)
regData[DMD_MODULATION_SCHEME_ADDR]) {
switch ((MXL_HYDRA_MODULATION_E) regData[DMD_MODULATION_SCHEME_ADDR]) {
case MXL_HYDRA_MOD_QPSK:
p->modulation = QPSK;
break;
@ -801,8 +790,7 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
default:
break;
}
switch ((MXL_HYDRA_ROLLOFF_E)
regData[DMD_SPECTRUM_ROLL_OFF_ADDR]) {
switch ((MXL_HYDRA_ROLLOFF_E) regData[DMD_SPECTRUM_ROLL_OFF_ADDR]) {
case MXL_HYDRA_ROLLOFF_0_20:
p->rolloff = ROLLOFF_20;
break;
@ -825,25 +813,21 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
static int set_input(struct dvb_frontend *fe, int input)
{
struct mxl *state = fe->demodulator_priv;
#ifndef KERNEL_DVB_CORE
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
#endif
state->tuner = input;
#ifndef KERNEL_DVB_CORE
p->input = input;
#endif
state->tuner = p->input = input;
return 0;
}
static struct dvb_frontend_ops mxl_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
.info = {
.name = "MXL5XX",
.frequency_min_hz = 300000000,
.frequency_max_hz = 2350000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 0,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 0,
.frequency_tolerance = 0,
.symbol_rate_min = 1000000,
.symbol_rate_max = 45000000,
.caps = FE_CAN_INVERSION_AUTO |
@ -862,10 +846,7 @@ static struct dvb_frontend_ops mxl_ops = {
.read_signal_strength = read_signal_strength,
.read_ucblocks = read_ucblocks,
.get_frontend = get_frontend,
#ifndef KERNEL_DVB_CORE
.set_input = set_input,
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
#endif
.diseqc_send_master_cmd = send_master_cmd,
};
@ -922,14 +903,12 @@ static int write_fw_segment(struct mxl *state,
u32 origSize = 0;
u8 *wBufPtr = NULL;
u32 blockSize = ((MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH -
(MXL_HYDRA_I2C_HDR_SIZE +
MXL_HYDRA_REG_SIZE_IN_BYTES)) / 4) * 4;
(MXL_HYDRA_I2C_HDR_SIZE + MXL_HYDRA_REG_SIZE_IN_BYTES)) / 4) * 4;
u8 wMsgBuffer[MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH -
(MXL_HYDRA_I2C_HDR_SIZE + MXL_HYDRA_REG_SIZE_IN_BYTES)];
do {
size = origSize =
(((u32)(dataCount + blockSize)) > totalSize) ?
size = origSize = (((u32)(dataCount + blockSize)) > totalSize) ?
(totalSize - dataCount) : blockSize;
if (origSize & 3)
@ -950,8 +929,8 @@ static int write_fw_segment(struct mxl *state,
return status;
}
static int do_firmware_download(struct mxl *state, u8 *mbinBufferPtr,
u32 mbinBufferSize)
static int do_firmware_download(struct mxl *state, u8 *mbinBufferPtr, u32 mbinBufferSize)
{
int status;
u32 index = 0;
@ -976,31 +955,26 @@ static int do_firmware_download(struct mxl *state, u8 *mbinBufferPtr,
__func__, segmentPtr->header.id);
return -EINVAL;
}
segLength = get_big_endian(24,
&(segmentPtr->header.len24[0]));
segAddress = get_big_endian(32,
&(segmentPtr->header.address[0]));
segLength = get_big_endian(24, &(segmentPtr->header.len24[0]));
segAddress = get_big_endian(32, &(segmentPtr->header.address[0]));
if (state->base->type == MXL_HYDRA_DEVICE_568) {
if ((((segAddress & 0x90760000) == 0x90760000) ||
((segAddress & 0x90740000) == 0x90740000)) &&
(xcpuFwFlag == MXL_FALSE)) {
SET_REG_FIELD_DATA(PRCM_PRCM_CPU_SOFT_RST_N,
1);
SET_REG_FIELD_DATA(PRCM_PRCM_CPU_SOFT_RST_N, 1);
msleep(200);
write_register(state, 0x90720000, 0);
msleep(10);
xcpuFwFlag = MXL_TRUE;
}
status = write_fw_segment(state, segAddress,
segLength,
(u8 *) segmentPtr->data);
segLength, (u8 *) segmentPtr->data);
} else {
if (((segAddress & 0x90760000) != 0x90760000) &&
((segAddress & 0x90740000) != 0x90740000))
status = write_fw_segment(state, segAddress,
segLength,
(u8 *) segmentPtr->data);
segLength, (u8 *) segmentPtr->data);
}
if (status)
return status;
@ -1063,17 +1037,14 @@ static int firmware_download(struct mxl *state, u8 *mbin, u32 mbin_len)
if (status)
return status;
/* Disable clock to Baseband, Wideband, SerDes,
Alias ext & Transport modules */
status = write_register(state, HYDRA_MODULES_CLK_2_REG,
HYDRA_DISABLE_CLK_2);
/* Disable clock to Baseband, Wideband, SerDes, Alias ext & Transport modules */
status = write_register(state, HYDRA_MODULES_CLK_2_REG, HYDRA_DISABLE_CLK_2);
if (status)
return status;
/* Clear Software & Host interrupt status - (Clear on read) */
status = read_register(state, HYDRA_PRCM_ROOT_CLK_REG, &regData);
if (status)
return status;
status = do_firmware_download(state, mbin, mbin_len);
if (status)
return status;
@ -1108,15 +1079,15 @@ static int firmware_download(struct mxl *state, u8 *mbin, u32 mbin_len)
if (!firmware_is_alive(state))
return -1;
/* sometimes register values are wrong shortly
after first heart beats */
pr_info("mxl5xx: Hydra FW alive. Hail!\n");
/* sometimes register values are wrong shortly after first heart beats */
msleep(50);
devSkuCfg.skuType = state->base->sku_type;
BUILD_HYDRA_CMD(MXL_HYDRA_DEV_CFG_SKU_CMD, MXL_CMD_WRITE,
cmdSize, &devSkuCfg, cmdBuff);
status = send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE,
&cmdBuff[0]);
status = send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE, &cmdBuff[0]);
return status;
}
@ -1146,32 +1117,19 @@ static int cfg_ts_pad_mux(struct mxl *state, MXL_BOOL_E enableSerialTS)
case MXL_HYDRA_DEVICE_541S:
case MXL_HYDRA_DEVICE_561S:
case MXL_HYDRA_DEVICE_581S:
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_14_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_15_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_16_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_17_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_18_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_19_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_20_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_21_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_22_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_23_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_24_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_25_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_26_PINMUX_SEL,
padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_14_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_15_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_16_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_17_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_18_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_19_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_20_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_21_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_22_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_23_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_24_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_25_PINMUX_SEL, padMuxValue);
status |= SET_REG_FIELD_DATA(PAD_MUX_DIGIO_26_PINMUX_SEL, padMuxValue);
break;
case MXL_HYDRA_DEVICE_544:
@ -1355,7 +1313,7 @@ static int enable_tuner(struct mxl *state, u32 tuner, u32 enable)
if (!count)
return -1;
read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val);
/*pr_info("mxl5xx: tuner %u ready = %u\n", tuner , (val >> tuner) & 1);*/
pr_info("mxl5xx: tuner %u ready = %u\n", tuner , (val >> tuner) & 1);
#endif
return 0;
@ -1390,10 +1348,8 @@ static int config_ts(struct mxl *state, MXL_HYDRA_DEMOD_ID_E demodId,
{XPT_TS_CLK_PHASE4}, {XPT_TS_CLK_PHASE5},
{XPT_TS_CLK_PHASE6}, {XPT_TS_CLK_PHASE7} };
MXL_REG_FIELD_T xpt_lsb_first[MXL_HYDRA_DEMOD_MAX] = {
{XPT_LSB_FIRST0}, {XPT_LSB_FIRST1},
{XPT_LSB_FIRST2}, {XPT_LSB_FIRST3},
{XPT_LSB_FIRST4}, {XPT_LSB_FIRST5},
{XPT_LSB_FIRST6}, {XPT_LSB_FIRST7} };
{XPT_LSB_FIRST0}, {XPT_LSB_FIRST1}, {XPT_LSB_FIRST2}, {XPT_LSB_FIRST3},
{XPT_LSB_FIRST4}, {XPT_LSB_FIRST5}, {XPT_LSB_FIRST6}, {XPT_LSB_FIRST7} };
MXL_REG_FIELD_T xpt_sync_byte[MXL_HYDRA_DEMOD_MAX] = {
{XPT_SYNC_FULL_BYTE0}, {XPT_SYNC_FULL_BYTE1},
{XPT_SYNC_FULL_BYTE2}, {XPT_SYNC_FULL_BYTE3},
@ -1425,7 +1381,6 @@ static int config_ts(struct mxl *state, MXL_HYDRA_DEMOD_ID_E demodId,
{XPT_NCO_COUNT_MIN4}, {XPT_NCO_COUNT_MIN5},
{XPT_NCO_COUNT_MIN6}, {XPT_NCO_COUNT_MIN7} };
#if 0
MXL_REG_FIELD_T mxl561_xpt_ts_sync[MXL_HYDRA_DEMOD_ID_6] = {
{PAD_MUX_DIGIO_25_PINMUX_SEL}, {PAD_MUX_DIGIO_20_PINMUX_SEL},
{PAD_MUX_DIGIO_17_PINMUX_SEL}, {PAD_MUX_DIGIO_11_PINMUX_SEL},
@ -1434,13 +1389,11 @@ static int config_ts(struct mxl *state, MXL_HYDRA_DEMOD_ID_E demodId,
{PAD_MUX_DIGIO_26_PINMUX_SEL}, {PAD_MUX_DIGIO_19_PINMUX_SEL},
{PAD_MUX_DIGIO_18_PINMUX_SEL}, {PAD_MUX_DIGIO_10_PINMUX_SEL},
{PAD_MUX_DIGIO_09_PINMUX_SEL}, {PAD_MUX_DIGIO_02_PINMUX_SEL} };
#endif
demodId = state->base->ts_map[demodId];
if (MXL_ENABLE == mpegOutParamPtr->enable) {
if (mpegOutParamPtr->mpegMode ==
MXL_HYDRA_MPEG_MODE_PARALLEL) {
if (mpegOutParamPtr->mpegMode == MXL_HYDRA_MPEG_MODE_PARALLEL) {
#if 0
for (i = MXL_HYDRA_DEMOD_ID_0; i < MXL_HYDRA_DEMOD_MAX; i++) {
mxlStatus |= MxLWare_Hydra_UpdateByMnemonic(devId,
@ -1574,8 +1527,7 @@ static int config_ts(struct mxl *state, MXL_HYDRA_DEMOD_ID_E demodId,
}
if (mpegOutParamPtr->mpegMode != MXL_HYDRA_MPEG_MODE_PARALLEL) {
status |=
update_by_mnemonic(state,
status |= update_by_mnemonic(state,
xpt_enable_output[demodId].regAddr,
xpt_enable_output[demodId].lsbPos,
xpt_enable_output[demodId].numOfBits,
@ -1599,7 +1551,6 @@ static int config_mux(struct mxl *state)
return 0;
}
#if 0
static int config_dis(struct mxl *state, u32 id)
{
MXL_HYDRA_DISEQC_ID_E diseqcId = id;
@ -1618,10 +1569,8 @@ static int config_dis(struct mxl *state, u32 id)
BUILD_HYDRA_CMD(MXL_HYDRA_DISEQC_CFG_MSG_CMD,
MXL_CMD_WRITE, cmdSize, &diseqcMsg, cmdBuff);
return send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE,
&cmdBuff[0]);
return send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE, &cmdBuff[0]);
}
#endif
static int load_fw(struct mxl *state, struct mxl5xx_cfg *cfg)
{
@ -1647,7 +1596,7 @@ static int load_fw(struct mxl *state, struct mxl5xx_cfg *cfg)
static int validate_sku(struct mxl *state)
{
u32 padMuxBond = 0, prcmChipId = 0, prcmSoCId = 0;
u32 padMuxBond, prcmChipId, prcmSoCId;
int status;
u32 type = state->base->type;
@ -1882,8 +1831,7 @@ static int probe(struct mxl *state, struct mxl5xx_cfg *cfg)
struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c,
struct mxl5xx_cfg *cfg,
u32 demod, u32 tuner,
int (**fn_set_input)(struct dvb_frontend *, int))
u32 demod, u32 tuner)
{
struct mxl *state;
struct mxl_base *base;
@ -1923,12 +1871,9 @@ struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c,
list_add(&base->mxllist, &mxllist);
}
state->fe.ops = mxl_ops;
#ifndef KERNEL_DVB_CORE
state->fe.ops.xbar[1] = demod;
state->fe.dtv_property_cache.input = tuner;
#endif
state->fe.demodulator_priv = state;
*fn_set_input = set_input;
state->fe.dtv_property_cache.input = tuner;
list_add(&state->mxl, &base->mxls);
return &state->fe;
@ -1941,4 +1886,4 @@ EXPORT_SYMBOL_GPL(mxl5xx_attach);
MODULE_DESCRIPTION("MXL5XX driver");
MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL");

View File

@ -23,15 +23,12 @@ struct mxl5xx_cfg {
extern struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c,
struct mxl5xx_cfg *cfg,
u32 demod, u32 tuner,
int (**fn_set_input)(struct dvb_frontend *, int));
u32 demod, u32 tuner);
#else
static inline struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c,
struct mxl5xx_cfg *cfg,
u32 demod, u32 tuner,
int (**fn_set_input)(struct dvb_frontend *, int))
u32 demod, u32 tuner)
{
pr_warn("%s: driver disabled by Kconfig\n", __func__);
return NULL;

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