256 Commits

Author SHA1 Message Date
Ralph Metzler
03ce6c980c new release 0.9.36 2018-08-16 12:14:24 +02:00
Ralph Metzler
b52eb4bd17 add ids and structs for Octopus GT Mini 2018-08-13 15:05:43 +02:00
Ralph Metzler
bf3cad1094 override stv0910 cards to slower TS speed if not on latest firmware. 2018-08-10 08:48:01 +02:00
Ralph Metzler
bc2e1a39ff add tsspeed override 2018-08-10 08:47:29 +02:00
Ralph Metzler
21f00bd922 print correct card name 2018-08-09 15:49:21 +02:00
Julian Scheel
6089b4f5c2 wip: stv0910: Adapt symbolrate in blindscan mode
The blindscan mode searches for a symbolrate-range of +/-25% around the
given start value. To ensure that the highes scanned symbolrate could be
received at all the frontend must be configured to set the
basebandfilter for this symbolrate. Thus increase the symbolrate which
is given to the frontend by 25%.
2018-07-28 14:12:59 +02:00
Julian Scheel
8521ce4753 wip: stv0910: Add blindscan mode
Allow to use the AEP blind scan mode, which autodetects symbol rate
within a +/-25% range of the given symbol rate. Currently this is
enabled by using the lsb of symbol rate as a flag. This is hackish and
shall better be replaced by a dedicated dtv property.
2018-07-28 12:47:18 +02:00
Ralph Metzler
06aecc3d66 new release because of bugfix 2018-07-24 14:47:15 +02:00
rjkm
e6b06c1f3d Merge pull request #33 from dmarion/fix
Remove double spinlock unlock
2018-07-24 14:20:09 +02:00
Damjan Marion
cf77db4fcd Remove double spinlock unlock
This is causing crash on some platforms, observed on arm64.
2018-07-24 13:31:02 +02:00
Ralph Metzler
ce99c601f8 new release version 0.9.34 2018-07-24 11:58:02 +02:00
Ralph Metzler
43ab548777 Ensure CAM stability after reset
Wait 2 secs in low level CI reset function as some CAMs become crazy
if we talk to them just after the reset (SmarDTV / TDT Premium).

from: faudebert-anevia authored and Richard Bérichon committed on Apr 2, 2012
2018-07-20 13:18:27 +02:00
Ralph Metzler
2808cf0d50 increase maximum number of minors 2018-07-18 09:45:07 +02:00
Ralph Metzler
186ba6d414 change clock phase to prevent cross-talk on some hardware
(this value is better than the previously suggested change to 0xe0)
2018-07-18 09:41:24 +02:00
Ralph Metzler
f570b2e071 add more frontend statistics 2018-06-29 12:48:12 +02:00
Ralph Metzler
32f46389be adjust to latest MCI upstream drivers 2018-06-23 16:52:22 +02:00
Ralph Metzler
4b68bcad91 add MaxM4 ID 2018-06-23 16:47:10 +02:00
Ralph Metzler
1ad4dfacd1 remove leftover smp_load_acquire() for older kernels 2018-06-23 16:46:00 +02:00
Ralph Metzler
f7772c7a88 allow fmode 4 2018-06-23 16:44:16 +02:00
Ralph Metzler
6219e19ece add support for MaxM4 2018-06-23 16:43:29 +02:00
Ralph Metzler
192a4ad20d add wrappers to pacify Sparse 2018-05-28 16:41:11 +02:00
Ralph Metzler
e13cec82e4 Return correct frequency
Signed-off-by: Julian Scheel <julian@jusst.de>
2018-05-28 16:40:43 +02:00
Ralph Metzler
d13416157c remove unused offs 2018-05-28 16:40:02 +02:00
Ralph Metzler
755f502602 set array size to 4 2018-05-28 16:39:42 +02:00
Ralph Metzler
a05d1852a3 Set modulation to QPSK for DVB-S
Signed-off-by: Julian Scheel <julian@jusst.de>
2018-05-28 16:39:21 +02:00
Ralph Metzler
1e15f5474d add templX for sensors on GT link cards 2018-05-25 23:05:26 +02:00
Ralph Metzler
9c1fc648dc stop frontend on sleep and input changes 2018-05-25 23:04:25 +02:00
Ralph Metzler
2e5056c4a1 add temperature attribute for MCI cards 2018-05-25 00:12:31 +02:00
Ralph Metzler
1b89edb4b1 missing parts of previous patch 2018-05-25 00:11:03 +02:00
Ralph Metzler
875a768266 properly support frontend input switching for MAX SX8 2018-05-25 00:09:50 +02:00
Ralph Metzler
09c068c74c remove wrong strength conversion 2018-05-25 00:08:27 +02:00
Ralph Metzler
c471123f17 style cleanup 2018-05-24 11:04:59 +02:00
Ralph Metzler
8dbd33fd82 - make 8PSK/QPSK default (for AUTO mode)
- when selecting modulation, also enable all lower modulations
2018-05-24 11:03:45 +02:00
Ralph Metzler
a978e9455f disable automatic code search 2018-05-18 14:47:19 +02:00
Ralph Metzler
9d8c7d4a63 - separate MCI and SX8 code
- move SX8 code to ddbridge-sx8.c
- adjust SX8 code to latest version from upstream
- add file with skeleton driver for M4
2018-05-15 23:01:39 +02:00
Ralph Metzler
81ed8fed9d change first MCI id value and use seperate ids for each type of MCI card 2018-05-14 04:30:58 +02:00
Ralph Metzler
f24a329f2f remove debug message 2018-05-14 04:27:55 +02:00
Ralph Metzler
5d7f4fcbe8 simplify link structure access 2018-05-14 04:26:51 +02:00
Ralph Metzler
6243397d99 add Octonet Pro 2018-05-14 04:08:21 +02:00
Ralph Metzler
5b86ac7627 limit link to 0-3 2018-05-02 15:45:00 +02:00
Ralph Metzler
c831ccfc9e add check for minimum FPGA firmware version 2018-05-02 15:39:09 +02:00
Ralph Metzler
cad161f939 enable net interface by default 2018-05-02 15:35:28 +02:00
Ralph Metzler
67257ce132 replace mdio_num with mdio_base 2018-04-11 21:20:25 +02:00
Ralph Metzler
bdea58c1b2 replace direct register based mdio with ioctl 2018-04-11 21:18:00 +02:00
Ralph Metzler
29eda9be8e add missing paranthesis 2018-04-09 14:42:39 +02:00
Ralph Metzler
2c3c9bdf08 comment out old debugging messages
can be removed soon
2018-04-07 20:21:58 +02:00
Ralph Metzler
2693c181bc new Octopus Net Pro flash layout 2018-04-07 20:21:15 +02:00
Ralph Metzler
53464162de detect LNBH address to prevent error message in driver 2018-04-07 20:17:38 +02:00
Ralph Metzler
8cbb835de0 add general make rule 2018-04-07 20:16:32 +02:00
Ralph Metzler
d0f7b9be1f uncomment send_burst for legacy hardware and replace some register setting
functions with new version.
2018-03-28 19:47:26 +02:00
Ralph Metzler
6b0feea253 add ULL 2018-03-28 19:46:31 +02:00
Ralph Metzler
bed4be534a add cast 2018-03-28 19:44:15 +02:00
Ralph Metzler
1d7d8bc413 report I2C bus errors 2018-03-28 19:43:04 +02:00
Ralph Metzler
70778b818e always assume adapter_alloc=3 for octopusnet pro 2018-03-28 19:42:03 +02:00
Ralph Metzler
e0fdedbef3 adjust to newer include files and firmware 2018-03-22 19:36:08 +01:00
Ralph Metzler
9acbf467ec add axplanations for bbframe mode 2018-03-22 19:33:35 +01:00
Ralph Metzler
3db30defab use correct MODULE_LINCESE for GPL v2 only according to notice in header 2018-03-22 19:32:17 +01:00
Ralph Metzler
5bf9edba06 add entry for M4 2018-03-22 19:30:45 +01:00
Ralph Metzler
8f0365e36a add file with GPLv2 2018-03-22 19:20:29 +01:00
Ralph Metzler
08a161ba04 remove old code 2018-03-20 22:37:13 +01:00
Ralph Metzler
efbc108939 check on correct link instead of link 0 2018-03-20 22:36:20 +01:00
Ralph Metzler
033432cf2f increase version number 2018-03-14 15:11:52 +01:00
Ralph Metzler
948c6c4fe7 fix handling of separated MSI IRQs 2018-03-04 23:43:39 +01:00
Ralph Metzler
dedb5bd387 fixes for 3.x kernels 2018-03-02 10:46:28 +01:00
Ralph Metzler
991393950b use svalue instead if uvalue for signed values 2018-02-12 22:47:31 +01:00
Ralph Metzler
ae9644d934 set devid entry for link 0 2018-02-12 22:43:45 +01:00
Ralph Metzler
9cc6942c07 add warning regarding incompatibilities 2018-02-09 20:51:12 +01:00
Ralph Metzler
67e36cdef0 fix output buffer check
We have to leave a 188 byte gap between writer
and consumer. So, we need at least 2*188 bytes to be able to write.
2018-01-21 11:54:09 +01:00
Ralph Metzler
4f622ec27c fixes for input/output handlers
add casts and use spin_lock_irqsave
2018-01-21 11:53:16 +01:00
Ralph Metzler
e7d9457ef8 remove typedef 2018-01-20 10:37:26 +01:00
Ralph Metzler
00a3e78f69 fix kernel 4.15 compile problems 2018-01-18 01:05:21 +01:00
Ralph Metzler
fc335de763 add demod lock state 2018-01-16 23:56:30 +01:00
Ralph Metzler
62e491c2cd increase max symbol rate 2018-01-16 23:55:53 +01:00
Ralph Metzler
402a822751 get frontend info at appropriate places 2018-01-16 23:55:21 +01:00
Ralph Metzler
e19f29dbfa fix MSI handling for older kernels 2018-01-16 23:54:51 +01:00
Ralph Metzler
caa1dbecce clean up ci attach and detach 2018-01-16 23:54:15 +01:00
Ralph Metzler
642a010be6 make get_frontend report current DVB-S2 roll-off 2018-01-16 23:53:13 +01:00
Ralph Metzler
94dfd16461 only define ca_pid_t for user space 2018-01-16 23:52:17 +01:00
Ralph Metzler
a6b6e3be29 add DVB-S2X roll-offs 2018-01-16 23:51:38 +01:00
Ralph Metzler
4f136e5659 change pls to official scrambling_sequence_index 2018-01-16 23:50:40 +01:00
Ralph Metzler
bda6c538ae clear cmd struct before using it 2018-01-16 23:43:02 +01:00
Ralph Metzler
2eb3b3e723 add init values for TSINSDELM/L 2018-01-02 19:58:33 +01:00
Ralph Metzler
2e1c7b62a9 make registration states more fine grained 2018-01-01 21:04:00 +01:00
Ralph Metzler
6001c5baf5 remove buffer size debugging message 2018-01-01 21:03:27 +01:00
Ralph Metzler
02b292987b remove extra DVB-T frontend parameter 2018-01-01 21:02:33 +01:00
Ralph Metzler
4ebb3ca938 adapt to latest MCI interface changes 2018-01-01 21:01:49 +01:00
Ralph Metzler
c5b45cdbac remove extra parameter fro DVB-T frontend 2018-01-01 21:00:11 +01:00
Ralph Metzler
23826d9981 increase TS output speed for parallel connections 2017-12-27 22:17:36 +01:00
Ralph Metzler
da3539c994 remove mistakenly added transmission mode 64K 2017-12-27 22:11:17 +01:00
Ralph Metzler
db463d0839 add link to FW update 2017-12-22 19:19:56 +01:00
Ralph Metzler
c07e4bebbd add documentation about bb frame mode 2017-12-15 00:25:51 +01:00
Ralph Metzler
dfff0f5953 add -DCONFIG_DVB_CXD2099 to fix problem with CI attach 2017-12-14 22:06:28 +01:00
Ralph Metzler
d87246de12 throw a warning on double unlocks
based on patch by Daniel Scheller
2017-12-12 10:19:52 +01:00
Ralph Metzler
b54e6ed689 do not try to close gate if opening it failed 2017-12-12 01:52:14 +01:00
Ralph Metzler
3b44e78bd0 Move get_cur_symbol_rate call to get_frontend() 2017-12-12 01:38:22 +01:00
Ralph Metzler
f7fbeed21e add IQ command and return struct 2017-12-12 01:22:16 +01:00
Ralph Metzler
a14cbc0eff use kernel gcd and move comment regarding calculation to correct
function
2017-12-11 23:04:14 +01:00
Ralph Metzler
2d41161cb4 reject too small symbol rates 2017-12-11 23:02:15 +01:00
Ralph Metzler
c75a7892d9 remove unnecessary casts 2017-12-11 16:41:32 +01:00
Ralph Metzler
d5bbd3a025 replace 0 with proper NULL pointer 2017-12-11 16:20:24 +01:00
Ralph Metzler
096bf9d5a9 assignment used 0 instead of link from argument 2017-12-11 16:12:23 +01:00
Ralph Metzler
3806b4d2da remove unnecessary init value 2017-12-11 16:11:20 +01:00
Ralph Metzler
b42358eaa2 backwards compatibility 2017-12-11 16:10:37 +01:00
Ralph Metzler
04fc90e4d6 do not use dvb_attach, it is not in a seperate module 2017-12-07 19:31:44 +01:00
Ralph Metzler
50cf06cbb8 properly reference dvbs2_signal_info 2017-12-07 19:31:11 +01:00
Ralph Metzler
d398909c1d add first basic support for MCI frontends like the MAXSX8 (incomplete) 2017-12-05 19:59:23 +01:00
Ralph Metzler
b814026565 - simplify init_search_param() with new register access functions
- add stream id 0x80000000 to set streaming mode
2017-12-05 19:57:08 +01:00
Ralph Metzler
611065f572 add defines to simply IRQ handler 2017-12-05 19:37:29 +01:00
Ralph Metzler
eabde4ab5a add back old input handler as option 2017-12-05 19:33:16 +01:00
Ralph Metzler
efd5070f76 add flash update for MaxSX8 2017-12-05 19:30:25 +01:00
Ralph Metzler
ea09ce3b7b add device id 9 for MaxSX8 type cards 2017-12-05 19:26:26 +01:00
Ralph Metzler
de27043d42 add NO_INPUT define and initialize input property to NO_INPUT 2017-12-05 19:25:02 +01:00
Ralph Metzler
f7e8b25e02 add higher APSK mods for DVB-S2X 2017-12-05 19:24:05 +01:00
Ralph Metzler
c56e156176 add MaxSX8 hardware defs 2017-12-05 19:23:07 +01:00
Ralph Metzler
6f164f38d8 re-add some obsolete structs to make older programs compile 2017-12-05 19:20:51 +01:00
Ralph Metzler
ca3c26808f simply enable_puncture_rate 2017-10-27 13:11:11 +02:00
Ralph Metzler
9e5576c562 add field and register reading/writing macros 2017-10-25 23:13:26 +02:00
Ralph Metzler
021eae2eac simplify i2c functions 2017-10-25 23:07:43 +02:00
Ralph Metzler
b7c9038f51 add ddb_irq_set to set irq handlers
always use tasklet/workqueue for input/ouput handlers
2017-10-25 23:03:16 +02:00
Ralph Metzler
a385bcb70c clean up ddbread/write function names 2017-10-25 23:01:46 +02:00
Ralph Metzler
7bb6cf99e2 add dummy tuner with 125MByte/s dummy data stream 2017-10-23 21:07:28 +02:00
Ralph Metzler
7e6f9d6e9d change dma buffer number and size from defines to module parameters 2017-10-23 00:14:39 +02:00
Ralph Metzler
e239a6d772 move common workqueue and class init/exit to core 2017-10-22 20:58:58 +02:00
Ralph Metzler
3a2e87eefe add MSI-X support 2017-10-22 19:55:07 +02:00
Ralph Metzler
0f05b1988a - add lock loss irq handler
- add modulator ioctl mutex
- some more documentation about modulator properties
2017-10-17 23:49:31 +02:00
Ralph Metzler
4a93f79093 add info about modulator reset and status 2017-10-17 09:36:56 +02:00
Ralph Metzler
8fa925317c fix typo: 0190 instead of 0910 2017-10-16 11:25:05 +02:00
Ralph Metzler
0f4beb4e64 add new modulator test program 2017-10-12 14:22:38 +02:00
Ralph Metzler
6ca3e2f2b3 add data64 property field
add modualtor status property
2017-10-12 14:21:18 +02:00
Ralph Metzler
249b1e0b40 add lock lost define 2017-10-12 14:20:14 +02:00
Ralph Metzler
4a137b3d1a add some documentation about modulator properties 2017-10-12 14:18:38 +02:00
Ralph Metzler
20d4867869 add property get for attenuator, gain and status 2017-10-12 14:18:00 +02:00
Ralph Metzler
8a1f27c3d2 add field offset to field defines 2017-10-11 14:32:01 +02:00
Ralph Metzler
3778a64de5 add MODULATOR_RESET property 2017-10-11 13:47:50 +02:00
Ralph Metzler
6bdfe43958 remove accidentally committed test code 2017-10-03 20:49:45 +02:00
Ralph Metzler
83000cd73a handle gate control errors 2017-10-02 00:54:53 +02:00
Ralph Metzler
b5ae7ac76f adapt cxd2099 to mainline 4.14-rc2 2017-09-26 22:09:05 +02:00
Ralph Metzler
872f99fbbe patch by Iprium:
fix SYS_DVBC2 in dvbv3_type()
add SYS_DVBC2 case in dvbv3_type() function to return correct DVBV3_OFDM result instead of DVBV3_UNKNOWN. now driver locks correct to DVB-C2 modulator.
2017-09-26 22:09:05 +02:00
Ralph Metzler
1c22a07eaa adapt dvb-core, includes and affected files to mainline 4.14-rc2 2017-09-26 22:09:05 +02:00
mvoelkel
f84d196a1e compiling for kernel 4.12.x 2017-09-25 19:20:17 +02:00
mvoelkel
41897e48c8 bump version to 0.9.32 2017-09-23 12:12:38 +02:00
Ralph Metzler
4765eac57a optimize stat checks and only allow stat checks once a second 2017-09-20 21:00:21 +02:00
Ralph Metzler
7756a09420 add i2c commands 2017-09-20 02:36:58 +02:00
Ralph Metzler
92b64711ec strict checkpatch style adjustments 2017-09-16 15:31:52 +02:00
Ralph Metzler
e817b91860 re-enable port_attach error handling 2017-09-10 23:12:54 +02:00
Ralph Metzler
b814cf09e4 use enums instead of types 2017-09-10 23:11:15 +02:00
Ralph Metzler
0dd0997133 change FSM card channel number detection to use register 0x1c 2017-09-10 22:25:02 +02:00
Ralph Metzler
983949f4dd - initialize modulators before registering devices to prevent races
- check for number of FSM modulator channels before allocating ports
2017-09-09 00:21:11 +02:00
Ralph Metzler
fe5f6b737c convert all device information structs to const and fix related problems 2017-09-08 14:47:14 +02:00
Ralph Metzler
3e67af1b5b remove old commented out buggy codepath 2017-09-07 21:55:56 +02:00
Ralph Metzler
e4acb524a7 return EINVAL if input NULL (e.g. in case of mod devices) 2017-09-06 17:51:30 +02:00
Ralph Metzler
aa2762747f move MaxS8 and special MAX card LNB functions to separate file 2017-08-27 23:54:49 +02:00
Ralph Metzler
117d9a065d correct header line 2017-08-27 22:17:27 +02:00
Ralph Metzler
17b3e1ed26 move ci support to separate file 2017-08-27 22:09:43 +02:00
Ralph Metzler
07f7720145 prefix irq handlers with ddb_ to avoid name collisions 2017-08-27 21:42:02 +02:00
Ralph Metzler
b2ca06e639 strict checkpatch style fixes 2017-08-26 22:04:37 +02:00
Ralph Metzler
2b6babfdc0 coding style fixes according to checkpatch 2017-08-26 10:32:53 +02:00
Ralph Metzler
5074e28e10 change output functions from pr_ to dev_ 2017-08-25 23:30:58 +02:00
Ralph Metzler
df4f23384b lower lowest symbol rate to 100000 2017-08-25 23:30:28 +02:00
Ralph Metzler
838eb620ba write register with mode last 2017-08-25 22:07:43 +02:00
Ralph Metzler
e55dcd2fd2 correct status check order 2017-08-25 22:07:43 +02:00
Ralph Metzler
27601b4769 fix for new kernels 2017-08-25 22:07:43 +02:00
mvoelkel
5751c3fb1a bump version to 0.9.31 2017-08-11 22:57:02 +02:00
Ralph Metzler
5c032058b9 add support for PLS 2017-08-11 16:03:45 +02:00
Ralph Metzler
a44dbc889b correct lock check order 2017-08-11 16:03:03 +02:00
Ralph Metzler
3d5fae7dd8 add some explanation and correct help message 2017-08-08 22:06:36 +02:00
Ralph Metzler
7602ecf3e5 fixed regression for FSM modulators 2017-08-04 17:50:03 +02:00
Ralph Metzler
bf0315bcc0 move io functions to ddbridge-io.[ch] 2017-08-02 20:22:52 +02:00
Ralph Metzler
dcddb3437d compile parts of ddbridge and octonet seperately 2017-08-02 17:40:24 +02:00
Ralph Metzler
665b5ef857 add Kconfigs and Makefiles for OctopusNet kernel 2017-08-02 17:34:53 +02:00
Ralph Metzler
c063cffa63 fix comparison for older cards 2017-08-02 16:47:56 +02:00
Ralph Metzler
640c15f4a7 add "pls" too to convert between gold and root codes for DVB-S2 PLS 2017-08-02 00:10:13 +02:00
Ralph Metzler
d3ca949ec5 wrong bitmask for compatibility mode 2017-07-29 14:47:57 +02:00
Ralph Metzler
fd41904378 fix gap handling
gap attribute of 128 will now disable gap
2017-07-27 21:56:39 +02:00
Ralph Metzler
eb81f006e4 bump version to 0.9.30 2017-07-26 15:16:14 +02:00
Ralph Metzler
af554da865 add ddbridge-hw file with hardware info 2017-07-26 15:15:06 +02:00
Ralph Metzler
d6f56c1807 dkms compatibility
Build against specified kernel version (dkms ... -k VERSION) or against current running (uname -r) if not specified
2017-07-26 02:44:56 +02:00
Ralph Metzler
31f22ef4de also clean .*.o.d files 2017-07-26 02:42:35 +02:00
Ralph Metzler
d4d0a9b84e Improvements for cit
- Added error checking.
- Added help text.
- Added info.

Signed-off-by: Jasmin Jessich <jasmin@anw.at>
2017-07-26 02:35:40 +02:00
Ralph Metzler
24503d35ad remove no longer used module parameter 2017-07-26 02:13:27 +02:00
Ralph Metzler
3556d6464b Move device info into ddbridge-hw.c and use get_ddb_info
in ddbridge.c, ddbridge-core.c and octonet.c to get
ddb_info for specific devices.

This unifies the method for getting the device info for all hardware.
It also no longer relies on driver_data in struct pci_dev_id
which is deprecated to be used as a pointer.
2017-07-24 22:24:47 +02:00
Ralph Metzler
862c7bfc60 check for error during write 2017-07-24 22:24:13 +02:00
Ralph Metzler
fd21584ecc Use ddbridge version macro for octonet version 2017-07-24 01:05:31 +02:00
Ralph Metzler
6814a8fa23 move common functions of ddbridge and octonet to core 2017-07-24 01:03:40 +02:00
Ralph Metzler
49d4bd0da8 fix MSI/non-MSI compilation 2017-07-18 01:25:55 +02:00
Ralph Metzler
6d1cfd4cd2 acivate CAM race condition handler 2017-07-18 00:26:09 +02:00
Ralph Metzler
e68ce2ef62 add __refdata 2017-07-18 00:23:13 +02:00
Ralph Metzler
023ae44411 add missing version include 2017-07-17 23:49:19 +02:00
Ralph Metzler
7222bd58b3 change lock check order 2017-07-11 20:37:38 +02:00
Ralph Metzler
f404b3fb6d add multi-stream capability announcement 2017-07-11 20:36:52 +02:00
Ralph Metzler
de34e2ebbd correct array access 2017-07-11 20:29:20 +02:00
Ralph Metzler
774e92bd44 change to unsigned because of possible wrong range 2017-07-11 20:27:42 +02:00
Ralph Metzler
8c46d9a86a change pointer check order 2017-07-11 20:20:39 +02:00
Ralph Metzler
452771913e fix for 4.12. kernels 2017-07-11 20:17:28 +02:00
Ralph Metzler
3285b6ade0 modulator type 1 has no vga 2017-06-12 14:23:35 +02:00
Ralph Metzler
e6dd33deec write really availalble modulator channels to port_num 2017-06-12 14:21:21 +02:00
Ralph Metzler
93e42deeaa only eval register 0x1c for modulator type 1 2017-06-12 14:21:21 +02:00
Ralph Metzler
e415b6e203 force gap setting if given by attribute 2017-06-12 14:21:21 +02:00
manf
1354b9021f increased fm power 2017-06-02 01:14:15 +02:00
manf
4d17f2f5f0 mod3: atten,gain fixed 2017-06-01 20:13:08 +02:00
Ralph Metzler
5fa08eb288 add gain control 2017-06-01 16:46:44 +02:00
mvoelkel
933779aa24 Readme markup fixed 2017-05-19 16:59:30 +02:00
mvoelkel
01d35aad26 Release 0.9.29
New Hardware, fixes, testet up to kernel 4.11.1
2017-05-19 15:48:35 +02:00
Ralph Metzler
40c32767ec new release 2017-05-17 19:42:25 +02:00
Ralph Metzler
8704ceaf94 change default frequencies for SDR modulator 2017-05-16 21:25:30 +02:00
Ralph Metzler
12b792ef3f remove possible mutex deadlock 2017-05-16 21:24:48 +02:00
Ralph Metzler
3063b8e88b revert struct name change 2017-05-04 16:08:13 +02:00
Ralph Metzler
7d73553b61 start output DMA with stall bit set 2017-05-04 09:09:34 +02:00
Ralph Metzler
5d4259f6f6 remove warning for unused code 2017-04-25 19:00:19 +02:00
Ralph Metzler
04294ab5ef increase to 32 buffers for SDR 2017-04-25 18:59:47 +02:00
Ralph Metzler
4699a19bfb increase default adapter number to 64 2017-04-20 15:55:27 +02:00
Ralph Metzler
f44a9dfcbd coding style fixes 2017-04-16 21:20:52 +02:00
Ralph Metzler
b3b7a0ef2e cleanup old code 2017-04-16 14:55:00 +02:00
Ralph Metzler
8a98bd88cd allow wideband frequencies 2017-04-15 11:06:16 +02:00
Ralph Metzler
bfd1f1979d swapped if/else 2017-04-10 17:32:16 +02:00
Ralph Metzler
8931ae4d9e add frequency and center frequency setting for SDR modulator 2017-04-10 11:55:44 +02:00
Ralph Metzler
4070713556 more 4.11 fixes 2017-04-10 11:52:49 +02:00
Ralph Metzler
bba5fa5683 kernel 4.11 fixes 2017-04-10 11:46:36 +02:00
Ralph Metzler
ae37a1e4e9 change SDR to 16 outputs 2017-04-10 11:45:43 +02:00
Ralph Metzler
2aee51e447 wrong port type for ct2ti card 2017-04-09 13:20:22 +02:00
Ralph Metzler
264f08fbad add sub-ids for MAX A8 cards on GT-Link 2017-04-07 22:22:06 +02:00
Ralph Metzler
6830f4df08 add sat selection for fmode 1 and 2 2017-04-07 22:21:06 +02:00
Ralph Metzler
785d7c5126 change command name from UNI to SCIF 2017-04-07 22:20:40 +02:00
Ralph Metzler
52b81cfd8e typo 2017-04-07 12:50:01 +02:00
Ralph Metzler
263d593bcf simplify device table 2017-04-07 12:28:55 +02:00
Ralph Metzler
f56ec446ae add ARI property 2017-04-07 12:28:27 +02:00
Ralph Metzler
fa36763d43 - add support for setting ARI
- use coorect base frequency
2017-04-07 12:27:35 +02:00
Ralph Metzler
08a6d78da7 print used devices 2017-04-07 12:26:03 +02:00
Ralph Metzler
b3806c61ce typo 2017-04-07 12:22:29 +02:00
Ralph Metzler
eb6652f18f lower gain for 16 output channel image 2017-03-13 13:00:12 +01:00
Ralph Metzler
21c69918d3 add support for higher IRQs in case of multiple MSI interrupts 2017-03-10 12:29:11 +01:00
Ralph Metzler
326e928f66 add ids 2017-03-10 12:28:57 +01:00
Ralph Metzler
0e09153b1f use $(CC) instead of gcc 2017-03-10 12:28:31 +01:00
mvoelkel
adf4e40256 Fixed updating of a preloaded GTL version 2017-02-24 20:11:30 +01:00
mvoelkel
9dcd81fe42 Damn 2017-02-24 16:07:17 +01:00
mvoelkel
a7ce2ef8da Verify flash after writing 2017-02-24 15:27:14 +01:00
mvoelkel
285d7aed49 check for old golden version 2017-02-24 15:01:11 +01:00
Ralph Metzler
9eb5458eeb also update golden image 2017-02-24 12:48:00 +01:00
Ralph Metzler
d51a9db022 increase buffer for SDR
more SDR card init in driver
2017-02-21 17:12:35 +01:00
Ralph Metzler
532afaa97c changes for latest SDR card devel version 2017-02-09 10:12:43 +01:00
Ralph Metzler
1984377f72 remove debug message 2017-02-09 10:12:33 +01:00
Ralph Metzler
37de742aad add id for pro advanced 2017-02-06 13:28:45 +01:00
Ralph Metzler
4bfdb11762 add id for pro advanced 2017-02-06 13:25:57 +01:00
Ralph Metzler
1e99122d52 support cine s2 v7a 2017-02-06 12:49:16 +01:00
Ralph Metzler
cd5de95023 fix error handling and ID output length 2017-02-06 12:48:54 +01:00
Ralph Metzler
c56f593a4c add support for single demod mode for testing high bit rates 2017-02-06 12:48:48 +01:00
Ralph Metzler
3a3a48654e support cine s2 v7a 2017-02-01 17:48:59 +01:00
Ralph Metzler
1a80437b98 use correct type u32 for pll init table 2017-01-22 13:43:53 +01:00
Ralph Metzler
28a2aaa653 improved PLL setup for modulator 2017-01-22 02:05:44 +01:00
Ralph Metzler
f6c7586815 fix wrong qam register access for SDR cad 2017-01-19 16:37:50 +01:00
Ralph Metzler
d069dc051f basic support for SDR card 2017-01-09 19:28:26 +01:00
Ralph Metzler
9392ccec22 fix error handling and ID output length 2017-01-09 19:27:27 +01:00
Ralph Metzler
4c276fbc75 add SDR support 2017-01-09 19:26:52 +01:00
Ralph Metzler
7cc9107597 add support for single demod mode for testing high bit rates 2016-12-30 15:03:38 +01:00
Ralph Metzler
1f77192d62 mask lower bits for temp 2016-12-14 19:24:58 +01:00
Ralph Metzler
fc4a807b4e add support for new cine and change 24 MHz osciallator handling 2016-12-14 19:11:57 +01:00
86 changed files with 15174 additions and 7528 deletions

View File

@@ -1,3 +1,7 @@
0.9.29 compiles with most kernels up to 4.11.1
see git commit messages for newer changes
0.9.24 2016.08.03
- suport new V2 modulator cards

339
COPYING.GPLv2 Normal file
View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -1,7 +1,9 @@
KDIR ?= /lib/modules/$(shell uname -r)/build
kernelver ?= $(shell uname -r)
KDIR ?= /lib/modules/$(kernelver)/build
PWD := $(shell pwd)
MODDEFS := CONFIG_DVB_CORE=m CONFIG_DVB_DDBRIDGE=m CONFIG_DVB_DRXK=m CONFIG_DVB_TDA18271C2DD=m CONFIG_DVB_CXD2099=m CONFIG_DVB_LNBP21=m CONFIG_DVB_STV090x=m CONFIG_DVB_STV6110x=m CONFIG_DVB_STV0367=m CONFIG_DVB_TDA18212=m CONFIG_DVB_STV0367DD=m CONFIG_DVB_TDA18212DD=m CONFIG_DVB_OCTONET=m CONFIG_DVB_CXD2843=m CONFIG_DVB_STV0910=m CONFIG_DVB_STV6111=m CONFIG_DVB_LNBH25=m CONFIG_DVB_MXL5XX=m
MODDEFS := CONFIG_DVB_CORE=m CONFIG_DVB_DDBRIDGE=m CONFIG_DVB_DRXK=m CONFIG_DVB_TDA18271C2DD=m CONFIG_DVB_CXD2099=m CONFIG_DVB_LNBP21=m CONFIG_DVB_STV090x=m CONFIG_DVB_STV6110x=m CONFIG_DVB_STV0367=m CONFIG_DVB_TDA18212=m CONFIG_DVB_STV0367DD=m CONFIG_DVB_TDA18212DD=m CONFIG_DVB_OCTONET=m CONFIG_DVB_CXD2843=m CONFIG_DVB_STV0910=m CONFIG_DVB_STV6111=m CONFIG_DVB_LNBH25=m CONFIG_DVB_MXL5XX=m CONFIG_DVB_NET=m
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) $(MODDEFS) modules
@@ -14,6 +16,6 @@ install: all
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules_install
clean:
rm -rf */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules*
rm -rf */.*.o.d */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules*

View File

@@ -1,10 +1,16 @@
# DDBridge Driver
###Prepare for Building
### Patches
We can only accept patches which don't break compilation for older kernels (as far back as 2.6.37).
Due to this and other changes not approved by us the kernel version of the ddbridge driver might contain
incompatiblities to this driver package.
### Prepare for Building
TBD
###Building
### Building
TBD

View File

@@ -1,22 +1,20 @@
all: cit citin flashprog modt ddtest setmod ddflash setmod2
all: cit citin flashprog modt ddtest setmod ddflash setmod2 pls setmod3
cit: cit.c
gcc -o cit cit.c -lpthread
$(CC) -o cit cit.c -lpthread
modt: modt.c
gcc -o modt modt.c -lpthread
$(CC) -o modt modt.c -lpthread
setmod: setmod.c
gcc -o setmod setmod.c -I../include/
$(CC) -o setmod setmod.c -I../include/
setmod2: setmod2.c
gcc -o setmod2 setmod2.c -I../include/
$(CC) -o setmod2 setmod2.c -I../include/
flashprog: flashprog.c
gcc -o flashprog flashprog.c
setmod3: setmod3.c
$(CC) -o setmod3 setmod3.c -I../include/
ddtest: ddtest.c
gcc -o ddtest ddtest.c
%.o: %.c
$(CC) $(CFLAGS) -o $@ $<
ddflash: ddflash.c
gcc -o ddflash ddflash.c

View File

@@ -91,8 +91,13 @@ void *get_ts(void *a)
if (!buf)
return NULL;
sprintf(fname, "/dev/dvb/adapter%u/ci%u", adapter, device);
printf("using %s for reading\n", fname);
fdi = open(fname, O_RDONLY);
if (fdi == -1) {
printf("Failed to open %s for read: %m\n", fname);
return NULL;
}
while (1) {
memset(buf, 0, 188*rnum);
len=read(fdi, buf, 188*rnum);
@@ -122,7 +127,12 @@ int send(void)
if (!buf)
return -1;
sprintf(fname, "/dev/dvb/adapter%u/ci%u", adapter, device);
printf("using %s for writing\n", fname);
fdo=open(fname, O_WRONLY);
if (fdo == -1) {
printf("Failed to open %s to write: %m\n", fname);
exit(2);
}
while (1) {
for (i=0; i<snum; i++) {
@@ -146,7 +156,7 @@ int send(void)
int main(int argc, char **argv)
{
pthread_t th;
while (1) {
int option_index = 0;
int c;
@@ -178,6 +188,8 @@ int main(int argc, char **argv)
rnum = strtoul(optarg, NULL, 10);
break;
case 'h':
printf("cit -a<adapter> -d<device>\n");
exit(-1);
default:
break;
@@ -186,6 +198,7 @@ int main(int argc, char **argv)
if (optind < argc) {
printf("Warning: unused arguments\n");
}
printf("adapter %d, device: %d\n", adapter, device);
memset(ts+8, 180, 0x5a);
pthread_create(&th, NULL, get_ts, NULL);
usleep(10000);

View File

@@ -210,9 +210,13 @@ int main(int argc, char **argv)
printf("Octopus 35\n");
break;
case 0x0003:
fname="DVBBridgeV1B_DVBBridgeV1B.bit";
fname="DVBBridgeV1B_DVBBridgeV1B.fpga";
printf("Octopus\n");
break;
case 0x0005:
fname="DVBBridgeV2A_DD01_0005_STD.fpga";
printf("Octopus Classic\n");
break;
case 0x0006:
fname="DVBBridgeV2A_DD01_0006_STD.fpga";
printf("CineS2 V7\n");
@@ -225,6 +229,14 @@ int main(int argc, char **argv)
fname="DVBBridgeV2A_DD01_0008_CXD.fpga";
printf("Octopus 4/8\n");
break;
case 0x0009:
fname="DVBBridgeV2A_DD01_0009_SX8.fpga";
printf("Octopus MAXSX8\n");
break;
case 0x000a:
fname="DVBBridgeV2A_DD01_000A_M4.fpga";
printf("Octopus MAXM4\n");
break;
case 0x0011:
fname="CIBridgeV1B_CIBridgeV1B.fpga";
printf("Octopus CI\n");
@@ -249,6 +261,10 @@ int main(int argc, char **argv)
fname="DVBModulatorV2A_DD01_0210.fpga";
printf("Modulator V2\n");
break;
case 0x0220:
fname="SDRModulatorV1A_DD01_0220.fpga";
printf("SDRModulator\n");
break;
default:
printf("UNKNOWN\n");
break;
@@ -314,6 +330,7 @@ int main(int argc, char **argv)
err = FlashWritePageMode(ddb,FlashOffset,buffer,BufferSize,0x3C);
break;
case SPANSION_S25FL116K:
case SPANSION_S25FL164K:
err = FlashWritePageMode(ddb,FlashOffset,buffer,BufferSize,0x1C);
break;
}

View File

@@ -426,7 +426,7 @@ static int flash_detect(struct ddflash *ddf)
}
if (ddf->sector_size) {
ddf->buffer = malloc(ddf->sector_size);
printf("allocated buffer %08x@%08x\n", ddf->sector_size, (uint32_t) ddf->buffer);
//printf("allocated buffer %08x@%08x\n", ddf->sector_size, (uint32_t) ddf->buffer);
if (!ddf->buffer)
return -1;
}
@@ -510,7 +510,12 @@ static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off)
goto out;
}
} else if (!strcasecmp(key, "Version")) {
sscanf(val, "%x", &version);
if (strchr(val,'.')) {
int major = 0, minor = 0;
sscanf(val,"%d.%d",&major,&minor);
version = (major << 16) + minor;
} else
sscanf(val, "%x", &version);
} else if (!strcasecmp(key, "Length")) {
sscanf(val, "%u", &length);
}
@@ -565,8 +570,13 @@ static int update_image(struct ddflash *ddf, char *fn,
if (res < 0)
goto out;
res = flashwrite(ddf, fs, adr, len, fw_off);
if (res == 0)
res = 1;
if (res == 0) {
res = flashcmp(ddf, fs, adr, len, fw_off);
if (res == -2) {
res = 1;
}
}
out:
close(fs);
return res;
@@ -607,18 +617,40 @@ static int update_flash(struct ddflash *ddf)
if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 0)) == 1)
stat |= 1;
} else {
if ((res = update_image(ddf, "/config/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1)
if (ddf->id.device == 0x0307) {
if (res == -1)
if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1)
stat |= 1;
} else {
if ((res = update_image(ddf, "/config/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1)
stat |= 1;
}
}
#if 1
if ( (stat&1) && (ddf->id.hw & 0xffffff) <= 0x010001) {
if (ddf->id.device == 0x0307) {
if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x160000, 0x80000, 1, 0)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x160000, 0x80000, 1, 0)) == 1)
stat |= 1;
} else {
if ((res = update_image(ddf, "/config/fpga.img", 0x160000, 0x80000, 1, 0)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga.img", 0x160000, 0x80000, 1, 0)) == 1)
stat |= 1;
}
}
#endif
break;
case 0x320:
//fname="/boot/DVBNetV1A_DD01_0300.bit";
@@ -627,6 +659,13 @@ static int update_flash(struct ddflash *ddf)
stat |= 1;
return stat;
break;
case 0x322:
//fname="/boot/DVBNetV1A_DD01_0300.bit";
fname="/boot/fpga.img";
if ((res = update_image(ddf, fname, 0x10000, 0x100000, 1, 0)) == 1)
stat |= 1;
return stat;
break;
default:
return 0;
}

View File

@@ -722,9 +722,10 @@ int mdio(int dev, int argc, char* argv[], uint32_t Flags)
adr = strtoul(argv[0], NULL, 16);
reg = strtoul(argv[1], NULL, 16);
#if 0
writereg(dev, 0x24, adr);
writereg(dev, 0x28, reg);
if(argc > 2) {
if (argc > 2) {
val = strtoul(argv[2], NULL, 16);
writereg(dev, 0x2c, val);
writereg(dev, 0x20, 0x03);
@@ -739,6 +740,23 @@ int mdio(int dev, int argc, char* argv[], uint32_t Flags)
readreg(dev, 0x2c, &val);
printf("%04x\n", val);
}
#else
{
struct ddb_mdio mdio = {
.adr = adr,
.reg = reg,
};
if(argc > 2) {
mdio.val = strtoul(argv[2], NULL, 16);
return ioctl(dev, IOCTL_DDB_WRITE_MDIO, &mdio);
} else {
if (ioctl(dev, IOCTL_DDB_READ_MDIO, &mdio) < 0)
return -1;
printf("%04x\n", mdio.val);
}
}
#endif
return 0;
}
@@ -1310,15 +1328,129 @@ int read_id(int dev, int argc, char* argv[], uint32_t Flags)
break;
default:
printf("Unsupported Flash\n");
break;
return -1;
}
printf("ID: ");
for (i = 0; i < 8; i++)
for (i = 0; i < len; i++)
printf("%02x ", Id[i]);
printf("\n");
}
int i2cread(int dev, int argc, char* argv[], uint32_t Flags)
{
uint8_t BusNumber = 0;
uint8_t DeviceAddress = 0;
int i;
uint32_t tmp;
char *p;
uint32_t BufferLength;
uint32_t ReadLen;
uint8_t *Buffer;
int Repeat = (Flags & REPEAT_FLAG) != 0;
int Silent = (Flags & SILENT_FLAG) != 0;
if (argc < 2)
return -1;
tmp = strtoul(argv[0],&p,16);
if (tmp > 255)
return -1;
if (*p == ':') {
BusNumber = (uint8_t) (tmp - 1);
tmp = strtoul(&p[1],NULL,16);
}
if (tmp > 255 || BusNumber > 3)
return -1;
DeviceAddress = (uint8_t) tmp;
BufferLength = (argc-2);
ReadLen = strtoul(argv[argc-1],NULL,0);
if (ReadLen > BufferLength)
BufferLength = ReadLen ;
printf(" BufferLength = %d tmp = %d\n", BufferLength, ReadLen);
Buffer = malloc(BufferLength);
for (i = 1; i < (argc-1); i += 1 ) {
tmp = strtoul(argv[i],NULL,16);
if (tmp > 255) {
free(Buffer);
return -1;
}
Buffer[i-1] = (uint8_t) tmp;
}
do {
int hr = i2c_read(dev, BusNumber, DeviceAddress, Buffer, argc-2, Buffer, ReadLen);
if (hr < 0) {
printf("ioctl error\n");
free(Buffer);
return 0;
}
if (!Silent) {
printf("OK\n");
Dump(&Buffer[0],0,ReadLen);
}
} while (Repeat);
free(Buffer);
return 0;
}
int i2cwrite(int dev, int argc, char* argv[], uint32_t Flags)
{
uint8_t BusNumber = 0;
uint8_t DeviceAddress = 0;
uint32_t tmp;
char *p;
uint8_t *Buffer;
int i;
int Repeat = (Flags & REPEAT_FLAG) != 0;
int Silent = (Flags & SILENT_FLAG) != 0;
if( argc < 1 )
return -1;
tmp = strtoul(argv[0],&p,16);
if( tmp > 255 )
return -1;
if (*p == ':') {
BusNumber = (uint8_t) (tmp - 1);
tmp = strtoul(&p[1],NULL,16);
}
if( tmp > 255 || BusNumber > 3)
return -1;
DeviceAddress = (uint8_t) tmp;
Buffer = malloc(argc - 1);
for (i = 1; i < argc; i += 1) {
tmp = strtoul(argv[i],NULL,16);
if (tmp > 255 ) {
free(Buffer);
return -1;
}
Buffer[i-1] = (uint8_t) tmp;
}
do {
int hr =i2c_write(dev, BusNumber,DeviceAddress,NULL,0,Buffer,argc-1);
if (hr < 0) {
printf("ioctl error\n");
free(Buffer);
return 0;
}
if( !Silent )
printf("OK\n");
} while( Repeat );
free(Buffer);
return 0;
}
struct SCommand CommandTable[] =
{
{ "memread", ReadDeviceMemory, 1, "Read Device Memory : memread <start> <count>" },
@@ -1343,6 +1475,8 @@ struct SCommand CommandTable[] =
{ "licexport", lic_export, 1, "License Export : licexport" },
{ "licerase", lic_erase, 1, "License Erase : licerase" },
{ "read_id", read_id, 1, "Read Unique ID : read_id" },
{ "i2cread", i2cread, 1, "I2C Read : I2CRead <[BusNumber:]DeviceAddress> [<write data>..] <read count>" },
{ "i2write", i2cwrite, 1, "I2C Write : I2CWrite <[BusNumber:]DeviceAddress> [<write data>..]"},
{ NULL,NULL,0 }
};

167
apps/pls.c Normal file
View File

@@ -0,0 +1,167 @@
/*
* pls.c: Convert between Gold and Root Codes for DVB-S2 PLS
*
* Copyright (C) 2017 Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdlib.h>
#include <getopt.h>
#include <stdio.h>
#include <stdint.h>
/* According to ETSI EN 302 307 5.5.4 the PLS (Physical Layer
Scrambling) for DVB-S2 consists of a complex randomization
sequence which is ultimately derived from two recursively
defined m-sequences (=MLS or maximum length sequences)
x(i) and y(i) of polynomials over GF(2) with m=18
(thus their length is 2^18 - 1).
These m-sequences with sequence y starting from y(0) and
sequence x starting from x(n) are combined to form a set
of 2^18 - 1 different Gold code sequences.
This starting number n of sequence x selects which
of those 2^18 - 1 Gold code sequences to use.
As a DVB-S2 tuning parameter n is called the scrambling sequence index
(cf. ETSI EN 300 468 table 41) or Gold sequence index,
commonly also just called "Gold code".
The 18 values of the sequence x starting from x(n)
(x(n) ... x(n+17)) are also called the "Root code".
So, Gold and Root codes are not different ways of PLS, they are
just different ways to select the same sequence start point.
The initial values for x(i), i=0..18 are x(0)=1, x(1)=0, .., x(17)=0 .
The polynomial used for the x sequence recursion is 1+x^7+x^18.
If the lower 18 bits of a variable "uint32_t X" contain x(n) ... x(n+17),
then we can simply calculate x(n+1) ... x(n+18) by doing:
X = (((X ^ (X >> 7)) & 1) << 17) | (X >> 1);
So, if X contained the "Root code" corresponding to "Gold code" n,
it will now contain the "Root code" corresponding to "Gold code" (n+1).
Note that X=0 and n=2^18 - 1 do not exist (or rather the lattter is the same
as n = 0) and for n=0 to 2^18 - 2 and X=1 to 2^18 - 1 there is a
one-to-one correspondence (bijection).
Note that PLS has nothing to do with encryption for DRM purposes. It is used
to minimize interference between transponders.
"Combo code":
There is no such thing as a combo code. It is the result of a bug in older
STV090x drivers which resulted in a crazy race condition between a Gold->Root
conversion in the STV and an ongoing I2C write.
Better forget about it and determine the proper Root or Gold code.
*/
static uint32_t gold2root(uint32_t gold)
{
uint32_t x, g;
for (g = 0, x = 1; g < gold; g++)
x = (((x ^ (x >> 7)) & 1) << 17) | (x >> 1);
return x;
}
static uint32_t root2gold(uint32_t root)
{
uint32_t x, g;
for (g = 0, x = 1; g < 0x3ffff; g++) {
if (root == x)
return g;
x = (((x ^ (x >> 7)) & 1) << 17) | (x >> 1);
}
return 0xffffffff;
}
int main(int argc, char **argv)
{
uint32_t gold = 0xffffffff, root = 0xffffffff;
while (1) {
int option_index = 0;
int c;
static struct option long_options[] = {
{"gold", required_argument, 0, 'g'},
{"root", required_argument, 0, 'r'},
{"help", no_argument , 0, 'h'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"r:g:h",
long_options, &option_index);
if (c==-1)
break;
switch (c) {
case 'g':
gold = strtoul(optarg, NULL, 0);
break;
case 'r':
root = strtoul(optarg, NULL, 0);
break;
case 'h':
printf("pls -g gold_code\n");
printf("or\n");
printf("pls -r root_code\n");
exit(-1);
default:
break;
}
}
if (optind < argc) {
printf("Warning: unused arguments\n");
}
if (gold != 0xffffffff && root != 0xffffffff) {
printf("Only specify root or gold code\n");
exit(-1);
};
if (gold != 0xffffffff) {
if (gold < 0x3ffff) {
root = gold2root(gold);
printf("gold = %llu (0x%05x) root = %llu (0x%05x)\n",
gold, gold, root, root);
} else
printf("Invalid gold code specified.\n");
exit(0);
}
if (root != 0xffffffff) {
if (root > 0 && root < 0x40000)
gold = root2gold(root);
if (gold != 0xffffffff)
printf("gold = %llu (0x%05x) root = %llu (0x%05x)\n",
gold, gold, root, root);
else
printf("Invalid root code specified.\n");
exit(0);
}
printf("Specify either root or gold code with -r or -g.\n");
}

83
apps/setmod3.c Normal file
View File

@@ -0,0 +1,83 @@
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <linux/dvb/mod.h>
static int set_property(int fd, uint32_t cmd, uint32_t data)
{
struct dtv_property p;
struct dtv_properties c;
int ret;
p.cmd = cmd;
c.num = 1;
c.props = &p;
p.u.data = data;
ret = ioctl(fd, FE_SET_PROPERTY, &c);
if (ret < 0) {
fprintf(stderr, "FE_SET_PROPERTY returned %d\n", errno);
return -1;
}
return 0;
}
static int get_property(int fd, uint32_t cmd, uint32_t *data)
{
struct dtv_property p;
struct dtv_properties c;
int ret;
p.cmd = cmd;
c.num = 1;
c.props = &p;
ret = ioctl(fd, FE_GET_PROPERTY, &c);
if (ret < 0) {
fprintf(stderr, "FE_GET_PROPERTY returned %d\n", ret);
return -1;
}
*data = p.u.data;
return 0;
}
int main()
{
int fd;
struct dvb_mod_params mp;
struct dvb_mod_channel_params mc;
uint32_t data;
fd = open("/dev/dvb/adapter0/mod0", O_RDONLY);
/* gain 0-255 */
get_property(fd, MODULATOR_GAIN, &data);
printf("Modulator gain = %u\n", data);
set_property(fd, MODULATOR_GAIN, 100);
get_property(fd, MODULATOR_GAIN, &data);
printf("Modulator gain = %u\n", data);
get_property(fd, MODULATOR_ATTENUATOR, &data);
printf("Modulator attenuator = %u\n", data);
get_property(fd, MODULATOR_STATUS, &data);
printf("Modulator status = %u\n", data);
set_property(fd, MODULATOR_STATUS, 2);
//set_property(fd, MODULATOR_RESET, 0);
close(fd);
}

View File

@@ -1,4 +1,7 @@
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2843 -DCONFIG_DVB_LNBP21 -DCONFIG_DVB_STV090x -DCONFIG_DVB_STV6110x -DCONFIG_DVB_DRXK -DCONFIG_DVB_STV0910 -DCONFIG_DVB_STV6111 -DCONFIG_DVB_LNBH25 -DCONFIG_DVB_MXL5XX
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2843 -DCONFIG_DVB_LNBP21 -DCONFIG_DVB_STV090x -DCONFIG_DVB_STV6110x -DCONFIG_DVB_DRXK -DCONFIG_DVB_STV0910 -DCONFIG_DVB_STV6111 -DCONFIG_DVB_LNBH25 -DCONFIG_DVB_MXL5XX -DCONFIG_DVB_CXD2099 -DCONFIG_DVB_NET
ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
obj-$(CONFIG_DVB_OCTONET) += octonet.o

46
ddbridge/Kconfig Normal file
View File

@@ -0,0 +1,46 @@
config DVB_DDBRIDGE
tristate "Digital Devices bridge support"
depends on MEDIA_PCI_SUPPORT && DVB_CORE && PCI && I2C
select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT
select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA18212DD if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0367DD if MEDIA_SUBDRV_AUTOSELECT
select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT
select DVB_CXD2843 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT
---help---
Support for cards with the Digital Devices PCI express bridge:
- Octopus PCIe Bridge
- Octopus mini PCIe Bridge
- Octopus LE
- DuoFlex S2 Octopus
- DuoFlex CT Octopus
- cineS2(v6)
Say Y if you own such a card and want to use it.
config DVB_OCTONET
tristate "Digital Devices octonet support"
depends on MEDIA_DIGITAL_TV_SUPPORT && DVB_CORE && I2C
select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT
select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA18212DD if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0367DD if MEDIA_SUBDRV_AUTOSELECT
select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT
select DVB_CXD2843 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0910 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV6111 if MEDIA_SUBDRV_AUTOSELECT
select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT
---help---
Support for OctopusNet
Say Y if you own such a card and want to use it.

View File

@@ -1,19 +1,14 @@
KDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
#
# Makefile for the ddbridge device driver
#
MODDEFS := CONFIG_DVB_DDBRIDGE=m
ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) $(MODDEFS) modules
$(MAKE) -C apps
dep:
DIR=`pwd`; (cd $(TOPDIR); make SUBDIRS=$$DIR dep)
install: all
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules_install
clean:
rm -rf */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules*
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
obj-$(CONFIG_DVB_OCTONET) += octonet.o
ccflags-y += -Idrivers/media/dvb-core/
ccflags-y += -Idrivers/media/dvb-frontends/
ccflags-y += -Idrivers/media/tuners/

14
ddbridge/Makefile.kernel Normal file
View File

@@ -0,0 +1,14 @@
#
# Makefile for the ddbridge device driver
#
ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
obj-$(CONFIG_DVB_OCTONET) += octonet.o
ccflags-y += -Idrivers/media/dvb-core/
ccflags-y += -Idrivers/media/dvb-frontends/
ccflags-y += -Idrivers/media/tuners/

345
ddbridge/ddbridge-ci.c Normal file
View File

@@ -0,0 +1,345 @@
/*
* ddbridge-ci.c: Digital Devices bridge and DuoFlex CI driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
#include "ddbridge-io.h"
#include "ddbridge-i2c.h"
/* Octopus CI internal CI interface */
static int wait_ci_ready(struct ddb_ci *ci)
{
u32 count = 10;
ndelay(500);
do {
if (ddbreadl(ci->port->dev,
CI_CONTROL(ci->nr)) & CI_READY)
break;
usleep_range(1, 2);
if ((--count) == 0)
return -1;
} while (1);
return 0;
}
static int read_attribute_mem(struct dvb_ca_en50221 *ca,
int slot, int address)
{
struct ddb_ci *ci = ca->data;
u32 val, off = (address >> 1) & (CI_BUFFER_SIZE - 1);
if (address > CI_BUFFER_SIZE)
return -1;
ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address,
CI_DO_READ_ATTRIBUTES(ci->nr));
wait_ci_ready(ci);
val = 0xff & ddbreadl(ci->port->dev, CI_BUFFER(ci->nr) + off);
return val;
}
static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
int address, u8 value)
{
struct ddb_ci *ci = ca->data;
ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,
CI_DO_ATTRIBUTE_RW(ci->nr));
wait_ci_ready(ci);
return 0;
}
static int read_cam_control(struct dvb_ca_en50221 *ca,
int slot, u8 address)
{
u32 count = 100;
struct ddb_ci *ci = ca->data;
u32 res;
ddbwritel(ci->port->dev, CI_READ_CMD | address,
CI_DO_IO_RW(ci->nr));
ndelay(500);
do {
res = ddbreadl(ci->port->dev, CI_READDATA(ci->nr));
if (res & CI_READY)
break;
usleep_range(1, 2);
if ((--count) == 0)
return -1;
} while (1);
return 0xff & res;
}
static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,
u8 address, u8 value)
{
struct ddb_ci *ci = ca->data;
ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,
CI_DO_IO_RW(ci->nr));
wait_ci_ready(ci);
return 0;
}
static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
{
struct ddb_ci *ci = ca->data;
ddbwritel(ci->port->dev, CI_POWER_ON,
CI_CONTROL(ci->nr));
msleep(100);
ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM,
CI_CONTROL(ci->nr));
ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM,
CI_CONTROL(ci->nr));
usleep_range(20, 25);
ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON,
CI_CONTROL(ci->nr));
return 0;
}
static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
{
struct ddb_ci *ci = ca->data;
ddbwritel(ci->port->dev, 0, CI_CONTROL(ci->nr));
msleep(300);
return 0;
}
static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
{
struct ddb_ci *ci = ca->data;
u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr));
ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE,
CI_CONTROL(ci->nr));
return 0;
}
static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
{
struct ddb_ci *ci = ca->data;
u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr));
int stat = 0;
if (val & CI_CAM_DETECT)
stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
if (val & CI_CAM_READY)
stat |= DVB_CA_EN50221_POLL_CAM_READY;
return stat;
}
static struct dvb_ca_en50221 en_templ = {
.read_attribute_mem = read_attribute_mem,
.write_attribute_mem = write_attribute_mem,
.read_cam_control = read_cam_control,
.write_cam_control = write_cam_control,
.slot_reset = slot_reset,
.slot_shutdown = slot_shutdown,
.slot_ts_enable = slot_ts_enable,
.poll_slot_status = poll_slot_status,
};
static void ci_attach(struct ddb_port *port)
{
struct ddb_ci *ci;
ci = kzalloc(sizeof(*ci), GFP_KERNEL);
if (!ci)
return;
memcpy(&ci->en, &en_templ, sizeof(en_templ));
ci->en.data = ci;
port->en = &ci->en;
ci->port = port;
ci->nr = port->nr - 2;
}
/* DuoFlex Dual CI support */
static int write_creg(struct ddb_ci *ci, u8 data, u8 mask)
{
struct i2c_adapter *i2c = &ci->port->i2c->adap;
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
ci->port->creg = (ci->port->creg & ~mask) | data;
return i2c_write_reg(i2c, adr, 0x02, ci->port->creg);
}
static int read_attribute_mem_xo2(struct dvb_ca_en50221 *ca,
int slot, int address)
{
struct ddb_ci *ci = ca->data;
struct i2c_adapter *i2c = &ci->port->i2c->adap;
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
int res;
u8 val;
res = i2c_read_reg16(i2c, adr, 0x8000 | address, &val);
return res ? res : val;
}
static int write_attribute_mem_xo2(struct dvb_ca_en50221 *ca, int slot,
int address, u8 value)
{
struct ddb_ci *ci = ca->data;
struct i2c_adapter *i2c = &ci->port->i2c->adap;
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
return i2c_write_reg16(i2c, adr, 0x8000 | address, value);
}
static int read_cam_control_xo2(struct dvb_ca_en50221 *ca,
int slot, u8 address)
{
struct ddb_ci *ci = ca->data;
struct i2c_adapter *i2c = &ci->port->i2c->adap;
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
u8 val;
int res;
res = i2c_read_reg(i2c, adr, 0x20 | (address & 3), &val);
return res ? res : val;
}
static int write_cam_control_xo2(struct dvb_ca_en50221 *ca, int slot,
u8 address, u8 value)
{
struct ddb_ci *ci = ca->data;
struct i2c_adapter *i2c = &ci->port->i2c->adap;
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
return i2c_write_reg(i2c, adr, 0x20 | (address & 3), value);
}
static int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot)
{
struct ddb_ci *ci = ca->data;
write_creg(ci, 0x01, 0x01);
write_creg(ci, 0x04, 0x04);
msleep(20);
write_creg(ci, 0x02, 0x02);
write_creg(ci, 0x00, 0x04);
write_creg(ci, 0x18, 0x18);
return 0;
}
static int slot_shutdown_xo2(struct dvb_ca_en50221 *ca, int slot)
{
struct ddb_ci *ci = ca->data;
/*i2c_write_reg(i2c, adr, 0x03, 0x60);*/
/*i2c_write_reg(i2c, adr, 0x00, 0xc0);*/
write_creg(ci, 0x10, 0xff);
write_creg(ci, 0x08, 0x08);
return 0;
}
static int slot_ts_enable_xo2(struct dvb_ca_en50221 *ca, int slot)
{
struct ddb_ci *ci = ca->data;
write_creg(ci, 0x00, 0x10);
return 0;
}
static int poll_slot_status_xo2(struct dvb_ca_en50221 *ca, int slot, int open)
{
struct ddb_ci *ci = ca->data;
struct i2c_adapter *i2c = &ci->port->i2c->adap;
u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
u8 val = 0;
int stat = 0;
i2c_read_reg(i2c, adr, 0x01, &val);
if (val & 2)
stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
if (val & 1)
stat |= DVB_CA_EN50221_POLL_CAM_READY;
return stat;
}
static struct dvb_ca_en50221 en_xo2_templ = {
.read_attribute_mem = read_attribute_mem_xo2,
.write_attribute_mem = write_attribute_mem_xo2,
.read_cam_control = read_cam_control_xo2,
.write_cam_control = write_cam_control_xo2,
.slot_reset = slot_reset_xo2,
.slot_shutdown = slot_shutdown_xo2,
.slot_ts_enable = slot_ts_enable_xo2,
.poll_slot_status = poll_slot_status_xo2,
};
static void ci_xo2_attach(struct ddb_port *port)
{
struct ddb_ci *ci;
struct i2c_adapter *i2c;
ci = kzalloc(sizeof(*ci), GFP_KERNEL);
if (!ci)
return;
memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ));
ci->en.data = ci;
port->en = &ci->en;
ci->port = port;
ci->nr = port->nr - 2;
ci->port->creg = 0;
i2c = &ci->port->i2c->adap;
write_creg(ci, 0x10, 0xff);
write_creg(ci, 0x08, 0x08);
}
static struct cxd2099_cfg cxd_cfg = {
.bitrate = 72000,
.adr = 0x40,
.polarity = 1,
.clock_mode = 1,
.max_i2c = 512,
};
int ddb_ci_attach(struct ddb_port *port, u32 bitrate)
{
switch (port->type) {
case DDB_CI_EXTERNAL_SONY:
cxd_cfg.bitrate = bitrate;
port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap);
break;
case DDB_CI_EXTERNAL_XO2:
case DDB_CI_EXTERNAL_XO2_B:
ci_xo2_attach(port);
break;
case DDB_CI_INTERNAL:
ci_attach(port);
break;
default:
return -ENODEV;
}
if (!port->en)
return -ENODEV;
dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1);
return 0;
}

File diff suppressed because it is too large Load Diff

807
ddbridge/ddbridge-hw.c Normal file
View File

@@ -0,0 +1,807 @@
/*
* ddbridge-hw.c: Digital Devices device information tables
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static const struct ddb_regset octopus_mod_odma = {
.base = 0x300,
.num = 0x0a,
.size = 0x10,
};
static const struct ddb_regset octopus_mod_odma_buf = {
.base = 0x2000,
.num = 0x0a,
.size = 0x100,
};
static const struct ddb_regset octopus_mod_channel = {
.base = 0x400,
.num = 0x0a,
.size = 0x40,
};
/****************************************************************************/
static const struct ddb_regset octopus_mod_2_odma = {
.base = 0x400,
.num = 0x18,
.size = 0x10,
};
static const struct ddb_regset octopus_mod_2_odma_buf = {
.base = 0x8000,
.num = 0x18,
.size = 0x100,
};
static const struct ddb_regset octopus_mod_2_channel = {
.base = 0x800,
.num = 0x18,
.size = 0x40,
};
static const struct ddb_regset octopus_sdr_output = {
.base = 0x240,
.num = 0x14,
.size = 0x10,
};
/****************************************************************************/
static const struct ddb_regset octopus_input = {
.base = 0x200,
.num = 0x08,
.size = 0x10,
};
static const struct ddb_regset octopus_output = {
.base = 0x280,
.num = 0x08,
.size = 0x10,
};
static const struct ddb_regset octopus_idma = {
.base = 0x300,
.num = 0x08,
.size = 0x10,
};
static const struct ddb_regset octopus_idma_buf = {
.base = 0x2000,
.num = 0x08,
.size = 0x100,
};
static const struct ddb_regset octopus_odma = {
.base = 0x380,
.num = 0x04,
.size = 0x10,
};
static const struct ddb_regset octopus_odma_buf = {
.base = 0x2800,
.num = 0x04,
.size = 0x100,
};
static const struct ddb_regset octopus_i2c = {
.base = 0x80,
.num = 0x04,
.size = 0x20,
};
static const struct ddb_regset octopus_i2c_buf = {
.base = 0x1000,
.num = 0x04,
.size = 0x200,
};
/****************************************************************************/
static const struct ddb_regset octopro_input = {
.base = 0x400,
.num = 0x14,
.size = 0x10,
};
static const struct ddb_regset octopro_output = {
.base = 0x600,
.num = 0x0a,
.size = 0x10,
};
static const struct ddb_regset octopro_idma = {
.base = 0x800,
.num = 0x40,
.size = 0x10,
};
static const struct ddb_regset octopro_idma_buf = {
.base = 0x4000,
.num = 0x40,
.size = 0x100,
};
static const struct ddb_regset octopro_odma = {
.base = 0xc00,
.num = 0x20,
.size = 0x10,
};
static const struct ddb_regset octopro_odma_buf = {
.base = 0x8000,
.num = 0x20,
.size = 0x100,
};
static const struct ddb_regset octopro_i2c = {
.base = 0x200,
.num = 0x0a,
.size = 0x20,
};
static const struct ddb_regset octopro_i2c_buf = {
.base = 0x2000,
.num = 0x0a,
.size = 0x200,
};
static const struct ddb_regset octopro_gtl = {
.base = 0xe00,
.num = 0x03,
.size = 0x40,
};
/****************************************************************************/
/****************************************************************************/
static const struct ddb_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 octopro_map = {
.irq_version = 2,
.irq_base_i2c = 32,
.irq_base_idma = 64,
.irq_base_odma = 128,
.irq_base_gtl = 8,
.i2c = &octopro_i2c,
.i2c_buf = &octopro_i2c_buf,
.idma = &octopro_idma,
.idma_buf = &octopro_idma_buf,
.odma = &octopro_odma,
.odma_buf = &octopro_odma_buf,
.input = &octopro_input,
.output = &octopro_output,
.gtl = &octopro_gtl,
};
static const struct ddb_regmap octopro_hdin_map = {
.irq_version = 2,
.irq_base_i2c = 32,
.irq_base_idma = 64,
.irq_base_odma = 128,
.i2c = &octopro_i2c,
.i2c_buf = &octopro_i2c_buf,
.idma = &octopro_idma,
.idma_buf = &octopro_idma_buf,
.odma = &octopro_odma,
.odma_buf = &octopro_odma_buf,
.input = &octopro_input,
.output = &octopro_output,
};
static const struct ddb_regmap octopus_mod_map = {
.irq_version = 1,
.irq_base_odma = 8,
.irq_base_rate = 18,
.output = &octopus_output,
.odma = &octopus_mod_odma,
.odma_buf = &octopus_mod_odma_buf,
.channel = &octopus_mod_channel,
};
static const struct ddb_regmap octopus_mod_2_map = {
.irq_version = 2,
.irq_base_odma = 64,
.irq_base_rate = 32,
.output = &octopus_output,
.odma = &octopus_mod_2_odma,
.odma_buf = &octopus_mod_2_odma_buf,
.channel = &octopus_mod_2_channel,
};
static const struct ddb_regmap octopus_sdr_map = {
.irq_version = 2,
.irq_base_odma = 64,
.irq_base_rate = 32,
.output = &octopus_sdr_output,
.odma = &octopus_mod_2_odma,
.odma_buf = &octopus_mod_2_odma_buf,
.channel = &octopus_mod_2_channel,
};
static const struct ddb_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_CI,
.name = "Digital Devices Octopus CI",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x03,
};
static const struct ddb_info ddb_cis = {
.type = DDB_OCTOPUS_CI,
.name = "Digital Devices Octopus CI single",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x03,
};
static const struct ddb_info ddb_ci_s2_pro = {
.type = DDB_OCTOPUS_CI,
.name = "Digital Devices Octopus CI S2 Pro",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x01,
.board_control = 2,
.board_control_2 = 4,
.hw_min = 0x010007,
};
static const struct ddb_info ddb_ci_s2_pro_a = {
.type = DDB_OCTOPUS_CI,
.name = "Digital Devices Octopus CI S2 Pro Advanced",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x01,
.board_control = 2,
.board_control_2 = 4,
.hw_min = 0x010007,
};
static const struct ddb_info ddb_dvbct = {
.type = DDB_OCTOPUS,
.name = "Digital Devices DVBCT V6.1 DVB adapter",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x07,
};
/****************************************************************************/
static const struct ddb_info ddb_mod = {
.type = DDB_MOD,
.name = "Digital Devices DVB-C modulator",
.regmap = &octopus_mod_map,
.port_num = 10,
.temp_num = 1,
};
static const struct ddb_info ddb_mod_4 = {
.type = DDB_MOD,
.name = "Digital Devices DVB-C modulator",
.regmap = &octopus_mod_map,
.port_num = 4,
.temp_num = 1,
};
static const struct ddb_info ddb_mod_fsm_24 = {
.type = DDB_MOD,
.version = 2,
.name = "Digital Devices DVB-C modulator FSM-24",
.regmap = &octopus_mod_2_map,
.port_num = 24,
.temp_num = 1,
.tempmon_irq = 8,
.lostlock_irq = 9,
};
static const struct ddb_info ddb_mod_fsm_16 = {
.type = DDB_MOD,
.version = 2,
.name = "Digital Devices DVB-C modulator FSM-16",
.regmap = &octopus_mod_2_map,
.port_num = 16,
.temp_num = 1,
.tempmon_irq = 8,
.lostlock_irq = 9,
};
static const struct ddb_info ddb_mod_fsm_8 = {
.type = DDB_MOD,
.name = "Digital Devices DVB-C modulator FSM-8",
.version = 2,
.regmap = &octopus_mod_2_map,
.port_num = 8,
.temp_num = 1,
.tempmon_irq = 8,
.lostlock_irq = 9,
};
static const struct ddb_info ddb_mod_fsm_4 = {
.type = DDB_MOD,
.name = "Digital Devices DVB-C modulator FSM-8",
.version = 2,
.regmap = &octopus_mod_2_map,
.port_num = 4,
.temp_num = 1,
.tempmon_irq = 8,
.lostlock_irq = 9,
};
static const struct ddb_info ddb_sdr = {
.type = DDB_MOD,
.name = "Digital Devices SDR",
.version = 3,
.regmap = &octopus_sdr_map,
.port_num = 16,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_octopro_hdin = {
.type = DDB_OCTOPRO_HDIN,
.name = "Digital Devices OctopusNet Pro HDIN",
.regmap = &octopro_hdin_map,
.port_num = 10,
.i2c_mask = 0x3ff,
.mdio_base = 0x10020,
};
static const struct ddb_info ddb_octopro = {
.type = DDB_OCTOPRO,
.name = "Digital Devices OctopusNet Pro",
.regmap = &octopro_map,
.port_num = 10,
.i2c_mask = 0x3ff,
.mdio_base = 0x10020,
};
static const struct ddb_info ddb_s2_48 = {
.type = DDB_OCTOPUS_MAX,
.name = "Digital Devices MAX S8 4/8",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x01,
.board_control = 1,
.tempmon_irq = 24,
};
static const struct ddb_info ddb_ct2_8 = {
.type = DDB_OCTOPUS_MAX_CT,
.name = "Digital Devices MAX A8 CT2",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 0x0ff,
.board_control_2 = 0xf00,
.ts_quirks = TS_QUIRK_SERIAL,
.tempmon_irq = 24,
};
static const struct ddb_info ddb_c2t2_8 = {
.type = DDB_OCTOPUS_MAX_CT,
.name = "Digital Devices MAX A8 C2T2",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 0x0ff,
.board_control_2 = 0xf00,
.ts_quirks = TS_QUIRK_SERIAL,
.tempmon_irq = 24,
};
static const struct ddb_info ddb_isdbt_8 = {
.type = DDB_OCTOPUS_MAX_CT,
.name = "Digital Devices MAX A8 ISDBT",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 0x0ff,
.board_control_2 = 0xf00,
.ts_quirks = TS_QUIRK_SERIAL,
.tempmon_irq = 24,
};
static const struct ddb_info ddb_c2t2i_v0_8 = {
.type = DDB_OCTOPUS_MAX_CT,
.name = "Digital Devices MAX A8 C2T2I V0",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 0x0ff,
.board_control_2 = 0xf00,
.ts_quirks = TS_QUIRK_SERIAL | TS_QUIRK_ALT_OSC,
.tempmon_irq = 24,
};
static const struct ddb_info ddb_c2t2i_8 = {
.type = DDB_OCTOPUS_MAX_CT,
.name = "Digital Devices MAX A8 C2T2I",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 0x0ff,
.board_control_2 = 0xf00,
.ts_quirks = TS_QUIRK_SERIAL,
.tempmon_irq = 24,
};
static const struct ddb_info ddb_s2x_48 = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX SX8",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x00,
.tempmon_irq = 24,
.mci_ports = 4,
.mci_type = 0,
.temp_num = 1,
};
static const struct ddb_info ddb_m4 = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX M4",
.regmap = &octopus_map,
.port_num = 2,
.i2c_mask = 0x00,
.tempmon_irq = 24,
.mci_ports = 2,
.mci_type = 1,
.temp_num = 1,
};
static const struct ddb_info ddb_gtl_mini = {
.type = DDB_OCTONET,
.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(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(0x0020, 0x0012, ddb_gtl_mini),
/* Modulators */
DDB_DEVID(0x0201, 0x0001, ddb_mod),
DDB_DEVID(0x0201, 0x0002, ddb_mod),
DDB_DEVID(0x0201, 0x0004, ddb_mod_4), /* dummy entry ! */
DDB_DEVID(0x0203, 0x0001, ddb_mod),
DDB_DEVID(0x0210, 0x0000, ddb_mod_fsm_4), /* dummy entry ! */
DDB_DEVID(0x0210, 0x0001, ddb_mod_fsm_24),
DDB_DEVID(0x0210, 0x0002, ddb_mod_fsm_16),
DDB_DEVID(0x0210, 0x0003, ddb_mod_fsm_8),
DDB_DEVID(0x0220, 0x0001, ddb_sdr),
/* testing on OctopusNet Pro */
DDB_DEVID(0x0320, 0xffff, ddb_octopro_hdin),
DDB_DEVID(0x0321, 0xffff, ddb_none),
DDB_DEVID(0x0322, 0xffff, ddb_octopro),
DDB_DEVID(0x0323, 0xffff, ddb_none),
DDB_DEVID(0x0328, 0xffff, ddb_none),
DDB_DEVID(0x0329, 0xffff, ddb_octopro_hdin),
};
const struct ddb_info *get_ddb_info(u16 vendor, u16 device,
u16 subvendor, u16 subdevice)
{
int i;
for (i = 0; i < ARRAY_SIZE(ddb_device_ids); i++) {
const struct ddb_device_id *id = &ddb_device_ids[i];
if (vendor == id->vendor &&
device == id->device &&
subvendor == id->subvendor &&
(subdevice == id->subdevice ||
id->subdevice == 0xffff))
return id->info;
}
return &ddb_none;
}

View File

@@ -1,7 +1,7 @@
/*
* ddbridge-i2c.c: Digital Devices bridge i2c driver
*
* Copyright (C) 2010-2015 Digital Devices GmbH
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
@@ -17,93 +17,12 @@
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
static int i2c_io(struct i2c_adapter *adapter, u8 adr,
u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
{
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
.buf = wbuf, .len = wlen },
{.addr = adr, .flags = I2C_M_RD,
.buf = rbuf, .len = rlen } };
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
}
static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
{
struct i2c_msg msg = {.addr = adr, .flags = 0,
.buf = data, .len = len};
return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1;
}
static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
{
struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD,
.buf = val, .len = 1 } };
return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
}
static int i2c_read_regs(struct i2c_adapter *adapter,
u8 adr, u8 reg, u8 *val, u8 len)
{
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
.buf = &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);
}
#include "ddbridge.h"
#include "ddbridge-io.h"
static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
{
@@ -115,8 +34,8 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
stat = wait_for_completion_timeout(&i2c->completion, HZ);
val = ddbreadl(dev, i2c->regs + I2C_COMMAND);
if (stat == 0) {
pr_err("DDBridge: I2C timeout, card %d, port %d, link %u\n",
dev->nr, i2c->nr, i2c->link);
dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n",
dev->nr, i2c->nr, i2c->link);
#if 1
{
u32 istat = ddbreadl(dev, INTERRUPT_STATUS);
@@ -144,7 +63,10 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
#endif
return -EIO;
}
if (val & 0x70000)
val &= 0x70000;
if (val == 0x20000)
dev_err(dev->dev, "I2C bus errorx\n");
if (val)
return -EIO;
return 0;
}
@@ -152,42 +74,47 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
static int ddb_i2c_master_xfer(struct i2c_adapter *adapter,
struct i2c_msg msg[], int num)
{
struct ddb_i2c *i2c = (struct ddb_i2c *) i2c_get_adapdata(adapter);
struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter);
struct ddb *dev = i2c->dev;
u8 addr = 0;
if (num != 1 && num != 2)
return -EIO;
addr = msg[0].addr;
if (msg[0].len > i2c->bsize)
return -EIO;
if (num == 2 && msg[1].flags & I2C_M_RD &&
!(msg[0].flags & I2C_M_RD)) {
if (msg[1].len > i2c->bsize)
return -EIO;
ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len);
ddbwritel(dev, msg[0].len | (msg[1].len << 16),
i2c->regs + I2C_TASKLENGTH);
if (!ddb_i2c_cmd(i2c, addr, 1)) {
ddbcpyfrom(dev, msg[1].buf,
i2c->rbuf,
msg[1].len);
return num;
}
}
if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len);
ddbwritel(dev, msg[0].len, i2c->regs + I2C_TASKLENGTH);
if (!ddb_i2c_cmd(i2c, addr, 2))
return num;
}
if (num == 1 && (msg[0].flags & I2C_M_RD)) {
ddbwritel(dev, msg[0].len << 16, i2c->regs + I2C_TASKLENGTH);
if (!ddb_i2c_cmd(i2c, addr, 3)) {
switch (num) {
case 1:
if (msg[0].flags & I2C_M_RD) {
ddbwritel(dev, msg[0].len << 16,
i2c->regs + I2C_TASKLENGTH);
if (ddb_i2c_cmd(i2c, addr, 3))
break;
ddbcpyfrom(dev, msg[0].buf,
i2c->rbuf, msg[0].len);
return num;
}
ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len);
ddbwritel(dev, msg[0].len, i2c->regs + I2C_TASKLENGTH);
if (ddb_i2c_cmd(i2c, addr, 2))
break;
return num;
case 2:
if ((msg[0].flags & I2C_M_RD) == I2C_M_RD)
break;
if ((msg[1].flags & I2C_M_RD) != I2C_M_RD)
break;
if (msg[1].len > i2c->bsize)
break;
ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len);
ddbwritel(dev, msg[0].len | (msg[1].len << 16),
i2c->regs + I2C_TASKLENGTH);
if (ddb_i2c_cmd(i2c, addr, 1))
break;
ddbcpyfrom(dev, msg[1].buf,
i2c->rbuf,
msg[1].len);
return num;
default:
break;
}
return -EIO;
}
@@ -202,7 +129,7 @@ struct i2c_algorithm ddb_i2c_algo = {
.functionality = ddb_i2c_functionality,
};
static void ddb_i2c_release(struct ddb *dev)
void ddb_i2c_release(struct ddb *dev)
{
int i;
struct ddb_i2c *i2c;
@@ -213,15 +140,16 @@ static void ddb_i2c_release(struct ddb *dev)
}
}
static void i2c_handler(unsigned long priv)
static void i2c_handler(void *priv)
{
struct ddb_i2c *i2c = (struct ddb_i2c *) priv;
struct ddb_i2c *i2c = (struct ddb_i2c *)priv;
complete(&i2c->completion);
}
static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c,
struct ddb_regmap *regmap, int link, int i, int num)
const struct ddb_regmap *regmap,
int link, int i, int num)
{
struct i2c_adapter *adap;
@@ -241,13 +169,12 @@ static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c,
adap = &i2c->adap;
i2c_set_adapdata(adap, i2c);
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG;
adap->class = I2C_ADAP_CLASS_TV_DIGITAL | I2C_CLASS_TV_ANALOG;
#else
#ifdef I2C_CLASS_TV_ANALOG
adap->class = I2C_CLASS_TV_ANALOG;
#endif
#endif
/*strcpy(adap->name, "ddbridge");*/
snprintf(adap->name, I2C_NAME_SIZE, "ddbridge_%02x.%x.%x",
dev->nr, i2c->link, i);
adap->algo = &ddb_i2c_algo;
@@ -256,13 +183,13 @@ static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c,
return i2c_add_adapter(adap);
}
static int ddb_i2c_init(struct ddb *dev)
int ddb_i2c_init(struct ddb *dev)
{
int stat = 0;
u32 i, j, num = 0, l, base;
struct ddb_i2c *i2c;
struct i2c_adapter *adap;
struct ddb_regmap *regmap;
const struct ddb_regmap *regmap;
for (l = 0; l < DDB_MAX_LINK; l++) {
if (!dev->link[l].info)
@@ -275,8 +202,7 @@ static int ddb_i2c_init(struct ddb *dev)
if (!(dev->link[l].info->i2c_mask & (1 << i)))
continue;
i2c = &dev->i2c[num];
dev->handler_data[l][i + base] = (unsigned long) i2c;
dev->handler[l][i + base] = i2c_handler;
ddb_irq_set(dev, l, i + base, i2c_handler, i2c);
stat = ddb_i2c_add(dev, i2c, regmap, l, i, num);
if (stat)
break;
@@ -289,8 +215,9 @@ static int ddb_i2c_init(struct ddb *dev)
adap = &i2c->adap;
i2c_del_adapter(adap);
}
} else
} else {
dev->i2c_num = num;
}
return stat;
}

View File

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

178
ddbridge/ddbridge-io.c Normal file
View File

@@ -0,0 +1,178 @@
/*
* ddbridge-io.c: Digital Devices bridge I/O functions
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
#include "ddbridge-io.h"
u32 ddblreadl(struct ddb_link *link, u32 adr)
{
if (unlikely(link->nr)) {
unsigned long flags;
u32 val;
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddblwritel0(link, adr & 0xfffc, link->regs + 0x14);
ddblwritel0(link, 3, link->regs + 0x10);
gtlw(link);
val = ddblreadl0(link, link->regs + 0x1c);
spin_unlock_irqrestore(&link->lock, flags);
return val;
}
return readl(link->dev->regs + adr);
}
void ddblwritel(struct ddb_link *link, u32 val, u32 adr)
{
if (unlikely(link->nr)) {
unsigned long flags;
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
ddblwritel0(link, val, link->regs + 0x18);
ddblwritel0(link, 1, link->regs + 0x10);
spin_unlock_irqrestore(&link->lock, flags);
return;
}
writel(val, link->dev->regs + adr);
}
u32 ddbreadl(struct ddb *dev, u32 adr)
{
if (unlikely(adr & 0xf0000000)) {
unsigned long flags;
u32 val, l = (adr >> DDB_LINK_SHIFT) & 3;
struct ddb_link *link = &dev->link[l];
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddblwritel0(link, adr & 0xfffc, link->regs + 0x14);
ddblwritel0(link, 3, link->regs + 0x10);
gtlw(link);
val = ddblreadl0(link, link->regs + 0x1c);
spin_unlock_irqrestore(&link->lock, flags);
return val;
}
return readl(dev->regs + adr);
}
void ddbwritel(struct ddb *dev, u32 val, u32 adr)
{
if (unlikely(adr & 0xf0000000)) {
unsigned long flags;
u32 l = (adr >> DDB_LINK_SHIFT);
struct ddb_link *link = &dev->link[l];
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
ddblwritel0(link, val, link->regs + 0x18);
ddblwritel0(link, 1, link->regs + 0x10);
spin_unlock_irqrestore(&link->lock, flags);
return;
}
writel(val, dev->regs + adr);
}
void gtlcpyto(struct ddb *dev, u32 adr, const u8 *buf,
unsigned int count)
{
u32 val = 0, p = adr;
u32 aa = p & 3;
if (aa) {
while (p & 3 && count) {
val >>= 8;
val |= *buf << 24;
p++;
buf++;
count--;
}
ddbwritel(dev, val, adr);
}
while (count >= 4) {
val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
ddbwritel(dev, val, p);
p += 4;
buf += 4;
count -= 4;
}
if (count) {
val = buf[0];
if (count > 1)
val |= buf[1] << 8;
if (count > 2)
val |= buf[2] << 16;
ddbwritel(dev, val, p);
}
}
void gtlcpyfrom(struct ddb *dev, u8 *buf, u32 adr, long count)
{
u32 val = 0, p = adr;
u32 a = p & 3;
if (a) {
val = ddbreadl(dev, p) >> (8 * a);
while (p & 3 && count) {
*buf = val & 0xff;
val >>= 8;
p++;
buf++;
count--;
}
}
while (count >= 4) {
val = ddbreadl(dev, p);
buf[0] = val & 0xff;
buf[1] = (val >> 8) & 0xff;
buf[2] = (val >> 16) & 0xff;
buf[3] = (val >> 24) & 0xff;
p += 4;
buf += 4;
count -= 4;
}
if (count) {
val = ddbreadl(dev, p);
buf[0] = val & 0xff;
if (count > 1)
buf[1] = (val >> 8) & 0xff;
if (count > 2)
buf[2] = (val >> 16) & 0xff;
}
}
void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count)
{
if (unlikely(adr & 0xf0000000))
return gtlcpyto(dev, adr, src, count);
return memcpy_toio(dev->regs + adr, src, count);
}
void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count)
{
if (unlikely(adr & 0xf0000000))
return gtlcpyfrom(dev, dst, adr, count);
return memcpy_fromio(dst, dev->regs + adr, count);
}

97
ddbridge/ddbridge-io.h Normal file
View File

@@ -0,0 +1,97 @@
/*
* ddbridge-io.h: Digital Devices bridge I/O functions
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef _DDBRIDGE_IO_H_
#define _DDBRIDGE_IO_H_
u32 ddblreadl(struct ddb_link *link, u32 adr);
void ddblwritel(struct ddb_link *link, u32 val, u32 adr);
u32 ddbreadl(struct ddb *dev, u32 adr);
void ddbwritel(struct ddb *dev, u32 val, u32 adr);
void gtlcpyto(struct ddb *dev, u32 adr, const u8 *buf,
unsigned int count);
void gtlcpyfrom(struct ddb *dev, u8 *buf, u32 adr, long count);
void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count);
void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count);
static inline void ddbwriteb0(struct ddb *dev, u32 val, u32 adr)
{
writeb(val, dev->regs + adr);
}
static inline u32 ddbreadb0(struct ddb *dev, u32 adr)
{
return readb(dev->regs + adr);
}
static inline void ddbwritel0(struct ddb *dev, u32 val, u32 adr)
{
writel(val, dev->regs + adr);
}
static inline u32 ddbreadl0(struct ddb *dev, u32 adr)
{
return readl(dev->regs + adr);
}
static inline void ddblwritel0(struct ddb_link *link, u32 val, u32 adr)
{
writel(val, link->dev->regs + adr);
}
static inline u32 ddblreadl0(struct ddb_link *link, u32 adr)
{
return readl(link->dev->regs + adr);
}
#if 0
static inline void gtlw(struct ddb_link *link)
{
u32 count = 0;
static u32 max;
while (1 & ddblreadl0(link, link->regs + 0x10)) {
if (++count == 1024) {
pr_info("LTO\n");
break;
}
}
if (count > max) {
max = count;
pr_info("TO=%u\n", max);
}
if (ddblreadl0(link, link->regs + 0x10) & 0x8000)
pr_err("link error\n");
}
#else
static inline void gtlw(struct ddb_link *link)
{
while (1 & ddblreadl0(link, link->regs + 0x10))
;
}
#endif
#define ddbmemset(_dev, _adr, _val, _count) \
memset_io(((_dev)->regs + (_adr)), (_val), (_count))
#endif

449
ddbridge/ddbridge-m4.c Normal file
View File

@@ -0,0 +1,449 @@
/*
* ddbridge-m4.c: Digital Devices MAX M4 driver
*
* Copyright (C) 2018 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
#include "ddbridge-io.h"
#include "ddbridge-i2c.h"
#include "ddbridge-mci.h"
struct m4_base {
struct mci_base mci_base;
};
struct m4 {
struct mci mci;
int started;
int t2_signalling_valid;
int iq_constellation_point;
int iq_constellation_point_max;
int iq_constellation_tap;
int first_time_lock;
};
static int stop(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct mci_command cmd;
struct mci_base *mci_base = state->mci.base;
if (!state->started)
return -1;
state->started = 0;
state->t2_signalling_valid = 0;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_STOP;
cmd.demod = state->mci.demod;
ddb_mci_cmd(&state->mci, &cmd, NULL);
return 0;
}
static int search_s2(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct m4_base *m4_base = (struct m4_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_DVBS;
cmd.dvbs2_search.flags = 3;
cmd.dvbs2_search.s2_modulation_mask = 3;
cmd.dvbs2_search.retry = 2;
cmd.dvbs2_search.frequency = p->frequency * 1000;
cmd.dvbs2_search.symbol_rate = p->symbol_rate;
cmd.dvbs2_search.scrambling_sequence_index = 0; //p->scrambling_sequence_index;
cmd.dvbs2_search.input_stream_id = p->stream_id;
cmd.tuner = state->mci.nr;
cmd.demod = state->mci.tuner;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_c(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct m4_base *m4_base = (struct m4_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_DVBC;
switch (p->bandwidth_hz) {
case 6000000:
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_6MHZ;
break;
case 7000000:
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_7MHZ;
break;
default:
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_8MHZ;
break;
}
cmd.dvbc_search.retry = 2;
cmd.dvbc_search.frequency = p->frequency;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_t(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct m4_base *m4_base = (struct m4_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_DVBT;
switch (p->bandwidth_hz) {
case 5000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_5MHZ;
break;
case 6000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_6MHZ;
break;
case 7000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_7MHZ;
break;
default:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_8MHZ;
break;
}
cmd.dvbt_search.retry = 2;
cmd.dvbt_search.frequency = p->frequency;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_t2(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct m4_base *m4_base = (struct m4_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
u32 flags = 0;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_DVBT2;
switch (p->bandwidth_hz) {
case 1700000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_1_7MHZ;
break;
case 5000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_5MHZ;
break;
case 6000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_6MHZ;
break;
case 7000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_7MHZ;
break;
default:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_8MHZ;
break;
}
cmd.dvbt2_search.retry = 2;
cmd.dvbt2_search.frequency = p->frequency;
if (p->stream_id != NO_STREAM_ID_FILTER) {
cmd.dvbt2_search.plp = p->stream_id & 0xff;
cmd.dvbt2_search.flags |= 0x80;
cmd.dvbt2_search.flags |= (p->stream_id >> 8) & 1;
}
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_c2(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct m4_base *m4_base = (struct m4_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
u32 flags = 0;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_DVBC2;
switch (p->bandwidth_hz) {
case 6000000:
cmd.dvbc2_search.bandwidth = MCI_BANDWIDTH_6MHZ;
break;
default:
cmd.dvbc2_search.bandwidth = MCI_BANDWIDTH_8MHZ;
break;
}
cmd.dvbc2_search.retry = 2;
cmd.dvbc2_search.frequency = p->frequency;
if (p->stream_id != NO_STREAM_ID_FILTER) {
cmd.dvbc2_search.plp = p->stream_id & 0xff;
cmd.dvbc2_search.data_slice = (p->stream_id >> 8) & 0xff;
}
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_isdbt(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct m4_base *m4_base = (struct m4_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
u32 flags = 0;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_ISDBT;
switch (p->bandwidth_hz) {
case 8000000:
cmd.isdbt_search.bandwidth = MCI_BANDWIDTH_8MHZ;
break;
case 7000000:
cmd.isdbt_search.bandwidth = MCI_BANDWIDTH_7MHZ;
break;
default:
cmd.isdbt_search.bandwidth = MCI_BANDWIDTH_6MHZ;
break;
}
cmd.isdbt_search.retry = 2;
cmd.isdbt_search.frequency = p->frequency;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int set_parameters(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
int res;
stop(fe);
state->t2_signalling_valid = 0;
state->iq_constellation_point = 0;
state->iq_constellation_point_max = 0;
state->iq_constellation_tap = 0;
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBS:
case SYS_DVBS2:
res = search_s2(fe);
break;
case SYS_DVBC_ANNEX_A:
res = search_c(fe);
break;
case SYS_DVBT:
state->iq_constellation_tap = 5;
res = search_t(fe);
break;
case SYS_DVBT2:
res = search_t2(fe);
break;
case SYS_DVBC2:
res = search_c2(fe);
break;
case SYS_ISDBT:
res = search_isdbt(fe);
break;
default:
return -EINVAL;
}
if (!res) {
state->started = 1;
state->first_time_lock = 1;
}
return res;
}
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{
int stat;
struct m4 *state = fe->demodulator_priv;
struct mci_result res;
stat = ddb_mci_get_status(&state->mci, &res);
if (stat)
return stat;
*status = 0x00;
ddb_mci_get_info(&state->mci);
ddb_mci_get_strength(fe);
if (res.status == M4_DEMOD_WAIT_SIGNAL)
*status = 0x01;
if (res.status == M4_DEMOD_LOCKED) {
*status = 0x1f;
ddb_mci_get_snr(fe);
}
return stat;
}
static int tune(struct dvb_frontend *fe, bool re_tune,
unsigned int mode_flags,
unsigned int *delay, enum fe_status *status)
{
int r;
if (re_tune) {
r = set_parameters(fe);
if (r)
return r;
}
r = read_status(fe, status);
if (r)
return r;
if (*status & FE_HAS_LOCK)
return 0;
*delay = HZ / 10;
return 0;
}
static int sleep(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
if (state->started)
stop(fe);
return 0;
}
static void release(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
mci_base->count--;
if (mci_base->count == 0) {
list_del(&mci_base->mci_list);
kfree(mci_base);
}
kfree(state);
}
static int get_algo(struct dvb_frontend *fe)
{
return DVBFE_ALGO_HW;
}
static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{
struct m4 *state = fe->demodulator_priv;
ddb_mci_proc_info(&state->mci, p);
return 0;
}
static struct dvb_frontend_ops m4_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2, SYS_DVBC2, SYS_ISDBT,
SYS_DVBS, SYS_DVBS2, },
.info = {
.name = "M4",
.frequency_min = 950000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */
.symbol_rate_min = 100000,
.symbol_rate_max = 100000000,
.frequency_stepsize = 0,
.frequency_tolerance = 0,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_4_5 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION
},
.release = release,
.get_frontend_algo = get_algo,
.get_frontend = get_frontend,
.read_status = read_status,
.tune = tune,
.sleep = sleep,
};
static int init(struct mci *mci)
{
//struct m4 *state = (struct m4 *) mci;
return 0;
}
static int base_init(struct mci_base *mci_base)
{
//struct m4_base *base = (struct m4_base *) mci_base;
return 0;
}
struct mci_cfg ddb_max_m4_cfg = {
.type = 0,
.fe_ops = &m4_ops,
.base_size = sizeof(struct m4_base),
.state_size = sizeof(struct m4),
.init = init,
.base_init = base_init,
};

472
ddbridge/ddbridge-main.c Normal file
View File

@@ -0,0 +1,472 @@
/*
* ddbridge.c: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
#include "ddbridge-io.h"
#ifdef CONFIG_PCI_MSI
static int msi = 1;
module_param(msi, int, 0444);
MODULE_PARM_DESC(msi,
" Control MSI interrupts: 0-disable, 1-enable (default)");
#endif
#if (KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE)
#if (KERNEL_VERSION(3, 19, 0) > LINUX_VERSION_CODE)
#define msi_desc_to_dev(desc) (&(desc)->dev.dev)
#define dev_to_msi_list(dev) (&to_pci_dev((dev))->msi_list)
#define first_msi_entry(dev) \
list_first_entry(dev_to_msi_list((dev)), struct msi_desc, list)
#define for_each_msi_entry(desc, dev) \
list_for_each_entry((desc), dev_to_msi_list((dev)), list)
#ifdef CONFIG_PCI_MSI
#define first_pci_msi_entry(pdev) first_msi_entry(&(pdev)->dev)
#define for_each_pci_msi_entry(desc, pdev) \
for_each_msi_entry((desc), &(pdev)->dev)
#endif
#endif
#include <linux/msi.h>
int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
{
#ifdef CONFIG_PCI_MSI
if (dev->msix_enabled) {
struct msi_desc *entry;
int i = 0;
for_each_pci_msi_entry(entry, dev) {
if (i == nr)
return entry->irq;
i++;
}
WARN_ON_ONCE(1);
return -EINVAL;
}
/* This does not work < 3.19 because nvec_used is used differently. */
#if (KERNEL_VERSION(3, 19, 0) <= LINUX_VERSION_CODE)
if (dev->msi_enabled) {
struct msi_desc *entry = first_pci_msi_entry(dev);
if (WARN_ON_ONCE(nr >= entry->nvec_used))
return -EINVAL;
} else {
if (WARN_ON_ONCE(nr > 0))
return -EINVAL;
}
#endif
#endif
return dev->irq + nr;
}
#endif
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static void __devexit ddb_irq_disable(struct ddb *dev)
{
if (dev->link[0].info->regmap->irq_version == 2) {
ddbwritel(dev, 0x00000000, INTERRUPT_V2_CONTROL);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_1);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_2);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_3);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_4);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_5);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_6);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_7);
} else {
ddbwritel(dev, 0, INTERRUPT_ENABLE);
ddbwritel(dev, 0, MSI1_ENABLE);
}
}
static void __devexit ddb_msi_exit(struct ddb *dev)
{
#ifdef CONFIG_PCI_MSI
if (dev->msi) {
#if (KERNEL_VERSION(4, 8, 0) <= LINUX_VERSION_CODE)
pci_free_irq_vectors(dev->pdev);
#else
pci_disable_msi(dev->pdev);
#endif
}
#endif
}
static void __devexit ddb_irq_exit(struct ddb *dev)
{
ddb_irq_disable(dev);
if (dev->msi == 2)
free_irq(pci_irq_vector(dev->pdev, 1), dev);
free_irq(pci_irq_vector(dev->pdev, 0), dev);
}
static void __devexit ddb_remove(struct pci_dev *pdev)
{
struct ddb *dev = (struct ddb *)pci_get_drvdata(pdev);
ddb_device_destroy(dev);
ddb_nsd_detach(dev);
ddb_ports_detach(dev);
ddb_i2c_release(dev);
if (dev->link[0].info->ns_num)
ddbwritel(dev, 0, ETHER_CONTROL);
ddb_irq_exit(dev);
ddb_msi_exit(dev);
ddb_ports_release(dev);
ddb_buffers_free(dev);
ddb_unmap(dev);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
}
#if (KERNEL_VERSION(3, 8, 0) <= LINUX_VERSION_CODE)
#define __devinit
#define __devinitdata
#endif
static int __devinit ddb_irq_msi(struct ddb *dev, int nr)
{
int stat = 0;
#ifdef CONFIG_PCI_MSI
if (msi && pci_msi_enabled()) {
#if (KERNEL_VERSION(3, 15, 0) <= LINUX_VERSION_CODE)
#if (KERNEL_VERSION(4, 8, 0) <= LINUX_VERSION_CODE)
stat = pci_alloc_irq_vectors(dev->pdev, 1, nr,
PCI_IRQ_MSI | PCI_IRQ_MSIX);
#else
stat = pci_enable_msi_range(dev->pdev, 1, nr);
#endif
if (stat >= 1) {
dev->msi = stat;
dev_info(dev->dev, "using %d MSI interrupt(s)\n",
dev->msi);
} else {
dev_info(dev->dev, "MSI not available.\n");
}
#else
stat = pci_enable_msi_block(dev->pdev, nr);
if (stat == 0) {
dev->msi = nr;
dev_info(dev->dev, "using %d MSI interrupts\n", nr);
} else if (stat == 1) {
stat = pci_enable_msi(dev->pdev);
dev->msi = 1;
}
if (stat < 0)
dev_info(dev->dev, "MSI not available.\n");
#endif
}
#endif
return stat;
}
static int __devinit ddb_irq_init2(struct ddb *dev)
{
int stat;
int irq_flag = IRQF_SHARED;
dev_info(dev->dev, "init type 2 IRQ hardware block\n");
ddbwritel(dev, 0x00000000, INTERRUPT_V2_CONTROL);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_1);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_2);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_3);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_4);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_5);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_6);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_7);
ddb_irq_msi(dev, 1);
if (dev->msi)
irq_flag = 0;
stat = request_irq(pci_irq_vector(dev->pdev, 0), ddb_irq_handler_v2,
irq_flag, "ddbridge", (void *)dev);
if (stat < 0)
return stat;
ddbwritel(dev, 0x0000ff7f, INTERRUPT_V2_CONTROL);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_1);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_2);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_3);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_4);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_5);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_6);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_7);
return stat;
}
static int __devinit ddb_irq_init(struct ddb *dev)
{
int stat;
int irq_flag = IRQF_SHARED;
if (dev->link[0].info->regmap->irq_version == 2)
return ddb_irq_init2(dev);
ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE);
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
ddbwritel(dev, 0x00000000, MSI2_ENABLE);
ddbwritel(dev, 0x00000000, MSI3_ENABLE);
ddbwritel(dev, 0x00000000, MSI4_ENABLE);
ddbwritel(dev, 0x00000000, MSI5_ENABLE);
ddbwritel(dev, 0x00000000, MSI6_ENABLE);
ddbwritel(dev, 0x00000000, MSI7_ENABLE);
ddb_irq_msi(dev, 2);
if (dev->msi)
irq_flag = 0;
if (dev->msi == 2) {
stat = request_irq(pci_irq_vector(dev->pdev, 0), ddb_irq_handler0,
irq_flag, "ddbridge", (void *)dev);
if (stat < 0)
return stat;
stat = request_irq(pci_irq_vector(dev->pdev, 1), ddb_irq_handler1,
irq_flag, "ddbridge", (void *)dev);
if (stat < 0) {
free_irq(pci_irq_vector(dev->pdev, 0), dev);
return stat;
}
} else {
#ifdef DDB_TEST_THREADED
stat = request_threaded_irq(pci_irq_vector(dev->pdev, 0),
dev->pdev->irq, ddb_irq_handler,
irq_thread,
irq_flag,
"ddbridge", (void *)dev);
#else
stat = request_irq(pci_irq_vector(dev->pdev, 0),
ddb_irq_handler,
irq_flag, "ddbridge", (void *)dev);
#endif
if (stat < 0)
return stat;
}
/*ddbwritel(dev, 0xffffffff, INTERRUPT_ACK);*/
if (dev->msi == 2) {
ddbwritel(dev, 0x0fffff00, INTERRUPT_ENABLE);
ddbwritel(dev, 0x0000000f, MSI1_ENABLE);
} else {
ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE);
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
}
return stat;
}
static int __devinit ddb_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct ddb *dev;
int stat = 0;
if (pci_enable_device(pdev) < 0)
return -ENODEV;
pci_set_master(pdev);
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
return -ENODEV;
dev = vzalloc(sizeof(*dev));
if (!dev)
return -ENOMEM;
mutex_init(&dev->mutex);
dev->has_dma = 1;
dev->pdev = pdev;
dev->dev = &pdev->dev;
pci_set_drvdata(pdev, dev);
dev->link[0].ids.vendor = id->vendor;
dev->link[0].ids.device = id->device;
dev->link[0].ids.subvendor = id->subvendor;
dev->link[0].ids.subdevice = pdev->subsystem_device;
dev->link[0].ids.devid = (id->device << 16) | id->vendor;
dev->link[0].dev = dev;
dev->link[0].info = get_ddb_info(id->vendor, id->device,
id->subvendor, pdev->subsystem_device);
dev_info(dev->dev, "device name: %s\n", dev->link[0].info->name);
dev->regs_len = pci_resource_len(dev->pdev, 0);
dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
pci_resource_len(dev->pdev, 0));
if (!dev->regs) {
dev_err(dev->dev, "not enough memory for register map\n");
stat = -ENOMEM;
goto fail;
}
if (ddbreadl(dev, 0) == 0xffffffff) {
dev_err(dev->dev, "cannot read registers\n");
stat = -ENODEV;
goto fail;
}
dev->link[0].ids.hwid = ddbreadl(dev, 0);
dev->link[0].ids.regmapid = ddbreadl(dev, 4);
dev_info(dev->dev, "HW %08x REGMAP %08x\n",
dev->link[0].ids.hwid, dev->link[0].ids.regmapid);
if ((dev->link[0].ids.hwid & 0xffffff) <
dev->link[0].info->hw_min) {
u32 min = dev->link[0].info->hw_min;
dev_err(dev->dev, "Update firmware to at least version %u.%u to ensure full functionality!\n",
(min & 0xff0000) >> 16, min & 0xffff);
}
if (dev->link[0].info->ns_num) {
ddbwritel(dev, 0, ETHER_CONTROL);
ddb_reset_ios(dev);
}
ddbwritel(dev, 0, DMA_BASE_READ);
if (dev->link[0].info->type != DDB_MOD)
ddbwritel(dev, 0, DMA_BASE_WRITE);
if (dev->link[0].info->type == DDB_MOD
&& dev->link[0].info->version <= 1) {
if (ddbreadl(dev, 0x1c) == 4)
dev->link[0].info =
get_ddb_info(0xdd01, 0x0201, 0xdd01, 0x0004);
}
if (dev->link[0].info->type == DDB_MOD
&& dev->link[0].info->version == 2) {
u32 lic = ddbreadl(dev, 0x1c) & 7;
switch (lic) {
case 0:
dev->link[0].info =
get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0000);
break;
case 1:
dev->link[0].info =
get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0003);
break;
case 3:
dev->link[0].info =
get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0002);
break;
default:
break;
}
}
stat = ddb_irq_init(dev);
if (stat < 0)
goto fail0;
if (ddb_init(dev) == 0)
return 0;
ddb_irq_exit(dev);
fail0:
dev_err(dev->dev, "fail0\n");
ddb_msi_exit(dev);
fail:
dev_err(dev->dev, "fail\n");
ddb_unmap(dev);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
return -1;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
#define DDB_DEVICE_ANY(_device) \
{ PCI_DEVICE_SUB(0xdd01, _device, 0xdd01, PCI_ANY_ID) }
static const struct pci_device_id ddb_id_table[] __devinitconst = {
DDB_DEVICE_ANY(0x0002),
DDB_DEVICE_ANY(0x0003),
DDB_DEVICE_ANY(0x0005),
DDB_DEVICE_ANY(0x0006),
DDB_DEVICE_ANY(0x0007),
DDB_DEVICE_ANY(0x0008),
DDB_DEVICE_ANY(0x0009),
DDB_DEVICE_ANY(0x000a),
DDB_DEVICE_ANY(0x0011),
DDB_DEVICE_ANY(0x0012),
DDB_DEVICE_ANY(0x0013),
DDB_DEVICE_ANY(0x0020),
DDB_DEVICE_ANY(0x0201),
DDB_DEVICE_ANY(0x0203),
DDB_DEVICE_ANY(0x0210),
DDB_DEVICE_ANY(0x0220),
DDB_DEVICE_ANY(0x0320),
DDB_DEVICE_ANY(0x0321),
DDB_DEVICE_ANY(0x0322),
DDB_DEVICE_ANY(0x0323),
DDB_DEVICE_ANY(0x0328),
DDB_DEVICE_ANY(0x0329),
{0}
};
MODULE_DEVICE_TABLE(pci, ddb_id_table);
static struct pci_driver ddb_pci_driver = {
.name = "ddbridge",
.id_table = ddb_id_table,
.probe = ddb_probe,
.remove = ddb_remove,
};
static __init int module_init_ddbridge(void)
{
int stat;
pr_info("Digital Devices PCIE bridge driver "
DDBRIDGE_VERSION
", Copyright (C) 2010-17 Digital Devices GmbH\n");
stat = ddb_init_ddbridge();
if (stat < 0)
return stat;
stat = pci_register_driver(&ddb_pci_driver);
if (stat < 0)
ddb_exit_ddbridge(0, stat);
return stat;
}
static __exit void module_exit_ddbridge(void)
{
pci_unregister_driver(&ddb_pci_driver);
ddb_exit_ddbridge(0, 0);
}
module_init(module_init_ddbridge);
module_exit(module_exit_ddbridge);
MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(DDBRIDGE_VERSION);

521
ddbridge/ddbridge-max.c Normal file
View File

@@ -0,0 +1,521 @@
/*
* ddbridge-max.c: Digital Devices MAX card line support functions
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
#include "ddbridge-io.h"
#include "ddbridge-i2c.h"
/* MAX LNB interface related module parameters */
static int fmode;
module_param(fmode, int, 0444);
MODULE_PARM_DESC(fmode, "frontend emulation mode");
static int fmode_sat = -1;
module_param(fmode_sat, int, 0444);
MODULE_PARM_DESC(fmode_sat, "set frontend emulation mode sat");
static int old_quattro;
module_param(old_quattro, int, 0444);
MODULE_PARM_DESC(old_quattro, "old quattro LNB input order ");
/* MAX LNB interface related functions */
static int lnb_command(struct ddb *dev, u32 link, u32 lnb, u32 cmd)
{
u32 c, v = 0, tag = DDB_LINK_TAG(link);
v = LNB_TONE & (dev->link[link].lnb.tone << (15 - lnb));
ddbwritel(dev, cmd | v, tag | LNB_CONTROL(lnb));
for (c = 0; c < 10; c++) {
v = ddbreadl(dev, tag | LNB_CONTROL(lnb));
if ((v & LNB_BUSY) == 0)
break;
msleep(20);
}
if (c == 10)
dev_info(dev->dev,
"%s lnb = %08x cmd = %08x\n",
__func__, lnb, cmd);
return 0;
}
static int max_set_input_unlocked(struct dvb_frontend *fe, int in);
static int max_emulate_switch(struct dvb_frontend *fe,
u8 *cmd, u32 len)
{
int input;
if (len !=4)
return -1;
if ((cmd[0] != 0xe0) || (cmd[1] != 0x10) || (cmd[2] != 0x39))
return -1;
input = cmd[3] & 3;
max_set_input_unlocked(fe, input);
return 0;
}
static int max_send_master_cmd(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd)
{
struct ddb_input *input = fe->sec_priv;
struct ddb_port *port = input->port;
struct ddb *dev = port->dev;
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
u32 tag = DDB_LINK_TAG(port->lnr);
int i;
u32 fmode = dev->link[port->lnr].lnb.fmode;
if (fmode == 2 || fmode == 1)
return 0;
if (fmode == 4)
max_emulate_switch(fe, cmd->msg, cmd->msg_len);
if (dvb->diseqc_send_master_cmd)
dvb->diseqc_send_master_cmd(fe, cmd);
mutex_lock(&dev->link[port->lnr].lnb.lock);
ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(dvb->input));
for (i = 0; i < cmd->msg_len; i++)
ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(dvb->input));
lnb_command(dev, port->lnr, dvb->input, LNB_CMD_DISEQC);
mutex_unlock(&dev->link[port->lnr].lnb.lock);
return 0;
}
static int lnb_send_diseqc(struct ddb *dev, u32 link, u32 input,
struct dvb_diseqc_master_cmd *cmd)
{
u32 tag = DDB_LINK_TAG(link);
int i;
ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(input));
for (i = 0; i < cmd->msg_len; i++)
ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(input));
lnb_command(dev, link, input, LNB_CMD_DISEQC);
return 0;
}
static int lnb_set_sat(struct ddb *dev, u32 link,
u32 input, u32 sat, u32 band, u32 hor)
{
struct dvb_diseqc_master_cmd cmd = {
.msg = {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00},
.msg_len = 4
};
cmd.msg[3] = 0xf0 | (((sat << 2) & 0x0c) |
(band ? 1 : 0) | (hor ? 2 : 0));
return lnb_send_diseqc(dev, link, input, &cmd);
}
static int lnb_set_tone(struct ddb *dev, u32 link, u32 input,
enum fe_sec_tone_mode tone)
{
int s = 0;
u32 mask = (1ULL << input);
switch (tone) {
case SEC_TONE_OFF:
if (!(dev->link[link].lnb.tone & mask))
return 0;
dev->link[link].lnb.tone &= ~(1ULL << input);
break;
case SEC_TONE_ON:
if (dev->link[link].lnb.tone & mask)
return 0;
dev->link[link].lnb.tone |= (1ULL << input);
break;
default:
s = -EINVAL;
break;
}
if (!s)
s = lnb_command(dev, link, input, LNB_CMD_NOP);
return s;
}
static int lnb_set_voltage(struct ddb *dev, u32 link, u32 input,
enum fe_sec_voltage voltage)
{
int s = 0;
if (dev->link[link].lnb.oldvoltage[input] == voltage)
return 0;
switch (voltage) {
case SEC_VOLTAGE_OFF:
if (dev->link[link].lnb.voltage[input])
return 0;
lnb_command(dev, link, input, LNB_CMD_OFF);
break;
case SEC_VOLTAGE_13:
lnb_command(dev, link, input, LNB_CMD_LOW);
break;
case SEC_VOLTAGE_18:
lnb_command(dev, link, input, LNB_CMD_HIGH);
break;
default:
s = -EINVAL;
break;
}
dev->link[link].lnb.oldvoltage[input] = voltage;
return s;
}
static int max_set_input_unlocked(struct dvb_frontend *fe, int in)
{
struct ddb_input *input = fe->sec_priv;
struct ddb_port *port = input->port;
struct ddb *dev = port->dev;
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
int res = 0;
if (in > 3)
return -EINVAL;
if (dvb->input != in) {
u32 bit = (1ULL << input->nr);
u32 obit = dev->link[port->lnr].lnb.voltage[dvb->input] & bit;
dev->link[port->lnr].lnb.voltage[dvb->input] &= ~bit;
dvb->input = in;
dev->link[port->lnr].lnb.voltage[dvb->input] |= obit;
}
if (dvb->set_input)
res = dvb->set_input(fe, in);
return res;
}
static int max_set_input(struct dvb_frontend *fe, int in)
{
struct ddb_input *input = fe->sec_priv;
struct ddb_port *port = input->port;
struct ddb *dev = input->port->dev;
int res;
mutex_lock(&dev->link[port->lnr].lnb.lock);
res = max_set_input_unlocked(fe, in);
mutex_unlock(&dev->link[port->lnr].lnb.lock);
return res;
}
static int max_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
{
struct ddb_input *input = fe->sec_priv;
struct ddb_port *port = input->port;
struct ddb *dev = port->dev;
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
int tuner = 0;
int res = 0;
u32 fmode = dev->link[port->lnr].lnb.fmode;
mutex_lock(&dev->link[port->lnr].lnb.lock);
dvb->tone = tone;
switch (fmode) {
default:
case 0:
case 3:
res = lnb_set_tone(dev, port->lnr, dvb->input, tone);
break;
case 1:
case 2:
if (old_quattro) {
if (dvb->tone == SEC_TONE_ON)
tuner |= 2;
if (dvb->voltage == SEC_VOLTAGE_18)
tuner |= 1;
} else {
if (dvb->tone == SEC_TONE_ON)
tuner |= 1;
if (dvb->voltage == SEC_VOLTAGE_18)
tuner |= 2;
}
res = max_set_input_unlocked(fe, tuner);
break;
}
mutex_unlock(&dev->link[port->lnr].lnb.lock);
return res;
}
static int max_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage)
{
struct ddb_input *input = fe->sec_priv;
struct ddb_port *port = input->port;
struct ddb *dev = port->dev;
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
int tuner = 0;
u32 nv, ov = dev->link[port->lnr].lnb.voltages;
int res = 0;
u32 fmode = dev->link[port->lnr].lnb.fmode;
mutex_lock(&dev->link[port->lnr].lnb.lock);
dvb->voltage = voltage;
switch (fmode) {
case 3:
default:
case 0:
if (fmode == 3)
max_set_input_unlocked(fe, 0);
if (voltage == SEC_VOLTAGE_OFF)
dev->link[port->lnr].lnb.voltage[dvb->input] &=
~(1ULL << input->nr);
else
dev->link[port->lnr].lnb.voltage[dvb->input] |=
(1ULL << input->nr);
res = lnb_set_voltage(dev, port->lnr, dvb->input, voltage);
break;
case 1:
case 2:
if (voltage == SEC_VOLTAGE_OFF)
dev->link[port->lnr].lnb.voltages &=
~(1ULL << input->nr);
else
dev->link[port->lnr].lnb.voltages |=
(1ULL << input->nr);
nv = dev->link[port->lnr].lnb.voltages;
if (old_quattro) {
if (dvb->tone == SEC_TONE_ON)
tuner |= 2;
if (dvb->voltage == SEC_VOLTAGE_18)
tuner |= 1;
} else {
if (dvb->tone == SEC_TONE_ON)
tuner |= 1;
if (dvb->voltage == SEC_VOLTAGE_18)
tuner |= 2;
}
res = max_set_input_unlocked(fe, tuner);
if (nv != ov) {
if (nv) {
lnb_set_voltage(dev, port->lnr, 0,
SEC_VOLTAGE_13);
if (fmode == 1) {
lnb_set_voltage(dev, port->lnr, 0,
SEC_VOLTAGE_13);
if (old_quattro) {
lnb_set_voltage(dev,
port->lnr, 1,
SEC_VOLTAGE_18);
lnb_set_voltage(dev, port->lnr,
2,
SEC_VOLTAGE_13);
} else {
lnb_set_voltage(dev, port->lnr,
1,
SEC_VOLTAGE_13);
lnb_set_voltage(dev, port->lnr,
2,
SEC_VOLTAGE_18);
}
lnb_set_voltage(dev, port->lnr, 3,
SEC_VOLTAGE_18);
}
} else {
lnb_set_voltage(dev, port->lnr,
0, SEC_VOLTAGE_OFF);
if (fmode == 1) {
lnb_set_voltage(dev, port->lnr, 1,
SEC_VOLTAGE_OFF);
lnb_set_voltage(dev, port->lnr, 2,
SEC_VOLTAGE_OFF);
lnb_set_voltage(dev, port->lnr, 3,
SEC_VOLTAGE_OFF);
}
}
}
break;
}
mutex_unlock(&dev->link[port->lnr].lnb.lock);
return res;
}
static int max_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
{
return 0;
}
static int max_send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst)
{
return 0;
}
static int mxl_fw_read(void *priv, u8 *buf, u32 len)
{
struct ddb_link *link = priv;
struct ddb *dev = link->dev;
dev_info(dev->dev,
"Read mxl_fw from link %u\n", link->nr);
return ddbridge_flashread(dev, link->nr, buf, 0xc0000, len);
}
int ddb_lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm)
{
u32 l = link->nr;
if (link->lnb.fmode == fm)
return 0;
dev_info(dev->dev, "Set fmode link %u = %u\n", l, fm);
mutex_lock(&link->lnb.lock);
if (fm == 2 || fm == 1) {
if (fmode_sat >= 0) {
lnb_set_sat(dev, l, 0, fmode_sat, 0, 0);
if (old_quattro) {
lnb_set_sat(dev, l, 1, fmode_sat, 0, 1);
lnb_set_sat(dev, l, 2, fmode_sat, 1, 0);
} else {
lnb_set_sat(dev, l, 1, fmode_sat, 1, 0);
lnb_set_sat(dev, l, 2, fmode_sat, 0, 1);
}
lnb_set_sat(dev, l, 3, fmode_sat, 1, 1);
}
lnb_set_tone(dev, l, 0, SEC_TONE_OFF);
if (old_quattro) {
lnb_set_tone(dev, l, 1, SEC_TONE_OFF);
lnb_set_tone(dev, l, 2, SEC_TONE_ON);
} else {
lnb_set_tone(dev, l, 1, SEC_TONE_ON);
lnb_set_tone(dev, l, 2, SEC_TONE_OFF);
}
lnb_set_tone(dev, l, 3, SEC_TONE_ON);
}
link->lnb.fmode = fm;
mutex_unlock(&link->lnb.lock);
return 0;
}
/* MAXS8 related functions */
static struct mxl5xx_cfg mxl5xx = {
.adr = 0x60,
.type = 0x01,
.clk = 27000000,
.ts_clk = 139,
.cap = 12,
.fw_read = mxl_fw_read,
};
int ddb_fe_attach_mxl5xx(struct ddb_input *input)
{
struct ddb *dev = input->port->dev;
struct i2c_adapter *i2c = &input->port->i2c->adap;
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
struct ddb_port *port = input->port;
struct ddb_link *link = &dev->link[port->lnr];
struct mxl5xx_cfg cfg;
int demod, tuner;
cfg = mxl5xx;
cfg.fw_priv = link;
if (dev->link[0].info->type == DDB_OCTONET)
;/*cfg.ts_clk = 69;*/
demod = input->nr;
tuner = demod & 3;
if (fmode >= 3)
tuner = 0;
dvb->fe = dvb_attach(mxl5xx_attach, i2c, &cfg, demod, tuner);
if (!dvb->fe) {
dev_err(dev->dev, "No MXL5XX found!\n");
return -ENODEV;
}
if (input->nr < 4) {
lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT);
lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF);
}
ddb_lnb_init_fmode(dev, link, fmode);
dvb->fe->ops.set_voltage = max_set_voltage;
dvb->fe->ops.enable_high_lnb_voltage = max_enable_high_lnb_voltage;
dvb->fe->ops.set_tone = max_set_tone;
dvb->diseqc_send_master_cmd = dvb->fe->ops.diseqc_send_master_cmd;
dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd;
dvb->fe->ops.diseqc_send_burst = max_send_burst;
dvb->fe->sec_priv = input;
dvb->set_input = dvb->fe->ops.set_input;
dvb->fe->ops.set_input = max_set_input;
dvb->input = tuner;
return 0;
}
/* MAX MCI related functions */
extern struct mci_cfg ddb_max_sx8_cfg;
extern struct mci_cfg ddb_max_m4_cfg;
int ddb_fe_attach_mci(struct ddb_input *input, u32 type)
{
struct ddb *dev = input->port->dev;
//struct i2c_adapter *i2c = &input->port->i2c->adap;
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
struct ddb_port *port = input->port;
struct ddb_link *link = &dev->link[port->lnr];
int demod, tuner;
struct mci_cfg cfg;
int fm = fmode;
demod = input->nr;
tuner = demod & 3;
switch (type) {
case DDB_TUNER_MCI_SX8:
cfg = ddb_max_sx8_cfg;
if (fm >= 3)
tuner = 0;
break;
case DDB_TUNER_MCI_M4:
fm = 0;
cfg = ddb_max_m4_cfg;
break;
default:
return -EINVAL;
}
dvb->fe = ddb_mci_attach(input, &cfg, demod, tuner);
if (!dvb->fe) {
dev_err(dev->dev, "No MCI card found!\n");
return -ENODEV;
}
if (input->nr < 4) {
lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT);
lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF);
}
ddb_lnb_init_fmode(dev, link, fm);
dvb->fe->ops.set_voltage = max_set_voltage;
dvb->fe->ops.enable_high_lnb_voltage = max_enable_high_lnb_voltage;
dvb->fe->ops.set_tone = max_set_tone;
dvb->diseqc_send_master_cmd = dvb->fe->ops.diseqc_send_master_cmd;
dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd;
dvb->fe->ops.diseqc_send_burst = max_send_burst;
dvb->fe->sec_priv = input;
dvb->set_input = dvb->fe->ops.set_input;
dvb->fe->ops.set_input = max_set_input;
dvb->input = tuner;
return 0;
}

377
ddbridge/ddbridge-mci.c Normal file
View File

@@ -0,0 +1,377 @@
/*
* ddbridge-mci.c: Digital Devices microcode interface
*
* Copyright (C) 2017-2018 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
#include "ddbridge-io.h"
#include "ddbridge-mci.h"
static LIST_HEAD(mci_list);
static int mci_reset(struct mci *state)
{
struct ddb_link *link = state->base->link;
u32 status = 0;
u32 timeout = 40;
ddblwritel(link, MCI_CONTROL_RESET, MCI_CONTROL);
ddblwritel(link, 0, MCI_CONTROL + 4); /* 1= no internal init */
msleep(300);
ddblwritel(link, 0, MCI_CONTROL);
while(1) {
status = ddblreadl(link, MCI_CONTROL);
if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY)
break;
if (--timeout == 0)
break;
msleep(50);
}
if ((status & MCI_CONTROL_READY) == 0 )
return -1;
if (link->ids.device == 0x0009)
ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG);
return 0;
}
int ddb_mci_config(struct mci *state, u32 config)
{
struct ddb_link *link = state->base->link;
if (link->ids.device != 0x0009)
return -EINVAL;
ddblwritel(link, config, SX8_TSCONFIG);
return 0;
}
static int ddb_mci_cmd_raw_unlocked(struct mci *state,
u32 *cmd, u32 cmd_len,
u32 *res, u32 res_len)
{
struct ddb_link *link = state->base->link;
u32 i, val;
unsigned long stat;
val = ddblreadl(link, MCI_CONTROL);
if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND))
return -EIO;
if (cmd && cmd_len)
for (i = 0; i < cmd_len; i++)
ddblwritel(link, cmd[i], MCI_COMMAND + i * 4);
val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT);
ddblwritel(link, val, MCI_CONTROL);
stat = wait_for_completion_timeout(&state->base->completion, HZ);
if (stat == 0) {
printk("MCI timeout\n");
return -EIO;
}
if (res && res_len)
for (i = 0; i < res_len; i++)
res[i] = ddblreadl(link, MCI_RESULT + i * 4);
return 0;
}
int ddb_mci_cmd_unlocked(struct mci *state,
struct mci_command *command,
struct mci_result *result)
{
u32 *cmd = (u32 *) command;
u32 *res = (u32 *) result;
return ddb_mci_cmd_raw_unlocked(state, cmd, sizeof(*command)/sizeof(u32),
res, sizeof(*result)/sizeof(u32));
}
int ddb_mci_cmd(struct mci *state,
struct mci_command *command,
struct mci_result *result)
{
int stat;
mutex_lock(&state->base->mci_lock);
stat = ddb_mci_cmd_raw_unlocked(state,
(u32 *)command, sizeof(*command)/sizeof(u32),
(u32 *)result, sizeof(*result)/sizeof(u32));
mutex_unlock(&state->base->mci_lock);
return stat;
}
int ddb_mci_cmd_raw(struct mci *state,
struct mci_command *command, u32 command_len,
struct mci_result *result, u32 result_len)
{
int stat;
mutex_lock(&state->base->mci_lock);
stat = ddb_mci_cmd_raw_unlocked(state,
(u32 *)command, command_len,
(u32 *)result, result_len);
mutex_unlock(&state->base->mci_lock);
return stat;
}
static int ddb_mci_get_iq(struct mci *mci, u32 demod, s16 *i, s16 *q)
{
int stat;
struct mci_command cmd;
struct mci_result res;
memset(&cmd, 0, sizeof(cmd));
memset(&res, 0, sizeof(res));
cmd.command = MCI_CMD_GET_IQSYMBOL;
cmd.demod = demod;
stat = ddb_mci_cmd(mci, &cmd, &res);
if (!stat) {
*i = res.iq_symbol.i;
*q = res.iq_symbol.q;
}
return stat;
}
int ddb_mci_get_status(struct mci *mci, struct mci_result *res)
{
struct mci_command cmd;
cmd.command = MCI_CMD_GETSTATUS;
cmd.demod = mci->demod;
return ddb_mci_cmd_raw(mci, &cmd, 1, res, 1);
}
int ddb_mci_get_snr(struct dvb_frontend *fe)
{
struct mci *mci = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
p->cnr.len = 1;
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
p->cnr.stat[0].svalue = (s64) mci->
signal_info.dvbs2_signal_info.signal_to_noise * 10;
return 0;
}
int ddb_mci_get_strength(struct dvb_frontend *fe)
{
struct mci *mci = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
s32 str;
str = mci->signal_info.dvbs2_signal_info.channel_power * 10;
p->strength.len = 1;
p->strength.stat[0].scale = FE_SCALE_DECIBEL;
p->strength.stat[0].svalue = str;
return 0;
}
int ddb_mci_get_info(struct mci *mci)
{
int stat;
struct mci_command cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_GETSIGNALINFO;
cmd.demod = mci->demod;
stat = ddb_mci_cmd(mci, &cmd, &mci->signal_info);
return stat;
}
/****************************************************************************/
/****************************************************************************/
void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p)
{
const enum fe_modulation modcod2mod[0x20] = {
QPSK, QPSK, QPSK, QPSK,
QPSK, QPSK, QPSK, QPSK,
QPSK, QPSK, QPSK, QPSK,
PSK_8, PSK_8, PSK_8, PSK_8,
PSK_8, PSK_8, APSK_16, APSK_16,
APSK_16, APSK_16, APSK_16, APSK_16,
APSK_32, APSK_32, APSK_32, APSK_32,
APSK_32,
};
const enum fe_code_rate modcod2fec[0x20] = {
FEC_NONE, FEC_1_4, FEC_1_3, FEC_2_5,
FEC_1_2, FEC_3_5, FEC_2_3, FEC_3_4,
FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10,
FEC_3_5, FEC_2_3, FEC_3_4, FEC_5_6,
FEC_8_9, FEC_9_10, FEC_2_3, FEC_3_4,
FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10,
FEC_3_4, FEC_4_5, FEC_5_6, FEC_8_9,
FEC_9_10, FEC_NONE, FEC_NONE, FEC_NONE,
};
const enum fe_code_rate dvbs_fec_lut[8] = {
FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6,
FEC_NONE, FEC_7_8, FEC_NONE, FEC_NONE,
};
const enum fe_rolloff ro_lut[8] = {
ROLLOFF_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_10,
ROLLOFF_5, ROLLOFF_15, ROLLOFF_35, ROLLOFF_35
};
p->frequency =
mci->signal_info.dvbs2_signal_info.frequency;
switch (p->delivery_system) {
default:
case SYS_DVBS:
case SYS_DVBS2:
{
u32 pls_code =
mci->signal_info.dvbs2_signal_info.pls_code;
p->frequency =
mci->signal_info.dvbs2_signal_info.frequency / 1000;
p->delivery_system =
(mci->signal_info.dvbs2_signal_info.standard == 2) ?
SYS_DVBS2 : SYS_DVBS;
if (mci->signal_info.dvbs2_signal_info.standard == 2) {
u32 modcod = (0x7c & pls_code) >> 2;
p->delivery_system = SYS_DVBS2;
p->rolloff =
ro_lut[mci->signal_info.
dvbs2_signal_info.roll_off & 7];
p->pilot = (pls_code & 1) ? PILOT_ON : PILOT_OFF;
p->fec_inner = modcod2fec[modcod];
p->modulation = modcod2mod[modcod];
p->transmission_mode = pls_code;
} else {
p->delivery_system = SYS_DVBS;
p->rolloff = ROLLOFF_35;
p->pilot = PILOT_OFF;
p->fec_inner = dvbs_fec_lut[pls_code & 7];
p->modulation = QPSK;
}
break;
}
case SYS_DVBC_ANNEX_A:
break;
case SYS_DVBT:
break;
case SYS_DVBT2:
break;
case SYS_DVBC2:
break;
case SYS_ISDBT:
break;
}
p->pre_bit_error.len = 1;
p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
p->pre_bit_error.stat[0].uvalue =
mci->signal_info.dvbs2_signal_info.ber_numerator;
p->pre_bit_count.len = 1;
p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
p->pre_bit_count.stat[0].uvalue =
mci->signal_info.dvbs2_signal_info.ber_denominator;
p->block_error.len = 1;
p->block_error.stat[0].scale = FE_SCALE_COUNTER;
p->block_error.stat[0].uvalue =
mci->signal_info.dvbs2_signal_info.packet_errors;
p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
p->cnr.len = 1;
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
p->cnr.stat[0].svalue = (s64) mci->
signal_info.dvbs2_signal_info.signal_to_noise * 10;
p->strength.len = 1;
p->strength.stat[0].scale = FE_SCALE_DECIBEL;
p->strength.stat[0].svalue =
mci->signal_info.dvbs2_signal_info.channel_power * 10;
}
static void mci_handler(void *priv)
{
struct mci_base *base = (struct mci_base *)priv;
complete(&base->completion);
}
static struct mci_base *match_base(void *key)
{
struct mci_base *p;
list_for_each_entry(p, &mci_list, mci_list)
if (p->key == key)
return p;
return NULL;
}
static int probe(struct mci *state)
{
mci_reset(state);
return 0;
}
struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, struct mci_cfg *cfg, int nr, int tuner)
{
struct ddb_port *port = input->port;
struct ddb *dev = port->dev;
struct ddb_link *link = &dev->link[port->lnr];
struct mci_base *base;
struct mci *state;
void *key = cfg->type ? (void *) port : (void *) link;
state = kzalloc(cfg->state_size, GFP_KERNEL);
if (!state)
return NULL;
base = match_base(key);
if (base) {
base->count++;
state->base = base;
} else {
base = kzalloc(cfg->base_size, GFP_KERNEL);
if (!base)
goto fail;
base->key = key;
base->count = 1;
base->link = link;
mutex_init(&base->mci_lock);
mutex_init(&base->tuner_lock);
ddb_irq_set(dev, link->nr, 0, mci_handler, base);
init_completion(&base->completion);
state->base = base;
if (probe(state) < 0) {
kfree(base);
goto fail;
}
list_add(&base->mci_list, &mci_list);
if (cfg->base_init)
cfg->base_init(base);
}
memcpy(&state->fe.ops, cfg->fe_ops, sizeof(struct dvb_frontend_ops));
state->fe.demodulator_priv = state;
state->nr = nr;
state->demod = nr;
state->tuner = tuner;
if (cfg->init)
cfg->init(state);
return &state->fe;
fail:
kfree(state);
return NULL;
}

547
ddbridge/ddbridge-mci.h Normal file
View File

@@ -0,0 +1,547 @@
/*
* ddbridge-mci.h: Digital Devices micro code interface
*
* Copyright (C) 2017-2018 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef _DDBRIDGE_MCI_H_
#define _DDBRIDGE_MCI_H_
#define SX8_TSINPUT (0x280)
#define MIC_CONTROL (0x500)
#define MIC_PROGMEM_OLD (0x4000)
#define MIC_PROGMEM_OLD_SIZE (0x4000)
#define MIC_PROGMEM (0x8000)
#define MIC_PROGMEM_SIZE (0x8000)
#define MIC_DATAMEM (0x8000)
#define MIC_DATAMEM_SIZE (0x2000)
#define MIC_INTERFACE_IN (0x0600)
#define MIC_INTERFACE_OUT (0x0680)
#define MIC_INTERFACE_VER (0x06F0)
#define MCI_CONTROL (0x500)
#define MCI_COMMAND (0x600)
#define MCI_RESULT (0x680)
#define MCI_COMMAND_SIZE (0x80)
#define MCI_RESULT_SIZE (0x80)
#define MCI_CONTROL_START_COMMAND (0x00000001)
#define MCI_CONTROL_ENABLE_DONE_INTERRUPT (0x00000002)
#define MCI_CONTROL_RESET (0x00008000)
#define MCI_CONTROL_READY (0x00010000)
#define SX8_TSCONFIG (0x280)
#define SX8_TSCONFIG_MODE_MASK (0x00000003)
#define SX8_TSCONFIG_MODE_OFF (0x00000000)
#define SX8_TSCONFIG_MODE_NORMAL (0x00000001)
#define SX8_TSCONFIG_MODE_IQ (0x00000003)
/*
* IQMode only vailable on MaxSX8 on a single tuner
*
* IQ_MODE_SAMPLES
* sampling rate is 1550/24 MHz (64.583 MHz)
* channel agc is frozen, to allow stitching the FFT results together
*
* IQ_MODE_VTM
* sampling rate is the supplied symbolrate
* channel agc is active
*
* in both cases down sampling is done with a RRC Filter (currently fixed to alpha = 0.05)
* which causes some (ca 5%) aliasing at the edges from outside the spectrum
*/
#define SX8_TSCONFIG_TSHEADER (0x00000004)
#define SX8_TSCONFIG_BURST (0x00000008)
#define SX8_TSCONFIG_BURSTSIZE_MASK (0x00000030)
#define SX8_TSCONFIG_BURSTSIZE_2K (0x00000000)
#define SX8_TSCONFIG_BURSTSIZE_4K (0x00000010)
#define SX8_TSCONFIG_BURSTSIZE_8K (0x00000020)
#define SX8_TSCONFIG_BURSTSIZE_16K (0x00000030)
/* additional TS input control bits on MaxSX8 DD01:0009 */
#define TS_INPUT_CONTROL_SIZEMASK (0x00000030)
#define TS_INPUT_CONTROL_SIZE188 (0x00000000)
#define TS_INPUT_CONTROL_SIZE192 (0x00000010)
#define TS_INPUT_CONTROL_SIZE196 (0x00000020)
/********************************************************/
#define SX8_DEMOD_STOPPED (0)
#define SX8_DEMOD_IQ_MODE (1)
#define SX8_DEMOD_WAIT_SIGNAL (2)
#define SX8_DEMOD_WAIT_MATYPE (3)
#define SX8_DEMOD_TIMEOUT (14)
#define SX8_DEMOD_LOCKED (15)
#define M4_DEMOD_STOPPED (0)
#define M4_DEMOD_WAIT_SIGNAL (1)
#define M4_DEMOD_TIMEOUT (14)
#define M4_DEMOD_LOCKED (15)
#define MCI_CMD_STOP (0x01)
#define MCI_CMD_GETSTATUS (0x02)
#define MCI_CMD_GETSIGNALINFO (0x03)
#define MCI_CMD_RFPOWER (0x04)
#define MCI_CMD_SEARCH_DVBS (0x10)
#define MCI_CMD_SEARCH_DVBC (0x20)
#define MCI_CMD_SEARCH_DVBT (0x21)
#define MCI_CMD_SEARCH_DVBT2 (0x22)
#define MCI_CMD_SEARCH_DVBC2 (0x23)
#define MCI_CMD_SEARCH_ISDBT (0x24)
#define MCI_CMD_GET_IQSYMBOL (0x30)
#define MCI_BANDWIDTH_UNKNOWN (0)
#define MCI_BANDWIDTH_1_7MHZ (1)
#define MCI_BANDWIDTH_5MHZ (5)
#define MCI_BANDWIDTH_6MHZ (6)
#define MCI_BANDWIDTH_7MHZ (7)
#define MCI_BANDWIDTH_8MHZ (8)
#define M4_MODE_DVBSX (2)
#define M4_MODE_DVBC (3)
#define M4_MODE_DVBT (4)
#define M4_MODE_DVBT2 (5)
#define M4_MODE_DVBC2 (6)
#define M4_MODE_ISDBT (7)
#define SX8_CMD_INPUT_ENABLE (0x40)
#define SX8_CMD_INPUT_DISABLE (0x41)
#define SX8_CMD_START_IQ (0x42)
#define SX8_CMD_STOP_IQ (0x43)
#define SX8_CMD_ENABLE_IQOUTPUT (0x44)
#define SX8_CMD_DISABLE_IQOUTPUT (0x45)
#define M4_CMD_GET_T2_L1INFO (0x50)
#define M4_CMD_GET_C2_L1P2 (0x50)
#define M4_CMD_GET_IDS (0x51)
#define MCI_STATUS_OK (0x00)
#define MCI_STATUS_UNSUPPORTED (0x80)
#define MCI_STATUS_RETRY (0xFD)
#define MCI_STATUS_NOT_READY (0xFE)
#define MCI_STATUS_ERROR (0xFF)
#define MCI_SUCCESS(status) ((status & MCI_STATUS_UNSUPPORTED) == 0)
/********************************************************/
struct mci_command {
union {
u32 command_word;
struct {
u8 command;
u8 tuner;
u8 demod;
u8 output;
};
};
union {
u32 params[31];
struct {
u8 flags; /* Bit 0: DVB-S Enabled, 1: DVB-S2 Enabled, 7: InputStreamID*/
/* Bit 0 : QPSK, 1: 8PSK/8APSK, 2 : 16APSK, 3: 32APSK, 4: 64APSK, 5: 128APSK, 6: 256APSK */
u8 s2_modulation_mask;
u8 rsvd1;
u8 retry;
u32 frequency;
u32 symbol_rate;
u8 input_stream_id;
u8 rsvd2[3];
u32 scrambling_sequence_index;
u32 frequency_range;
} dvbs2_search;
struct {
u8 flags;
u8 bandwidth;
u8 rsvd1;
u8 retry;
u32 frequency;
} dvbc_search;
struct {
u8 flags; /* Bit 0: LP Stream */
u8 bandwidth;
u8 rsvd1;
u8 retry;
u32 frequency;
} dvbt_search;
struct {
u8 flags; /* Bit 0: T2 Lite Profile, 7: PLP, */
u8 bandwidth;
u8 rsvd1;
u8 retry;
u32 frequency;
u32 reserved;
u8 plp;
u8 rsvd2[3];
} dvbt2_search;
struct {
u8 flags;
u8 bandwidth;
u8 rsvd1;
u8 retry;
u32 frequency;
u32 reserved;
u8 plp;
u8 data_slice;
u8 rsvd2[2];
} dvbc2_search;
struct {
u8 flags;
u8 bandwidth;
u8 rsvd1;
u8 retry;
u32 frequency;
} isdbt_search;
struct {
u8 tap;
u8 rsvd;
u16 point;
} get_iq_symbol;
struct {
u8 flags; /* Bit 0 : 0 = VTM, 1 = SCAN. Bit 1: Set Gain */
u8 roll_off;
u8 rsvd1;
u8 rsvd2;
u32 frequency;
u32 symbol_rate; /* Only in VTM mode. */
u16 gain;
} sx8_start_iq;
struct {
/* Bit 1:0 = STVVGLNA Gain. 0 = AGC, 1 = 0dB,
2 = Minimum, 3 = Maximum */
u8 flags;
} sx8_input_enable;
struct {
u8 Offset; // Offset into list, must be multiple of 64
u8 Select; // 0 = Slices, 1 = PLPs (C2 Only)
u8 DataSlice; // DataSlice to get PLPList (C2 Only)
} get_ids;
struct {
u8 select; // 0 = Base, 1 = DataSilce, 2 = PLP, Bit 7: Set new ID
u8 id; // DataSliceID, PLPId
} get_l1_info;
};
};
struct mci_result {
union {
u32 status_word;
struct {
u8 status;
u8 mode;
u16 time;
};
};
union {
u32 result[27];
struct {
u8 standard; /* 1 = DVB-S, 2 = DVB-S2X */
u8 pls_code; /* puncture rate for DVB-S */
u8 roll_off; /* 2-0: rolloff */
u8 rsvd;
u32 frequency; /* actual frequency in Hz */
u32 symbol_rate; /* actual symbolrate in Hz */
s16 channel_power; /* channel power in dBm x 100 */
s16 band_power; /*/ band power in dBm x 100 */
s16 signal_to_noise; /* SNR in dB x 100, Note: negativ values are valid in DVB-S2 */
s16 rsvd2;
u32 packet_errors; /* Counter for packet errors. (set to 0 on Start command) */
u32 ber_numerator; /* Bit error rate: PreRS in DVB-S, PreBCH in DVB-S2X */
u32 ber_denominator;
} dvbs2_signal_info;
struct {
u8 modulation;
u8 rsvd1[3];
u32 frequency; /* actual frequency in Hz */
u32 symbol_rate; /* actual symbolrate in Hz */
s16 channel_power; /* channel power in dBm x 100 */
s16 band_power; /* band power in dBm x 100 */
s16 signal_to_noise; /* SNR in dB x 100, Note: negativ values are valid in DVB-S2 */
s16 rsvd2;
u32 packet_errors; /* Counter for packet errors. (set to 0 on Start command) */
u32 ber_numerator; /* Bit error rate: PreRS */
u32 ber_denominator;
} dvbc_signal_info;
struct {
u8 tps_25_32; /* Constellation (2), Hierarchy (3), Coderate HP (3) */
u8 tps_33_39; /* Coderate LP (3), Guardinterval (2), FFT (2), 0 (1) */
u16 tps_cell_id; /* Cell Identifier */
u32 frequency; /* actual frequency in Hz */
u32 rsvd1;
s16 channel_power; /* channel power in dBm x 100 */
s16 band_power; /* band power in dBm x 100 */
s16 signal_to_noise; /* SNR in dB x 100, Note: negativ values are valid in DVB-S2 */
s16 rsvd2;
u32 packet_errors; /* Counter for packet errors. (set to 0 on Start command) */
u32 ber_numerator; /* Bit error rate: PreRS */
u32 ber_denominator;
} dvbt_signal_info;
struct {
u32 rsvd0;
u32 frequency; /* actual frequency in Hz */
u32 rsvd1;
s16 channel_power; /* channel power in dBm x 100 */
s16 band_power; /* band power in dBm x 100 */
s16 signal_to_noise; /* SNR in dB x 100, Note: negativ values are valid in DVB-S2 */
s16 rsvd2;
u32 packet_errors; /* Counter for packet errors. (set to 0 on Start command) */
u32 ber_numerator; /* Bit error rate: PreRS */
u32 ber_denominator;
} dvbt2_signal_info;
struct { // Work in Progress
u32 rsvd0 ; // Cell Identifier
u32 frequency; // actual frequency in Hz
u32 rsvd1; //
s16 channel_power; // channel power in dBm x 100
s16 band_power; // band power in dBm x 100
s16 signal_to_noise; // SNR in dB x 100, Note: negativ values are valid in DVB-S2
s16 rsvd2;
u32 packet_errors; // Counter for packet errors. (set to 0 on Start command)
u32 ber_numerator; // Bit error rate: PreBCH
u32 ber_denominator;
} dvbc2_signal_info;
struct {
u32 rsvd0;
u32 frequency; // actual frequency in Hz
u32 rsvd1; //
s16 channel_power; // channel power in dBm x 100
s16 band_power; // band power in dBm x 100
s16 signal_to_noise; // SNR in dB x 100, Note: negativ values are valid in DVB-S2
s16 rsvd2;
u32 packet_errors; // Counter for packet errors. (set to 0 on Start command)
u32 ber_numerator; // Bit error rate: PreRS
u32 ber_denominator;
u8 tmcc_info[13]; // TMCC B20 - B121
} isdbt_signal_info;
struct {
s16 i;
s16 q;
} iq_symbol;
struct {
u8 t2_l1_pre[37];
u8 t2_l1_post[15];
u8 t2_l1_post_d[19];
u8 t2_l1_post_c[19];
} dvbt2_l1_info;
struct {
u8 NetworkID[2];
u8 C2SystemID[2];
u8 StartFrequency[3];
u8 C2BandWidth[2];
u8 GuardInterval;
u8 C2FrameLength[2];
u8 L1P2ChangeCounter;
u8 NumDataSlices;
u8 NumNotches;
struct {
u8 Start[2];
u8 Width[2];
u8 Reserved3;
} NotchData[15];
u8 ReservedTone;
u8 Reserved4[2]; // EWS 1 bit, C2_Version 4 bit, Rsvd 11 bit
} DVBC2_L1Part2;
struct {
u8 NumIDs;
u8 Offset;
u8 IDs[64];
} DVBC2_IDList;
struct {
u8 SliceID;
u8 TunePosition[2];
u8 OffsetLeft[2];
u8 OffsetRight[2];
u8 TIDepth;
u8 Type;
u8 FECHeaderType;
u8 ConstConf;
u8 LeftNotch;
u8 NumPLP;
u8 Reserved2;
} DVBC2_SliceInfo;
struct {
u8 PLPID;
u8 Bundled;
u8 Type;
u8 PayloadType;
u8 GroupID;
u8 Start[2];
u8 FEC_Type;
u8 Mod;
u8 Cod;
u8 PSISIReprocessing;
u8 TransportstreamID[2];
u8 OrginalNetworkID[2];
u8 Reserved1;
} DVBC2_PLPInfo;
};
u32 version[4];
};
/* Helper Macros */
/* DVB-T2 L1-Pre Signalling Data ( ETSI EN 302 755 V1.4.1 Chapter 7.2.2 ) */
#define L1PRE_TYPE(p) ((p)[0] & 0xFF)
#define L1PRE_BWT_EXT(p) ((p)[1] & 0x01)
#define L1PRE_S1(p) ((p)[2] & 0x07)
#define L1PRE_S2(p) ((p)[3] & 0x0F)
#define L1PRE_L1_REPETITION_FLAG(p) ((p)[4] & 0x01)
#define L1PRE_GUARD_INTERVAL(p) ((p)[5] & 0x07)
#define L1PRE_PAPR(p) ((p)[6] & 0x0F)
#define L1PRE_L1_MOD(p) ((p)[7] & 0x0F)
#define L1PRE_L1_COD(p) ((p)[8] & 0x03)
#define L1PRE_L1_FEC_TYPE(p) ((p)[9] & 0x03)
#define L1PRE_L1_POST_SIZE(p) (((u32)((p)[10] & 0x03) << 16) | ((u32)(p)[11] << 8) | (p)[12])
#define L1PRE_L1_POST_INFO_SIZE(p) (((u32)((p)[13] & 0x03) << 16) | ((u32)(p)[14] << 8) | (p)[15])
#define L1PRE_PILOT_PATTERN(p) ((p)[16] & 0x0F)
#define L1PRE_TX_ID_AVAILABILITY(p) ((p)[17] & 0xFF)
#define L1PRE_CELL_ID(p) (((u16)(p)[18] << 8) | (p)[19])
#define L1PRE_NETWORK_ID(p) (((u16)(p)[20] << 8) | (p)[21])
#define L1PRE_T2_SYSTEM_ID(p) (((u16)(p)[22] << 8) | (p)[23])
#define L1PRE_NUM_T2_FRAMES(p) ((p)[24] & 0xFF)
#define L1PRE_NUM_DATA_SYMBOLS(p) (((u16)((p)[25] & 0x0F) << 8) | (p)[26])
#define L1PRE_REGEN_FLAG(p) ((p)[27] & 0x07)
#define L1PRE_L1_POST_EXTENSION(p) ((p)[28] & 0x01)
#define L1PRE_NUM_RF(p) ((p)[29] & 0x07)
#define L1PRE_CURRENT_RF_IDX(p) ((p)[30] & 0x07)
#define L1PRE_T2_VERSION(p) ((((p)[31] & 0x03) << 2) | (((p)[32] & 0xC0) >> 6))
#define L1PRE_L1_POST_SCRAMBLED(p) (((p)[32] & 0x20) >> 5)
#define L1PRE_T2_BASE_LITE(p) (((p)[32] & 0x10) >> 4)
/* DVB-T2 L1-Post Signalling Data ( ETSI EN 302 755 V1.4.1 Chapter 7.2.3 ) */
#define L1POST_SUB_SLICES_PER_FRAME(p) (((u16)(p)[ 0] & 0x7F) | (p)[ 1])
#define L1POST_NUM_PLP(p) ((p)[2] & 0xFF)
#define L1POST_NUM_AUX(p) ((p)[3] & 0x0F)
#define L1POST_AUX_CONFIG_RFU(p) ((p)[4] & 0xFF)
#define L1POST_RF_IDX(p) ((p)[5] & 0x07)
#define L1POST_FREQUENCY(p) (((u32)(p)[6] << 24) | ((u32)(p)[7] << 16) | ((u32)(p)[8] << 8) | (p)[9])
#define L1POST_FEF_TYPE(p) ((p)[10] & 0x0F)
#define L1POST_FEF_LENGTH(p) (((u32)(p)[11] << 16) | ((u32)(p)[12] << 8) | (p)[13])
#define L1POST_FEF_INTERVAL(p) ((p)[14] & 0xFF)
/* Repeated for each PLP, */
/* Hardware is restricted to retrieve only values for current data PLP and common PLP */
#define L1POST_PLP_ID(p) ((p)[0] & 0xFF)
#define L1POST_PLP_TYPE(p) ((p)[1] & 0x07)
#define L1POST_PLP_PAYLOAD_TYPE(p) ((p)[2] & 0x1F)
#define L1POST_FF_FLAG(p) ((p)[3] & 0x01)
#define L1POST_FIRST_RF_IDX(p) ((p)[4] & 0x07)
#define L1POST_FIRST_FRAME_IDX(p) ((p)[5] & 0xFF)
#define L1POST_PLP_GROUP_ID(p) ((p)[6] & 0xFF)
#define L1POST_PLP_COD(p) ((p)[7] & 0x07)
#define L1POST_PLP_MOD(p) ((p)[8] & 0x07)
#define L1POST_PLP_ROTATION(p) ((p)[9] & 0x01)
#define L1POST_PLP_FEC_TYPE(p) ((p)[10] & 0x03)
#define L1POST_PLP_NUM_BLOCKS_MAX(p) (((u16)((p)[11] & 0x03) << 8) | (p)[12])
#define L1POST_FRAME_INTERVAL(p) ((p)[13] & 0xFF)
#define L1POST_TIME_IL_LENGTH(p) ((p)[14] & 0xFF)
#define L1POST_TIME_IL_TYPE(p) ((p)[15] & 0x01)
#define L1POST_IN_BAND_A_FLAG(p) ((p)[16] & 0x01)
#define L1POST_IN_BAND_B_FLAG(p) (((p)[17] >> 7) & 0x01)
#define L1POST_RESERVED_1(p) (((u16)((p)[17] & 0x7F) << 4) | ((p)[18] & 0xF0) >> 4)
#define L1POST_PLP_MODE(p) (((p)[18] >> 2) & 0x03)
#define L1POST_STATIC_FLAG(p) (((p)[18] >> 1) & 0x01)
#define L1POST_STATIC_PADDING_FLAG(p) (((p)[18] >> 1) & 0x01)
struct mci_base {
struct list_head mci_list;
void *key;
struct ddb_link *link;
struct completion completion;
struct i2c_adapter *i2c;
struct mutex i2c_lock;
struct mutex tuner_lock;
struct mutex mci_lock;
int count;
int type;
};
struct mci {
struct mci_base *base;
struct dvb_frontend fe;
int nr;
int demod;
int tuner;
struct mci_result signal_info;
};
struct mci_cfg {
int type;
struct dvb_frontend_ops *fe_ops;
u32 base_size;
u32 state_size;
int (*init)(struct mci *mci);
int (*base_init)(struct mci_base *mci_base);
};
int ddb_mci_cmd(struct mci *state, struct mci_command *command, struct mci_result *result);
int ddb_mci_cmd_raw(struct mci *state, struct mci_command *command, u32 command_len,
struct mci_result *result, u32 result_len);
int ddb_mci_config(struct mci *state, u32 config);
int ddb_mci_get_status(struct mci *mci, struct mci_result *res);
int ddb_mci_get_snr(struct dvb_frontend *fe);
int ddb_mci_get_info(struct mci *mci);
int ddb_mci_get_strength(struct dvb_frontend *fe);
void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
* ddbridge-ns.c: Digital Devices PCIe bridge driver net streaming
*
* Copyright (C) 2010-2015 Marcus Metzler <mocm@metzlerbros.de>
* Copyright (C) 2010-2017Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
* Digital Devices GmbH
*
@@ -17,14 +17,12 @@
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
static int ddb_dvb_ns_input_start(struct ddb_input *input);
static int ddb_dvb_ns_input_stop(struct ddb_input *input);
#include "ddbridge.h"
#include "ddbridge-io.h"
static u16 calc_pcs(struct dvb_ns_params *p)
{
@@ -62,7 +60,7 @@ static u16 calc_pcs16(struct dvb_ns_params *p, int ipv)
static void ns_free(struct dvbnss *nss)
{
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
struct dvb_netstream *ns = nss->ns;
struct ddb_input *input = ns->priv;
struct ddb *dev = input->port->dev;
@@ -87,7 +85,6 @@ static int ns_alloc(struct dvbnss *nss)
dev->ns[i].fe = input;
nss->priv = &dev->ns[i];
ret = 0;
/*pr_info("DDBridge: %s i=%d fe=%d\n", __func__, i, input->nr); */
break;
}
ddbwritel(dev, 0x03, RTP_MASTER_CONTROL);
@@ -100,7 +97,7 @@ static int ns_set_pids(struct dvbnss *nss)
struct dvb_netstream *ns = nss->ns;
struct ddb_input *input = ns->priv;
struct ddb *dev = input->port->dev;
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
if (dev->link[0].ids.devid == 0x0301dd01) {
u32 sys = 0;
@@ -118,8 +115,9 @@ static int ns_set_pids(struct dvbnss *nss)
/* disable unused pids */
for (; j < 5; j++)
ddbwritel(dev, 0, PID_FILTER_PID(dns->nr, j));
} else
} else {
ddbcpyto(dev, STREAM_PIDS(dns->nr), nss->pids, 0x400);
}
return 0;
}
@@ -128,7 +126,7 @@ static int ns_set_pid(struct dvbnss *nss, u16 pid)
struct dvb_netstream *ns = nss->ns;
struct ddb_input *input = ns->priv;
struct ddb *dev = input->port->dev;
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
u16 byte = (pid & 0x1fff) >> 3;
u8 bit = 1 << (pid & 7);
u32 off = STREAM_PIDS(dns->nr);
@@ -154,12 +152,12 @@ static int ns_set_pid(struct dvbnss *nss, u16 pid)
else
ddbmemset(dev, off, 0x00, 0x400);
} else {
u8 val = ddbreadb(dev, off + byte);
u8 val = ddbreadb0(dev, off + byte);
if (pid & 0x8000)
ddbwriteb(dev, val | bit, off + byte);
ddbwriteb0(dev, val | bit, off + byte);
else
ddbwriteb(dev, val & ~bit, off + byte);
ddbwriteb0(dev, val & ~bit, off + byte);
}
}
#else
@@ -187,7 +185,7 @@ static int ns_set_ci(struct dvbnss *nss, u8 ci)
struct dvb_netstream *ns = nss->ns;
struct ddb_input *input = ns->priv;
struct ddb *dev = input->port->dev;
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
int ciport;
if (ci == 255) {
@@ -198,8 +196,8 @@ static int ns_set_ci(struct dvbnss *nss, u8 ci)
if (ciport < 0)
return -EINVAL;
pr_info("DDBridge: input %d.%d to ci %d at port %d\n",
input->port->lnr, input->nr, ci, ciport);
dev_info(dev->dev, "DDBridge: input %d.%d to ci %d at port %d\n",
input->port->lnr, input->nr, ci, ciport);
ddbwritel(dev, (input->port->lnr << 21) | (input->nr << 16) | 0x1c,
TS_CONTROL(dev->port[ciport].output));
usleep_range(1, 5);
@@ -247,7 +245,7 @@ static int ns_set_rtcp_msg(struct dvbnss *nss, u8 *msg, u32 len)
struct dvb_netstream *ns = nss->ns;
struct ddb_input *input = ns->priv;
struct ddb *dev = input->port->dev;
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
u32 off = STREAM_PACKET_ADR(dns->nr);
u32 coff = 96;
u16 wlen;
@@ -371,7 +369,7 @@ static u32 set_nsbuf(struct dvb_ns_params *p, u8 *buf,
static int ns_set_ts_packets(struct dvbnss *nss, u8 *buf, u32 len)
{
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
struct dvb_netstream *ns = nss->ns;
struct ddb_input *input = ns->priv;
struct ddb *dev = input->port->dev;
@@ -388,7 +386,7 @@ static int ns_set_ts_packets(struct dvbnss *nss, u8 *buf, u32 len)
static int ns_insert_ts_packets(struct dvbnss *nss, u8 count)
{
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
struct dvb_netstream *ns = nss->ns;
struct ddb_input *input = ns->priv;
struct ddb *dev = input->port->dev;
@@ -410,7 +408,7 @@ static int ns_set_net(struct dvbnss *nss)
struct ddb_input *input = ns->priv;
struct ddb *dev = input->port->dev;
struct dvb_ns_params *p = &nss->params;
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
u32 off = STREAM_PACKET_ADR(dns->nr);
u32 coff = 96;
@@ -429,7 +427,7 @@ static int ns_set_net(struct dvbnss *nss)
static int ns_start(struct dvbnss *nss)
{
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
struct dvb_netstream *ns = nss->ns;
struct ddb_input *input = ns->priv;
struct ddb *dev = input->port->dev;
@@ -446,8 +444,6 @@ static int ns_start(struct dvbnss *nss)
if (dns->fe != input)
ddb_dvb_ns_input_start(dns->fe);
ddb_dvb_ns_input_start(input);
/* printk("ns start ns %u, fe %u link %u\n",
dns->nr, dns->fe->nr, dns->fe->port->lnr); */
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
STREAM_CONTROL(dns->nr));
return 0;
@@ -455,7 +451,7 @@ static int ns_start(struct dvbnss *nss)
static int ns_stop(struct dvbnss *nss)
{
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
struct ddb_ns *dns = (struct ddb_ns *)nss->priv;
struct dvb_netstream *ns = nss->ns;
struct ddb_input *input = ns->priv;
struct ddb *dev = input->port->dev;
@@ -467,7 +463,7 @@ static int ns_stop(struct dvbnss *nss)
return 0;
}
static int netstream_init(struct ddb_input *input)
int netstream_init(struct ddb_input *input)
{
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
struct dvb_adapter *adap = dvb->adap;

View File

@@ -1,7 +1,7 @@
/*
* ddbridge-regs.h: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2016 Digital Devices GmbH
* Copyright (C) 2010-2017 Digital Devices GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -15,19 +15,22 @@
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
/* Register Definitions */
#define CUR_REGISTERMAP_VERSION_V1 0x00010001
#define CUR_REGISTERMAP_VERSION_V2 0x00020000
#define CUR_REGISTERMAP_VERSION 0x10004
#define CUR_REGISTERMAP_VERSION_0007 0x10002
#define CUR_REGISTERMAP_VERSION_0008 0x10002
#define CUR_REGISTERMAP_VERSION_CI 0x10000
#define CUR_REGISTERMAP_VERSION_CI_PRO 0x10000
#define HARDWARE_VERSION 0x00000000
#define REGISTERMAP_VERSION 0x00000004
#define HARDWARE_VERSION 0x0000
#define REGISTERMAP_VERSION 0x0004
#define DEVICE_ID 0x0008
#define BOARD_ID 0x000C
/* ------------------------------------------------------------------------- */
/* SPI Controller */
@@ -45,10 +48,10 @@
/* ------------------------------------------------------------------------- */
/* MDIO */
#define MDIO_CTRL 0x20
#define MDIO_ADR 0x24
#define MDIO_REG 0x28
#define MDIO_VAL 0x2C
#define MDIO_CTRL_OFF 0x00
#define MDIO_ADR_OFF 0x04
#define MDIO_REG_OFF 0x08
#define MDIO_VAL_OFF 0x0C
/* ------------------------------------------------------------------------- */
@@ -57,9 +60,9 @@
/* ------------------------------------------------------------------------- */
/* Interrupt controller
How many MSI's are available depends on HW (Min 2 max 8)
How many are usable also depends on Host platform
*/
* How many MSI's are available depends on HW (Min 2 max 8)
* How many are usable also depends on Host platform
*/
#define INTERRUPT_BASE (0x40)
@@ -105,7 +108,6 @@
#define INTMASK_TSOUTPUT3 (0x00040000)
#define INTMASK_TSOUTPUT4 (0x00080000)
#define INTERRUPT_V2_CONTROL (INTERRUPT_BASE + 0x00)
#define INTERRUPT_V2_ENABLE_1 (INTERRUPT_BASE + 0x04)
#define INTERRUPT_V2_ENABLE_2 (INTERRUPT_BASE + 0x08)
@@ -124,9 +126,6 @@
#define INTERRUPT_V2_STATUS_6 (INTERRUPT_BASE + 0x38)
#define INTERRUPT_V2_STATUS_7 (INTERRUPT_BASE + 0x3c)
/* Modulator registers */
/* Clock Generator ( Sil598 @ 0xAA I2c ) */
@@ -139,8 +138,8 @@
/* DAC ( AD9781/AD9783 SPI ) */
#define DAC_BASE (0x090)
#define DAC_CONTROL (DAC_BASE)
#define DAC_WRITE_DATA (DAC_BASE+4)
#define DAC_READ_DATA (DAC_BASE+8)
#define DAC_WRITE_DATA (DAC_BASE + 4)
#define DAC_READ_DATA (DAC_BASE + 8)
#define DAC_CONTROL_INSTRUCTION_REG (0xFF)
#define DAC_CONTROL_STARTIO (0x100)
@@ -153,32 +152,47 @@
#define TEMPMON_CONTROL_SCAN (0x00000001)
#define TEMPMON_CONTROL_AUTOSCAN (0x00000002)
#define TEMPMON_CONTROL_INTENABLE (0x00000004)
#define TEMPMON_CONTROL_CLEAR (0x00000008)
#define TEMPMON_CONTROL_OVERTEMP (0x00008000)
#define TEMPMON_STATUS_SHUTDOWN (0x00008000)
/* SHORT Temperature in <20>C x 256 */
/* Temperature in C x 256 */
#define TEMPMON_CORE (TEMPMON_BASE + 0x04)
#define TEMPMON_SENSOR0 (TEMPMON_BASE + 0x04)
#define TEMPMON_SENSOR1 (TEMPMON_BASE + 0x08)
#define TEMPMON_SENSOR2 (TEMPMON_BASE + 0x0C)
#define TEMPMON_FANCONTROL (TEMPMON_BASE + 0x10)
#define TEMPMON_FANPWM (0x00000F00) // PWM speed in 10% steps
#define TEMPMON_FANTACHO (0x000000FF) // Rotations in 100/min steps
#define TEMPMON_FANPWM (0x00000F00) /* PWM speed in 10% steps */
#define TEMPMON_FANTACHO (0x000000FF) /* Rotations in 100/min steps */
// V1 Temperature Monitor
// Temperature Monitor TEMPMON_CONTROL & 0x8000 == 0 : ( 2x LM75A @ 0x90,0x92 )
// Temperature Monitor TEMPMON_CONTROL & 0x8000 == 1 : ( 1x LM75A @ 0x90, 1x ADM1032 @ 0x9A )
#define TEMPMON_INTERRUPT_V1 (24)
#define TEMPMON_INTERRUPT_V1_MASK (1<<24)
#define TEMPMON1_CORE (TEMPMON_SENSOR0) // SHORT Temperature in <20>C x 256 (ADM1032 ext)
#define TEMPMON1_SENSOR1 (TEMPMON_BASE + 0x08) // SHORT Temperature in <20>C x 256 (LM75A 0x90)
#define TEMPMON1_SENSOR2 (TEMPMON_BASE + 0x0C) // SHORT Temperature in <20>C x 256 (LM75A 0x92 or ADM1032 Int)
/* V1 Temperature Monitor
* Temperature Monitor TEMPMON_CONTROL & 0x8000 == 0 : ( 2x LM75A @ 0x90,0x92 )
* Temperature Monitor TEMPMON_CONTROL & 0x8000 == 1 :
* ( 1x LM75A @ 0x90, 1x ADM1032 @ 0x9A )
*/
// V2 Temperature Monitor 2 ADM1032
/* Temperature in C x 256 (ADM1032 ext) */
#define TEMPMON1_CORE (TEMPMON_SENSOR0)
/* Temperature in C x 256 (LM75A 0x90) */
#define TEMPMON1_SENSOR1 (TEMPMON_BASE + 0x08)
/* Temperature in C x 256 (LM75A 0x92 or ADM1032 Int) */
#define TEMPMON1_SENSOR2 (TEMPMON_BASE + 0x0C)
/* V2 Temperature Monitor 2 ADM1032 */
/* Temperature in C x 256 (ADM1032 int) */
#define TEMPMON2_BOARD (TEMPMON_SENSOR0)
/* Temperature in C x 256 (ADM1032 ext) */
#define TEMPMON2_FPGACORE (TEMPMON_SENSOR1)
/* Temperature in C x 256 (ADM1032 ext) */
#define TEMPMON2_QAMCORE (TEMPMON_SENSOR2)
/* SHORT Temperature in C x 256 (ADM1032 ext) */
#define TEMPMON2_DACCORE (TEMPMON_SENSOR2)
#define TEMPMON2_BOARD (TEMPMON_SENSOR0) // SHORT Temperature in <20>C x 256 (ADM1032 int)
#define TEMPMON2_FPGACORE (TEMPMON_SENSOR1) // SHORT Temperature in <20>C x 256 (ADM1032 ext)
#define TEMPMON2_QAMCORE (TEMPMON_SENSOR2) // SHORT Temperature in <20>C x 256 (ADM1032 ext)
/* ------------------------------------------------------------------------- */
/* I2C Master Controller */
@@ -197,7 +211,6 @@
#define I2C_SPEED_77 (0x19181919)
#define I2C_SPEED_50 (0x27262727)
/* ------------------------------------------------------------------------- */
/* DMA Controller */
@@ -217,18 +230,20 @@
#define DMA_DIAG_WAITOVERFLOWCOUNTER (0x38)
#define DMA_DIAG_WAITCOUNTER (0x3C)
#define TS_CONTROL(_io) (_io->regs + 0x00)
#define TS_CONTROL2(_io) (_io->regs + 0x04)
#define TS_CONTROL(_io) ((_io)->regs + 0x00)
#define TS_CONTROL2(_io) ((_io)->regs + 0x04)
#define TS_INPUT_CONTROL_ENABLE (0x00000001)
#define TS_INPUT_CONTROL_RESET (0x00000002)
#define TS_INPUT_CONTROL_SKIPERROR (0x00000008)
/* ------------------------------------------------------------------------- */
/* DMA Buffer */
#define DMA_BUFFER_CONTROL(_dma) (_dma->regs + 0x00)
#define DMA_BUFFER_ACK(_dma) (_dma->regs + 0x04)
#define DMA_BUFFER_CURRENT(_dma) (_dma->regs + 0x08)
#define DMA_BUFFER_SIZE(_dma) (_dma->regs + 0x0c)
#define DMA_BUFFER_CONTROL(_dma) ((_dma)->regs + 0x00)
#define DMA_BUFFER_ACK(_dma) ((_dma)->regs + 0x04)
#define DMA_BUFFER_CURRENT(_dma) ((_dma)->regs + 0x08)
#define DMA_BUFFER_SIZE(_dma) ((_dma)->regs + 0x0c)
/* ------------------------------------------------------------------------- */
@@ -242,10 +257,12 @@
#define LNB_CMD_HIGH 4
#define LNB_CMD_OFF 5
#define LNB_CMD_DISEQC 6
#define LNB_CMD_UNI 7
#define LNB_CMD_SCIF 7
#define LNB_BUSY (1ULL << 4)
#define LNB_TONE (1ULL << 15)
#define LNB_BUSY BIT_ULL(4)
#define LNB_TONE BIT_ULL(15)
#define LNB_INTERRUPT_BASE 4
#define LNB_STATUS(i) (LNB_BASE + (i) * 0x20 + 0x04)
#define LNB_VOLTAGE(i) (LNB_BASE + (i) * 0x20 + 0x08)
@@ -253,6 +270,11 @@
#define LNB_BUF_LEVEL(i) (LNB_BASE + (i) * 0x20 + 0x10)
#define LNB_BUF_WRITE(i) (LNB_BASE + (i) * 0x20 + 0x14)
#define LNB_SETTING(i) (LNB_BASE + (i) * 0x20 + 0x0c)
#define LNB_FIFO_LEVEL(i) (LNB_BASE + (i) * 0x20 + 0x10)
#define LNB_RESET_FIFO(i) (LNB_BASE + (i) * 0x20 + 0x10)
#define LNB_WRITE_FIFO(i) (LNB_BASE + (i) * 0x20 + 0x14)
/* ------------------------------------------------------------------------- */
/* CI Interface (only CI-Bridge) */
@@ -291,14 +313,14 @@
#define CI_BUFFER_BASE (0x3000)
#define CI_BUFFER_SIZE (0x0800)
#define CI_BLOCKIO_BUFFER_SIZE (CI_BUFFER_SIZE/2)
#define CI_BLOCKIO_BUFFER_SIZE (CI_BUFFER_SIZE / 2)
#define CI_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE)
#define CI_BLOCKIO_RECEIVE_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE)
#define CI_BLOCKIO_SEND_BUFFER(i) \
(CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE + CI_BLOCKIO_BUFFER_SIZE)
// V1
/* V1 */
#define VCO1_BASE (0xC0)
#define VCO1_CONTROL (VCO1_BASE + 0x00)
@@ -330,16 +352,27 @@
/* Muxout from VCO (usually = Lock) */
#define VCO3_CONTROL_MUXOUT (0x00000004)
// V2
/* V2 */
#define MAX2871_BASE (0xC0)
#define MAX2871_CONTROL (MAX2871_BASE + 0x00)
#define MAX2871_OUTDATA (MAX2871_BASE + 0x04) // 32 Bit
#define MAX2871_INDATA (MAX2871_BASE + 0x08) // 32 Bit
#define MAX2871_CONTROL_WRITE (0x00000001) // 1 = Trigger write, resets when done
#define MAX2871_CONTROL_CE (0x00000002) // 0 = Put VCO into power down
#define MAX2871_CONTROL_MUXOUT (0x00000004) // Muxout from VCO
#define MAX2871_CONTROL_LOCK (0x00000008) // Lock from VCO
#define MAX2871_OUTDATA (MAX2871_BASE + 0x04)
#define MAX2871_INDATA (MAX2871_BASE + 0x08)
/* 1 = Trigger write, resets when done */
#define MAX2871_CONTROL_WRITE (0x00000001)
/* 0 = Put VCO into power down */
#define MAX2871_CONTROL_CE (0x00000002)
/* Muxout from VCO */
#define MAX2871_CONTROL_MUXOUT (0x00000004)
/* Lock from VCO */
#define MAX2871_CONTROL_LOCK (0x00000008)
/* Signal the loss of lock event (currently only an interrupt) */
#define MAX2871_CONTROL_ENABLE_LOSTLOCK_EVENT (0x00000010)
/* Loss of Lock, needs to be cleared by writing a 1
* during initial setup this bit can be set.
*/
#define MAX2871_CONTROL_LOSTLOCK (0x00008000)
#define FSM_BASE (0x200)
#define FSM_CONTROL (FSM_BASE + 0x00)
@@ -356,11 +389,10 @@
#define FSM_STATUS_READY (0x00010000)
#define FSM_STATUS_QAMREADY (0x00020000)
#define FSM_CAPACITY (FSM_BASE + 0x04)
#define FSM_CAPACITY_MAX (0x3F000000)
#define FSM_CAPACITY_CUR (0x003F0000)
#define FSM_CAPACITY_INUSE (0x0000003F)
#define FSM_CAPACITY_MAX (0x3F000000)
#define FSM_CAPACITY_CUR (0x003F0000)
#define FSM_CAPACITY_INUSE (0x0000003F)
#define FSM_GAIN (FSM_BASE + 0x10)
#define FSM_GAINMASK (0x000000FF)
@@ -373,21 +405,20 @@
#define FSM_GAIN_N24 (0x00000029)
#define FSM_GAIN_N96 (0x00000011)
// Attenuator/VGA
/* Attenuator/VGA */
#define RF_ATTENUATOR (0xD8)
#define RF_ATTENUATOR (0xD8)
/* 0x00 = 0 dB
0x01 = 1 dB
...
0x1F = 31 dB
*/
* 0x01 = 1 dB
* ...
* 0x1F = 31 dB
*/
#define RF_VGA (0xDC)
/* Only V2 */
/* 8 bit range 0 - 31.75 dB Gain */
/* VGA Gain for same output level as V1 Modulator */
#define RF_VGA_GAIN_N8 (85)
#define RF_VGA_GAIN_N16 (117)
@@ -395,7 +426,6 @@
#define RF_VGA_GAIN_MAX (200)
/* V1 only */
#define RF_POWER (0xE0)
@@ -408,10 +438,9 @@
#define RF_POWER_CONTROL_VALIDMASK (0x00000700)
#define RF_POWER_CONTROL_VALID (0x00000500)
/* --------------------------------------------------------------------------
Output control
*/
/*
* Output control
*/
#define IQOUTPUT_BASE (0x240)
#define IQOUTPUT_CONTROL (IQOUTPUT_BASE + 0x00)
@@ -440,14 +469,13 @@
#define IQOUTPUT_CONTROL_ENABLE_PEAK (0x00000008)
#define IQOUTPUT_CONTROL_BYPASS_EQUALIZER (0x00000010)
/* Modulator Base V1 */
#define MODULATOR_BASE (0x200)
#define MODULATOR_CONTROL (MODULATOR_BASE)
#define MODULATOR_IQTABLE_END (MODULATOR_BASE+4)
#define MODULATOR_IQTABLE_INDEX (MODULATOR_BASE+8)
#define MODULATOR_IQTABLE_DATA (MODULATOR_BASE+12)
#define MODULATOR_IQTABLE_END (MODULATOR_BASE + 4)
#define MODULATOR_IQTABLE_INDEX (MODULATOR_BASE + 8)
#define MODULATOR_IQTABLE_DATA (MODULATOR_BASE + 12)
#define MODULATOR_IQTABLE_INDEX_CHANNEL_MASK (0x000F0000)
#define MODULATOR_IQTABLE_INDEX_IQ_MASK (0x00008000)
@@ -456,7 +484,6 @@
#define MODULATOR_IQTABLE_INDEX_SEL_Q (MODULATOR_IQTABLE_INDEX_IQ_MASK)
#define MODULATOR_IQTABLE_SIZE (2048)
/* Modulator Channels */
#define CHANNEL_BASE dev->link[0].info->regmap->channel->base
@@ -508,12 +535,11 @@
#define CHANNEL_SETTINGS2_OUTPUT_MASK (0x0000007F)
#define KFLF_MAX (0x07FFFFFFUL)
#define KF_INIT(Symbolrate) (Symbolrate)
#define LF_INIT(Symbolrate) (9000000UL)
#define KF_INIT(_symbol_rate) (_symbol_rate)
#define LF_INIT(_symbol_rate) (9000000UL)
#define MIN_SYMBOLRATE (1000000)
#define MAX_SYMBOLRATE (7100000)
/* OCTONET */
#define ETHER_BASE (0x100)
@@ -550,5 +576,70 @@
#define PID_FILTER_SYSTEM_PIDS(i) (PID_FILTER_BASE + (i) * 0x20)
#define PID_FILTER_PID(i, j) (PID_FILTER_BASE + (i) * 0x20 + (j) * 4)
/* V2 */
/* MAX2871 same as DVB Modulator V2 */
#define RFDAC_BASE (0x200)
#define RFDAC_CONTROL (RFDAC_BASE + 0x00)
#define RFDAC_CMD_MASK (0x00000087)
#define RFDAC_CMD_STATUS (0x00000080)
#define RFDAC_CMD_RESET (0x00000080)
#define RFDAC_CMD_POWERDOWN (0x00000081)
#define RFDAC_CMD_SETUP (0x00000082)
#define RFDAC_STATUS (RFDAC_BASE + 0x00)
#define RFDAC_STATUS_READY (0x00010000)
#define RFDAC_STATUS_DACREADY (0x00020000)
#define RFDAC_FCW (RFDAC_BASE + 0x10)
#define JESD204B_BASE (0x280)
/* Additional Status Bits */
#define DMA_PCIE_LANES_MASK (0x00070000)
/* Modulator Channels, partially compatible to DVB Modulator V1 */
#define SDR_CHANNEL_BASE (0x800)
#define SDR_CHANNEL_CONTROL(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x00)
#define SDR_CHANNEL_CONFIG(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x04)
#define SDR_CHANNEL_CFCW(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x08)
#define SDR_CHANNEL_ARICW(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x0C)
#define SDR_CHANNEL_RGAIN(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x10)
#define SDR_CHANNEL_SETFIR(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x14)
#define SDR_CHANNEL_FMDCW(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x20)
#define SDR_CHANNEL_FM1FCW(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x24)
#define SDR_CHANNEL_FM2FCW(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x28)
#define SDR_CHANNEL_FM1GAIN(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x2C)
#define SDR_CHANNEL_FM2GAIN(i) ((SDR_CHANNEL_BASE) + (i) * 64 + 0x30)
/* Control and status bits */
#define SDR_CONTROL_ENABLE_CHANNEL (0x00000004)
#define SDR_CONTROL_ENABLE_DMA (0x00000008)
#define SDR_STATUS_DMA_UNDERRUN (0x00010000)
/* Config */
#define SDR_CONFIG_ENABLE_FM1 (0x00000002)
#define SDR_CONFIG_ENABLE_FM2 (0x00000004)
#define SDR_CONFIG_DISABLE_ARI (0x00000010)
#define SDR_CONFIG_DISABLE_VSB (0x00000020)
/* SET FIR */
#define SDR_FIR_COEFF_MASK (0x00000FFF)
#define SDR_FIR_TAP_MASK (0x001F0000)
#define SDR_FIR_SELECT_MASK (0x00C00000)
#define SDR_VSB_LENGTH_MASK (0x01000000)
#define SDR_SET_FIR(select, tap, coeff, vsblen) \
((((select) << 22) & SDR_FIR_SELECT_MASK) | \
(((tap) << 16) & SDR_FIR_TAP_MASK) | \
((coeff) & SDR_FIR_COEFF_MASK) | \
(((vsblen) << 24) & SDR_VSB_LENGTH_MASK) | \
0 \
)

521
ddbridge/ddbridge-sx8.c Normal file
View File

@@ -0,0 +1,521 @@
/*
* ddbridge-sx8.c: Digital Devices MAX SX8 driver
*
* Copyright (C) 2018 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
#include "ddbridge-io.h"
#include "ddbridge-i2c.h"
#include "ddbridge-mci.h"
static const u32 MCLK = (1550000000 / 12);
static const u32 MAX_LDPC_BITRATE = (720000000);
static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6);
#define SX8_TUNER_NUM 4
#define SX8_DEMOD_NUM 8
#define SX8_DEMOD_NONE 0xff
struct sx8_base {
struct mci_base mci_base;
u8 tuner_use_count[SX8_TUNER_NUM];
u32 gain_mode[SX8_TUNER_NUM];
u32 used_ldpc_bitrate[SX8_DEMOD_NUM];
u8 demod_in_use[SX8_DEMOD_NUM];
u32 iq_mode;
u32 burst_size;
u32 direct_mode;
};
struct sx8 {
struct mci mci;
int first_time_lock;
int started;
u32 bb_mode;
u32 local_frequency;
};
static const u8 dvbs2_bits_per_symbol[] = {
0, 0, 0, 0,
/* S2 QPSK */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* S2 8PSK */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
/* S2 16APSK */
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
/* S2 32APSK */
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3, 0, 4, 0,
2, 2, 2, 2, 2, 2, // S2X QPSK
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // S2X 8PSK
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // S2X 16APSK
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // S2X 32APSK
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // S2X 64APSK
7, 7, 7, 7, // S2X 128APSK
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // S2X 256APSK
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // S2X QPSK
3, 3, 3, 3, 3, 3, 3, 3, // S2X 8PSK
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // S2X 16APSK
5, 5, 5, 5, // S2X 32APSK
3, 4, 5, 6, 8, 10,
};
static void release(struct dvb_frontend *fe)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
mci_base->count--;
if (mci_base->count == 0) {
list_del(&mci_base->mci_list);
kfree(mci_base);
}
kfree(state);
}
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{
int stat;
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_result res;
stat = ddb_mci_get_status(&state->mci, &res);
if (stat)
return stat;
*status = 0x00;
ddb_mci_get_info(&state->mci);
if (res.status == SX8_DEMOD_WAIT_MATYPE)
*status = 0x0f;
if (res.status == SX8_DEMOD_LOCKED) {
*status = 0x1f;
if (state->mci.signal_info.dvbs2_signal_info.standard == 2) {
sx8_base->used_ldpc_bitrate[state->mci.nr] =
p->symbol_rate *
dvbs2_bits_per_symbol[
state->mci.signal_info.
dvbs2_signal_info.pls_code];
} else
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
}
return stat;
}
static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct mci_command cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.tuner = state->mci.tuner;
cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE;
cmd.sx8_input_enable.flags = sx8_base->gain_mode[state->mci.tuner];
return ddb_mci_cmd(&state->mci, &cmd, NULL);
}
static int stop(struct dvb_frontend *fe)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct mci_command cmd;
u32 input = state->mci.tuner;
if (!state->started)
return -1;
memset(&cmd, 0, sizeof(cmd));
if (state->mci.demod != SX8_DEMOD_NONE) {
cmd.command = MCI_CMD_STOP;
cmd.demod = state->mci.demod;
ddb_mci_cmd(&state->mci, &cmd, NULL);
if (sx8_base->iq_mode) {
cmd.command = SX8_CMD_DISABLE_IQOUTPUT;
cmd.demod = state->mci.demod;
cmd.output = 0;
ddb_mci_cmd(&state->mci, &cmd, NULL);
ddb_mci_config(&state->mci, SX8_TSCONFIG_MODE_NORMAL);
}
}
mutex_lock(&mci_base->tuner_lock);
sx8_base->tuner_use_count[input]--;
if (!sx8_base->tuner_use_count[input])
mci_set_tuner(fe, input, 0);
if (state->mci.demod != SX8_DEMOD_NONE) {
sx8_base->demod_in_use[state->mci.demod] = 0;
state->mci.demod = SX8_DEMOD_NONE;
}
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
sx8_base->iq_mode = 0;
mutex_unlock(&mci_base->tuner_lock);
state->started = 0;
return 0;
}
static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6);
u32 used_ldpc_bitrate = 0, free_ldpc_bitrate;
u32 used_demods = 0;
struct mci_command cmd;
u32 input = state->mci.tuner;
u32 bits_per_symbol = 0;
int i = -1, stat = 0;
if (p->symbol_rate >= MCLK / 2)
flags &= ~1;
if ((flags & 3) == 0)
return -EINVAL;
if (flags & 2) {
u32 tmp = modmask;
bits_per_symbol = 1;
while (tmp & 1) {
tmp >>= 1;
bits_per_symbol++;
}
}
mutex_lock(&mci_base->tuner_lock);
if (sx8_base->iq_mode) {
stat = -EBUSY;
goto unlock;
}
if (sx8_base->direct_mode) {
if (p->symbol_rate >= MCLK / 2) {
if (state->mci.nr < 4)
i = state->mci.nr;
} else {
i = state->mci.nr;
}
} else {
for (i = 0; i < SX8_DEMOD_NUM; i++) {
used_ldpc_bitrate += sx8_base->used_ldpc_bitrate[i];
if (sx8_base->demod_in_use[i])
used_demods++;
}
printk("used_ldpc_bitrate = %u\n", used_ldpc_bitrate);
if ((used_ldpc_bitrate >= MAX_LDPC_BITRATE) ||
((ts_config & SX8_TSCONFIG_MODE_MASK) >
SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) {
stat = -EBUSY;
goto unlock;
}
free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate;
if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE)
free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE;
while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate)
bits_per_symbol--;
if (bits_per_symbol < 2) {
stat = -EBUSY;
goto unlock;
}
modmask &= ((1 << (bits_per_symbol - 1)) - 1);
if( ((flags & 0x02) != 0) && (modmask == 0)) {
stat = -EBUSY;
goto unlock;
}
i = (p->symbol_rate > MCLK / 2) ? 3 : 7;
while (i >= 0 && sx8_base->demod_in_use[i])
i--;
}
if (i < 0) {
stat = -EBUSY;
goto unlock;
}
sx8_base->demod_in_use[i] = 1;
sx8_base->used_ldpc_bitrate[state->mci.nr] = p->symbol_rate * bits_per_symbol;
state->mci.demod = i;
if (!sx8_base->tuner_use_count[input])
mci_set_tuner(fe, input, 1);
sx8_base->tuner_use_count[input]++;
sx8_base->iq_mode = (ts_config > 1);
unlock:
mutex_unlock(&mci_base->tuner_lock);
if (stat)
return stat;
memset(&cmd, 0, sizeof(cmd));
if (sx8_base->iq_mode) {
cmd.command = SX8_CMD_ENABLE_IQOUTPUT;
cmd.demod = state->mci.demod;
cmd.output = 0;
ddb_mci_cmd(&state->mci, &cmd, NULL);
ddb_mci_config(&state->mci, ts_config);
}
if (p->stream_id != NO_STREAM_ID_FILTER && p->stream_id != 0x80000000)
flags |= 0x80;
printk("frontend %u: tuner=%u demod=%u\n", state->mci.nr, state->mci.tuner, state->mci.demod);
cmd.command = MCI_CMD_SEARCH_DVBS;
cmd.dvbs2_search.flags = flags;
cmd.dvbs2_search.s2_modulation_mask = modmask;
cmd.dvbs2_search.retry = 2;
cmd.dvbs2_search.frequency = p->frequency * 1000;
cmd.dvbs2_search.symbol_rate = p->symbol_rate;
cmd.dvbs2_search.scrambling_sequence_index =
p->scrambling_sequence_index | 0x80000000;
cmd.dvbs2_search.input_stream_id = p->stream_id;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
if (p->stream_id == 0x80000000)
cmd.output |= 0x80;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int start_iq(struct dvb_frontend *fe, u32 flags,
u32 roll_off, u32 ts_config)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 used_demods = 0;
struct mci_command cmd;
u32 input = state->mci.tuner;
int i, stat = 0;
mutex_lock(&mci_base->tuner_lock);
if (sx8_base->iq_mode) {
stat = -EBUSY;
goto unlock;
}
for (i = 0; i < SX8_DEMOD_NUM; i++)
if (sx8_base->demod_in_use[i])
used_demods++;
if (used_demods > 0) {
stat = -EBUSY;
goto unlock;
}
state->mci.demod = 0;
if (!sx8_base->tuner_use_count[input])
mci_set_tuner(fe, input, 1);
sx8_base->tuner_use_count[input]++;
sx8_base->iq_mode = (ts_config > 1);
unlock:
mutex_unlock(&mci_base->tuner_lock);
if (stat)
return stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = SX8_CMD_START_IQ;
cmd.sx8_start_iq.flags = flags;
cmd.sx8_start_iq.roll_off = roll_off;
cmd.sx8_start_iq.frequency = p->frequency * 1000;
cmd.sx8_start_iq.symbol_rate = p->symbol_rate;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
ddb_mci_config(&state->mci, ts_config);
return stat;
}
static int set_parameters(struct dvb_frontend *fe)
{
int stat = 0;
struct sx8 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 ts_config = SX8_TSCONFIG_MODE_NORMAL, iq_mode = 0, isi;
stop(fe);
isi = p->stream_id;
if (isi != NO_STREAM_ID_FILTER) {
iq_mode = (isi & 0x30000000) >> 28;
}
if (iq_mode)
ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
if (iq_mode < 2) {
u32 mask;
switch (p->modulation) {
case APSK_256:
mask = 0x7f;
break;
case APSK_128:
mask = 0x3f;
break;
case APSK_64:
mask = 0x1f;
break;
case APSK_32:
mask = 0x0f;
break;
case APSK_16:
mask = 0x07;
break;
default:
mask = 0x03;
break;
}
stat = start(fe, 3, mask, ts_config);
} else {
stat = start_iq(fe, iq_mode & 1, 4, ts_config);
}
if (!stat) {
state->started = 1;
state->first_time_lock = 1;
state->mci.signal_info.status = SX8_DEMOD_WAIT_SIGNAL;
}
return stat;
}
static int tune(struct dvb_frontend *fe, bool re_tune,
unsigned int mode_flags,
unsigned int *delay, enum fe_status *status)
{
int r;
if (re_tune) {
r = set_parameters(fe);
if (r)
return r;
}
r = read_status(fe, status);
if (r)
return r;
if (*status & FE_HAS_LOCK)
return 0;
*delay = HZ / 10;
return 0;
}
static int get_algo(struct dvb_frontend *fe)
{
return DVBFE_ALGO_HW;
}
static int set_input(struct dvb_frontend *fe, int input)
{
struct sx8 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
printk("fe %u, set input = %u\n", state->mci.nr, input);
if (input >= SX8_TUNER_NUM)
return -EINVAL;
if (state->mci.tuner == input)
return 0;
stop(fe);
state->mci.tuner = p->input = input;
printk("fe %u, input = %u\n", state->mci.nr, input);
return 0;
}
static int sleep(struct dvb_frontend *fe)
{
stop(fe);
return 0;
}
static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{
struct sx8 *state = fe->demodulator_priv;
ddb_mci_proc_info(&state->mci, p);
return 0;
}
static struct dvb_frontend_ops sx8_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2 },
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
.info = {
.name = "DVB-S/S2X",
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 0,
.frequency_tolerance = 0,
.symbol_rate_min = 100000,
.symbol_rate_max = 100000000,
.caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_AUTO |
FE_CAN_QPSK |
FE_CAN_2G_MODULATION |
FE_CAN_MULTISTREAM,
},
.get_frontend_algo = get_algo,
.get_frontend = get_frontend,
.tune = tune,
.release = release,
.read_status = read_status,
.set_input = set_input,
.sleep = sleep,
};
static int init(struct mci *mci)
{
struct sx8 *state = (struct sx8 *) mci;
state->mci.demod = SX8_DEMOD_NONE;
mci->fe.ops.xbar[1] = mci->nr;
mci->fe.dtv_property_cache.input = mci->tuner;
return 0;
}
static int base_init(struct mci_base *mci_base)
{
//struct sx8_base *base = (struct sx8_base *) mci_base;
return 0;
}
struct mci_cfg ddb_max_sx8_cfg = {
.type = 0,
.fe_ops = &sx8_ops,
.base_size = sizeof(struct sx8_base),
.state_size = sizeof(struct sx8),
.init = init,
.base_init = base_init,
};

View File

@@ -1,626 +0,0 @@
/*
* ddbridge.c: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2015 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/
#define DDB_USE_WORK
/*#define DDB_TEST_THREADED*/
#include "ddbridge.h"
#include "ddbridge-regs.h"
static struct workqueue_struct *ddb_wq;
static int adapter_alloc;
module_param(adapter_alloc, int, 0444);
MODULE_PARM_DESC(adapter_alloc,
"0-one adapter per io, 1-one per tab with io, 2-one per tab, 3-one for all");
#ifdef CONFIG_PCI_MSI
static int msi = 1;
module_param(msi, int, 0444);
MODULE_PARM_DESC(msi,
" Control MSI interrupts: 0-disable, 1-enable (default)");
#endif
#include "ddbridge-core.c"
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static void ddb_unmap(struct ddb *dev)
{
if (dev->regs)
iounmap(dev->regs);
vfree(dev);
}
static void __devexit ddb_irq_disable(struct ddb *dev)
{
if (dev->link[0].info->regmap->irq_version == 2) {
ddbwritel(dev, 0x00000000, INTERRUPT_V2_CONTROL);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_1);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_2);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_3);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_4);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_5);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_6);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_7);
} else {
ddbwritel(dev, 0, INTERRUPT_ENABLE);
ddbwritel(dev, 0, MSI1_ENABLE);
}
}
static void __devexit ddb_irq_exit(struct ddb *dev)
{
ddb_irq_disable(dev);
if (dev->msi == 2)
free_irq(dev->pdev->irq + 1, dev);
free_irq(dev->pdev->irq, dev);
#ifdef CONFIG_PCI_MSI
if (dev->msi)
pci_disable_msi(dev->pdev);
#endif
}
static void __devexit ddb_remove(struct pci_dev *pdev)
{
struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev);
ddb_device_destroy(dev);
ddb_nsd_detach(dev);
ddb_ports_detach(dev);
ddb_i2c_release(dev);
if (dev->link[0].info->ns_num)
ddbwritel(dev, 0, ETHER_CONTROL);
ddb_irq_exit(dev);
ddb_ports_release(dev);
ddb_buffers_free(dev);
ddb_unmap(dev);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
#define __devinit
#define __devinitdata
#endif
static int __devinit ddb_irq_msi(struct ddb *dev, int nr)
{
int stat;
#ifdef CONFIG_PCI_MSI
if (msi && pci_msi_enabled()) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
stat = pci_enable_msi_range(dev->pdev, 1, nr);
if (stat >= 1) {
dev->msi = stat;
pr_info("DDBridge: using %d MSI interrupt(s)\n",
dev->msi);
} else
pr_info("DDBridge: MSI not available.\n");
#else
stat = pci_enable_msi_block(dev->pdev, nr);
if (stat == 0) {
dev->msi = nr;
pr_info("DDBridge: using %d MSI interrupts\n", nr);
} else if (stat == 1) {
stat = pci_enable_msi(dev->pdev);
dev->msi = 1;
}
if (stat < 0)
pr_info("DDBridge: MSI not available.\n");
#endif
}
return stat;
}
static int __devinit ddb_irq_init2(struct ddb *dev)
{
int stat;
int irq_flag = IRQF_SHARED;
pr_info("DDBridge: init type 2 IRQ hardware block\n");
ddbwritel(dev, 0x00000000, INTERRUPT_V2_CONTROL);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_1);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_2);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_3);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_4);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_5);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_6);
ddbwritel(dev, 0x00000000, INTERRUPT_V2_ENABLE_7);
ddb_irq_msi(dev, 1);
if (dev->msi)
irq_flag = 0;
stat = request_irq(dev->pdev->irq, irq_handler_v2,
irq_flag, "ddbridge", (void *) dev);
if (stat < 0)
return stat;
ddbwritel(dev, 0x0000ff7f, INTERRUPT_V2_CONTROL);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_1);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_2);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_3);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_4);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_5);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_6);
ddbwritel(dev, 0xffffffff, INTERRUPT_V2_ENABLE_7);
return stat;
}
static int __devinit ddb_irq_init(struct ddb *dev)
{
int stat;
int irq_flag = IRQF_SHARED;
if (dev->link[0].info->regmap->irq_version == 2)
return ddb_irq_init2(dev);
ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE);
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
ddbwritel(dev, 0x00000000, MSI2_ENABLE);
ddbwritel(dev, 0x00000000, MSI3_ENABLE);
ddbwritel(dev, 0x00000000, MSI4_ENABLE);
ddbwritel(dev, 0x00000000, MSI5_ENABLE);
ddbwritel(dev, 0x00000000, MSI6_ENABLE);
ddbwritel(dev, 0x00000000, MSI7_ENABLE);
ddb_irq_msi(dev, 2);
if (dev->msi)
irq_flag = 0;
if (dev->msi == 2) {
stat = request_irq(dev->pdev->irq, irq_handler0,
irq_flag, "ddbridge", (void *) dev);
if (stat < 0)
return stat;
stat = request_irq(dev->pdev->irq + 1, irq_handler1,
irq_flag, "ddbridge", (void *) dev);
if (stat < 0) {
free_irq(dev->pdev->irq, dev);
return stat;
}
} else
#endif
{
#ifdef DDB_TEST_THREADED
stat = request_threaded_irq(dev->pdev->irq, irq_handler,
irq_thread,
irq_flag,
"ddbridge", (void *) dev);
#else
stat = request_irq(dev->pdev->irq, irq_handler,
irq_flag, "ddbridge", (void *) dev);
#endif
if (stat < 0)
return stat;
}
/*ddbwritel(dev, 0xffffffff, INTERRUPT_ACK);*/
if (dev->msi == 2) {
ddbwritel(dev, 0x0fffff00, INTERRUPT_ENABLE);
ddbwritel(dev, 0x0000000f, MSI1_ENABLE);
} else {
ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE);
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
}
return stat;
}
static int __devinit ddb_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct ddb *dev;
int stat = 0;
if (pci_enable_device(pdev) < 0)
return -ENODEV;
pci_set_master(pdev);
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
return -ENODEV;
dev = vzalloc(sizeof(struct ddb));
if (dev == NULL)
return -ENOMEM;
mutex_init(&dev->mutex);
dev->has_dma = 1;
dev->pdev = pdev;
dev->dev = &pdev->dev;
pci_set_drvdata(pdev, dev);
dev->link[0].ids.vendor = id->vendor;
dev->link[0].ids.device = id->device;
dev->link[0].ids.subvendor = id->subvendor;
dev->link[0].ids.subdevice = id->subdevice;
dev->link[0].dev = dev;
dev->link[0].info = (struct ddb_info *) id->driver_data;
pr_info("DDBridge: device name: %s\n", dev->link[0].info->name);
dev->regs_len = pci_resource_len(dev->pdev, 0);
dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
pci_resource_len(dev->pdev, 0));
if (!dev->regs) {
pr_err("DDBridge: not enough memory for register map\n");
stat = -ENOMEM;
goto fail;
}
if (ddbreadl(dev, 0) == 0xffffffff) {
pr_err("DDBridge: cannot read registers\n");
stat = -ENODEV;
goto fail;
}
dev->link[0].ids.hwid = ddbreadl(dev, 0);
dev->link[0].ids.regmapid = ddbreadl(dev, 4);
pr_info("DDBridge: HW %08x REGMAP %08x\n",
dev->link[0].ids.hwid, dev->link[0].ids.regmapid);
if (dev->link[0].info->ns_num) {
ddbwritel(dev, 0, ETHER_CONTROL);
ddb_reset_ios(dev);
}
ddbwritel(dev, 0, DMA_BASE_READ);
if (dev->link[0].info->type != DDB_MOD)
ddbwritel(dev, 0, DMA_BASE_WRITE);
if (dev->link[0].info->type == DDB_MOD) {
if (ddbreadl(dev, 0x1c) == 4)
dev->link[0].info->port_num = 4;
}
stat = ddb_irq_init(dev);
if (stat < 0)
goto fail0;
if (ddb_init(dev) == 0)
return 0;
ddb_irq_disable(dev);
fail0:
pr_err("DDBridge: fail0\n");
if (dev->msi)
pci_disable_msi(dev->pdev);
fail:
pr_err("DDBridge: fail\n");
ddb_unmap(dev);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
return -1;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static struct ddb_info ddb_none = {
.type = DDB_NONE,
.name = "unknown Digital Devices PCIe card, install newer driver",
.regmap = &octopus_map,
};
static struct ddb_info ddb_octopus = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus DVB adapter",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
};
static struct ddb_info ddb_octopusv3 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus V3 DVB adapter",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
};
static struct ddb_info ddb_octopus_le = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus LE DVB adapter",
.regmap = &octopus_map,
.port_num = 2,
.i2c_mask = 0x03,
};
static struct ddb_info ddb_octopus_oem = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus OEM",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.led_num = 1,
.fan_num = 1,
.temp_num = 1,
.temp_bus = 0,
};
static struct ddb_info ddb_octopus_mini = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus Mini",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
};
static struct ddb_info ddb_v6 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Cine S2 V6 DVB adapter",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x07,
};
static struct ddb_info ddb_v6_5 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Cine S2 V6.5 DVB adapter",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
};
static struct ddb_info ddb_v7 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Cine S2 V7 DVB adapter",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 2,
.board_control_2 = 4,
.ts_quirks = TS_QUIRK_REVERSED,
};
static struct ddb_info ddb_ctv7 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Cine CT V7 DVB adapter",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 3,
.board_control_2 = 4,
};
static struct ddb_info ddb_satixS2v3 = {
.type = DDB_OCTOPUS,
.name = "Mystique SaTiX-S2 V3 DVB adapter",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x07,
};
static struct ddb_info ddb_ci = {
.type = DDB_OCTOPUS_CI,
.name = "Digital Devices Octopus CI",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x03,
};
static struct ddb_info ddb_cis = {
.type = DDB_OCTOPUS_CI,
.name = "Digital Devices Octopus CI single",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x03,
};
static struct ddb_info ddb_ci_s2_pro = {
.type = DDB_OCTOPUS_CI,
.name = "Digital Devices Octopus CI S2 Pro",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x01,
.board_control = 2,
.board_control_2 = 4,
};
static struct ddb_info ddb_dvbct = {
.type = DDB_OCTOPUS,
.name = "Digital Devices DVBCT V6.1 DVB adapter",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x07,
};
/****************************************************************************/
static struct ddb_info ddb_mod = {
.type = DDB_MOD,
.name = "Digital Devices DVB-C modulator",
.regmap = &octopus_mod_map,
.port_num = 10,
.temp_num = 1,
};
static struct ddb_info ddb_mod_fsm_24 = {
.type = DDB_MOD,
.version = 2,
.name = "Digital Devices DVB-C modulator FSM-24",
.regmap = &octopus_mod_2_map,
.port_num = 24,
.temp_num = 1,
.tempmon_irq = 8,
};
static struct ddb_info ddb_mod_fsm_16 = {
.type = DDB_MOD,
.version = 2,
.name = "Digital Devices DVB-C modulator FSM-16",
.regmap = &octopus_mod_2_map,
.port_num = 16,
.temp_num = 1,
.tempmon_irq = 8,
};
static struct ddb_info ddb_mod_fsm_8 = {
.type = DDB_MOD,
.name = "Digital Devices DVB-C modulator FSM-8",
.version = 2,
.regmap = &octopus_mod_2_map,
.port_num = 8,
.temp_num = 1,
.tempmon_irq = 8,
};
static struct ddb_info ddb_octopro_hdin = {
.type = DDB_OCTOPRO_HDIN,
.name = "Digital Devices OctopusNet Pro HDIN",
.regmap = &octopro_hdin_map,
.port_num = 10,
.i2c_mask = 0x3ff,
.mdio_num = 1,
};
static struct ddb_info ddb_octopro = {
.type = DDB_OCTOPRO,
.name = "Digital Devices OctopusNet Pro",
.regmap = &octopro_map,
.port_num = 10,
.i2c_mask = 0x3ff,
.mdio_num = 1,
};
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
#define DDVID 0xdd01 /* Digital Devices Vendor ID */
#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \
.vendor = _vend, .device = _dev, \
.subvendor = _subvend, .subdevice = _subdev, \
.driver_data = (unsigned long)&_driverdata }
static const struct pci_device_id ddb_id_tbl[] __devinitconst = {
DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus),
DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus),
DDB_ID(DDVID, 0x0005, DDVID, 0x0004, ddb_octopusv3),
DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le),
DDB_ID(DDVID, 0x0003, DDVID, 0x0003, ddb_octopus_oem),
DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus_mini),
DDB_ID(DDVID, 0x0005, DDVID, 0x0011, ddb_octopus_mini),
DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6),
DDB_ID(DDVID, 0x0003, DDVID, 0x0021, ddb_v6_5),
DDB_ID(DDVID, 0x0006, DDVID, 0x0022, ddb_v7),
DDB_ID(DDVID, 0x0003, DDVID, 0x0030, ddb_dvbct),
DDB_ID(DDVID, 0x0003, DDVID, 0xdb03, ddb_satixS2v3),
DDB_ID(DDVID, 0x0006, DDVID, 0x0031, ddb_ctv7),
DDB_ID(DDVID, 0x0006, DDVID, 0x0032, ddb_ctv7),
DDB_ID(DDVID, 0x0006, DDVID, 0x0033, ddb_ctv7),
DDB_ID(DDVID, 0x0007, DDVID, 0x0023, ddb_s2_48),
DDB_ID(DDVID, 0x0008, DDVID, 0x0034, ddb_ct2_8),
DDB_ID(DDVID, 0x0008, DDVID, 0x0035, ddb_c2t2_8),
DDB_ID(DDVID, 0x0008, DDVID, 0x0036, ddb_isdbt_8),
DDB_ID(DDVID, 0x0008, DDVID, 0x0037, ddb_c2t2i_v0_8),
DDB_ID(DDVID, 0x0008, DDVID, 0x0038, ddb_c2t2i_8),
DDB_ID(DDVID, 0x0011, DDVID, 0x0040, ddb_ci),
DDB_ID(DDVID, 0x0011, DDVID, 0x0041, ddb_cis),
DDB_ID(DDVID, 0x0012, DDVID, 0x0042, ddb_ci),
DDB_ID(DDVID, 0x0013, DDVID, 0x0043, ddb_ci_s2_pro),
DDB_ID(DDVID, 0x0201, DDVID, 0x0001, ddb_mod),
DDB_ID(DDVID, 0x0201, DDVID, 0x0002, ddb_mod),
DDB_ID(DDVID, 0x0203, DDVID, 0x0001, ddb_mod),
DDB_ID(DDVID, 0x0210, DDVID, 0x0001, ddb_mod_fsm_24),
DDB_ID(DDVID, 0x0210, DDVID, 0x0002, ddb_mod_fsm_16),
DDB_ID(DDVID, 0x0210, DDVID, 0x0003, ddb_mod_fsm_8),
/* testing on OctopusNet Pro */
DDB_ID(DDVID, 0x0320, PCI_ANY_ID, PCI_ANY_ID, ddb_octopro_hdin),
DDB_ID(DDVID, 0x0321, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0322, PCI_ANY_ID, PCI_ANY_ID, ddb_octopro),
DDB_ID(DDVID, 0x0323, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0328, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0329, PCI_ANY_ID, PCI_ANY_ID, ddb_octopro_hdin),
/* in case sub-ids got deleted in flash */
DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0005, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0006, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0007, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0008, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0011, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0013, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0201, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0320, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
{0}
};
MODULE_DEVICE_TABLE(pci, ddb_id_tbl);
static struct pci_driver ddb_pci_driver = {
.name = "ddbridge",
.id_table = ddb_id_tbl,
.probe = ddb_probe,
.remove = ddb_remove,
};
static __init int module_init_ddbridge(void)
{
int stat = -1;
pr_info("DDBridge: Digital Devices PCIE bridge driver "
DDBRIDGE_VERSION
", Copyright (C) 2010-16 Digital Devices GmbH\n");
if (ddb_class_create() < 0)
return -1;
ddb_wq = create_workqueue("ddbridge");
if (ddb_wq == NULL)
goto exit1;
stat = pci_register_driver(&ddb_pci_driver);
if (stat < 0)
goto exit2;
return stat;
exit2:
destroy_workqueue(ddb_wq);
exit1:
ddb_class_destroy();
return stat;
}
static __exit void module_exit_ddbridge(void)
{
pci_unregister_driver(&ddb_pci_driver);
destroy_workqueue(ddb_wq);
ddb_class_destroy();
}
module_init(module_init_ddbridge);
module_exit(module_exit_ddbridge);
MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
MODULE_LICENSE("GPL");
MODULE_VERSION(DDBRIDGE_VERSION);

View File

@@ -1,7 +1,7 @@
/*
* ddbridge.h: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2015 Digital Devices GmbH
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rmetzler@digitaldevices.de>
*
* This program is free software; you can redistribute it and/or
@@ -16,18 +16,19 @@
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef _DDBRIDGE_H_
#define _DDBRIDGE_H_
#define DDB_USE_WORK
/*#define DDB_TEST_THREADED*/
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
#if (KERNEL_VERSION(3, 8, 0) <= LINUX_VERSION_CODE)
#define __devexit
#define __devinit
#define __devinitconst
@@ -55,7 +56,6 @@
#include <linux/completion.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <asm/dma.h>
@@ -91,6 +91,9 @@
#include "lnbh25.h"
#include "mxl5xx.h"
#include "ddbridge-regs.h"
#include "ddbridge-mci.h"
#define DDB_MAX_I2C 32
#define DDB_MAX_PORT 32
#define DDB_MAX_INPUT 64
@@ -98,7 +101,7 @@
#define DDB_MAX_LINK 4
#define DDB_LINK_SHIFT 28
#define DDB_LINK_TAG(_x) (_x << DDB_LINK_SHIFT)
#define DDB_LINK_TAG(_x) ((_x) << DDB_LINK_SHIFT)
struct ddb_regset {
u32 base;
@@ -114,22 +117,18 @@ struct ddb_regmap {
u32 irq_base_gtl;
u32 irq_base_rate;
struct ddb_regset *i2c;
struct ddb_regset *i2c_buf;
struct ddb_regset *idma;
struct ddb_regset *idma_buf;
struct ddb_regset *odma;
struct ddb_regset *odma_buf;
const struct ddb_regset *i2c;
const struct ddb_regset *i2c_buf;
const struct ddb_regset *idma;
const struct ddb_regset *idma_buf;
const struct ddb_regset *odma;
const struct ddb_regset *odma_buf;
struct ddb_regset *input;
struct ddb_regset *output;
struct ddb_regset *channel;
//struct ddb_regset *ci;
//struct ddb_regset *pid_filter;
//struct ddb_regset *ns;
struct ddb_regset *gtl;
//struct ddb_regset *mdio;
const struct ddb_regset *input;
const struct ddb_regset *output;
const struct ddb_regset *channel;
const struct ddb_regset *gtl;
};
struct ddb_ids {
@@ -146,58 +145,47 @@ struct ddb_ids {
struct ddb_info {
u32 type;
#define DDB_NONE 0
#define DDB_OCTOPUS 1
#define DDB_OCTOPUS_CI 2
#define DDB_MOD 3
#define DDB_OCTONET 4
#define DDB_OCTOPUS_MAX 5
#define DDB_OCTOPUS_MAX_CT 6
#define DDB_OCTOPRO 7
#define DDB_OCTOPRO_HDIN 8
#define DDB_NONE 0
#define DDB_OCTOPUS 1
#define DDB_OCTOPUS_CI 2
#define DDB_MOD 3
#define DDB_OCTONET 4
#define DDB_OCTOPUS_MAX 5
#define DDB_OCTOPUS_MAX_CT 6
#define DDB_OCTOPRO 7
#define DDB_OCTOPRO_HDIN 8
#define DDB_OCTOPUS_MCI 9
u32 version;
char *name;
u32 i2c_mask;
u32 board_control;
u32 board_control_2;
u8 port_num;
u8 led_num;
u8 fan_num;
u8 temp_num;
u8 temp_bus;
u32 board_control;
u32 board_control_2;
u8 ns_num;
u8 mdio_num;
u8 con_clock; /* use a continuous clock */
u8 ts_quirks;
#define TS_QUIRK_SERIAL 1
#define TS_QUIRK_REVERSED 2
#define TS_QUIRK_NO_OUTPUT 4
u32 tempmon_irq;
struct ddb_regmap *regmap;
#define TS_QUIRK_ALT_OSC 8
u8 mci_ports;
u8 mci_type;
u32 tempmon_irq;
u32 lostlock_irq;
u32 mdio_base;
u32 hw_min;
const struct ddb_regmap *regmap;
};
/* DMA_SIZE MUST be smaller than 256k and
MUST be divisible by 188 and 128 !!! */
#define DMA_MAX_BUFS 32 /* hardware table limit */
#ifdef SMALL_DMA_BUFS
#define INPUT_DMA_BUFS 32
#define INPUT_DMA_SIZE (128*47*5)
#define INPUT_DMA_IRQ_DIV 1
#define OUTPUT_DMA_BUFS 32
#define OUTPUT_DMA_SIZE (128*47*5)
#define OUTPUT_DMA_IRQ_DIV 1
#else
#define INPUT_DMA_BUFS 8
#define INPUT_DMA_SIZE (128*47*21)
#define INPUT_DMA_IRQ_DIV 1
#define OUTPUT_DMA_BUFS 8
#define OUTPUT_DMA_SIZE (128*47*21)
#define OUTPUT_DMA_IRQ_DIV 1
#endif
#define OUTPUT_DMA_BUFS_SDR 32
#define OUTPUT_DMA_SIZE_SDR (256 * 1024)
struct ddb;
struct ddb_port;
@@ -219,7 +207,7 @@ struct ddb_dma {
#else
struct tasklet_struct tasklet;
#endif
spinlock_t lock;
spinlock_t lock; /* DMA lock */
wait_queue_head_t wq;
int running;
u32 stat;
@@ -244,11 +232,12 @@ struct ddb_dvb {
u32 attached;
u8 input;
fe_sec_tone_mode_t tone;
fe_sec_voltage_t voltage;
enum fe_sec_tone_mode tone;
enum fe_sec_voltage voltage;
int (*i2c_gate_ctrl)(struct dvb_frontend *, int);
int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
int (*set_voltage)(struct dvb_frontend *fe,
enum fe_sec_voltage voltage);
int (*set_input)(struct dvb_frontend *fe, int input);
int (*diseqc_send_master_cmd)(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd);
@@ -258,7 +247,6 @@ struct ddb_ci {
struct dvb_ca_en50221 en;
struct ddb_port *port;
u32 nr;
struct mutex lock;
};
struct ddb_io {
@@ -292,7 +280,7 @@ struct ddb_port {
u32 regs;
u32 lnr;
struct ddb_i2c *i2c;
struct mutex i2c_gate_lock;
struct mutex i2c_gate_lock; /* I2C access lock */
u32 class;
#define DDB_PORT_NONE 0
#define DDB_PORT_CI 1
@@ -302,6 +290,7 @@ struct ddb_port {
char *name;
char *type_name;
u32 type;
#define DDB_TUNER_DUMMY 0xffffffff
#define DDB_TUNER_NONE 0
#define DDB_TUNER_DVBS_ST 1
#define DDB_TUNER_DVBS_ST_AA 2
@@ -317,6 +306,7 @@ struct ddb_port {
#define DDB_CI_EXTERNAL_XO2 12
#define DDB_CI_EXTERNAL_XO2_B 13
#define DDB_TUNER_DVBS_STV0910_PR 14
#define DDB_TUNER_DVBC2T2I_SONY_P 15
#define DDB_TUNER_XO2 32
#define DDB_TUNER_DVBS_STV0910 (DDB_TUNER_XO2 + 0)
@@ -326,6 +316,10 @@ struct ddb_port {
#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)
struct ddb_input *input[2];
struct ddb_output *output;
struct dvb_ca_en50221 *en;
@@ -343,13 +337,11 @@ struct mod_base {
struct ddb_mod {
struct ddb_port *port;
u32 nr;
u32 regs;
u32 frequency;
u32 modulation;
u32 symbolrate;
u64 obitrate;
u64 ibitrate;
u32 pcr_correction;
@@ -403,28 +395,34 @@ struct ddb_ns {
};
struct ddb_lnb {
struct mutex lock;
struct mutex lock; /* lock lnb access */
u32 tone;
fe_sec_voltage_t oldvoltage[4];
enum fe_sec_voltage oldvoltage[4];
u32 voltage[4];
u32 voltages;
u32 fmode;
};
struct ddb_irq {
void (*handler)(void *);
void *data;
};
struct ddb_link {
struct ddb *dev;
struct ddb_info *info;
const struct ddb_info *info;
u32 nr;
u32 regs;
spinlock_t lock;
struct mutex flash_mutex;
spinlock_t lock; /* lock link access */
struct mutex flash_mutex; /* lock flash access */
struct ddb_lnb lnb;
struct tasklet_struct tasklet;
struct ddb_ids ids;
spinlock_t temp_lock;
int OverTemperatureError;
spinlock_t temp_lock; /* lock temp chip access */
int over_temperature_error;
u8 temp_tab[11];
struct ddb_irq irq[256];
};
struct ddb {
@@ -450,9 +448,6 @@ struct ddb {
struct ddb_dma idma[DDB_MAX_INPUT];
struct ddb_dma odma[DDB_MAX_OUTPUT];
void (*handler[4][256])(unsigned long);
unsigned long handler_data[4][256];
struct device *ddb_dev;
u32 ddb_dev_users;
u32 nr;
@@ -465,230 +460,16 @@ struct ddb {
int ns_num;
struct ddb_ns ns[DDB_NS_MAX];
int vlan;
struct mutex mutex;
struct mutex mutex; /* lock accces to global ddb array */
struct dvb_device *nsd_dev;
u8 tsbuf[TS_CAPTURE_LEN];
struct mod_base mod_base;
struct ddb_mod mod[24];
struct mutex ioctl_mutex; /* lock extra ioctls */
};
static inline void ddbwriteb(struct ddb *dev, u32 val, u32 adr)
{
writeb(val, (char *) (dev->regs + (adr)));
}
static inline u32 ddbreadb(struct ddb *dev, u32 adr)
{
return readb((char *) (dev->regs + (adr)));
}
static inline void ddbwritel0(struct ddb_link *link, u32 val, u32 adr)
{
writel(val, (char *) (link->dev->regs + (adr)));
}
static inline u32 ddbreadl0(struct ddb_link *link, u32 adr)
{
return readl((char *) (link->dev->regs + (adr)));
}
#if 0
static inline void gtlw(struct ddb_link *link)
{
u32 count = 0;
static u32 max;
while (1 & ddbreadl0(link, link->regs + 0x10)) {
if (++count == 1024) {
pr_info("LTO\n");
break;
}
}
if (count > max) {
max = count;
pr_info("TO=%u\n", max);
}
if (ddbreadl0(link, link->regs + 0x10) & 0x8000)
pr_err("link error\n");
}
#else
static inline void gtlw(struct ddb_link *link)
{
while (1 & ddbreadl0(link, link->regs + 0x10))
;
}
#endif
static u32 ddblreadl(struct ddb_link *link, u32 adr)
{
if (unlikely(link->nr)) {
unsigned long flags;
u32 val;
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddbwritel0(link, adr & 0xfffc, link->regs + 0x14);
ddbwritel0(link, 3, link->regs + 0x10);
gtlw(link);
val = ddbreadl0(link, link->regs + 0x1c);
spin_unlock_irqrestore(&link->lock, flags);
return val;
}
return readl((char *) (link->dev->regs + (adr)));
}
static void ddblwritel(struct ddb_link *link, u32 val, u32 adr)
{
if (unlikely(link->nr)) {
unsigned long flags;
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddbwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
ddbwritel0(link, val, link->regs + 0x18);
ddbwritel0(link, 1, link->regs + 0x10);
spin_unlock_irqrestore(&link->lock, flags);
return;
}
writel(val, (char *) (link->dev->regs + (adr)));
}
static u32 ddbreadl(struct ddb *dev, u32 adr)
{
if (unlikely(adr & 0xf0000000)) {
unsigned long flags;
u32 val, l = (adr >> DDB_LINK_SHIFT);
struct ddb_link *link = &dev->link[l];
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddbwritel0(link, adr & 0xfffc, link->regs + 0x14);
ddbwritel0(link, 3, link->regs + 0x10);
gtlw(link);
val = ddbreadl0(link, link->regs + 0x1c);
spin_unlock_irqrestore(&link->lock, flags);
return val;
}
return readl((char *) (dev->regs + (adr)));
}
static void ddbwritel(struct ddb *dev, u32 val, u32 adr)
{
if (unlikely(adr & 0xf0000000)) {
unsigned long flags;
u32 l = (adr >> DDB_LINK_SHIFT);
struct ddb_link *link = &dev->link[l];
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddbwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
ddbwritel0(link, val, link->regs + 0x18);
ddbwritel0(link, 1, link->regs + 0x10);
spin_unlock_irqrestore(&link->lock, flags);
return;
}
writel(val, (char *) (dev->regs + (adr)));
}
static void gtlcpyto(struct ddb *dev, u32 adr, const u8 *buf,
unsigned int count)
{
u32 val = 0, p = adr;
u32 aa = p & 3;
if (aa) {
while (p & 3 && count) {
val >>= 8;
val |= *buf << 24;
p++;
buf++;
count--;
}
ddbwritel(dev, val, adr);
}
while (count >= 4) {
val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
ddbwritel(dev, val, p);
p += 4;
buf += 4;
count -= 4;
}
if (count) {
val = buf[0];
if (count > 1)
val |= buf[1] << 8;
if (count > 2)
val |= buf[2] << 16;
ddbwritel(dev, val, p);
}
}
static void gtlcpyfrom(struct ddb *dev, u8 *buf, u32 adr, long count)
{
u32 val = 0, p = adr;
u32 a = p & 3;
if (a) {
val = ddbreadl(dev, p) >> (8 * a);
while (p & 3 && count) {
*buf = val & 0xff;
val >>= 8;
p++;
buf++;
count--;
}
}
while (count >= 4) {
val = ddbreadl(dev, p);
buf[0] = val & 0xff;
buf[1] = (val >> 8) & 0xff;
buf[2] = (val >> 16) & 0xff;
buf[3] = (val >> 24) & 0xff;
p += 4;
buf += 4;
count -= 4;
}
if (count) {
val = ddbreadl(dev, p);
buf[0] = val & 0xff;
if (count > 1)
buf[1] = (val >> 8) & 0xff;
if (count > 2)
buf[2] = (val >> 16) & 0xff;
}
}
static void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count)
{
if (unlikely(adr & 0xf0000000))
return gtlcpyto(dev, adr, src, count);
return memcpy_toio((char *) (dev->regs + adr), src, count);
}
static void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count)
{
if (unlikely(adr & 0xf0000000))
return gtlcpyfrom(dev, dst, adr, count);
return memcpy_fromio(dst, (char *) (dev->regs + adr), count);
}
#if 0
#define ddbcpyto(_dev, _adr, _src, _count) \
memcpy_toio((char *) (_dev->regs + (_adr)), (_src), (_count))
#define ddbcpyfrom(_dev, _dst, _adr, _count) \
memcpy_fromio((_dst), (char *) (_dev->regs + (_adr)), (_count))
#endif
#define ddbmemset(_dev, _adr, _val, _count) \
memset_io((char *) (_dev->regs + (_adr)), (_val), (_count))
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
@@ -741,16 +522,51 @@ struct DDMOD_FLASH {
#define DDMOD_FLASH_MAGIC 0x5F564d5F
int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
#define DDBRIDGE_VERSION "0.9.36"
/* linked function prototypes */
const struct ddb_info *get_ddb_info(u16 vendor, u16 device,
u16 subvendor, u16 subdevice);
int netstream_init(struct ddb_input *input);
int ddb_dvb_ns_input_start(struct ddb_input *input);
int ddb_dvb_ns_input_stop(struct ddb_input *input);
int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg);
int ddbridge_mod_init(struct ddb *dev);
void ddbridge_mod_output_stop(struct ddb_output *output);
int ddbridge_mod_output_start(struct ddb_output *output);
void ddbridge_mod_rate_handler(unsigned long data);
void ddbridge_mod_rate_handler(void *);
void ddb_device_destroy(struct ddb *dev);
void ddb_nsd_detach(struct ddb *dev);
void ddb_ports_detach(struct ddb *dev);
void ddb_ports_release(struct ddb *dev);
void ddb_buffers_free(struct ddb *dev);
void ddb_unmap(struct ddb *dev);
irqreturn_t ddb_irq_handler0(int irq, void *dev_id);
irqreturn_t ddb_irq_handler1(int irq, void *dev_id);
irqreturn_t ddb_irq_handler(int irq, void *dev_id);
irqreturn_t ddb_irq_handler_v2(int irq, void *dev_id);
void ddb_reset_ios(struct ddb *dev);
int ddb_init(struct ddb *dev);
int ddb_exit_ddbridge(int stage, int error);
int ddb_init_ddbridge(void);
int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
int ddb_i2c_init(struct ddb *dev);
void ddb_i2c_release(struct ddb *dev);
#define DDBRIDGE_VERSION "0.9.28"
int ddb_ci_attach(struct ddb_port *port, u32 bitrate);
int ddb_fe_attach_mxl5xx(struct ddb_input *input);
int ddb_fe_attach_mci(struct ddb_input *input, u32 type);
int ddb_lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm);
struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr,
void (*handler)(void *), void *data);
struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, struct mci_cfg *cfg, int nr, int tuner);
#endif

View File

@@ -1,7 +1,7 @@
/*
* octonet.c: Digital Devices network tuner driver
*
* Copyright (C) 2012-16 Digital Devices GmbH
* Copyright (C) 2012-17 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
@@ -17,96 +17,12 @@
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
#include "ddbridge-regs.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0))
#include <asm-generic/pci-dma-compat.h>
#else
#include <linux/pci-dma-compat.h>
#endif
static int adapter_alloc = 3;
module_param(adapter_alloc, int, 0444);
MODULE_PARM_DESC(adapter_alloc,
"0-one adapter per io, 1-one per tab with io, 2-one per tab, 3-one for all");
#include "ddbridge-core.c"
static struct ddb_regmap octopus_net_map = {
.irq_version = 1,
.irq_base_i2c = 0,
.i2c = &octopus_i2c,
.i2c_buf = &octopus_i2c_buf,
.input = &octopus_input,
.output = &octopus_output,
};
static struct ddb_regset octopus_gtl = {
.base = 0x180,
.num = 0x01,
.size = 0x20,
};
static struct ddb_regmap octopus_net_gtl = {
.irq_version = 1,
.irq_base_i2c = 0,
.irq_base_gtl = 10,
.i2c = &octopus_i2c,
.i2c_buf = &octopus_i2c_buf,
.input = &octopus_input,
.output = &octopus_output,
.gtl = &octopus_gtl,
};
static struct ddb_info ddb_octonet = {
.type = DDB_OCTONET,
.name = "Digital Devices OctopusNet network DVB adapter",
.regmap = &octopus_net_map,
.port_num = 4,
.i2c_mask = 0x0f,
.ns_num = 12,
.mdio_num = 1,
};
static struct ddb_info ddb_octonet_jse = {
.type = DDB_OCTONET,
.name = "Digital Devices OctopusNet network DVB adapter JSE",
.regmap = &octopus_net_map,
.port_num = 4,
.i2c_mask = 0x0f,
.ns_num = 15,
.mdio_num = 1,
};
static struct ddb_info ddb_octonet_gtl = {
.type = DDB_OCTONET,
.name = "Digital Devices OctopusNet GTL",
.regmap = &octopus_net_gtl,
.port_num = 4,
.i2c_mask = 0x05,
.ns_num = 12,
.mdio_num = 1,
.con_clock = 1,
};
static struct ddb_info ddb_octonet_tbd = {
.type = DDB_OCTONET,
.name = "Digital Devices OctopusNet",
.regmap = &octopus_net_map,
};
static void octonet_unmap(struct ddb *dev)
{
if (dev->regs)
iounmap(dev->regs);
vfree(dev);
}
#include "ddbridge-io.h"
static int __exit octonet_remove(struct platform_device *pdev)
{
@@ -125,7 +41,7 @@ static int __exit octonet_remove(struct platform_device *pdev)
free_irq(platform_get_irq(dev->pfdev, 0), dev);
ddb_ports_release(dev);
octonet_unmap(dev);
ddb_unmap(dev);
platform_set_drvdata(pdev, 0);
return 0;
}
@@ -136,7 +52,7 @@ static int __init octonet_probe(struct platform_device *pdev)
struct resource *regs;
int irq;
dev = vzalloc(sizeof(struct ddb));
dev = vzalloc(sizeof(*dev));
if (!dev)
return -ENOMEM;
platform_set_drvdata(pdev, dev);
@@ -149,7 +65,7 @@ static int __init octonet_probe(struct platform_device *pdev)
return -ENXIO;
dev->regs_len = (regs->end - regs->start) + 1;
dev_info(dev->dev, "regs_start=%08x regs_len=%08x\n",
(u32) regs->start, (u32) dev->regs_len);
(u32)regs->start, (u32)dev->regs_len);
dev->regs = ioremap(regs->start, dev->regs_len);
if (!dev->regs) {
@@ -168,19 +84,13 @@ static int __init octonet_probe(struct platform_device *pdev)
dev->link[0].ids.subdevice = dev->link[0].ids.devid >> 16;
dev->link[0].dev = dev;
if (dev->link[0].ids.devid == 0x0300dd01)
dev->link[0].info = &ddb_octonet;
else if (dev->link[0].ids.devid == 0x0301dd01)
dev->link[0].info = &ddb_octonet_jse;
else if (dev->link[0].ids.devid == 0x0307dd01)
dev->link[0].info = &ddb_octonet_gtl;
else
dev->link[0].info = &ddb_octonet_tbd;
pr_info("DDBridge: HW %08x REGMAP %08x\n",
dev->link[0].ids.hwid, dev->link[0].ids.regmapid);
pr_info("DDBridge: MAC %08x DEVID %08x\n",
dev->link[0].ids.mac, dev->link[0].ids.devid);
dev->link[0].info = get_ddb_info(dev->link[0].ids.vendor,
dev->link[0].ids.device,
0xdd01, 0xffff);
dev_info(dev->dev, "DDBridge: HW %08x REGMAP %08x\n",
dev->link[0].ids.hwid, dev->link[0].ids.regmapid);
dev_info(dev->dev, "DDBridge: MAC %08x DEVID %08x\n",
dev->link[0].ids.mac, dev->link[0].ids.devid);
ddbwritel(dev, 0, ETHER_CONTROL);
ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE);
@@ -190,9 +100,9 @@ static int __init octonet_probe(struct platform_device *pdev)
irq = platform_get_irq(dev->pfdev, 0);
if (irq < 0)
goto fail;
if (request_irq(irq, irq_handler,
if (request_irq(irq, ddb_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"octonet-dvb", (void *) dev) < 0)
"octonet-dvb", (void *)dev) < 0)
goto fail;
ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE);
@@ -203,7 +113,7 @@ fail:
dev_err(dev->dev, "fail\n");
ddbwritel(dev, 0, ETHER_CONTROL);
ddbwritel(dev, 0, INTERRUPT_ENABLE);
octonet_unmap(dev);
ddb_unmap(dev);
platform_set_drvdata(pdev, 0);
return -1;
}
@@ -217,7 +127,7 @@ static const struct of_device_id octonet_dt_ids[] = {
MODULE_DEVICE_TABLE(of, octonet_dt_ids);
#endif
static struct platform_driver octonet_driver = {
static struct platform_driver octonet_driver __refdata = {
.remove = __exit_p(octonet_remove),
.probe = octonet_probe,
.driver = {
@@ -231,25 +141,23 @@ static struct platform_driver octonet_driver = {
static __init int init_octonet(void)
{
int res;
int stat;
pr_info("DDBridge: Digital Devices OctopusNet driver " DDBRIDGE_VERSION
", Copyright (C) 2010-16 Digital Devices GmbH\n");
res = ddb_class_create();
if (res)
return res;
res = platform_driver_probe(&octonet_driver, octonet_probe);
if (res) {
ddb_class_destroy();
return res;
}
return 0;
", Copyright (C) 2010-17 Digital Devices GmbH\n");
stat = ddb_init_ddbridge();
if (stat < 0)
return stat;
stat = platform_driver_probe(&octonet_driver, octonet_probe);
if (stat < 0)
ddb_exit_ddbridge(0, stat);
return stat;
}
static __exit void exit_octonet(void)
{
platform_driver_unregister(&octonet_driver);
ddb_class_destroy();
ddb_exit_ddbridge(0, 0);
}
module_init(init_octonet);
@@ -257,5 +165,5 @@ module_exit(exit_octonet);
MODULE_DESCRIPTION("GPL");
MODULE_AUTHOR("Marcus and Ralph Metzler, Metzler Brothers Systementwicklung GbR");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.6");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(DDBRIDGE_VERSION);

104
docs/bbframes Normal file
View File

@@ -0,0 +1,104 @@
To allow the transport of DVB-S2 baseband frames (BBFrame) across existing hard- and software
interfaces, we have added the ability to embed the BBFrame data into
an MPEG2 transport stream.
This feature is available on supported cards as firmware update and
is currently considered experimental.
Supported hardware:
Cine V7A (>=1.7 FW)
OctopusCI S2 Pro Advanced (>=1.7 FW)
Duoflex S2 v4 Advanced (TBA)
MaxSX8 (NOT the MAXS8!)
The following cards are based on the broadcast version of the
DVB-S2 demodulator. The BBFrame output is working but
not documented. We therefore can not guarantee the
feature will work under all conditions.
cineS2 V7 (>=1.7 FW)
OctopusCI S2 Pro (>=1.7 FW)
Duoflex S2 v4 (TBA)
Current FPGA images (including FW 1.7 for the above mentioned cards)
can be found here:
http://download.digital-devices.de/download/firmware/html/firmwareupdate.html
Packet format:
The BBFrames are packetized into MPEG2 private sections (0x80), one section per transport stream
packet. The PID is fixed at 0x010E.
Header packet of frame:
0x47 0x41 0x0E 0x1X 0x00 0x80 0x00 L 0xB8 BBHeader (169 * Data)
L: Section Length, always 180 (0xB4)
BBHeader: 10 Bytes BBFrame header (see DVB-S2, EN-302307)
Data: 169 Bytes of BBFrame payload
Payload packets:
0x47 0x41 0x0E 0x1X 0x00 0x80 0x00 L N (179 * Data)
L: Section Length, always 180 (0xB4)
N: Packet counter, starting with 0x01 after header packet
Data: 179 Bytes of BBFrame payload
Last packet:
0x47 0x41 0x0E 0x1X 0x00 0x80 0x00 L N ((L-1) * Data) ((180 L) * 0xFF)
L: Section Length, remaining Data 1, (0x01 .. 0xB4)
N: Packet counter
Data: L-1 Bytes of BBFrame payload
Automatic detection of input format:
The bridge firmware allows automatic detection of the incoming data.
To receive regular transport streams in this formats it is still required to setup
the DVB-S2 demodulator to output BBFrames instead of regular TS Packets.
When enabled the embedding mode is automatically turned on or off depending on incoming data
from the DVB-S2/S2X frontend. The decision depends currently only on the first byte of a packet.
If it is 0x47 it switches to transport stream mode else it switches to embedding mode.
Note that 0x47 can currently not occur in the first byte of a BBFrame header if all reserved
values of DVB-S2 and -S2X are observed.
API:
Currently DTV_STREAM_ID is misused.
Set it to 0x80000000 to enable frame mode in the demod.
Because there were some questions why we use this data format,
here are some examples for why using this format this makes handling BBFrames easier:
- The start of a frame is easily found because a new set of sections is
started.
- Existing software layers like the Linux kernel DVB demuxer can be used unchanged.
- Existing hardware like the OctopusNet SAT>IP server which can only handle TS packets can
stream BBFrames via SAT>IP with this method.
- There is at least one demodulator (e.g. on the MaxSX8) which supports this format in hardware.

View File

@@ -26,4 +26,105 @@ talks to the CI to decrypt the desired services.
For testing one can use a standard application that
supports decryption. Additionally to seeing the
decoded service on the PC it will then also be streamed
into cable by the modulator.
into cable by the modulator.
The modulator device can be controlled with the
following properties:
MODULATOR_FREQUENCY:
Set the frequency on Version 2 (FSM) cards
units - Hz
range - 114000000-874000000
allowed values - 114 + 8000000*X
For older cards you have to use the
DVB_MOD_SET ioctl.
MODULATOR_SYMBOLRATE:
Set the symbol rate
units - Hz
range - Version 1 cards: only 6900000
Version 2 cards(FSM): X-7100000
MODULATOR_MODULATION:
Set the modulation type
range: QAM_16 .. QAM_256
MODULATOR_ATTENUATION:
range - 0-31
unit - 1 dB
MODULATOR_GAIN:
range - 0-255
unit - 0.125 dB
The MODULATOR_ATTENUATOR is based on a switched resistor network,
also it is backward compatible to our old modulator.
the MODULATOR_GAIN is based on a variable gain amplifier, so it is less
accurate then the attenuator.
High gain values will drive the output amplifier into clipping. The
limit depends on # of channels active.
MODULATOR_INPUT_BITRATE:
The modulator will ALWAY insert null packets if it
does not get enough data.
If you specify the input bitrate it will insert additional
null packets according to the difference between input
and output bit rate.
The latter is determined by symbol rte and modulation.
So, this property should be set last.
unit - 2^-32 Hz
Debugging features:
MODULATOR_STATUS and MODULATOR_RESET have been added to debug
possible problems with too high temperatures (overtemperature)
or PLL lock loss on FSM type cards.
The MODULATOR_STATUS property returns a __u32 with the following status bits:
- bit 0 : Lock status 1=lock OK, 0 = lock lost
- bit 1 : Sticky lock lost indicator
0 = no PLL lock loss since last status read
1 = lock has been lost since last status read
- bit 2 : 0 = no overtemperature
1 = overtemperature detected
- bit 4 : 0 = PCIe link OK
1 = PCIe link lost
In case of overtemperratur or PCIe link loss you will have to reboot the PC.
Putting a MODULATOR_STATUS property with value 2 will enable the lost lock
interrupt. This will set the gain to 0 and the attenuation to 31 in case
of a lost PLL lock.
The MODULATOR_RESET property can be used to reset the modulator without
needing to reload the driver or rebooting in case of PLL lock loss.
All channels should be stopped before using it and restarted after using it.
Otherwise, results are unpredictable.

View File

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

42
dvb-core/Kconfig Normal file
View File

@@ -0,0 +1,42 @@
#
# DVB device configuration
#
config DVB_MAX_ADAPTERS
int "maximum number of DVB/ATSC adapters"
depends on DVB_CORE
default 16
range 1 255
help
Maximum number of DVB/ATSC adapters. Increasing this number
increases the memory consumption of the DVB subsystem even
if a much lower number of DVB/ATSC adapters is present.
Only values in the range 4-32 are tested.
If you are unsure about this, use the default value 16
config DVB_DYNAMIC_MINORS
bool "Dynamic DVB minor allocation"
depends on DVB_CORE
default n
help
If you say Y here, the DVB subsystem will use dynamic minor
allocation for any device that uses the DVB major number.
This means that you can have more than 4 of a single type
of device (like demuxes and frontends) per adapter, but udev
will be required to manage the device nodes.
If you are unsure about this, say N here.
config DVB_DEMUX_SECTION_LOSS_LOG
bool "Enable DVB demux section packet loss log"
depends on DVB_CORE
default n
help
Enable extra log messages meant to detect packet loss
inside the Kernel.
Should not be enabled on normal cases, as logs can
be very verbose.
If you are unsure about this, say N here.

12
dvb-core/Makefile.kernel Normal file
View File

@@ -0,0 +1,12 @@
#
# Makefile for the kernel DVB device drivers.
#
dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
dvb_ca_en50221.o dvb_frontend.o \
$(dvb-net-y) dvb_ringbuffer.o dvb_math.o \
dvb_netstream.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o

View File

@@ -1,6 +1,10 @@
/*
* demux.h
*
* The Kernel Digital TV Demux kABI defines a driver-internal interface for
* registering low-level, hardware specific driver to a hardware independent
* demux layer.
*
* Copyright (c) 2002 Convergence GmbH
*
* based on code:
@@ -17,10 +21,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __DEMUX_H
@@ -32,9 +32,9 @@
#include <linux/time.h>
#include <linux/dvb/dmx.h>
/*--------------------------------------------------------------------------*/
/* Common definitions */
/*--------------------------------------------------------------------------*/
/*
* Common definitions
*/
/*
* DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
@@ -45,7 +45,8 @@
#endif
/*
* DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
* DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed
* filter.
*/
#ifndef DMX_MAX_SECTION_SIZE
@@ -55,187 +56,534 @@
#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
#endif
/*
* enum dmx_success: Success codes for the Demux Callback API.
* TS packet reception
*/
enum dmx_success {
DMX_OK = 0, /* Received Ok */
DMX_LENGTH_ERROR, /* Incorrect length */
DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
DMX_CRC_ERROR, /* Incorrect CRC */
DMX_FRAME_ERROR, /* Frame alignment error */
DMX_FIFO_ERROR, /* Receiver FIFO overrun */
DMX_MISSED_ERROR /* Receiver missed packet */
} ;
/*--------------------------------------------------------------------------*/
/* TS packet reception */
/*--------------------------------------------------------------------------*/
/* TS filter type for set() */
#define TS_PACKET 1 /* send TS packets (188 bytes) to callback (default) */
#define TS_PAYLOAD_ONLY 2 /* in case TS_PACKET is set, only send the TS
payload (<=184 bytes per packet) to callback */
#define TS_DECODER 4 /* send stream to built-in decoder (if present) */
#define TS_DEMUX 8 /* in case TS_PACKET is set, send the TS to
the demux device, not to the dvr device */
/**
* enum ts_filter_type - filter type bitmap for dmx_ts_feed.set\(\)
*
* @TS_PACKET: Send TS packets (188 bytes) to callback (default).
* @TS_PAYLOAD_ONLY: In case TS_PACKET is set, only send the TS payload
* (<=184 bytes per packet) to callback
* @TS_DECODER: Send stream to built-in decoder (if present).
* @TS_DEMUX: In case TS_PACKET is set, send the TS to the demux
* device, not to the dvr device
*/
enum ts_filter_type {
TS_PACKET = 1,
TS_PAYLOAD_ONLY = 2,
TS_DECODER = 4,
TS_DEMUX = 8,
};
/**
* struct dmx_ts_feed - Structure that contains a TS feed filter
*
* @is_filtering: Set to non-zero when filtering in progress
* @parent: pointer to struct dmx_demux
* @priv: pointer to private data of the API client
* @set: sets the TS filter
* @start_filtering: starts TS filtering
* @stop_filtering: stops TS filtering
*
* A TS feed is typically mapped to a hardware PID filter on the demux chip.
* Using this API, the client can set the filtering properties to start/stop
* filtering TS packets on a particular TS feed.
*/
struct dmx_ts_feed {
int is_filtering; /* Set to non-zero when filtering in progress */
struct dmx_demux *parent; /* Back-pointer */
void *priv; /* Pointer to private data of the API client */
int (*set) (struct dmx_ts_feed *feed,
u16 pid,
int type,
enum dmx_ts_pes pes_type,
size_t circular_buffer_size,
struct timespec timeout);
int (*start_filtering) (struct dmx_ts_feed* feed);
int (*stop_filtering) (struct dmx_ts_feed* feed);
int is_filtering;
struct dmx_demux *parent;
void *priv;
int (*set)(struct dmx_ts_feed *feed,
u16 pid,
int type,
enum dmx_ts_pes pes_type,
ktime_t timeout);
int (*start_filtering)(struct dmx_ts_feed *feed);
int (*stop_filtering)(struct dmx_ts_feed *feed);
};
/*--------------------------------------------------------------------------*/
/* Section reception */
/*--------------------------------------------------------------------------*/
/*
* Section reception
*/
/**
* struct dmx_section_filter - Structure that describes a section filter
*
* @filter_value: Contains up to 16 bytes (128 bits) of the TS section header
* that will be matched by the section filter
* @filter_mask: Contains a 16 bytes (128 bits) filter mask with the bits
* specified by @filter_value that will be used on the filter
* match logic.
* @filter_mode: Contains a 16 bytes (128 bits) filter mode.
* @parent: Pointer to struct dmx_section_feed.
* @priv: Pointer to private data of the API client.
*
*
* The @filter_mask controls which bits of @filter_value are compared with
* the section headers/payload. On a binary value of 1 in filter_mask, the
* corresponding bits are compared. The filter only accepts sections that are
* equal to filter_value in all the tested bit positions.
*/
struct dmx_section_filter {
u8 filter_value [DMX_MAX_FILTER_SIZE];
u8 filter_mask [DMX_MAX_FILTER_SIZE];
u8 filter_mode [DMX_MAX_FILTER_SIZE];
struct dmx_section_feed* parent; /* Back-pointer */
void* priv; /* Pointer to private data of the API client */
u8 filter_value[DMX_MAX_FILTER_SIZE];
u8 filter_mask[DMX_MAX_FILTER_SIZE];
u8 filter_mode[DMX_MAX_FILTER_SIZE];
struct dmx_section_feed *parent; /* Back-pointer */
void *priv; /* Pointer to private data of the API client */
};
/**
* struct dmx_section_feed - Structure that contains a section feed filter
*
* @is_filtering: Set to non-zero when filtering in progress
* @parent: pointer to struct dmx_demux
* @priv: pointer to private data of the API client
* @check_crc: If non-zero, check the CRC values of filtered sections.
* @set: sets the section filter
* @allocate_filter: This function is used to allocate a section filter on
* the demux. It should only be called when no filtering
* is in progress on this section feed. If a filter cannot
* be allocated, the function fails with -ENOSPC.
* @release_filter: This function releases all the resources of a
* previously allocated section filter. The function
* should not be called while filtering is in progress
* on this section feed. After calling this function,
* the caller should not try to dereference the filter
* pointer.
* @start_filtering: starts section filtering
* @stop_filtering: stops section filtering
*
* A TS feed is typically mapped to a hardware PID filter on the demux chip.
* Using this API, the client can set the filtering properties to start/stop
* filtering TS packets on a particular TS feed.
*/
struct dmx_section_feed {
int is_filtering; /* Set to non-zero when filtering in progress */
struct dmx_demux* parent; /* Back-pointer */
void* priv; /* Pointer to private data of the API client */
int is_filtering;
struct dmx_demux *parent;
void *priv;
int check_crc;
/* private: Used internally at dvb_demux.c */
u32 crc_val;
u8 *secbuf;
u8 secbuf_base[DMX_MAX_SECFEED_SIZE];
u16 secbufp, seclen, tsfeedp;
int (*set) (struct dmx_section_feed* feed,
u16 pid,
size_t circular_buffer_size,
int check_crc);
int (*allocate_filter) (struct dmx_section_feed* feed,
struct dmx_section_filter** filter);
int (*release_filter) (struct dmx_section_feed* feed,
struct dmx_section_filter* filter);
int (*start_filtering) (struct dmx_section_feed* feed);
int (*stop_filtering) (struct dmx_section_feed* feed);
/* public: */
int (*set)(struct dmx_section_feed *feed,
u16 pid,
int check_crc);
int (*allocate_filter)(struct dmx_section_feed *feed,
struct dmx_section_filter **filter);
int (*release_filter)(struct dmx_section_feed *feed,
struct dmx_section_filter *filter);
int (*start_filtering)(struct dmx_section_feed *feed);
int (*stop_filtering)(struct dmx_section_feed *feed);
};
/*--------------------------------------------------------------------------*/
/* Callback functions */
/*--------------------------------------------------------------------------*/
/**
* typedef dmx_ts_cb - DVB demux TS filter callback function prototype
*
* @buffer1: Pointer to the start of the filtered TS packets.
* @buffer1_length: Length of the TS data in buffer1.
* @buffer2: Pointer to the tail of the filtered TS packets, or NULL.
* @buffer2_length: Length of the TS data in buffer2.
* @source: Indicates which TS feed is the source of the callback.
*
* This function callback prototype, provided by the client of the demux API,
* is called from the demux code. The function is only called when filtering
* on a TS feed has been enabled using the start_filtering\(\) function at
* the &dmx_demux.
* Any TS packets that match the filter settings are copied to a circular
* buffer. The filtered TS packets are delivered to the client using this
* callback function.
* It is expected that the @buffer1 and @buffer2 callback parameters point to
* addresses within the circular buffer, but other implementations are also
* possible. Note that the called party should not try to free the memory
* the @buffer1 and @buffer2 parameters point to.
*
* When this function is called, the @buffer1 parameter typically points to
* the start of the first undelivered TS packet within a circular buffer.
* The @buffer2 buffer parameter is normally NULL, except when the received
* TS packets have crossed the last address of the circular buffer and
* "wrapped" to the beginning of the buffer. In the latter case the @buffer1
* parameter would contain an address within the circular buffer, while the
* @buffer2 parameter would contain the first address of the circular buffer.
* The number of bytes delivered with this function (i.e. @buffer1_length +
* @buffer2_length) is usually equal to the value of callback_length parameter
* given in the set() function, with one exception: if a timeout occurs before
* receiving callback_length bytes of TS data, any undelivered packets are
* immediately delivered to the client by calling this function. The timeout
* duration is controlled by the set() function in the TS Feed API.
*
* If a TS packet is received with errors that could not be fixed by the
* TS-level forward error correction (FEC), the Transport_error_indicator
* flag of the TS packet header should be set. The TS packet should not be
* discarded, as the error can possibly be corrected by a higher layer
* protocol. If the called party is slow in processing the callback, it
* is possible that the circular buffer eventually fills up. If this happens,
* the demux driver should discard any TS packets received while the buffer
* is full and return -EOVERFLOW.
*
* The type of data returned to the callback can be selected by the
* &dmx_ts_feed.@set function. The type parameter decides if the raw
* TS packet (TS_PACKET) or just the payload (TS_PACKET|TS_PAYLOAD_ONLY)
* should be returned. If additionally the TS_DECODER bit is set the stream
* will also be sent to the hardware MPEG decoder.
*
* Return:
*
* - 0, on success;
*
* - -EOVERFLOW, on buffer overflow.
*/
typedef int (*dmx_ts_cb)(const u8 *buffer1,
size_t buffer1_length,
const u8 *buffer2,
size_t buffer2_length,
struct dmx_ts_feed *source);
typedef int (*dmx_ts_cb) ( const u8 * buffer1,
size_t buffer1_length,
const u8 * buffer2,
size_t buffer2_length,
struct dmx_ts_feed* source,
enum dmx_success success);
/**
* typedef dmx_section_cb - DVB demux TS filter callback function prototype
*
* @buffer1: Pointer to the start of the filtered section, e.g.
* within the circular buffer of the demux driver.
* @buffer1_len: Length of the filtered section data in @buffer1,
* including headers and CRC.
* @buffer2: Pointer to the tail of the filtered section data,
* or NULL. Useful to handle the wrapping of a
* circular buffer.
* @buffer2_len: Length of the filtered section data in @buffer2,
* including headers and CRC.
* @source: Indicates which section feed is the source of the
* callback.
*
* This function callback prototype, provided by the client of the demux API,
* is called from the demux code. The function is only called when
* filtering of sections has been enabled using the function
* &dmx_ts_feed.@start_filtering. When the demux driver has received a
* complete section that matches at least one section filter, the client
* is notified via this callback function. Normally this function is called
* for each received section; however, it is also possible to deliver
* multiple sections with one callback, for example when the system load
* is high. If an error occurs while receiving a section, this
* function should be called with the corresponding error type set in the
* success field, whether or not there is data to deliver. The Section Feed
* implementation should maintain a circular buffer for received sections.
* However, this is not necessary if the Section Feed API is implemented as
* a client of the TS Feed API, because the TS Feed implementation then
* buffers the received data. The size of the circular buffer can be
* configured using the &dmx_ts_feed.@set function in the Section Feed API.
* If there is no room in the circular buffer when a new section is received,
* the section must be discarded. If this happens, the value of the success
* parameter should be DMX_OVERRUN_ERROR on the next callback.
*/
typedef int (*dmx_section_cb)(const u8 *buffer1,
size_t buffer1_len,
const u8 *buffer2,
size_t buffer2_len,
struct dmx_section_filter *source);
typedef int (*dmx_section_cb) ( const u8 * buffer1,
size_t buffer1_len,
const u8 * buffer2,
size_t buffer2_len,
struct dmx_section_filter * source,
enum dmx_success success);
/*--------------------------------------------------------------------------*/
/* DVB Front-End */
/*--------------------------------------------------------------------------*/
/*
* DVB Front-End
*/
/**
* enum dmx_frontend_source - Used to identify the type of frontend
*
* @DMX_MEMORY_FE: The source of the demux is memory. It means that
* the MPEG-TS to be filtered comes from userspace,
* via write() syscall.
*
* @DMX_FRONTEND_0: The source of the demux is a frontend connected
* to the demux.
*/
enum dmx_frontend_source {
DMX_MEMORY_FE,
DMX_FRONTEND_0,
DMX_FRONTEND_1,
DMX_FRONTEND_2,
DMX_FRONTEND_3,
DMX_STREAM_0, /* external stream input, e.g. LVDS */
DMX_STREAM_1,
DMX_STREAM_2,
DMX_STREAM_3
};
/**
* struct dmx_frontend - Structure that lists the frontends associated with
* a demux
*
* @connectivity_list: List of front-ends that can be connected to a
* particular demux;
* @source: Type of the frontend.
*
* FIXME: this structure should likely be replaced soon by some
* media-controller based logic.
*/
struct dmx_frontend {
struct list_head connectivity_list; /* List of front-ends that can
be connected to a particular
demux */
struct list_head connectivity_list;
enum dmx_frontend_source source;
};
/*--------------------------------------------------------------------------*/
/* MPEG-2 TS Demux */
/*--------------------------------------------------------------------------*/
/*
* Flags OR'ed in the capabilities field of struct dmx_demux.
* MPEG-2 TS Demux
*/
#define DMX_TS_FILTERING 1
#define DMX_PES_FILTERING 2
#define DMX_SECTION_FILTERING 4
#define DMX_MEMORY_BASED_FILTERING 8 /* write() available */
#define DMX_CRC_CHECKING 16
#define DMX_TS_DESCRAMBLING 32
/**
* enum dmx_demux_caps - MPEG-2 TS Demux capabilities bitmap
*
* @DMX_TS_FILTERING: set if TS filtering is supported;
* @DMX_SECTION_FILTERING: set if section filtering is supported;
* @DMX_MEMORY_BASED_FILTERING: set if write() available.
*
* Those flags are OR'ed in the &dmx_demux.capabilities field
*/
enum dmx_demux_caps {
DMX_TS_FILTERING = 1,
DMX_SECTION_FILTERING = 4,
DMX_MEMORY_BASED_FILTERING = 8,
};
/*
* Demux resource type identifier.
*/
*/
/*
* DMX_FE_ENTRY(): Casts elements in the list of registered
* front-ends from the generic type struct list_head
* to the type * struct dmx_frontend
*.
*/
#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list)
/**
* DMX_FE_ENTRY - Casts elements in the list of registered
* front-ends from the generic type struct list_head
* to the type * struct dmx_frontend
*
* @list: list of struct dmx_frontend
*/
#define DMX_FE_ENTRY(list) \
list_entry(list, struct dmx_frontend, connectivity_list)
/**
* struct dmx_demux - Structure that contains the demux capabilities and
* callbacks.
*
* @capabilities: Bitfield of capability flags.
*
* @frontend: Front-end connected to the demux
*
* @priv: Pointer to private data of the API client
*
* @open: This function reserves the demux for use by the caller and, if
* necessary, initializes the demux. When the demux is no longer needed,
* the function @close should be called. It should be possible for
* multiple clients to access the demux at the same time. Thus, the
* function implementation should increment the demux usage count when
* @open is called and decrement it when @close is called.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* It returns:
* 0 on success;
* -EUSERS, if maximum usage count was reached;
* -EINVAL, on bad parameter.
*
* @close: This function reserves the demux for use by the caller and, if
* necessary, initializes the demux. When the demux is no longer needed,
* the function @close should be called. It should be possible for
* multiple clients to access the demux at the same time. Thus, the
* function implementation should increment the demux usage count when
* @open is called and decrement it when @close is called.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* It returns:
* 0 on success;
* -ENODEV, if demux was not in use (e. g. no users);
* -EINVAL, on bad parameter.
*
* @write: This function provides the demux driver with a memory buffer
* containing TS packets. Instead of receiving TS packets from the DVB
* front-end, the demux driver software will read packets from memory.
* Any clients of this demux with active TS, PES or Section filters will
* receive filtered data via the Demux callback API (see 0). The function
* returns when all the data in the buffer has been consumed by the demux.
* Demux hardware typically cannot read TS from memory. If this is the
* case, memory-based filtering has to be implemented entirely in software.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @buf function parameter contains a pointer to the TS data in
* kernel-space memory.
* The @count function parameter contains the length of the TS data.
* It returns:
* 0 on success;
* -ERESTARTSYS, if mutex lock was interrupted;
* -EINTR, if a signal handling is pending;
* -ENODEV, if demux was removed;
* -EINVAL, on bad parameter.
*
* @allocate_ts_feed: Allocates a new TS feed, which is used to filter the TS
* packets carrying a certain PID. The TS feed normally corresponds to a
* hardware PID filter on the demux chip.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @feed function parameter contains a pointer to the TS feed API and
* instance data.
* The @callback function parameter contains a pointer to the callback
* function for passing received TS packet.
* It returns:
* 0 on success;
* -ERESTARTSYS, if mutex lock was interrupted;
* -EBUSY, if no more TS feeds is available;
* -EINVAL, on bad parameter.
*
* @release_ts_feed: Releases the resources allocated with @allocate_ts_feed.
* Any filtering in progress on the TS feed should be stopped before
* calling this function.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @feed function parameter contains a pointer to the TS feed API and
* instance data.
* It returns:
* 0 on success;
* -EINVAL on bad parameter.
*
* @allocate_section_feed: Allocates a new section feed, i.e. a demux resource
* for filtering and receiving sections. On platforms with hardware
* support for section filtering, a section feed is directly mapped to
* the demux HW. On other platforms, TS packets are first PID filtered in
* hardware and a hardware section filter then emulated in software. The
* caller obtains an API pointer of type dmx_section_feed_t as an out
* parameter. Using this API the caller can set filtering parameters and
* start receiving sections.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @feed function parameter contains a pointer to the TS feed API and
* instance data.
* The @callback function parameter contains a pointer to the callback
* function for passing received TS packet.
* It returns:
* 0 on success;
* -EBUSY, if no more TS feeds is available;
* -EINVAL, on bad parameter.
*
* @release_section_feed: Releases the resources allocated with
* @allocate_section_feed, including allocated filters. Any filtering in
* progress on the section feed should be stopped before calling this
* function.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @feed function parameter contains a pointer to the TS feed API and
* instance data.
* It returns:
* 0 on success;
* -EINVAL, on bad parameter.
*
* @add_frontend: Registers a connectivity between a demux and a front-end,
* i.e., indicates that the demux can be connected via a call to
* @connect_frontend to use the given front-end as a TS source. The
* client of this function has to allocate dynamic or static memory for
* the frontend structure and initialize its fields before calling this
* function. This function is normally called during the driver
* initialization. The caller must not free the memory of the frontend
* struct before successfully calling @remove_frontend.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @frontend function parameter contains a pointer to the front-end
* instance data.
* It returns:
* 0 on success;
* -EINVAL, on bad parameter.
*
* @remove_frontend: Indicates that the given front-end, registered by a call
* to @add_frontend, can no longer be connected as a TS source by this
* demux. The function should be called when a front-end driver or a demux
* driver is removed from the system. If the front-end is in use, the
* function fails with the return value of -EBUSY. After successfully
* calling this function, the caller can free the memory of the frontend
* struct if it was dynamically allocated before the @add_frontend
* operation.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @frontend function parameter contains a pointer to the front-end
* instance data.
* It returns:
* 0 on success;
* -ENODEV, if the front-end was not found,
* -EINVAL, on bad parameter.
*
* @get_frontends: Provides the APIs of the front-ends that have been
* registered for this demux. Any of the front-ends obtained with this
* call can be used as a parameter for @connect_frontend. The include
* file demux.h contains the macro DMX_FE_ENTRY() for converting an
* element of the generic type struct &list_head * to the type
* struct &dmx_frontend *. The caller must not free the memory of any of
* the elements obtained via this function call.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* It returns a struct list_head pointer to the list of front-end
* interfaces, or NULL in the case of an empty list.
*
* @connect_frontend: Connects the TS output of the front-end to the input of
* the demux. A demux can only be connected to a front-end registered to
* the demux with the function @add_frontend. It may or may not be
* possible to connect multiple demuxes to the same front-end, depending
* on the capabilities of the HW platform. When not used, the front-end
* should be released by calling @disconnect_frontend.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @frontend function parameter contains a pointer to the front-end
* instance data.
* It returns:
* 0 on success;
* -EINVAL, on bad parameter.
*
* @disconnect_frontend: Disconnects the demux and a front-end previously
* connected by a @connect_frontend call.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* It returns:
* 0 on success;
* -EINVAL on bad parameter.
*
* @get_pes_pids: Get the PIDs for DMX_PES_AUDIO0, DMX_PES_VIDEO0,
* DMX_PES_TELETEXT0, DMX_PES_SUBTITLE0 and DMX_PES_PCR0.
* The @demux function parameter contains a pointer to the demux API and
* instance data.
* The @pids function parameter contains an array with five u16 elements
* where the PIDs will be stored.
* It returns:
* 0 on success;
* -EINVAL on bad parameter.
*/
struct dmx_demux {
u32 capabilities; /* Bitfield of capability flags */
struct dmx_frontend* frontend; /* Front-end connected to the demux */
void* priv; /* Pointer to private data of the API client */
int (*open) (struct dmx_demux* demux);
int (*close) (struct dmx_demux* demux);
int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
int (*allocate_ts_feed) (struct dmx_demux* demux,
struct dmx_ts_feed** feed,
dmx_ts_cb callback);
int (*release_ts_feed) (struct dmx_demux* demux,
struct dmx_ts_feed* feed);
int (*allocate_section_feed) (struct dmx_demux* demux,
struct dmx_section_feed** feed,
dmx_section_cb callback);
int (*release_section_feed) (struct dmx_demux* demux,
struct dmx_section_feed* feed);
int (*add_frontend) (struct dmx_demux* demux,
struct dmx_frontend* frontend);
int (*remove_frontend) (struct dmx_demux* demux,
struct dmx_frontend* frontend);
struct list_head* (*get_frontends) (struct dmx_demux* demux);
int (*connect_frontend) (struct dmx_demux* demux,
struct dmx_frontend* frontend);
int (*disconnect_frontend) (struct dmx_demux* demux);
enum dmx_demux_caps capabilities;
struct dmx_frontend *frontend;
void *priv;
int (*open)(struct dmx_demux *demux);
int (*close)(struct dmx_demux *demux);
int (*write)(struct dmx_demux *demux, const char __user *buf,
size_t count);
int (*allocate_ts_feed)(struct dmx_demux *demux,
struct dmx_ts_feed **feed,
dmx_ts_cb callback);
int (*release_ts_feed)(struct dmx_demux *demux,
struct dmx_ts_feed *feed);
int (*allocate_section_feed)(struct dmx_demux *demux,
struct dmx_section_feed **feed,
dmx_section_cb callback);
int (*release_section_feed)(struct dmx_demux *demux,
struct dmx_section_feed *feed);
int (*add_frontend)(struct dmx_demux *demux,
struct dmx_frontend *frontend);
int (*remove_frontend)(struct dmx_demux *demux,
struct dmx_frontend *frontend);
struct list_head *(*get_frontends)(struct dmx_demux *demux);
int (*connect_frontend)(struct dmx_demux *demux,
struct dmx_frontend *frontend);
int (*disconnect_frontend)(struct dmx_demux *demux);
int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids);
int (*get_pes_pids)(struct dmx_demux *demux, u16 *pids);
int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps);
/* private: */
int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src);
int (*get_stc) (struct dmx_demux* demux, unsigned int num,
u64 *stc, unsigned int *base);
/*
* Only used at av7110, to read some data from firmware.
* As this was never documented, we have no clue about what's
* there, and its usage on other drivers aren't encouraged.
*/
int (*get_stc)(struct dmx_demux *demux, unsigned int num,
u64 *stc, unsigned int *base);
};
#endif /* #ifndef __DEMUX_H */

View File

@@ -14,12 +14,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#define pr_fmt(fmt) "dmxdev: " fmt
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -28,7 +26,7 @@
#include <linux/poll.h>
#include <linux/ioctl.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include "dmxdev.h"
static int debug;
@@ -36,7 +34,11 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
#define dprintk if (debug) printk
#define dprintk(fmt, arg...) do { \
if (debug) \
printk(KERN_DEBUG pr_fmt("%s: " fmt), \
__func__, ##arg); \
} while (0)
static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
const u8 *src, size_t len)
@@ -50,7 +52,7 @@ static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
free = dvb_ringbuffer_free(buf);
if (len > free) {
dprintk("dmxdev: buffer overflow\n");
dprintk("buffer overflow\n");
return -EOVERFLOW;
}
@@ -126,7 +128,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
struct dmxdev *dmxdev = dvbdev->priv;
struct dmx_frontend *front;
dprintk("function : %s\n", __func__);
dprintk("%s\n", __func__);
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
@@ -145,6 +147,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
void *mem;
if (!dvbdev->readers) {
mutex_unlock(&dmxdev->mutex);
return -EBUSY;
@@ -196,6 +199,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
dvbdev->readers++;
if (dmxdev->dvr_buffer.data) {
void *mem = dmxdev->dvr_buffer.data;
/*memory barrier*/
mb();
spin_lock_irq(&dmxdev->lock);
dmxdev->dvr_buffer.data = NULL;
@@ -206,8 +210,6 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
/* TODO */
dvbdev->users--;
if (dvbdev->users == 1 && dmxdev->exit == 1) {
fops_put(file->f_op);
file->f_op = NULL;
mutex_unlock(&dmxdev->mutex);
wake_up(&dvbdev->wait_queue);
} else
@@ -260,7 +262,7 @@ static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
void *newmem;
void *oldmem;
dprintk("function : %s\n", __func__);
dprintk("%s\n", __func__);
if (buf->size == size)
return 0;
@@ -327,10 +329,34 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
return 0;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
static void dvb_dmxdev_filter_timeout(struct timer_list *t)
{
struct dmxdev_filter *dmxdevfilter = from_timer(dmxdevfilter, t, timer);
dmxdevfilter->buffer.error = -ETIMEDOUT;
spin_lock_irq(&dmxdevfilter->dev->lock);
dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
spin_unlock_irq(&dmxdevfilter->dev->lock);
wake_up(&dmxdevfilter->buffer.queue);
}
static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
{
struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
del_timer(&dmxdevfilter->timer);
if (para->timeout) {
dmxdevfilter->timer.expires =
jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
add_timer(&dmxdevfilter->timer);
}
}
#else
static void dvb_dmxdev_filter_timeout(unsigned long data)
{
struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
dmxdevfilter->buffer.error = -ETIMEDOUT;
spin_lock_irq(&dmxdevfilter->dev->lock);
dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
@@ -341,7 +367,7 @@ static void dvb_dmxdev_filter_timeout(unsigned long data)
static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
{
struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
del_timer(&dmxdevfilter->timer);
if (para->timeout) {
dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
@@ -351,11 +377,10 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
add_timer(&dmxdevfilter->timer);
}
}
#endif
static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len,
struct dmx_section_filter *filter,
enum dmx_success success)
struct dmx_section_filter *filter)
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
int ret;
@@ -370,7 +395,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
return 0;
}
del_timer(&dmxdevfilter->timer);
dprintk("dmxdev: section callback %*ph\n", 6, buffer1);
dprintk("section callback %*ph\n", 6, buffer1);
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
buffer1_len);
if (ret == buffer1_len) {
@@ -388,8 +413,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len,
struct dmx_ts_feed *feed,
enum dmx_success success)
struct dmx_ts_feed *feed)
{
struct dmxdev_filter *dmxdevfilter = feed->priv;
struct dvb_ringbuffer *buffer;
@@ -560,14 +584,15 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
struct dmxdev_filter *filter,
struct dmxdev_feed *feed)
{
struct timespec timeout = { 0 };
ktime_t timeout;
struct dmx_pes_filter_params *para = &filter->params.pes;
dmx_output_t otype;
enum dmx_output otype;
int ret;
int ts_type;
enum dmx_ts_pes ts_pes;
struct dmx_ts_feed *tsfeed;
timeout = ktime_set(0, 0);
feed->ts = NULL;
otype = para->output;
@@ -593,7 +618,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
tsfeed = feed->ts;
tsfeed->priv = filter;
ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, timeout);
if (ret < 0) {
dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
return ret;
@@ -659,15 +684,15 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
secfeed,
dvb_dmxdev_section_callback);
if (ret < 0) {
printk("DVB (%s): could not alloc feed\n",
pr_err("DVB (%s): could not alloc feed\n",
__func__);
return ret;
}
ret = (*secfeed)->set(*secfeed, para->pid, 32768,
ret = (*secfeed)->set(*secfeed, para->pid,
(para->flags & DMX_CHECK_CRC) ? 1 : 0);
if (ret < 0) {
printk("DVB (%s): could not set feed\n",
pr_err("DVB (%s): could not set feed\n",
__func__);
dvb_dmxdev_feed_restart(filter);
return ret;
@@ -754,7 +779,11 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
timer_setup(&dmxdevfilter->timer, dvb_dmxdev_filter_timeout, 0);
#else
init_timer(&dmxdevfilter->timer);
#endif
dvbdev->users++;
@@ -787,7 +816,7 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
return 0;
}
static inline void invert_mode(dmx_filter_t *filter)
static inline void invert_mode(struct dmx_filter *filter)
{
int i;
@@ -848,7 +877,7 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter,
struct dmx_sct_filter_params *params)
{
dprintk("function : %s, PID=0x%04x, flags=%02x, timeout=%d\n",
dprintk("%s: PID=0x%04x, flags=%02x, timeout=%d\n",
__func__, params->pid, params->flags, params->timeout);
dvb_dmxdev_filter_stop(dmxdevfilter);
@@ -874,7 +903,7 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
dvb_dmxdev_filter_stop(dmxdevfilter);
dvb_dmxdev_filter_reset(dmxdevfilter);
if ((unsigned)params->pes_type > DMX_PES_OTHER)
if ((unsigned int)params->pes_type > DMX_PES_OTHER)
return -EINVAL;
dmxdevfilter->type = DMXDEV_TYPE_PES;
@@ -1025,22 +1054,6 @@ static int dvb_demux_do_ioctl(struct file *file,
dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
break;
case DMX_GET_CAPS:
if (!dmxdev->demux->get_caps) {
ret = -EINVAL;
break;
}
ret = dmxdev->demux->get_caps(dmxdev->demux, parg);
break;
case DMX_SET_SOURCE:
if (!dmxdev->demux->set_source) {
ret = -EINVAL;
break;
}
ret = dmxdev->demux->set_source(dmxdev->demux, parg);
break;
case DMX_GET_STC:
if (!dmxdev->demux->get_stc) {
ret = -EINVAL;
@@ -1089,8 +1102,8 @@ static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
struct dmxdev_filter *dmxdevfilter = file->private_data;
unsigned int mask = 0;
if (!dmxdevfilter)
return -EINVAL;
if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
return POLLERR;
poll_wait(file, &dmxdevfilter->buffer.queue, wait);
@@ -1119,9 +1132,7 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
mutex_lock(&dmxdev->mutex);
dmxdev->dvbdev->users--;
if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
fops_put(file->f_op);
file->f_op = NULL;
if (dmxdev->dvbdev->users == 1 && dmxdev->exit == 1) {
mutex_unlock(&dmxdev->mutex);
wake_up(&dmxdev->dvbdev->wait_queue);
} else
@@ -1140,10 +1151,13 @@ static const struct file_operations dvb_demux_fops = {
.llseek = default_llseek,
};
static struct dvb_device dvbdev_demux = {
static const struct dvb_device dvbdev_demux = {
.priv = NULL,
.users = 1,
.writers = 1,
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
.name = "dvb-demux",
#endif
.fops = &dvb_demux_fops
};
@@ -1183,7 +1197,10 @@ static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
struct dmxdev *dmxdev = dvbdev->priv;
unsigned int mask = 0;
dprintk("function : %s\n", __func__);
dprintk("%s\n", __func__);
if (dmxdev->exit)
return POLLERR;
poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
@@ -1210,13 +1227,15 @@ static const struct file_operations dvb_dvr_fops = {
.llseek = default_llseek,
};
static struct dvb_device dvbdev_dvr = {
static const struct dvb_device dvbdev_dvr = {
.priv = NULL,
.readers = 1,
.users = 1,
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
.name = "dvb-dvr",
#endif
.fops = &dvb_dvr_fops
};
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
{
int i;
@@ -1238,9 +1257,9 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
}
dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
DVB_DEVICE_DEMUX);
DVB_DEVICE_DEMUX, dmxdev->filternum);
dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
dmxdev, DVB_DEVICE_DVR);
dmxdev, DVB_DEVICE_DVR, dmxdev->filternum);
dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
@@ -1251,14 +1270,14 @@ EXPORT_SYMBOL(dvb_dmxdev_init);
void dvb_dmxdev_release(struct dmxdev *dmxdev)
{
dmxdev->exit=1;
dmxdev->exit = 1;
if (dmxdev->dvbdev->users > 1) {
wait_event(dmxdev->dvbdev->wait_queue,
dmxdev->dvbdev->users==1);
dmxdev->dvbdev->users == 1);
}
if (dmxdev->dvr_dvbdev->users > 1) {
wait_event(dmxdev->dvr_dvbdev->wait_queue,
dmxdev->dvr_dvbdev->users==1);
dmxdev->dvr_dvbdev->users == 1);
}
dvb_unregister_device(dmxdev->dvbdev);

View File

@@ -14,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef _DMXDEV_H_

File diff suppressed because it is too large Load Diff

View File

@@ -12,10 +12,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _DVB_CA_EN50221_H_
@@ -37,104 +33,110 @@
#define DVB_CA_EN50221_CAMCHANGE_REMOVED 0
#define DVB_CA_EN50221_CAMCHANGE_INSERTED 1
/* Structure describing a CA interface */
/**
* struct dvb_ca_en50221- Structure describing a CA interface
*
* @owner: the module owning this structure
* @read_attribute_mem: function for reading attribute memory on the CAM
* @write_attribute_mem: function for writing attribute memory on the CAM
* @read_cam_control: function for reading the control interface on the CAM
* @write_cam_control: function for reading the control interface on the CAM
* @read_data: function for reading data (block mode)
* @write_data: function for writing data (block mode)
* @slot_reset: function to reset the CAM slot
* @slot_shutdown: function to shutdown a CAM slot
* @slot_ts_enable: function to enable the Transport Stream on a CAM slot
* @poll_slot_status: function to poll slot status. Only necessary if
* DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set.
* @data: private data, used by caller.
* @private: Opaque data used by the dvb_ca core. Do not modify!
*
* NOTE: the read_*, write_* and poll_slot_status functions will be
* called for different slots concurrently and need to use locks where
* and if appropriate. There will be no concurrent access to one slot.
*/
struct dvb_ca_en50221 {
struct module *owner;
/* the module owning this structure */
struct module* owner;
int (*read_attribute_mem)(struct dvb_ca_en50221 *ca,
int slot, int address);
int (*write_attribute_mem)(struct dvb_ca_en50221 *ca,
int slot, int address, u8 value);
/* NOTE: the read_*, write_* and poll_slot_status functions will be
* called for different slots concurrently and need to use locks where
* and if appropriate. There will be no concurrent access to one slot.
*/
int (*read_cam_control)(struct dvb_ca_en50221 *ca,
int slot, u8 address);
int (*write_cam_control)(struct dvb_ca_en50221 *ca,
int slot, u8 address, u8 value);
/* functions for accessing attribute memory on the CAM */
int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
int (*read_data)(struct dvb_ca_en50221 *ca,
int slot, u8 *ebuf, int ecount);
int (*write_data)(struct dvb_ca_en50221 *ca,
int slot, u8 *ebuf, int ecount);
/* functions for accessing the control interface on the CAM */
int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address);
int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value);
int (*slot_reset)(struct dvb_ca_en50221 *ca, int slot);
int (*slot_shutdown)(struct dvb_ca_en50221 *ca, int slot);
int (*slot_ts_enable)(struct dvb_ca_en50221 *ca, int slot);
/* functions for readin/writing data */
int (*read_data)(struct dvb_ca_en50221* ca, int slot, u8 *ebuf, int ecount);
int (*write_data)(struct dvb_ca_en50221* ca, int slot, u8 *ebuf, int ecount);
int (*poll_slot_status)(struct dvb_ca_en50221 *ca, int slot, int open);
/* Functions for controlling slots */
int (*slot_reset)(struct dvb_ca_en50221* ca, int slot);
int (*slot_shutdown)(struct dvb_ca_en50221* ca, int slot);
int (*slot_ts_enable)(struct dvb_ca_en50221* ca, int slot);
void *data;
/*
* Poll slot status.
* Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
*/
int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open);
/* private data, used by caller */
void* data;
/* Opaque data used by the dvb_ca core. Do not modify! */
void* private;
void *private;
};
/* ******************************************************************************** */
/* Functions for reporting IRQ events */
/**
* A CAMCHANGE IRQ has occurred.
*
* @param ca CA instance.
* @param slot Slot concerned.
* @param change_type One of the DVB_CA_CAMCHANGE_* values
/*
* Functions for reporting IRQ events
*/
void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type);
/**
* A CAMREADY IRQ has occurred.
* dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred.
*
* @param ca CA instance.
* @param slot Slot concerned.
* @pubca: CA instance.
* @slot: Slot concerned.
* @change_type: One of the DVB_CA_CAMCHANGE_* values
*/
void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot);
void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot,
int change_type);
/**
* An FR or a DA IRQ has occurred.
* dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred.
*
* @param ca CA instance.
* @param slot Slot concerned.
* @pubca: CA instance.
* @slot: Slot concerned.
*/
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot);
/* ******************************************************************************** */
/* Initialisation/shutdown functions */
void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot);
/**
* Initialise a new DVB CA device.
* dvb_ca_en50221_frda_irq - An FR or a DA IRQ has occurred.
*
* @param dvb_adapter DVB adapter to attach the new CA device to.
* @param ca The dvb_ca instance.
* @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
* @param slot_count Number of slots supported.
* @ca: CA instance.
* @slot: Slot concerned.
*/
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *ca, int slot);
/*
* Initialisation/shutdown functions
*/
/**
* dvb_ca_en50221_init - Initialise a new DVB CA device.
*
* @dvb_adapter: DVB adapter to attach the new CA device to.
* @ca: The dvb_ca instance.
* @flags: Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
* @slot_count: Number of slots supported.
*
* @return 0 on success, nonzero on failure
*/
extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count);
int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
struct dvb_ca_en50221 *ca, int flags,
int slot_count);
/**
* Release a DVB CA device.
* dvb_ca_en50221_release - Release a DVB CA device.
*
* @param ca The associated dvb_ca instance.
* @ca: The associated dvb_ca instance.
*/
extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca);
void dvb_ca_en50221_release(struct dvb_ca_en50221 *ca);
#endif

View File

@@ -15,13 +15,16 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#define pr_fmt(fmt) "dvb_demux: " fmt
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
#include <linux/sched/signal.h>
#else
#include <linux/sched.h>
#endif
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -29,16 +32,18 @@
#include <linux/poll.h>
#include <linux/string.h>
#include <linux/crc32.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <asm/div64.h>
#include "dvb_demux.h"
#define NOBUFS
/*
** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog
*/
// #define DVB_DEMUX_SECTION_LOSS_LOG
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
static inline s64 ktime_ms_delta(const ktime_t later, const ktime_t earlier)
{
return ktime_to_ms(ktime_sub(later, earlier));
}
#endif
static int dvb_demux_tscheck;
module_param(dvb_demux_tscheck, int, 0644);
@@ -55,10 +60,13 @@ module_param(dvb_demux_feed_err_pkts, int, 0644);
MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
"when set to 0, drop packets with the TEI bit set (1 by default)");
#define dprintk_tscheck(x...) do { \
if (dvb_demux_tscheck && printk_ratelimit()) \
printk(x); \
} while (0)
#define dprintk(fmt, arg...) \
printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg)
#define dprintk_tscheck(x...) do { \
if (dvb_demux_tscheck && printk_ratelimit()) \
dprintk(x); \
} while (0)
/******************************************************************************
* static inlined helper functions
@@ -109,28 +117,30 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
{
int count = payload(buf);
int p;
//int ccok;
//u8 cc;
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
int ccok;
u8 cc;
#endif
if (count == 0)
return -1;
p = 188 - count;
/*
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
cc = buf[3] & 0x0f;
ccok = ((feed->cc + 1) & 0x0f) == cc;
feed->cc = cc;
if (!ccok)
printk("missed packet!\n");
*/
dprintk("missed packet!\n");
#endif
if (buf[1] & 0x40) // PUSI ?
feed->peslen = 0xfffa;
feed->peslen += count;
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts);
}
static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
@@ -152,7 +162,7 @@ static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
return 0;
return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
NULL, 0, &f->filter, DMX_OK);
NULL, 0, &f->filter);
}
static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
@@ -189,7 +199,7 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
{
struct dmx_section_feed *sec = &feed->feed.sec;
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
if (sec->secbufp < sec->tsfeedp) {
int i, n = sec->tsfeedp - sec->secbufp;
@@ -199,12 +209,12 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
* but just first and last.
*/
if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
printk("dvb_demux.c section ts padding loss: %d/%d\n",
dprintk("dvb_demux.c section ts padding loss: %d/%d\n",
n, sec->tsfeedp);
printk("dvb_demux.c pad data:");
dprintk("dvb_demux.c pad data:");
for (i = 0; i < n; i++)
printk(" %02x", sec->secbuf[i]);
printk("\n");
pr_cont(" %02x", sec->secbuf[i]);
pr_cont("\n");
}
}
#endif
@@ -242,8 +252,8 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
return 0;
if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
printk("dvb_demux.c section buffer full loss: %d/%d\n",
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
dprintk("dvb_demux.c section buffer full loss: %d/%d\n",
sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
DMX_MAX_SECFEED_SIZE);
#endif
@@ -276,9 +286,9 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
/* dump [secbuf .. secbuf+seclen) */
if (feed->pusi_seen)
dvb_dmx_swfilter_section_feed(feed);
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
else
printk("dvb_demux.c pusi not seen, discarding section data\n");
dprintk("dvb_demux.c pusi not seen, discarding section data\n");
#endif
sec->secbufp += seclen; /* secbufp and secbuf moving together is */
sec->secbuf += seclen; /* redundant but saves pointer arithmetic */
@@ -312,9 +322,9 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
}
if (!ccok || dc_i) {
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
printk("dvb_demux.c discontinuity detected %d bytes lost\n",
count);
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
dprintk("dvb_demux.c discontinuity detected %d bytes lost\n",
count);
/*
* those bytes under sume circumstances will again be reported
* in the following dvb_dmx_swfilter_section_new
@@ -344,9 +354,10 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
dvb_dmx_swfilter_section_copy_dump(feed, after,
after_len);
}
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
else if (count > 0)
printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
dprintk("dvb_demux.c PUSI=1 but %d bytes lost\n",
count);
#endif
} else {
/* PUSI=0 (is not set), no section boundary */
@@ -367,8 +378,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
if (feed->ts_type & TS_PAYLOAD_ONLY)
dvb_dmx_swfilter_payload(feed, buf);
else
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
DMX_OK);
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
}
if (feed->ts_type & TS_DECODER)
if (feed->demux->write_to_decoder)
@@ -399,31 +409,26 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
int dvr_done = 0;
if (dvb_demux_speedcheck) {
struct timespec cur_time, delta_time;
ktime_t cur_time;
u64 speed_bytes, speed_timedelta;
demux->speed_pkts_cnt++;
/* show speed every SPEED_PKTS_INTERVAL packets */
if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
cur_time = current_kernel_time();
cur_time = ktime_get();
if (demux->speed_last_time.tv_sec != 0 &&
demux->speed_last_time.tv_nsec != 0) {
delta_time = timespec_sub(cur_time,
demux->speed_last_time);
if (ktime_to_ns(demux->speed_last_time) != 0) {
speed_bytes = (u64)demux->speed_pkts_cnt
* 188 * 8;
/* convert to 1024 basis */
speed_bytes = 1000 * div64_u64(speed_bytes,
1024);
speed_timedelta =
(u64)timespec_to_ns(&delta_time);
speed_timedelta = div64_u64(speed_timedelta,
1000000); /* nsec -> usec */
printk(KERN_INFO "TS speed %llu Kbits/sec \n",
div64_u64(speed_bytes,
speed_timedelta));
speed_timedelta = ktime_ms_delta(cur_time,
demux->speed_last_time);
dprintk("TS speed %llu Kbits/sec \n",
div64_u64(speed_bytes,
speed_timedelta));
}
demux->speed_last_time = cur_time;
@@ -432,10 +437,9 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
}
if (buf[1] & 0x80) {
dprintk_tscheck("TEI detected. "
"PID=0x%x data1=0x%x\n",
dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n",
pid, buf[1]);
/* data in this packet cant be trusted - drop it unless
/* data in this packet can't be trusted - drop it unless
* module option dvb_demux_feed_err_pkts is set */
if (!dvb_demux_feed_err_pkts)
return;
@@ -469,14 +473,16 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
if (feed->pid == pid)
dvb_dmx_swfilter_packet_type(feed, buf);
else if (feed->pid == 0x2000)
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
}
}
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
size_t count)
{
spin_lock(&demux->lock);
unsigned long flags;
spin_lock_irqsave(&demux->lock, flags);
while (count--) {
if (buf[0] == 0x47)
@@ -484,7 +490,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
buf += 188;
}
spin_unlock(&demux->lock);
spin_unlock_irqrestore(&demux->lock, flags);
}
EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
@@ -519,8 +525,9 @@ static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
{
int p = 0, i, j;
const u8 *q;
unsigned long flags;
spin_lock(&demux->lock);
spin_lock_irqsave(&demux->lock, flags);
if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
i = demux->tsbufp;
@@ -564,7 +571,7 @@ static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
}
bailout:
spin_unlock(&demux->lock);
spin_unlock_irqrestore(&demux->lock, flags);
}
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
@@ -581,11 +588,13 @@ EXPORT_SYMBOL(dvb_dmx_swfilter_204);
void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
{
spin_lock(&demux->lock);
unsigned long flags;
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
spin_lock_irqsave(&demux->lock, flags);
spin_unlock(&demux->lock);
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts);
spin_unlock_irqrestore(&demux->lock, flags);
}
EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
@@ -636,7 +645,7 @@ static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
{
spin_lock_irq(&feed->demux->lock);
if (dvb_demux_feed_find(feed)) {
printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
pr_err("%s: feed already in list (type=%x state=%x pid=%x)\n",
__func__, feed->type, feed->state, feed->pid);
goto out;
}
@@ -650,7 +659,7 @@ static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
{
spin_lock_irq(&feed->demux->lock);
if (!(dvb_demux_feed_find(feed))) {
printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
pr_err("%s: feed not in list (type=%x state=%x pid=%x)\n",
__func__, feed->type, feed->state, feed->pid);
goto out;
}
@@ -661,8 +670,7 @@ out:
}
static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
enum dmx_ts_pes pes_type,
size_t circular_buffer_size, struct timespec timeout)
enum dmx_ts_pes pes_type, ktime_t timeout)
{
struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
struct dvb_demux *demux = feed->demux;
@@ -692,23 +700,10 @@ static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
dvb_demux_feed_add(feed);
feed->pid = pid;
feed->buffer_size = circular_buffer_size;
feed->timeout = timeout;
feed->ts_type = ts_type;
feed->pes_type = pes_type;
if (feed->buffer_size) {
#ifdef NOBUFS
feed->buffer = NULL;
#else
feed->buffer = vmalloc(feed->buffer_size);
if (!feed->buffer) {
mutex_unlock(&demux->mutex);
return -ENOMEM;
}
#endif
}
feed->state = DMX_STATE_READY;
mutex_unlock(&demux->mutex);
@@ -797,7 +792,6 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
feed->demux = demux;
feed->pid = 0xffff;
feed->peslen = 0xfffa;
feed->buffer = NULL;
(*ts_feed) = &feed->feed.ts;
(*ts_feed)->parent = dmx;
@@ -834,10 +828,6 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
mutex_unlock(&demux->mutex);
return -EINVAL;
}
#ifndef NOBUFS
vfree(feed->buffer);
feed->buffer = NULL;
#endif
feed->state = DMX_STATE_FREE;
feed->filter->state = DMX_STATE_FREE;
@@ -889,8 +879,7 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
}
static int dmx_section_feed_set(struct dmx_section_feed *feed,
u16 pid, size_t circular_buffer_size,
int check_crc)
u16 pid, int check_crc)
{
struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
@@ -904,19 +893,8 @@ static int dmx_section_feed_set(struct dmx_section_feed *feed,
dvb_demux_feed_add(dvbdmxfeed);
dvbdmxfeed->pid = pid;
dvbdmxfeed->buffer_size = circular_buffer_size;
dvbdmxfeed->feed.sec.check_crc = check_crc;
#ifdef NOBUFS
dvbdmxfeed->buffer = NULL;
#else
dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
if (!dvbdmxfeed->buffer) {
mutex_unlock(&dvbdmx->mutex);
return -ENOMEM;
}
#endif
dvbdmxfeed->state = DMX_STATE_READY;
mutex_unlock(&dvbdmx->mutex);
return 0;
@@ -1027,8 +1005,13 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
return -EINVAL;
}
if (feed->is_filtering)
if (feed->is_filtering) {
/* release dvbdmx->mutex as far as it is
acquired by stop_filtering() itself */
mutex_unlock(&dvbdmx->mutex);
feed->stop_filtering(feed);
mutex_lock(&dvbdmx->mutex);
}
spin_lock_irq(&dvbdmx->lock);
f = dvbdmxfeed->filter;
@@ -1070,7 +1053,6 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
dvbdmxfeed->feed.sec.tsfeedp = 0;
dvbdmxfeed->filter = NULL;
dvbdmxfeed->buffer = NULL;
(*feed) = &dvbdmxfeed->feed.sec;
(*feed)->is_filtering = 0;
@@ -1099,10 +1081,6 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux,
mutex_unlock(&dvbdmx->mutex);
return -EINVAL;
}
#ifndef NOBUFS
vfree(dvbdmxfeed->buffer);
dvbdmxfeed->buffer = NULL;
#endif
dvbdmxfeed->state = DMX_STATE_FREE;
dvb_demux_feed_del(dvbdmxfeed);
@@ -1264,7 +1242,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
if (!dvbdemux->cnt_storage)
printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
pr_warn("Couldn't allocate memory for TS/TEI check. Disabling it\n");
INIT_LIST_HEAD(&dvbdemux->frontend_list);

View File

@@ -14,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef _DVB_DEMUX_H_
@@ -80,10 +76,8 @@ struct dvb_demux_feed {
int type;
int state;
u16 pid;
u8 *buffer;
int buffer_size;
struct timespec timeout;
ktime_t timeout;
struct dvb_demux_filter *filter;
int ts_type;
@@ -134,7 +128,7 @@ struct dvb_demux {
uint8_t *cnt_storage; /* for TS continuity check */
struct timespec speed_last_time; /* for TS speed check */
ktime_t speed_last_time; /* for TS speed check */
uint32_t speed_pkts_cnt; /* for TS speed check */
};

View File

@@ -18,19 +18,23 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
* To obtain the license, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
/* Enables DVBv3 compatibility bits at the headers */
#define __DVB_CORE__
#define pr_fmt(fmt) "dvb_frontend: " fmt
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
#include <linux/sched/signal.h>
#else
#include <linux/sched.h>
#endif
#include <linux/wait.h>
#include <linux/slab.h>
#include <linux/poll.h>
@@ -40,6 +44,7 @@
#include <linux/freezer.h>
#include <linux/jiffies.h>
#include <linux/kthread.h>
#include <linux/ktime.h>
#include <asm/processor.h>
#include "dvb_frontend.h"
@@ -66,6 +71,9 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volt
module_param(dvb_mfe_wait_time, int, 0644);
MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
#define dprintk(fmt, arg...) \
printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg)
#define FESTATE_IDLE 1
#define FESTATE_RETUNE 2
#define FESTATE_TUNING_FAST 4
@@ -80,7 +88,6 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open(
#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
#define FE_ALGO_HW 1
/*
* FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
* FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
@@ -96,14 +103,9 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open(
* FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
*/
#define DVB_FE_NO_EXIT 0
#define DVB_FE_NORMAL_EXIT 1
#define DVB_FE_DEVICE_REMOVED 2
static DEFINE_MUTEX(frontend_mutex);
struct dvb_frontend_private {
/* thread/frontend values */
struct dvb_device *dvbdev;
struct dvb_frontend_parameters parameters_out;
@@ -113,9 +115,8 @@ struct dvb_frontend_private {
wait_queue_head_t wait_queue;
struct task_struct *thread;
unsigned long release_jiffies;
unsigned int exit;
unsigned int wakeup;
fe_status_t status;
enum fe_status status;
unsigned long tune_mode_flags;
unsigned int delay;
unsigned int reinitialise;
@@ -136,13 +137,46 @@ struct dvb_frontend_private {
int quality;
unsigned int check_wrapped;
enum dvbfe_search algo_status;
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
struct media_pipeline pipe;
#endif
};
static void dvb_frontend_invoke_release(struct dvb_frontend *fe,
void (*release)(struct dvb_frontend *fe));
static void dvb_frontend_free(struct kref *ref)
{
struct dvb_frontend *fe =
container_of(ref, struct dvb_frontend, refcount);
struct dvb_frontend_private *fepriv = fe->frontend_priv;
dvb_free_device(fepriv->dvbdev);
dvb_frontend_invoke_release(fe, fe->ops.release);
kfree(fepriv);
}
static void dvb_frontend_put(struct dvb_frontend *fe)
{
kref_put(&fe->refcount, dvb_frontend_free);
}
static void dvb_frontend_get(struct dvb_frontend *fe)
{
kref_get(&fe->refcount);
}
static void dvb_frontend_wakeup(struct dvb_frontend *fe);
static int dtv_get_frontend(struct dvb_frontend *fe,
struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p_out);
static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p);
static int
dtv_property_legacy_params_sync(struct dvb_frontend *fe,
const struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p);
static bool has_get_frontend(struct dvb_frontend *fe)
{
@@ -178,6 +212,7 @@ static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
case SYS_DVBT2:
case SYS_ISDBT:
case SYS_DTMB:
case SYS_DVBC2:
return DVBV3_OFDM;
case SYS_ATSC:
case SYS_ATSCMH:
@@ -198,9 +233,11 @@ static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
}
}
static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
static void dvb_frontend_add_event(struct dvb_frontend *fe,
enum fe_status status)
{
struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_fe_events *events = &fepriv->events;
struct dvb_frontend_event *e;
int wp;
@@ -208,7 +245,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
dev_dbg(fe->dvb->device, "%s:\n", __func__);
if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
dtv_get_frontend(fe, &fepriv->parameters_out);
dtv_get_frontend(fe, c, &fepriv->parameters_out);
mutex_lock(&events->mtx);
@@ -429,7 +466,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
{
fe_status_t s = 0;
enum fe_status s = FE_NONE;
int retval = 0;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
@@ -565,7 +602,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
{
struct dvb_frontend_private *fepriv = fe->frontend_priv;
if (fepriv->exit != DVB_FE_NO_EXIT)
if (fe->exit != DVB_FE_NO_EXIT)
return 1;
if (fepriv->dvbdev->writers == 1)
@@ -598,10 +635,10 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
static int dvb_frontend_thread(void *data)
{
struct dvb_frontend *fe = data;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
fe_status_t s;
enum fe_status s = FE_NONE;
enum dvbfe_algo algo;
bool re_tune = false;
bool semheld = false;
@@ -629,7 +666,7 @@ restart:
/* got signal or quitting */
if (!down_interruptible(&fepriv->sem))
semheld = true;
fepriv->exit = DVB_FE_NORMAL_EXIT;
fe->exit = DVB_FE_NORMAL_EXIT;
break;
}
@@ -701,7 +738,7 @@ restart:
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
fepriv->delay = HZ / 2;
}
dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
dtv_property_legacy_params_sync(fe, c, &fepriv->parameters_out);
fe->ops.read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s); /* update event list */
@@ -739,9 +776,9 @@ restart:
fepriv->thread = NULL;
if (kthread_should_stop())
fepriv->exit = DVB_FE_DEVICE_REMOVED;
fe->exit = DVB_FE_DEVICE_REMOVED;
else
fepriv->exit = DVB_FE_NO_EXIT;
fe->exit = DVB_FE_NO_EXIT;
mb();
if (semheld)
@@ -756,7 +793,8 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s:\n", __func__);
fepriv->exit = DVB_FE_NORMAL_EXIT;
if (fe->exit != DVB_FE_DEVICE_REMOVED)
fe->exit = DVB_FE_NORMAL_EXIT;
mb();
if (!fepriv->thread)
@@ -774,43 +812,22 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
fepriv->thread);
}
s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
{
return ((curtime.tv_usec < lasttime.tv_usec) ?
1000000 - lasttime.tv_usec + curtime.tv_usec :
curtime.tv_usec - lasttime.tv_usec);
}
EXPORT_SYMBOL(timeval_usec_diff);
static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
{
curtime->tv_usec += add_usec;
if (curtime->tv_usec >= 1000000) {
curtime->tv_usec -= 1000000;
curtime->tv_sec++;
}
}
/*
* Sleep until gettimeofday() > waketime + add_usec
* This needs to be as precise as possible, but as the delay is
* usually between 2ms and 32ms, it is done using a scheduled msleep
* followed by usleep (normally a busy-wait loop) for the remainder
* Sleep for the amount of time given by add_usec parameter
*
* This needs to be as precise as possible, as it affects the detection of
* the dish tone command at the satellite subsystem. The precision is improved
* by using a scheduled msleep followed by udelay for the remainder.
*/
void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec)
{
struct timeval lasttime;
s32 delta, newdelta;
s32 delta;
timeval_usec_add(waketime, add_usec);
do_gettimeofday(&lasttime);
delta = timeval_usec_diff(lasttime, *waketime);
*waketime = ktime_add_us(*waketime, add_usec);
delta = ktime_us_delta(ktime_get_boottime(), *waketime);
if (delta > 2500) {
msleep((delta - 1500) / 1000);
do_gettimeofday(&lasttime);
newdelta = timeval_usec_diff(lasttime, *waketime);
delta = (newdelta > delta) ? 0 : newdelta;
delta = ktime_us_delta(ktime_get_boottime(), *waketime);
}
if (delta > 0)
udelay(delta);
@@ -826,7 +843,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s:\n", __func__);
if (fepriv->thread) {
if (fepriv->exit == DVB_FE_NO_EXIT)
if (fe->exit == DVB_FE_NO_EXIT)
return 0;
else
dvb_frontend_stop (fe);
@@ -838,7 +855,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
return -EINTR;
fepriv->state = FESTATE_IDLE;
fepriv->exit = DVB_FE_NO_EXIT;
fe->exit = DVB_FE_NO_EXIT;
fepriv->thread = NULL;
mb();
@@ -955,7 +972,8 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
}
c->stream_id = NO_STREAM_ID_FILTER;
c->pls = NO_SCRAMBLING_CODE;
c->scrambling_sequence_index = 0;/* default sequence */
c->input = NO_INPUT;
switch (c->delivery_system) {
case SYS_DVBS:
@@ -967,6 +985,11 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
case SYS_ATSC:
c->modulation = VSB_8;
break;
case SYS_ISDBS:
c->symbol_rate = 28860000;
c->rolloff = ROLLOFF_35;
c->bandwidth_hz = c->symbol_rate / 100 * 135;
break;
default:
c->modulation = QAM_AUTO;
break;
@@ -985,6 +1008,17 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
.buffer = b \
}
struct dtv_cmds_h {
char *name; /* A display name for debugging purposes */
__u32 cmd; /* A unique ID */
/* Flags */
__u32 set:1; /* Either a set or get property */
__u32 buffer:1; /* Does this property use the buffer? */
__u32 reserved:30; /* Align */
};
static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
_DTV_CMD(DTV_TUNE, 1, 0),
_DTV_CMD(DTV_CLEAR, 1, 0),
@@ -1030,9 +1064,9 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
_DTV_CMD(DTV_STREAM_ID, 1, 0),
_DTV_CMD(DTV_DVBT2_PLP_ID_LEGACY, 1, 0),
_DTV_CMD(DTV_SCRAMBLING_SEQUENCE_INDEX, 1, 0),
_DTV_CMD(DTV_LNA, 1, 0),
_DTV_CMD(DTV_INPUT, 1, 0),
_DTV_CMD(DTV_PLS, 1, 0),
/* Get */
_DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
@@ -1068,18 +1102,24 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
_DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0),
};
static void dtv_property_dump(struct dvb_frontend *fe, struct dtv_property *tvp)
static void dtv_property_dump(struct dvb_frontend *fe,
bool is_set,
struct dtv_property *tvp)
{
int i;
if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
dev_warn(fe->dvb->device, "%s: tvp.cmd = 0x%08x undefined\n",
__func__, tvp->cmd);
dev_warn(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x undefined\n",
__func__,
is_set ? "SET" : "GET",
tvp->cmd);
return;
}
dev_dbg(fe->dvb->device, "%s: tvp.cmd = 0x%08x (%s)\n", __func__,
tvp->cmd, dtv_cmds[tvp->cmd].name);
dev_dbg(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x (%s)\n", __func__,
is_set ? "SET" : "GET",
tvp->cmd,
dtv_cmds[tvp->cmd].name);
if (dtv_cmds[tvp->cmd].buffer) {
dev_dbg(fe->dvb->device, "%s: tvp.u.buffer.len = 0x%02x\n",
@@ -1174,11 +1214,11 @@ static int dtv_property_cache_sync(struct dvb_frontend *fe,
/* Ensure the cached values are set correctly in the frontend
* legacy tuning structures, for the advanced tuning API.
*/
static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
static int
dtv_property_legacy_params_sync(struct dvb_frontend *fe,
const struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p)
{
const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
p->frequency = c->frequency;
p->inversion = c->inversion;
@@ -1250,16 +1290,17 @@ static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
* If p_out is not null, it will update the DVBv3 params pointed by it.
*/
static int dtv_get_frontend(struct dvb_frontend *fe,
struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p_out)
{
int r;
if (fe->ops.get_frontend) {
r = fe->ops.get_frontend(fe);
r = fe->ops.get_frontend(fe, c);
if (unlikely(r < 0))
return r;
if (p_out)
dtv_property_legacy_params_sync(fe, p_out);
dtv_property_legacy_params_sync(fe, c, p_out);
return 0;
}
@@ -1282,7 +1323,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
switch(tvp->cmd) {
case DTV_ENUM_DELSYS:
ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps];
ncaps++;
}
@@ -1464,8 +1505,9 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
tvp->u.buffer.len = 4;
break;
case DTV_PLS:
tvp->u.data = c->pls;
/* Physical layer scrambling support */
case DTV_SCRAMBLING_SEQUENCE_INDEX:
tvp->u.data = c->scrambling_sequence_index;
break;
/* Fill quality measures */
@@ -1507,7 +1549,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
return r;
}
dtv_property_dump(fe, tvp);
dtv_property_dump(fe, false, tvp);
return 0;
}
@@ -1516,12 +1558,8 @@ static int dtv_set_frontend(struct dvb_frontend *fe);
static bool is_dvbv3_delsys(u32 delsys)
{
bool status;
status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
(delsys == SYS_DVBS) || (delsys == SYS_ATSC);
return status;
return (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
(delsys == SYS_DVBS) || (delsys == SYS_ATSC);
}
/**
@@ -1611,7 +1649,7 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
* supported
*/
ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
if (fe->ops.delsys[ncaps] == desired_system) {
c->delivery_system = desired_system;
dev_dbg(fe->dvb->device,
@@ -1643,7 +1681,7 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
* of the desired system
*/
ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
if (dvbv3_type(fe->ops.delsys[ncaps]) == type)
delsys = fe->ops.delsys[ncaps];
ncaps++;
@@ -1718,7 +1756,7 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
* DVBv3 standard
*/
ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
if (dvbv3_type(fe->ops.delsys[ncaps]) != DVBV3_UNKNOWN) {
delsys = fe->ops.delsys[ncaps];
break;
@@ -1748,6 +1786,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
return r;
}
dtv_property_dump(fe, true, tvp);
switch(tvp->cmd) {
case DTV_CLEAR:
/*
@@ -1897,9 +1937,9 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
c->lna = tvp->u.data;
if (fe->ops.set_lna)
r = fe->ops.set_lna(fe);
if (r < 0)
c->lna = LNA_AUTO;
break;
if (r < 0)
c->lna = LNA_AUTO;
break;
case DTV_INPUT:
c->input = tvp->u.data;
@@ -1907,10 +1947,11 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
r = fe->ops.set_input(fe, c->input);
break;
case DTV_PLS:
c->pls = tvp->u.data;
/* Physical layer scrambling support */
case DTV_SCRAMBLING_SEQUENCE_INDEX:
c->scrambling_sequence_index = tvp->u.data;
break;
default:
return -EINVAL;
}
@@ -1931,7 +1972,7 @@ static int dvb_frontend_ioctl(struct file *file,
if (down_interruptible(&fepriv->sem))
return -ERESTARTSYS;
if (fepriv->exit != DVB_FE_NO_EXIT) {
if (fe->exit != DVB_FE_NO_EXIT) {
up(&fepriv->sem);
return -ENODEV;
}
@@ -1963,15 +2004,13 @@ static int dvb_frontend_ioctl_properties(struct file *file,
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int err = 0;
struct dtv_properties *tvps = NULL;
struct dtv_properties *tvps = parg;
struct dtv_property *tvp = NULL;
int i;
dev_dbg(fe->dvb->device, "%s:\n", __func__);
if(cmd == FE_SET_PROPERTY) {
tvps = (struct dtv_properties __user *)parg;
if (cmd == FE_SET_PROPERTY) {
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
@@ -1980,16 +2019,9 @@ static int dvb_frontend_ioctl_properties(struct file *file,
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
if (!tvp) {
err = -ENOMEM;
goto out;
}
if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
err = -EFAULT;
goto out;
}
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
for (i = 0; i < tvps->num; i++) {
err = dtv_property_process_set(fe, tvp + i, file);
@@ -2001,9 +2033,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
if (c->state == DTV_TUNE)
dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__);
} else
if(cmd == FE_GET_PROPERTY) {
tvps = (struct dtv_properties __user *)parg;
} else if (cmd == FE_GET_PROPERTY) {
struct dtv_frontend_properties getp = fe->dtv_property_cache;
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
@@ -2013,35 +2044,30 @@ static int dvb_frontend_ioctl_properties(struct file *file,
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
if (!tvp) {
err = -ENOMEM;
goto out;
}
if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
err = -EFAULT;
goto out;
}
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
/*
* Fills the cache out struct with the cache contents, plus
* the data retrieved from get_frontend, if the frontend
* is not idle. Otherwise, returns the cached content
* Let's use our own copy of property cache, in order to
* avoid mangling with DTV zigzag logic, as drivers might
* return crap, if they don't check if the data is available
* before updating the properties cache.
*/
if (fepriv->state != FESTATE_IDLE) {
err = dtv_get_frontend(fe, NULL);
err = dtv_get_frontend(fe, &getp, NULL);
if (err < 0)
goto out;
}
for (i = 0; i < tvps->num; i++) {
err = dtv_property_process_get(fe, c, tvp + i, file);
err = dtv_property_process_get(fe, &getp, tvp + i, file);
if (err < 0)
goto out;
(tvp + i)->result = err;
}
if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
if (copy_to_user((void __user *)tvps->props, tvp,
tvps->num * sizeof(struct dtv_property))) {
err = -EFAULT;
goto out;
}
@@ -2069,7 +2095,7 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
* the user. FE_SET_FRONTEND triggers an initial frontend event
* with status = 0, which copies output parameters to userspace.
*/
dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
dtv_property_legacy_params_sync(fe, c, &fepriv->parameters_out);
/*
* Be sure that the bandwidth will be filled for all
@@ -2101,11 +2127,29 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
case SYS_DVBC_ANNEX_C:
rolloff = 113;
break;
case SYS_DVBS:
case SYS_TURBO:
case SYS_ISDBS:
rolloff = 135;
break;
case SYS_DVBS2:
switch (c->rolloff) {
case ROLLOFF_20:
rolloff = 120;
break;
case ROLLOFF_25:
rolloff = 125;
break;
default:
case ROLLOFF_35:
rolloff = 135;
}
break;
default:
break;
}
if (rolloff)
c->bandwidth_hz = (c->symbol_rate * rolloff) / 100;
c->bandwidth_hz = mult_frac(c->symbol_rate, rolloff, 100);
/* force auto frequency inversion if requested */
if (dvb_force_auto_inversion)
@@ -2222,15 +2266,15 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n",
__func__, c->delivery_system, fe->ops.info.type);
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
* do it, it is done for it. */
info->caps |= FE_CAN_INVERSION_AUTO;
/* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */
if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT))
info->caps |= FE_CAN_INVERSION_AUTO;
err = 0;
break;
}
case FE_READ_STATUS: {
fe_status_t* status = parg;
enum fe_status *status = parg;
/* if retune was requested but hasn't occurred yet, prevent
* that user get signal state from previous tuning */
@@ -2292,7 +2336,13 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_DISEQC_SEND_MASTER_CMD:
if (fe->ops.diseqc_send_master_cmd) {
err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
struct dvb_diseqc_master_cmd *cmd = parg;
if (cmd->msg_len > sizeof(cmd->msg)) {
err = -EINVAL;
break;
}
err = fe->ops.diseqc_send_master_cmd(fe, cmd);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -2300,7 +2350,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_DISEQC_SEND_BURST:
if (fe->ops.diseqc_send_burst) {
err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
err = fe->ops.diseqc_send_burst(fe,
(enum fe_sec_mini_cmd)parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -2308,8 +2359,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_SET_TONE:
if (fe->ops.set_tone) {
err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
fepriv->tone = (fe_sec_tone_mode_t) parg;
err = fe->ops.set_tone(fe,
(enum fe_sec_tone_mode)parg);
fepriv->tone = (enum fe_sec_tone_mode)parg;
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -2317,8 +2369,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_SET_VOLTAGE:
if (fe->ops.set_voltage) {
err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
fepriv->voltage = (fe_sec_voltage_t) parg;
err = fe->ops.set_voltage(fe,
(enum fe_sec_voltage)parg);
fepriv->voltage = (enum fe_sec_voltage)parg;
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -2326,7 +2379,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_DISHNETWORK_SEND_LEGACY_CMD:
if (fe->ops.dishnetwork_send_legacy_command) {
err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
err = fe->ops.dishnetwork_send_legacy_command(fe,
(unsigned long)parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
} else if (fe->ops.set_voltage) {
@@ -2347,13 +2401,14 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
* include the initialization or start bit
*/
unsigned long swcmd = ((unsigned long) parg) << 1;
struct timeval nexttime;
struct timeval tv[10];
ktime_t nexttime;
ktime_t tv[10];
int i;
u8 last = 1;
if (dvb_frontend_debug)
printk("%s switch command: 0x%04lx\n", __func__, swcmd);
do_gettimeofday(&nexttime);
dprintk("%s switch command: 0x%04lx\n",
__func__, swcmd);
nexttime = ktime_get_boottime();
if (dvb_frontend_debug)
tv[0] = nexttime;
/* before sending a command, initialize by sending
@@ -2364,7 +2419,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
for (i = 0; i < 9; i++) {
if (dvb_frontend_debug)
do_gettimeofday(&tv[i + 1]);
tv[i+1] = ktime_get_boottime();
if ((swcmd & 0x01) != last) {
/* set voltage to (last ? 13V : 18V) */
fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
@@ -2375,10 +2430,11 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
dvb_frontend_sleep_until(&nexttime, 8000);
}
if (dvb_frontend_debug) {
printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
dprintk("%s(%d): switch delay (should be 32k followed by all 8k)\n",
__func__, fe->dvb->num);
for (i = 1; i < 10; i++)
printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
pr_info("%d: %d\n", i,
(int) ktime_us_delta(tv[i], tv[i-1]));
}
err = 0;
fepriv->state = FESTATE_DISEQC;
@@ -2410,10 +2466,18 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
err = dvb_frontend_get_event (fe, parg, file->f_flags);
break;
case FE_GET_FRONTEND:
err = dtv_get_frontend(fe, parg);
break;
case FE_GET_FRONTEND: {
struct dtv_frontend_properties getp = fe->dtv_property_cache;
/*
* Let's use our own copy of property cache, in order to
* avoid mangling with DTV zigzag logic, as drivers might
* return crap, if they don't check if the data is available
* before updating the properties cache.
*/
err = dtv_get_frontend(fe, &getp, parg);
break;
}
case FE_SET_FRONTEND_TUNE_MODE:
fepriv->tune_mode_flags = (unsigned long) parg;
err = 0;
@@ -2430,7 +2494,7 @@ static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struc
struct dvb_frontend *fe = dvbdev->priv;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
//dev_dbg_ratelimited(fe->dvb->device, "%s:\n", __func__);
dev_dbg_ratelimited(fe->dvb->device, "%s:\n", __func__);
poll_wait (file, &fepriv->events.wait_queue, wait);
@@ -2449,7 +2513,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
int ret;
dev_dbg(fe->dvb->device, "%s:\n", __func__);
if (fepriv->exit == DVB_FE_DEVICE_REMOVED)
if (fe->exit == DVB_FE_DEVICE_REMOVED)
return -ENODEV;
if (adapter->mfe_shared) {
@@ -2513,19 +2577,45 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
fepriv->tone = -1;
fepriv->voltage = -1;
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
if (fe->dvb->mdev) {
mutex_lock(&fe->dvb->mdev->graph_mutex);
if (fe->dvb->mdev->enable_source)
ret = fe->dvb->mdev->enable_source(
dvbdev->entity,
&fepriv->pipe);
mutex_unlock(&fe->dvb->mdev->graph_mutex);
if (ret) {
dev_err(fe->dvb->device,
"Tuner is busy. Error %d\n", ret);
goto err2;
}
}
#endif
ret = dvb_frontend_start (fe);
if (ret)
goto err2;
goto err3;
/* empty event queue */
fepriv->events.eventr = fepriv->events.eventw = 0;
}
dvb_frontend_get(fe);
if (adapter->mfe_shared)
mutex_unlock (&adapter->mfe_lock);
return ret;
err3:
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
if (fe->dvb->mdev) {
mutex_lock(&fe->dvb->mdev->graph_mutex);
if (fe->dvb->mdev->disable_source)
fe->dvb->mdev->disable_source(dvbdev->entity);
mutex_unlock(&fe->dvb->mdev->graph_mutex);
}
err2:
#endif
dvb_generic_release(inode, file);
err1:
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
@@ -2554,12 +2644,22 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
if (dvbdev->users == -1) {
wake_up(&fepriv->wait_queue);
if (fepriv->exit != DVB_FE_NO_EXIT)
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
if (fe->dvb->mdev) {
mutex_lock(&fe->dvb->mdev->graph_mutex);
if (fe->dvb->mdev->disable_source)
fe->dvb->mdev->disable_source(dvbdev->entity);
mutex_unlock(&fe->dvb->mdev->graph_mutex);
}
#endif
if (fe->exit != DVB_FE_NO_EXIT)
wake_up(&dvbdev->wait_queue);
if (fe->ops.ts_bus_ctrl)
fe->ops.ts_bus_ctrl(fe, 0);
}
dvb_frontend_put(fe);
return ret;
}
@@ -2579,7 +2679,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
fe->id);
if (fe->ops.tuner_ops.sleep)
if (fe->ops.tuner_ops.suspend)
ret = fe->ops.tuner_ops.suspend(fe);
else if (fe->ops.tuner_ops.sleep)
ret = fe->ops.tuner_ops.sleep(fe);
if (fe->ops.sleep)
@@ -2597,12 +2699,21 @@ int dvb_frontend_resume(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
fe->id);
fe->exit = DVB_FE_DEVICE_RESUME;
if (fe->ops.init)
ret = fe->ops.init(fe);
if (fe->ops.tuner_ops.init)
if (fe->ops.tuner_ops.resume)
ret = fe->ops.tuner_ops.resume(fe);
else if (fe->ops.tuner_ops.init)
ret = fe->ops.tuner_ops.init(fe);
if (fe->ops.set_tone && fepriv->tone != -1)
fe->ops.set_tone(fe, fepriv->tone);
if (fe->ops.set_voltage && fepriv->voltage != -1)
fe->ops.set_voltage(fe, fepriv->voltage);
fe->exit = DVB_FE_NO_EXIT;
fepriv->state = FESTATE_RETUNE;
dvb_frontend_wakeup(fe);
@@ -2614,11 +2725,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
struct dvb_frontend* fe)
{
struct dvb_frontend_private *fepriv;
static const struct dvb_device dvbdev_template = {
const struct dvb_device dvbdev_template = {
.users = ~0,
.writers = 1,
.readers = (~0)-1,
.fops = &dvb_frontend_fops,
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
.name = fe->ops.info.name,
#endif
.kernel_ioctl = dvb_frontend_ioctl
};
@@ -2634,6 +2748,15 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
}
fepriv = fe->frontend_priv;
kref_init(&fe->refcount);
/*
* After initialization, there need to be two references: one
* for dvb_unregister_frontend(), and another one for
* dvb_frontend_detach().
*/
dvb_frontend_get(fe);
sema_init(&fepriv->sem, 1);
init_waitqueue_head (&fepriv->wait_queue);
init_waitqueue_head (&fepriv->events.wait_queue);
@@ -2642,7 +2765,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
fepriv->inversion = INVERSION_OFF;
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND);
fe, DVB_DEVICE_FRONTEND, 0);
dev_info(fe->dvb->device,
"DVB: registering adapter %i frontend %i (%s)...\n",
@@ -2667,57 +2790,33 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
dev_dbg(fe->dvb->device, "%s:\n", __func__);
mutex_lock(&frontend_mutex);
dvb_frontend_stop (fe);
mutex_unlock(&frontend_mutex);
if (fepriv->dvbdev->users < -1)
wait_event(fepriv->dvbdev->wait_queue,
fepriv->dvbdev->users==-1);
mutex_lock(&frontend_mutex);
dvb_unregister_device (fepriv->dvbdev);
dvb_frontend_stop(fe);
dvb_remove_device(fepriv->dvbdev);
/* fe is invalid now */
kfree(fepriv);
mutex_unlock(&frontend_mutex);
dvb_frontend_put(fe);
return 0;
}
EXPORT_SYMBOL(dvb_unregister_frontend);
static void dvb_frontend_invoke_release(struct dvb_frontend *fe,
void (*release)(struct dvb_frontend *fe))
{
if (release) {
release(fe);
#ifdef CONFIG_MEDIA_ATTACH
void dvb_frontend_detach(struct dvb_frontend* fe)
{
void *ptr;
if (fe->ops.release_sec) {
fe->ops.release_sec(fe);
symbol_put_addr(fe->ops.release_sec);
}
if (fe->ops.tuner_ops.release) {
fe->ops.tuner_ops.release(fe);
symbol_put_addr(fe->ops.tuner_ops.release);
}
if (fe->ops.analog_ops.release) {
fe->ops.analog_ops.release(fe);
symbol_put_addr(fe->ops.analog_ops.release);
}
ptr = (void*)fe->ops.release;
if (ptr) {
fe->ops.release(fe);
symbol_put_addr(ptr);
}
}
#else
void dvb_frontend_detach(struct dvb_frontend* fe)
{
if (fe->ops.release_sec)
fe->ops.release_sec(fe);
if (fe->ops.tuner_ops.release)
fe->ops.tuner_ops.release(fe);
if (fe->ops.analog_ops.release)
fe->ops.analog_ops.release(fe);
if (fe->ops.release)
fe->ops.release(fe);
}
dvb_detach(release);
#endif
}
}
void dvb_frontend_detach(struct dvb_frontend* fe)
{
dvb_frontend_invoke_release(fe, fe->ops.release_sec);
dvb_frontend_invoke_release(fe, fe->ops.tuner_ops.release);
dvb_frontend_invoke_release(fe, fe->ops.analog_ops.release);
dvb_frontend_invoke_release(fe, fe->ops.detach);
dvb_frontend_put(fe);
}
EXPORT_SYMBOL(dvb_frontend_detach);

View File

@@ -1,6 +1,10 @@
/*
* dvb_frontend.h
*
* The Digital TV Frontend kABI defines a driver-internal interface for
* registering low-level, hardware specific driver to a hardware independent
* frontend layer.
*
* Copyright (C) 2001 convergence integrated media GmbH
* Copyright (C) 2004 convergence GmbH
*
@@ -29,7 +33,12 @@
#define _DVB_FRONTEND_H_
#include <linux/types.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
#include <linux/sched/signal.h>
#else
#include <linux/sched.h>
#endif
#include <linux/ioctl.h>
#include <linux/i2c.h>
#include <linux/module.h>
@@ -48,6 +57,15 @@
*/
#define MAX_DELSYS 8
/**
* struct dvb_frontend_tune_settings - parameters to adjust frontend tuning
*
* @min_delay_ms: minimum delay for tuning, in ms
* @step_size: step size between two consecutive frequencies
* @max_drift: maximum drift
*
* NOTE: step_size is in Hz, for terrestrial/cable or kHz for satellite
*/
struct dvb_frontend_tune_settings {
int min_delay_ms;
int step_size;
@@ -56,6 +74,20 @@ struct dvb_frontend_tune_settings {
struct dvb_frontend;
/**
* struct dvb_tuner_info - Frontend name and min/max ranges/bandwidths
*
* @name: name of the Frontend
* @frequency_min: minimal frequency supported
* @frequency_max: maximum frequency supported
* @frequency_step: frequency step
* @bandwidth_min: minimal frontend bandwidth supported
* @bandwidth_max: maximum frontend bandwidth supported
* @bandwidth_step: frontend bandwidth step
*
* NOTE: frequency parameters are in Hz, for terrestrial/cable or kHz for
* satellite.
*/
struct dvb_tuner_info {
char name[128];
@@ -68,6 +100,20 @@ struct dvb_tuner_info {
u32 bandwidth_step;
};
/**
* struct analog_parameters - Parameters to tune into an analog/radio channel
*
* @frequency: Frequency used by analog TV tuner (either in 62.5 kHz step,
* for TV, or 62.5 Hz for radio)
* @mode: Tuner mode, as defined on enum v4l2_tuner_type
* @audmode: Audio mode as defined for the rxsubchans field at videodev2.h,
* e. g. V4L2_TUNER_MODE_*
* @std: TV standard bitmap as defined at videodev2.h, e. g. V4L2_STD_*
*
* Hybrid tuners should be supported by both V4L2 and DVB APIs. This
* struct contains the data that are used by the V4L2 side. To avoid
* dependencies from V4L2 headers, all enums here are declared as integers.
*/
struct analog_parameters {
unsigned int frequency;
unsigned int mode;
@@ -75,76 +121,28 @@ struct analog_parameters {
u64 std;
};
enum dvbfe_modcod {
DVBFE_MODCOD_DUMMY_PLFRAME = 0,
DVBFE_MODCOD_QPSK_1_4,
DVBFE_MODCOD_QPSK_1_3,
DVBFE_MODCOD_QPSK_2_5,
DVBFE_MODCOD_QPSK_1_2,
DVBFE_MODCOD_QPSK_3_5,
DVBFE_MODCOD_QPSK_2_3,
DVBFE_MODCOD_QPSK_3_4,
DVBFE_MODCOD_QPSK_4_5,
DVBFE_MODCOD_QPSK_5_6,
DVBFE_MODCOD_QPSK_8_9,
DVBFE_MODCOD_QPSK_9_10,
DVBFE_MODCOD_8PSK_3_5,
DVBFE_MODCOD_8PSK_2_3,
DVBFE_MODCOD_8PSK_3_4,
DVBFE_MODCOD_8PSK_5_6,
DVBFE_MODCOD_8PSK_8_9,
DVBFE_MODCOD_8PSK_9_10,
DVBFE_MODCOD_16APSK_2_3,
DVBFE_MODCOD_16APSK_3_4,
DVBFE_MODCOD_16APSK_4_5,
DVBFE_MODCOD_16APSK_5_6,
DVBFE_MODCOD_16APSK_8_9,
DVBFE_MODCOD_16APSK_9_10,
DVBFE_MODCOD_32APSK_3_4,
DVBFE_MODCOD_32APSK_4_5,
DVBFE_MODCOD_32APSK_5_6,
DVBFE_MODCOD_32APSK_8_9,
DVBFE_MODCOD_32APSK_9_10,
DVBFE_MODCOD_RESERVED_1,
DVBFE_MODCOD_BPSK_1_3,
DVBFE_MODCOD_BPSK_1_4,
DVBFE_MODCOD_RESERVED_2
};
enum tuner_param {
DVBFE_TUNER_FREQUENCY = (1 << 0),
DVBFE_TUNER_TUNERSTEP = (1 << 1),
DVBFE_TUNER_IFFREQ = (1 << 2),
DVBFE_TUNER_BANDWIDTH = (1 << 3),
DVBFE_TUNER_REFCLOCK = (1 << 4),
DVBFE_TUNER_IQSENSE = (1 << 5),
DVBFE_TUNER_DUMMY = (1 << 31)
};
/*
* ALGO_HW: (Hardware Algorithm)
* ----------------------------------------------------------------
* Devices that support this algorithm do everything in hardware
* and no software support is needed to handle them.
* Requesting these devices to LOCK is the only thing required,
* device is supposed to do everything in the hardware.
/**
* enum dvbfe_algo - defines the algorithm used to tune into a channel
*
* ALGO_SW: (Software Algorithm)
* ----------------------------------------------------------------
* @DVBFE_ALGO_HW: Hardware Algorithm -
* Devices that support this algorithm do everything in hardware
* and no software support is needed to handle them.
* Requesting these devices to LOCK is the only thing required,
* device is supposed to do everything in the hardware.
*
* @DVBFE_ALGO_SW: Software Algorithm -
* These are dumb devices, that require software to do everything
*
* ALGO_CUSTOM: (Customizable Agorithm)
* ----------------------------------------------------------------
* Devices having this algorithm can be customized to have specific
* algorithms in the frontend driver, rather than simply doing a
* software zig-zag. In this case the zigzag maybe hardware assisted
* or it maybe completely done in hardware. In all cases, usage of
* this algorithm, in conjunction with the search and track
* callbacks, utilizes the driver specific algorithm.
* @DVBFE_ALGO_CUSTOM: Customizable Agorithm -
* Devices having this algorithm can be customized to have specific
* algorithms in the frontend driver, rather than simply doing a
* software zig-zag. In this case the zigzag maybe hardware assisted
* or it maybe completely done in hardware. In all cases, usage of
* this algorithm, in conjunction with the search and track
* callbacks, utilizes the driver specific algorithm.
*
* ALGO_RECOVERY: (Recovery Algorithm)
* ----------------------------------------------------------------
* These devices have AUTO recovery capabilities from LOCK failure
* @DVBFE_ALGO_RECOVERY: Recovery Algorithm -
* These devices have AUTO recovery capabilities from LOCK failure
*/
enum dvbfe_algo {
DVBFE_ALGO_HW = (1 << 0),
@@ -153,36 +151,27 @@ enum dvbfe_algo {
DVBFE_ALGO_RECOVERY = (1 << 31)
};
struct tuner_state {
u32 frequency;
u32 tunerstep;
u32 ifreq;
u32 bandwidth;
u32 iqsense;
u32 refclock;
};
/*
* search callback possible return status
/**
* enum dvbfe_search - search callback possible return status
*
* DVBFE_ALGO_SEARCH_SUCCESS
* The frontend search algorithm completed and returned successfully
* @DVBFE_ALGO_SEARCH_SUCCESS:
* The frontend search algorithm completed and returned successfully
*
* DVBFE_ALGO_SEARCH_ASLEEP
* The frontend search algorithm is sleeping
* @DVBFE_ALGO_SEARCH_ASLEEP:
* The frontend search algorithm is sleeping
*
* DVBFE_ALGO_SEARCH_FAILED
* The frontend search for a signal failed
* @DVBFE_ALGO_SEARCH_FAILED:
* The frontend search for a signal failed
*
* DVBFE_ALGO_SEARCH_INVALID
* The frontend search algorith was probably supplied with invalid
* parameters and the search is an invalid one
* @DVBFE_ALGO_SEARCH_INVALID:
* The frontend search algorith was probably supplied with invalid
* parameters and the search is an invalid one
*
* DVBFE_ALGO_SEARCH_ERROR
* The frontend search algorithm failed due to some error
* @DVBFE_ALGO_SEARCH_ERROR:
* The frontend search algorithm failed due to some error
*
* DVBFE_ALGO_SEARCH_AGAIN
* The frontend search algorithm was requested to search again
* @DVBFE_ALGO_SEARCH_AGAIN:
* The frontend search algorithm was requested to search again
*/
enum dvbfe_search {
DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0),
@@ -193,23 +182,64 @@ enum dvbfe_search {
DVBFE_ALGO_SEARCH_ERROR = (1 << 31),
};
/**
* struct dvb_tuner_ops - Tuner information and callbacks
*
* @info: embedded struct dvb_tuner_info with tuner properties
* @release: callback function called when frontend is dettached.
* drivers should free any allocated memory.
* @init: callback function used to initialize the tuner device.
* @sleep: callback function used to put the tuner to sleep.
* @suspend: callback function used to inform that the Kernel will
* suspend.
* @resume: callback function used to inform that the Kernel is
* resuming from suspend.
* @set_params: callback function used to inform the tuner to tune
* into a digital TV channel. The properties to be used
* are stored at @dvb_frontend.dtv_property_cache;. The
* tuner demod can change the parameters to reflect the
* changes needed for the channel to be tuned, and
* update statistics. This is the recommended way to set
* the tuner parameters and should be used on newer
* drivers.
* @set_analog_params: callback function used to tune into an analog TV
* channel on hybrid tuners. It passes @analog_parameters;
* to the driver.
* @set_config: callback function used to send some tuner-specific
* parameters.
* @get_frequency: get the actual tuned frequency
* @get_bandwidth: get the bandwitdh used by the low pass filters
* @get_if_frequency: get the Intermediate Frequency, in Hz. For baseband,
* should return 0.
* @get_status: returns the frontend lock status
* @get_rf_strength: returns the RF signal strengh. Used mostly to support
* analog TV and radio. Digital TV should report, instead,
* via DVBv5 API (@dvb_frontend.dtv_property_cache;).
* @get_afc: Used only by analog TV core. Reports the frequency
* drift due to AFC.
* @calc_regs: callback function used to pass register data settings
* for simple tuners. Shouldn't be used on newer drivers.
* @set_frequency: Set a new frequency. Shouldn't be used on newer drivers.
* @set_bandwidth: Set a new frequency. Shouldn't be used on newer drivers.
*
* NOTE: frequencies used on get_frequency and set_frequency are in Hz for
* terrestrial/cable or kHz for satellite.
*
*/
struct dvb_tuner_ops {
struct dvb_tuner_info info;
int (*release)(struct dvb_frontend *fe);
void (*release)(struct dvb_frontend *fe);
int (*init)(struct dvb_frontend *fe);
int (*sleep)(struct dvb_frontend *fe);
int (*suspend)(struct dvb_frontend *fe);
int (*resume)(struct dvb_frontend *fe);
/** This is for simple PLLs - set all parameters in one go. */
/* This is the recomended way to set the tuner */
int (*set_params)(struct dvb_frontend *fe);
int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
/** This is to allow setting tuner-specific configs */
int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
@@ -222,23 +252,56 @@ struct dvb_tuner_ops {
int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
/** These are provided separately from set_params in order to facilitate silicon
* tuners which require sophisticated tuning loops, controlling each parameter separately. */
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
/*
* This is support for demods like the mt352 - fills out the supplied
* buffer with what to write.
*
* Don't use on newer drivers.
*/
int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
/*
* These are provided separately from set_params in order to facilitate silicon
* tuners which require sophisticated tuning loops, controlling each parameter separately.
* These are provided separately from set_params in order to
* facilitate silicon tuners which require sophisticated tuning loops,
* controlling each parameter separately.
*
* Don't use on newer drivers.
*/
int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
};
/**
* struct analog_demod_info - Information struct for analog TV part of the demod
*
* @name: Name of the analog TV demodulator
*/
struct analog_demod_info {
char *name;
};
/**
* struct analog_demod_ops - Demodulation information and callbacks for
* analog TV and radio
*
* @info: pointer to struct analog_demod_info
* @set_params: callback function used to inform the demod to set the
* demodulator parameters needed to decode an analog or
* radio channel. The properties are passed via
* struct @analog_params;.
* @has_signal: returns 0xffff if has signal, or 0 if it doesn't.
* @get_afc: Used only by analog TV core. Reports the frequency
* drift due to AFC.
* @tuner_status: callback function that returns tuner status bits, e. g.
* TUNER_STATUS_LOCKED and TUNER_STATUS_STEREO.
* @standby: set the tuner to standby mode.
* @release: callback function called when frontend is dettached.
* drivers should free any allocated memory.
* @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C
* mux support instead.
* @set_config: callback function used to send some tuner-specific
* parameters.
*/
struct analog_demod_ops {
struct analog_demod_info info;
@@ -258,12 +321,103 @@ struct analog_demod_ops {
struct dtv_frontend_properties;
/**
* struct dvb_frontend_ops - Demodulation information and callbacks for
* ditialt TV
*
* @info: embedded struct dvb_tuner_info with tuner properties
* @delsys: Delivery systems supported by the frontend
* @detach: callback function called when frontend is detached.
* drivers should clean up, but not yet free the struct
* dvb_frontend allocation.
* @release: callback function called when frontend is ready to be
* freed.
* drivers should free any allocated memory.
* @release_sec: callback function requesting that the Satelite Equipment
* Control (SEC) driver to release and free any memory
* allocated by the driver.
* @init: callback function used to initialize the tuner device.
* @sleep: callback function used to put the tuner to sleep.
* @write: callback function used by some demod legacy drivers to
* allow other drivers to write data into their registers.
* Should not be used on new drivers.
* @tune: callback function used by demod drivers that use
* @DVBFE_ALGO_HW; to tune into a frequency.
* @get_frontend_algo: returns the desired hardware algorithm.
* @set_frontend: callback function used to inform the demod to set the
* parameters for demodulating a digital TV channel.
* The properties to be used are stored at
* @dvb_frontend.dtv_property_cache;. The demod can change
* the parameters to reflect the changes needed for the
* channel to be decoded, and update statistics.
* @get_tune_settings: callback function
* @get_frontend: callback function used to inform the parameters
* actuall in use. The properties to be used are stored at
* @dvb_frontend.dtv_property_cache; and update
* statistics. Please notice that it should not return
* an error code if the statistics are not available
* because the demog is not locked.
* @read_status: returns the locking status of the frontend.
* @read_ber: legacy callback function to return the bit error rate.
* Newer drivers should provide such info via DVBv5 API,
* e. g. @set_frontend;/@get_frontend;, implementing this
* callback only if DVBv3 API compatibility is wanted.
* @read_signal_strength: legacy callback function to return the signal
* strength. Newer drivers should provide such info via
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
* implementing this callback only if DVBv3 API
* compatibility is wanted.
* @read_snr: legacy callback function to return the Signal/Noise
* rate. Newer drivers should provide such info via
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
* implementing this callback only if DVBv3 API
* compatibility is wanted.
* @read_ucblocks: legacy callback function to return the Uncorrected Error
* Blocks. Newer drivers should provide such info via
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
* implementing this callback only if DVBv3 API
* compatibility is wanted.
* @diseqc_reset_overload: callback function to implement the
* FE_DISEQC_RESET_OVERLOAD ioctl (only Satellite)
* @diseqc_send_master_cmd: callback function to implement the
* FE_DISEQC_SEND_MASTER_CMD ioctl (only Satellite).
* @diseqc_recv_slave_reply: callback function to implement the
* FE_DISEQC_RECV_SLAVE_REPLY ioctl (only Satellite)
* @diseqc_send_burst: callback function to implement the
* FE_DISEQC_SEND_BURST ioctl (only Satellite).
* @set_tone: callback function to implement the
* FE_SET_TONE ioctl (only Satellite).
* @set_voltage: callback function to implement the
* FE_SET_VOLTAGE ioctl (only Satellite).
* @enable_high_lnb_voltage: callback function to implement the
* FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite).
* @dishnetwork_send_legacy_command: callback function to implement the
* FE_DISHNETWORK_SEND_LEGACY_CMD ioctl (only Satellite).
* Drivers should not use this, except when the DVB
* core emulation fails to provide proper support (e.g.
* if @set_voltage takes more than 8ms to work), and
* when backward compatibility with this legacy API is
* required.
* @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C
* mux support instead.
* @ts_bus_ctrl: callback function used to take control of the TS bus.
* @set_lna: callback function to power on/off/auto the LNA.
* @search: callback function used on some custom algo search algos.
* @tuner_ops: pointer to struct dvb_tuner_ops
* @analog_ops: pointer to struct analog_demod_ops
* @set_property: callback function to allow the frontend to validade
* incoming properties. Should not be used on new drivers.
* @get_property: callback function to allow the frontend to override
* outcoming properties. Should not be used on new drivers.
*/
struct dvb_frontend_ops {
struct dvb_frontend_info info;
u8 delsys[MAX_DELSYS];
void (*detach)(struct dvb_frontend *fe);
void (*release)(struct dvb_frontend* fe);
void (*release_sec)(struct dvb_frontend* fe);
@@ -277,7 +431,8 @@ struct dvb_frontend_ops {
bool re_tune,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status);
enum fe_status *status);
/* get frontend tuning algorithm from the module */
enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
@@ -285,9 +440,10 @@ struct dvb_frontend_ops {
int (*set_frontend)(struct dvb_frontend *fe);
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
int (*get_frontend)(struct dvb_frontend *fe);
int (*get_frontend)(struct dvb_frontend *fe,
struct dtv_frontend_properties *props);
int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
int (*read_status)(struct dvb_frontend *fe, enum fe_status *status);
int (*read_ber)(struct dvb_frontend* fe, u32* ber);
int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
int (*read_snr)(struct dvb_frontend* fe, u16* snr);
@@ -296,9 +452,11 @@ struct dvb_frontend_ops {
int (*diseqc_reset_overload)(struct dvb_frontend* fe);
int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
int (*diseqc_send_burst)(struct dvb_frontend *fe,
enum fe_sec_mini_cmd minicmd);
int (*set_tone)(struct dvb_frontend *fe, enum fe_sec_tone_mode tone);
int (*set_voltage)(struct dvb_frontend *fe,
enum fe_sec_voltage voltage);
int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
@@ -306,7 +464,8 @@ struct dvb_frontend_ops {
int (*set_lna)(struct dvb_frontend *);
int (*set_input)(struct dvb_frontend *, int);
/* These callbacks are for devices that implement their own
/*
* These callbacks are for devices that implement their own
* tuning algorithms, rather than a simple swzigzag
*/
enum dvbfe_search (*search)(struct dvb_frontend *fe);
@@ -323,6 +482,7 @@ struct dvb_frontend_ops {
#ifdef __DVB_CORE__
#define MAX_EVENT 8
/* Used only internally at dvb_frontend.c */
struct dvb_fe_events {
struct dvb_frontend_event events[MAX_EVENT];
int eventw;
@@ -333,30 +493,102 @@ struct dvb_fe_events {
};
#endif
/**
* struct dtv_frontend_properties - contains a list of properties that are
* specific to a digital TV standard.
*
* @frequency: frequency in Hz for terrestrial/cable or in kHz for
* Satellite
* @modulation: Frontend modulation type
* @voltage: SEC voltage (only Satellite)
* @sectone: SEC tone mode (only Satellite)
* @inversion: Spectral inversion
* @fec_inner: Forward error correction inner Code Rate
* @transmission_mode: Transmission Mode
* @bandwidth_hz: Bandwidth, in Hz. A zero value means that userspace
* wants to autodetect.
* @guard_interval: Guard Interval
* @hierarchy: Hierarchy
* @symbol_rate: Symbol Rate
* @code_rate_HP: high priority stream code rate
* @code_rate_LP: low priority stream code rate
* @pilot: Enable/disable/autodetect pilot tones
* @rolloff: Rolloff factor (alpha)
* @delivery_system: FE delivery system (e. g. digital TV standard)
* @interleaving: interleaving
* @isdbt_partial_reception: ISDB-T partial reception (only ISDB standard)
* @isdbt_sb_mode: ISDB-T Sound Broadcast (SB) mode (only ISDB standard)
* @isdbt_sb_subchannel: ISDB-T SB subchannel (only ISDB standard)
* @isdbt_sb_segment_idx: ISDB-T SB segment index (only ISDB standard)
* @isdbt_sb_segment_count: ISDB-T SB segment count (only ISDB standard)
* @isdbt_layer_enabled: ISDB Layer enabled (only ISDB standard)
* @layer: ISDB per-layer data (only ISDB standard)
* @layer.segment_count: Segment Count;
* @layer.fec: per layer code rate;
* @layer.modulation: per layer modulation;
* @layer.interleaving: per layer interleaving.
* @stream_id: If different than zero, enable substream filtering, if
* hardware supports (DVB-S2 and DVB-T2).
* @scrambling_sequence_index: Carries the index of the DVB-S2 physical layer
* scrambling sequence.
* @atscmh_fic_ver: Version number of the FIC (Fast Information Channel)
* signaling data (only ATSC-M/H)
* @atscmh_parade_id: Parade identification number (only ATSC-M/H)
* @atscmh_nog: Number of MH groups per MH subframe for a designated
* parade (only ATSC-M/H)
* @atscmh_tnog: Total number of MH groups including all MH groups
* belonging to all MH parades in one MH subframe
* (only ATSC-M/H)
* @atscmh_sgn: Start group number (only ATSC-M/H)
* @atscmh_prc: Parade repetition cycle (only ATSC-M/H)
* @atscmh_rs_frame_mode: Reed Solomon (RS) frame mode (only ATSC-M/H)
* @atscmh_rs_frame_ensemble: RS frame ensemble (only ATSC-M/H)
* @atscmh_rs_code_mode_pri: RS code mode pri (only ATSC-M/H)
* @atscmh_rs_code_mode_sec: RS code mode sec (only ATSC-M/H)
* @atscmh_sccc_block_mode: Series Concatenated Convolutional Code (SCCC)
* Block Mode (only ATSC-M/H)
* @atscmh_sccc_code_mode_a: SCCC code mode A (only ATSC-M/H)
* @atscmh_sccc_code_mode_b: SCCC code mode B (only ATSC-M/H)
* @atscmh_sccc_code_mode_c: SCCC code mode C (only ATSC-M/H)
* @atscmh_sccc_code_mode_d: SCCC code mode D (only ATSC-M/H)
* @lna: Power ON/OFF/AUTO the Linear Now-noise Amplifier (LNA)
* @strength: DVBv5 API statistics: Signal Strength
* @cnr: DVBv5 API statistics: Signal to Noise ratio of the
* (main) carrier
* @pre_bit_error: DVBv5 API statistics: pre-Viterbi bit error count
* @pre_bit_count: DVBv5 API statistics: pre-Viterbi bit count
* @post_bit_error: DVBv5 API statistics: post-Viterbi bit error count
* @post_bit_count: DVBv5 API statistics: post-Viterbi bit count
* @block_error: DVBv5 API statistics: block error count
* @block_count: DVBv5 API statistics: block count
*
* NOTE: derivated statistics like Uncorrected Error blocks (UCE) are
* calculated on userspace.
*
* Only a subset of the properties are needed for a given delivery system.
* For more info, consult the media_api.html with the documentation of the
* Userspace API.
*/
struct dtv_frontend_properties {
/* Cache State */
u32 state;
u32 frequency;
fe_modulation_t modulation;
enum fe_modulation modulation;
fe_sec_voltage_t voltage;
fe_sec_tone_mode_t sectone;
fe_spectral_inversion_t inversion;
fe_code_rate_t fec_inner;
fe_transmit_mode_t transmission_mode;
enum fe_sec_voltage voltage;
enum fe_sec_tone_mode sectone;
enum fe_spectral_inversion inversion;
enum fe_code_rate fec_inner;
enum fe_transmit_mode transmission_mode;
u32 bandwidth_hz; /* 0 = AUTO */
fe_guard_interval_t guard_interval;
fe_hierarchy_t hierarchy;
enum fe_guard_interval guard_interval;
enum fe_hierarchy hierarchy;
u32 symbol_rate;
fe_code_rate_t code_rate_HP;
fe_code_rate_t code_rate_LP;
enum fe_code_rate code_rate_HP;
enum fe_code_rate code_rate_LP;
fe_pilot_t pilot;
fe_rolloff_t rolloff;
enum fe_pilot pilot;
enum fe_rolloff rolloff;
fe_delivery_system_t delivery_system;
enum fe_delivery_system delivery_system;
enum fe_interleaving interleaving;
@@ -369,14 +601,17 @@ struct dtv_frontend_properties {
u8 isdbt_layer_enabled;
struct {
u8 segment_count;
fe_code_rate_t fec;
fe_modulation_t modulation;
enum fe_code_rate fec;
enum fe_modulation modulation;
u8 interleaving;
} layer[3];
/* Multistream specifics */
u32 stream_id;
/* Physical Layer Scrambling specifics */
u32 scrambling_sequence_index;
/* ATSC-MH specifics */
u8 atscmh_fic_ver;
u8 atscmh_parade_id;
@@ -397,8 +632,7 @@ struct dtv_frontend_properties {
u32 lna;
s32 input;
u32 pls;
/* statistics data */
struct dtv_fe_stats strength;
struct dtv_fe_stats cnr;
@@ -408,9 +642,41 @@ struct dtv_frontend_properties {
struct dtv_fe_stats post_bit_count;
struct dtv_fe_stats block_error;
struct dtv_fe_stats block_count;
/* private: */
/* Cache State */
u32 state;
};
#define DVB_FE_NO_EXIT 0
#define DVB_FE_NORMAL_EXIT 1
#define DVB_FE_DEVICE_REMOVED 2
#define DVB_FE_DEVICE_RESUME 3
/**
* struct dvb_frontend - Frontend structure to be used on drivers.
*
* @refcount: refcount to keep track of struct dvb_frontend
* references
* @ops: embedded struct dvb_frontend_ops
* @dvb: pointer to struct dvb_adapter
* @demodulator_priv: demod private data
* @tuner_priv: tuner private data
* @frontend_priv: frontend private data
* @sec_priv: SEC private data
* @analog_demod_priv: Analog demod private data
* @dtv_property_cache: embedded struct dtv_frontend_properties
* @callback: callback function used on some drivers to call
* either the tuner or the demodulator.
* @id: Frontend ID
* @exit: Used to inform the DVB core that the frontend
* thread should exit (usually, means that the hardware
* got disconnected.
*/
struct dvb_frontend {
struct kref refcount;
struct dvb_frontend_ops ops;
struct dvb_adapter *dvb;
void *demodulator_priv;
@@ -423,20 +689,129 @@ struct dvb_frontend {
#define DVB_FRONTEND_COMPONENT_DEMOD 1
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
int id;
unsigned int exit;
};
extern int dvb_register_frontend(struct dvb_adapter *dvb,
/**
* dvb_register_frontend() - Registers a DVB frontend at the adapter
*
* @dvb: pointer to the dvb adapter
* @fe: pointer to the frontend struct
*
* Allocate and initialize the private data needed by the frontend core to
* manage the frontend and calls dvb_register_device() to register a new
* frontend. It also cleans the property cache that stores the frontend
* parameters and selects the first available delivery system.
*/
int dvb_register_frontend(struct dvb_adapter *dvb,
struct dvb_frontend *fe);
extern int dvb_unregister_frontend(struct dvb_frontend *fe);
/**
* dvb_unregister_frontend() - Unregisters a DVB frontend
*
* @fe: pointer to the frontend struct
*
* Stops the frontend kthread, calls dvb_unregister_device() and frees the
* private frontend data allocated by dvb_register_frontend().
*
* NOTE: This function doesn't frees the memory allocated by the demod,
* by the SEC driver and by the tuner. In order to free it, an explicit call to
* dvb_frontend_detach() is needed, after calling this function.
*/
int dvb_unregister_frontend(struct dvb_frontend *fe);
extern void dvb_frontend_detach(struct dvb_frontend *fe);
/**
* dvb_frontend_detach() - Detaches and frees frontend specific data
*
* @fe: pointer to the frontend struct
*
* This function should be called after dvb_unregister_frontend(). It
* calls the SEC, tuner and demod release functions:
* &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_ops.release,
* &dvb_frontend_ops.analog_ops.release and &dvb_frontend_ops.release.
*
* If the driver is compiled with CONFIG_MEDIA_ATTACH, it also decreases
* the module reference count, needed to allow userspace to remove the
* previously used DVB frontend modules.
*/
void dvb_frontend_detach(struct dvb_frontend *fe);
extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
extern int dvb_frontend_suspend(struct dvb_frontend *fe);
extern int dvb_frontend_resume(struct dvb_frontend *fe);
/**
* dvb_frontend_suspend() - Suspends a Digital TV frontend
*
* @fe: pointer to the frontend struct
*
* This function prepares a Digital TV frontend to suspend.
*
* In order to prepare the tuner to suspend, if
* &dvb_frontend_ops.tuner_ops.suspend\(\) is available, it calls it. Otherwise,
* it will call &dvb_frontend_ops.tuner_ops.sleep\(\), if available.
*
* It will also call &dvb_frontend_ops.sleep\(\) to put the demod to suspend.
*
* The drivers should also call dvb_frontend_suspend\(\) as part of their
* handler for the &device_driver.suspend\(\).
*/
int dvb_frontend_suspend(struct dvb_frontend *fe);
extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
/**
* dvb_frontend_resume() - Resumes a Digital TV frontend
*
* @fe: pointer to the frontend struct
*
* This function resumes the usual operation of the tuner after resume.
*
* In order to resume the frontend, it calls the demod &dvb_frontend_ops.init\(\).
*
* If &dvb_frontend_ops.tuner_ops.resume\(\) is available, It, it calls it.
* Otherwise,t will call &dvb_frontend_ops.tuner_ops.init\(\), if available.
*
* Once tuner and demods are resumed, it will enforce that the SEC voltage and
* tone are restored to their previous values and wake up the frontend's
* kthread in order to retune the frontend.
*
* The drivers should also call dvb_frontend_resume() as part of their
* handler for the &device_driver.resume\(\).
*/
int dvb_frontend_resume(struct dvb_frontend *fe);
/**
* dvb_frontend_reinitialise() - forces a reinitialisation at the frontend
*
* @fe: pointer to the frontend struct
*
* Calls &dvb_frontend_ops.init\(\) and &dvb_frontend_ops.tuner_ops.init\(\),
* and resets SEC tone and voltage (for Satellite systems).
*
* NOTE: Currently, this function is used only by one driver (budget-av).
* It seems to be due to address some special issue with that specific
* frontend.
*/
void dvb_frontend_reinitialise(struct dvb_frontend *fe);
/**
* dvb_frontend_sleep_until() - Sleep for the amount of time given by
* add_usec parameter
*
* @waketime: pointer to a struct ktime_t
* @add_usec: time to sleep, in microseconds
*
* This function is used to measure the time required for the
* %FE_DISHNETWORK_SEND_LEGACY_CMD ioctl to work. It needs to be as precise
* as possible, as it affects the detection of the dish tone command at the
* satellite subsystem.
*
* Its used internally by the DVB frontend core, in order to emulate
* %FE_DISHNETWORK_SEND_LEGACY_CMD using the &dvb_frontend_ops.set_voltage\(\)
* callback.
*
* NOTE: it should not be used at the drivers, as the emulation for the
* legacy callback is provided by the Kernel. The only situation where this
* should be at the drivers is when there are some bugs at the hardware that
* would prevent the core emulation to work. On such cases, the driver would
* be writing a &dvb_frontend_ops.dishnetwork_send_legacy_command\(\) and
* calling this function directly.
*/
void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec);
#endif

View File

@@ -13,10 +13,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/bitops.h>

View File

@@ -13,10 +13,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __DVB_MATH_H
@@ -25,33 +21,45 @@
#include <linux/types.h>
/**
* computes log2 of a value; the result is shifted left by 24 bits
* intlog2 - computes log2 of a value; the result is shifted left by 24 bits
*
* @value: The value (must be != 0)
*
* to use rational values you can use the following method:
*
* intlog2(value) = intlog2(value * 2^x) - x * 2^24
*
* example: intlog2(8) will give 3 << 24 = 3 * 2^24
* example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
* example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
* Some usecase examples:
*
* @param value The value (must be != 0)
* @return log2(value) * 2^24
* intlog2(8) will give 3 << 24 = 3 * 2^24
*
* intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
*
* intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
*
*
* return: log2(value) * 2^24
*/
extern unsigned int intlog2(u32 value);
/**
* computes log10 of a value; the result is shifted left by 24 bits
* intlog10 - computes log10 of a value; the result is shifted left by 24 bits
*
* @value: The value (must be != 0)
*
* to use rational values you can use the following method:
*
* intlog10(value) = intlog10(value * 10^x) - x * 2^24
*
* example: intlog10(1000) will give 3 << 24 = 3 * 2^24
* An usecase example:
*
* intlog10(1000) will give 3 << 24 = 3 * 2^24
*
* due to the implementation intlog10(1000) might be not exactly 3 * 2^24
*
* look at intlog2 for similar examples
*
* @param value The value (must be != 0)
* @return log10(value) * 2^24
* return: log10(value) * 2^24
*/
extern unsigned int intlog10(u32 value);

File diff suppressed because it is too large Load Diff

View File

@@ -13,10 +13,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef _DVB_NET_H_

View File

@@ -241,7 +241,7 @@ int dvb_netstream_init(struct dvb_adapter *dvb_adapter,
spin_lock_init(&ns->lock);
ns->exit = 0;
dvb_register_device(dvb_adapter, &ns->dvbdev, &ns_dev, ns,
DVB_DEVICE_NS);
DVB_DEVICE_NS, 0);
INIT_LIST_HEAD(&ns->nssl);
return 0;
}

View File

@@ -18,10 +18,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
@@ -31,7 +27,12 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
#include <asm/uaccess.h>
#else
#include <linux/uaccess.h>
#endif
#include "dvb_ringbuffer.h"
@@ -55,7 +56,17 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
{
return (rbuf->pread==rbuf->pwrite);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
return (rbuf->pread == rbuf->pwrite);
#else
/* smp_load_acquire() to load write pointer on reader side
* this pairs with smp_store_release() in dvb_ringbuffer_write(),
* dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
*
* for memory barriers also see Documentation/circular-buffers.txt
*/
return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
#endif
}
@@ -64,7 +75,16 @@ ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
{
ssize_t free;
free = rbuf->pread - rbuf->pwrite;
/* ACCESS_ONCE() to load read pointer on writer side
* this pairs with smp_store_release() in dvb_ringbuffer_read(),
* dvb_ringbuffer_read_user(), dvb_ringbuffer_flush(),
* or dvb_ringbuffer_reset()
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
free = READ_ONCE(rbuf->pread) - rbuf->pwrite;
#else
free = ACCESS_ONCE(rbuf->pread) - rbuf->pwrite;
#endif
if (free <= 0)
free += rbuf->size;
return free-1;
@@ -76,7 +96,15 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
{
ssize_t avail;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
avail = rbuf->pwrite - rbuf->pread;
#else
/* smp_load_acquire() to load write pointer on reader side
* this pairs with smp_store_release() in dvb_ringbuffer_write(),
* dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
*/
avail = smp_load_acquire(&rbuf->pwrite) - rbuf->pread;
#endif
if (avail < 0)
avail += rbuf->size;
return avail;
@@ -86,14 +114,33 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
{
rbuf->pread = rbuf->pwrite;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pread = &rbuf->pwrite;
#else
/* dvb_ringbuffer_flush() counts as read operation
* smp_load_acquire() to load write pointer
* smp_store_release() to update read pointer, this ensures that the
* correct pointer is visible for subsequent dvb_ringbuffer_free()
* calls on other cpu cores
*/
smp_store_release(&rbuf->pread, smp_load_acquire(&rbuf->pwrite));
#endif
rbuf->error = 0;
}
EXPORT_SYMBOL(dvb_ringbuffer_flush);
void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pread = rbuf->pwrite = 0;
#else
/* dvb_ringbuffer_reset() counts as read and write operation
* smp_store_release() to update read pointer
*/
smp_store_release(&rbuf->pread, 0);
/* smp_store_release() to update write pointer */
smp_store_release(&rbuf->pwrite, 0);
#endif
rbuf->error = 0;
}
@@ -119,13 +166,25 @@ ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, si
return -EFAULT;
buf += split;
todo -= split;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pread = 0;
#else
/* smp_store_release() for read pointer update to ensure
* that buf is not overwritten until read is complete,
* this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
*/
smp_store_release(&rbuf->pread, 0);
#endif
}
if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
return -EFAULT;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pread = (rbuf->pread + todo) % rbuf->size;
#else
/* smp_store_release() to update read pointer, see above */
smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
#endif
return len;
}
@@ -139,11 +198,24 @@ void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
memcpy(buf, rbuf->data+rbuf->pread, split);
buf += split;
todo -= split;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pread = 0;
#else
/* smp_store_release() for read pointer update to ensure
* that buf is not overwritten until read is complete,
* this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
*/
smp_store_release(&rbuf->pread, 0);
#endif
}
memcpy(buf, rbuf->data+rbuf->pread, todo);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pread = (rbuf->pread + todo) % rbuf->size;
#else
/* smp_store_release() to update read pointer, see above */
smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
#endif
}
@@ -158,10 +230,63 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t
memcpy(rbuf->data+rbuf->pwrite, buf, split);
buf += split;
todo -= split;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pwrite = 0;
#else
/* smp_store_release() for write pointer update to ensure that
* written data is visible on other cpu cores before the pointer
* update, this pairs with smp_load_acquire() in
* dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
*/
smp_store_release(&rbuf->pwrite, 0);
#endif
}
memcpy(rbuf->data+rbuf->pwrite, buf, todo);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
#else
/* smp_store_release() for write pointer update, see above */
smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
#endif
return len;
}
ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
const u8 __user *buf, size_t len)
{
int status;
size_t todo = len;
size_t split;
split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
if (split > 0) {
status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split);
if (status)
return len - todo;
buf += split;
todo -= split;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pwrite = 0;
#else
/* smp_store_release() for write pointer update to ensure that
* written data is visible on other cpu cores before the pointer
* update, this pairs with smp_load_acquire() in
* dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
*/
smp_store_release(&rbuf->pwrite, 0);
#endif
}
status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
if (status)
return len - todo;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
#else
/* smp_store_release() for write pointer update, see above */
smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
#endif
return len;
}
@@ -297,3 +422,4 @@ EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
EXPORT_SYMBOL(dvb_ringbuffer_read_user);
EXPORT_SYMBOL(dvb_ringbuffer_read);
EXPORT_SYMBOL(dvb_ringbuffer_write);
EXPORT_SYMBOL(dvb_ringbuffer_write_user);

View File

@@ -18,10 +18,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _DVB_RINGBUFFER_H_
@@ -30,6 +26,18 @@
#include <linux/spinlock.h>
#include <linux/wait.h>
/**
* struct dvb_ringbuffer - Describes a ring buffer used at DVB framework
*
* @data: Area were the ringbuffer data is written
* @size: size of the ringbuffer
* @pread: next position to read
* @pwrite: next position to write
* @error: used by ringbuffer clients to indicate that an error happened.
* @queue: Wait queue used by ringbuffer clients to indicate when buffer
* was filled
* @lock: Spinlock used to protect the ringbuffer
*/
struct dvb_ringbuffer {
u8 *data;
ssize_t size;
@@ -43,144 +51,230 @@ struct dvb_ringbuffer {
#define DVB_RINGBUFFER_PKTHDRSIZE 3
/**
* dvb_ringbuffer_init - initialize ring buffer, lock and queue
*
* @rbuf: pointer to struct dvb_ringbuffer
* @data: pointer to the buffer where the data will be stored
* @len: bytes from ring buffer into @buf
*/
extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data,
size_t len);
/*
** Notes:
** ------
** (1) For performance reasons read and write routines don't check buffer sizes
** and/or number of bytes free/available. This has to be done before these
** routines are called. For example:
**
** *** write <buflen> bytes ***
** free = dvb_ringbuffer_free(rbuf);
** if (free >= buflen)
** count = dvb_ringbuffer_write(rbuf, buffer, buflen);
** else
** ...
**
** *** read min. 1000, max. <bufsize> bytes ***
** avail = dvb_ringbuffer_avail(rbuf);
** if (avail >= 1000)
** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
** else
** ...
**
** (2) If there is exactly one reader and one writer, there is no need
** to lock read or write operations.
** Two or more readers must be locked against each other.
** Flushing the buffer counts as a read operation.
** Resetting the buffer counts as a read and write operation.
** Two or more writers must be locked against each other.
*/
/* initialize ring buffer, lock and queue */
extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len);
/* test whether buffer is empty */
/**
* dvb_ringbuffer_empty - test whether buffer is empty
*
* @rbuf: pointer to struct dvb_ringbuffer
*/
extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
/* return the number of free bytes in the buffer */
/**
* dvb_ringbuffer_free - returns the number of free bytes in the buffer
*
* @rbuf: pointer to struct dvb_ringbuffer
*
* Return: number of free bytes in the buffer
*/
extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf);
/* return the number of bytes waiting in the buffer */
/**
* dvb_ringbuffer_avail - returns the number of bytes waiting in the buffer
*
* @rbuf: pointer to struct dvb_ringbuffer
*
* Return: number of bytes waiting in the buffer
*/
extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
/*
** Reset the read and write pointers to zero and flush the buffer
** This counts as a read and write operation
*/
/**
* dvb_ringbuffer_reset - resets the ringbuffer to initial state
*
* @rbuf: pointer to struct dvb_ringbuffer
*
* Resets the read and write pointers to zero and flush the buffer.
*
* This counts as a read and write operation
*/
extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf);
/*
* read routines & macros
*/
/* read routines & macros */
/* ---------------------- */
/* flush buffer */
/**
* dvb_ringbuffer_flush - flush buffer
*
* @rbuf: pointer to struct dvb_ringbuffer
*/
extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
/* flush buffer protected by spinlock and wake-up waiting task(s) */
/**
* dvb_ringbuffer_flush_spinlock_wakeup- flush buffer protected by spinlock
* and wake-up waiting task(s)
*
* @rbuf: pointer to struct dvb_ringbuffer
*/
extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
/* peek at byte <offs> in the buffer */
#define DVB_RINGBUFFER_PEEK(rbuf,offs) \
(rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size]
/**
* DVB_RINGBUFFER_PEEK - peek at byte @offs in the buffer
*
* @rbuf: pointer to struct dvb_ringbuffer
* @offs: offset inside the ringbuffer
*/
#define DVB_RINGBUFFER_PEEK(rbuf, offs) \
((rbuf)->data[((rbuf)->pread + (offs)) % (rbuf)->size])
/* advance read ptr by <num> bytes */
#define DVB_RINGBUFFER_SKIP(rbuf,num) \
(rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
/**
* DVB_RINGBUFFER_SKIP - advance read ptr by @num bytes
*
* @rbuf: pointer to struct dvb_ringbuffer
* @num: number of bytes to advance
*/
#define DVB_RINGBUFFER_SKIP(rbuf, num) {\
(rbuf)->pread = ((rbuf)->pread + (num)) % (rbuf)->size;\
}
/*
** read <len> bytes from ring buffer into <buf>
** <usermem> specifies whether <buf> resides in user space
** returns number of bytes transferred or -EFAULT
*/
/**
* dvb_ringbuffer_read_user - Reads a buffer into a user pointer
*
* @rbuf: pointer to struct dvb_ringbuffer
* @buf: pointer to the buffer where the data will be stored
* @len: bytes from ring buffer into @buf
*
* This variant assumes that the buffer is a memory at the userspace. So,
* it will internally call copy_to_user().
*
* Return: number of bytes transferred or -EFAULT
*/
extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
u8 __user *buf, size_t len);
/**
* dvb_ringbuffer_read - Reads a buffer into a pointer
*
* @rbuf: pointer to struct dvb_ringbuffer
* @buf: pointer to the buffer where the data will be stored
* @len: bytes from ring buffer into @buf
*
* This variant assumes that the buffer is a memory at the Kernel space
*
* Return: number of bytes transferred or -EFAULT
*/
extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
u8 *buf, size_t len);
/* write routines & macros */
/* ----------------------- */
/* write single byte to ring buffer */
#define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte) \
{ (rbuf)->data[(rbuf)->pwrite]=(byte); \
(rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; }
/*
** write <len> bytes to ring buffer
** <usermem> specifies whether <buf> resides in user space
** returns number of bytes transferred or -EFAULT
*/
* write routines & macros
*/
/**
* DVB_RINGBUFFER_WRITE_BYTE - write single byte to ring buffer
*
* @rbuf: pointer to struct dvb_ringbuffer
* @byte: byte to write
*/
#define DVB_RINGBUFFER_WRITE_BYTE(rbuf, byte) \
{ (rbuf)->data[(rbuf)->pwrite] = (byte); \
(rbuf)->pwrite = ((rbuf)->pwrite + 1) % (rbuf)->size; }
/**
* dvb_ringbuffer_write - Writes a buffer into the ringbuffer
*
* @rbuf: pointer to struct dvb_ringbuffer
* @buf: pointer to the buffer where the data will be read
* @len: bytes from ring buffer into @buf
*
* This variant assumes that the buffer is a memory at the Kernel space
*
* return: number of bytes transferred or -EFAULT
*/
extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
size_t len);
/**
* dvb_ringbuffer_write_user - Writes a buffer received via a user pointer
*
* @rbuf: pointer to struct dvb_ringbuffer
* @buf: pointer to the buffer where the data will be read
* @len: bytes from ring buffer into @buf
*
* This variant assumes that the buffer is a memory at the userspace. So,
* it will internally call copy_from_user().
*
* Return: number of bytes transferred or -EFAULT
*/
extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
const u8 __user *buf, size_t len);
/**
* Write a packet into the ringbuffer.
* dvb_ringbuffer_pkt_write - Write a packet into the ringbuffer.
*
* <rbuf> Ringbuffer to write to.
* <buf> Buffer to write.
* <len> Length of buffer (currently limited to 65535 bytes max).
* returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
* @rbuf: Ringbuffer to write to.
* @buf: Buffer to write.
* @len: Length of buffer (currently limited to 65535 bytes max).
*
* Return: Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
*/
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf,
size_t len);
/**
* Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
* does NOT update the read pointer in the ringbuffer. You must use
* dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required.
* dvb_ringbuffer_pkt_read_user - Read from a packet in the ringbuffer.
*
* <rbuf> Ringbuffer concerned.
* <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
* <offset> Offset into packet to read from.
* <buf> Destination buffer for data.
* <len> Size of destination buffer.
* <usermem> Set to 1 if <buf> is in userspace.
* returns Number of bytes read, or -EFAULT.
* @rbuf: Ringbuffer concerned.
* @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
* @offset: Offset into packet to read from.
* @buf: Destination buffer for data.
* @len: Size of destination buffer.
*
* Return: Number of bytes read, or -EFAULT.
*
* .. note::
*
* unlike dvb_ringbuffer_read(), this does **NOT** update the read pointer
* in the ringbuffer. You must use dvb_ringbuffer_pkt_dispose() to mark a
* packet as no longer required.
*/
extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf,
size_t idx,
int offset, u8 __user *buf,
size_t len);
/**
* dvb_ringbuffer_pkt_read - Read from a packet in the ringbuffer.
* Note: unlike dvb_ringbuffer_read_user(), this DOES update the read pointer
* in the ringbuffer.
*
* @rbuf: Ringbuffer concerned.
* @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
* @offset: Offset into packet to read from.
* @buf: Destination buffer for data.
* @len: Size of destination buffer.
*
* Return: Number of bytes read, or -EFAULT.
*/
extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
int offset, u8 __user *buf, size_t len);
extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
int offset, u8 *buf, size_t len);
/**
* Dispose of a packet in the ring buffer.
* dvb_ringbuffer_pkt_dispose - Dispose of a packet in the ring buffer.
*
* <rbuf> Ring buffer concerned.
* <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
* @rbuf: Ring buffer concerned.
* @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
*/
extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
/**
* Get the index of the next packet in a ringbuffer.
* dvb_ringbuffer_pkt_next - Get the index of the next packet in a ringbuffer.
*
* <rbuf> Ringbuffer concerned.
* <idx> Previous packet index, or -1 to return the first packet index.
* <pktlen> On success, will be updated to contain the length of the packet in bytes.
* @rbuf: Ringbuffer concerned.
* @idx: Previous packet index, or -1 to return the first packet index.
* @pktlen: On success, will be updated to contain the length of the packet
* in bytes.
* returns Packet index (if >=0), or -1 if no packets available.
*/
extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen);
extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf,
size_t idx, size_t *pktlen);
#endif /* _DVB_RINGBUFFER_H_ */

View File

@@ -15,12 +15,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#define pr_fmt(fmt) "dvbdev: " fmt
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/string.h>
@@ -35,13 +33,22 @@
#include <linux/version.h>
#include "dvbdev.h"
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0))
/* Due to enum tuner_pad_index */
#include <media/tuner.h>
#endif
static DEFINE_MUTEX(dvbdev_mutex);
static int dvbdev_debug;
module_param(dvbdev_debug, int, 0644);
MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
#define dprintk if (dvbdev_debug) printk
#define dprintk(fmt, arg...) do { \
if (dvbdev_debug) \
printk(KERN_DEBUG pr_fmt("%s: " fmt), \
__func__, ##arg); \
} while (0)
static LIST_HEAD(dvb_adapter_list);
static DEFINE_MUTEX(dvbdev_register_lock);
@@ -52,11 +59,11 @@ static const char * const dnames[] = {
};
#ifdef CONFIG_DVB_DYNAMIC_MINORS
#define MAX_DVB_MINORS 256
#define MAX_DVB_MINORS 512
#define DVB_MAX_IDS MAX_DVB_MINORS
#else
#define DVB_MAX_IDS 4
#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
#define nums2minor(num, type, id) ((num << 6) | (id << 4) | type)
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
#endif
@@ -75,22 +82,15 @@ static int dvb_device_open(struct inode *inode, struct file *file)
if (dvbdev && dvbdev->fops) {
int err = 0;
const struct file_operations *old_fops;
const struct file_operations *new_fops;
file->private_data = dvbdev;
old_fops = file->f_op;
file->f_op = fops_get(dvbdev->fops);
if (file->f_op == NULL) {
file->f_op = old_fops;
new_fops = fops_get(dvbdev->fops);
if (!new_fops)
goto fail;
}
if(file->f_op->open)
err = file->f_op->open(inode,file);
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
file->private_data = dvbdev;
replace_fops(file, new_fops);
if (file->f_op->open)
err = file->f_op->open(inode, file);
up_read(&minor_rwsem);
mutex_unlock(&dvbdev_mutex);
return err;
@@ -188,26 +188,266 @@ skip:
return -ENFILE;
}
static void dvb_media_device_free(struct dvb_device *dvbdev)
{
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
if (dvbdev->entity) {
media_device_unregister_entity(dvbdev->entity);
kfree(dvbdev->entity);
kfree(dvbdev->pads);
dvbdev->entity = NULL;
dvbdev->pads = NULL;
}
if (dvbdev->tsout_entity) {
int i;
for (i = 0; i < dvbdev->tsout_num_entities; i++) {
media_device_unregister_entity(&dvbdev->tsout_entity[i]);
kfree(dvbdev->tsout_entity[i].name);
}
kfree(dvbdev->tsout_entity);
kfree(dvbdev->tsout_pads);
dvbdev->tsout_entity = NULL;
dvbdev->tsout_pads = NULL;
dvbdev->tsout_num_entities = 0;
}
if (dvbdev->intf_devnode) {
media_devnode_remove(dvbdev->intf_devnode);
dvbdev->intf_devnode = NULL;
}
if (dvbdev->adapter->conn) {
media_device_unregister_entity(dvbdev->adapter->conn);
dvbdev->adapter->conn = NULL;
kfree(dvbdev->adapter->conn_pads);
dvbdev->adapter->conn_pads = NULL;
}
#endif
}
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
const char *name, int npads)
{
int i, ret = 0;
dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads),
GFP_KERNEL);
if (!dvbdev->tsout_pads)
return -ENOMEM;
dvbdev->tsout_entity = kcalloc(npads, sizeof(*dvbdev->tsout_entity),
GFP_KERNEL);
if (!dvbdev->tsout_entity)
return -ENOMEM;
dvbdev->tsout_num_entities = npads;
for (i = 0; i < npads; i++) {
struct media_pad *pads = &dvbdev->tsout_pads[i];
struct media_entity *entity = &dvbdev->tsout_entity[i];
entity->name = kasprintf(GFP_KERNEL, "%s #%d", name, i);
if (!entity->name)
return -ENOMEM;
entity->function = MEDIA_ENT_F_IO_DTV;
pads->flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(entity, 1, pads);
if (ret < 0)
return ret;
ret = media_device_register_entity(dvbdev->adapter->mdev,
entity);
if (ret < 0)
return ret;
}
return 0;
}
#define DEMUX_TSOUT "demux-tsout"
#define DVR_TSOUT "dvr-tsout"
static int dvb_create_media_entity(struct dvb_device *dvbdev,
int type, int demux_sink_pads)
{
int i, ret, npads;
switch (type) {
case DVB_DEVICE_FRONTEND:
npads = 2;
break;
case DVB_DEVICE_DVR:
ret = dvb_create_tsout_entity(dvbdev, DVR_TSOUT,
demux_sink_pads);
return ret;
case DVB_DEVICE_DEMUX:
npads = 1 + demux_sink_pads;
ret = dvb_create_tsout_entity(dvbdev, DEMUX_TSOUT,
demux_sink_pads);
if (ret < 0)
return ret;
break;
case DVB_DEVICE_CA:
npads = 2;
break;
case DVB_DEVICE_NET:
/*
* We should be creating entities for the MPE/ULE
* decapsulation hardware (or software implementation).
*
* However, the number of for the MPE/ULE decaps may not be
* fixed. As we don't have yet dynamic support for PADs at
* the Media Controller, let's not create the decap
* entities yet.
*/
return 0;
default:
return 0;
}
dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL);
if (!dvbdev->entity)
return -ENOMEM;
dvbdev->entity->name = dvbdev->name;
if (npads) {
dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
GFP_KERNEL);
if (!dvbdev->pads)
return -ENOMEM;
}
switch (type) {
case DVB_DEVICE_FRONTEND:
dvbdev->entity->function = MEDIA_ENT_F_DTV_DEMOD;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
break;
case DVB_DEVICE_DEMUX:
dvbdev->entity->function = MEDIA_ENT_F_TS_DEMUX;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
for (i = 1; i < npads; i++)
dvbdev->pads[i].flags = MEDIA_PAD_FL_SOURCE;
break;
case DVB_DEVICE_CA:
dvbdev->entity->function = MEDIA_ENT_F_DTV_CA;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
break;
default:
/* Should never happen, as the first switch prevents it */
kfree(dvbdev->entity);
kfree(dvbdev->pads);
dvbdev->entity = NULL;
dvbdev->pads = NULL;
return 0;
}
if (npads) {
ret = media_entity_pads_init(dvbdev->entity, npads, dvbdev->pads);
if (ret)
return ret;
}
ret = media_device_register_entity(dvbdev->adapter->mdev,
dvbdev->entity);
if (ret)
return ret;
pr_info("%s: media entity '%s' registered.\n",
__func__, dvbdev->entity->name);
return 0;
}
#endif
static int dvb_register_media_device(struct dvb_device *dvbdev,
int type, int minor,
unsigned demux_sink_pads)
{
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
struct media_link *link;
u32 intf_type;
int ret;
if (!dvbdev->adapter->mdev)
return 0;
ret = dvb_create_media_entity(dvbdev, type, demux_sink_pads);
if (ret)
return ret;
switch (type) {
case DVB_DEVICE_FRONTEND:
intf_type = MEDIA_INTF_T_DVB_FE;
break;
case DVB_DEVICE_DEMUX:
intf_type = MEDIA_INTF_T_DVB_DEMUX;
break;
case DVB_DEVICE_DVR:
intf_type = MEDIA_INTF_T_DVB_DVR;
break;
case DVB_DEVICE_CA:
intf_type = MEDIA_INTF_T_DVB_CA;
break;
case DVB_DEVICE_NET:
intf_type = MEDIA_INTF_T_DVB_NET;
break;
default:
return 0;
}
dvbdev->intf_devnode = media_devnode_create(dvbdev->adapter->mdev,
intf_type, 0,
DVB_MAJOR, minor);
if (!dvbdev->intf_devnode)
return -ENOMEM;
/*
* Create the "obvious" link, e. g. the ones that represent
* a direct association between an interface and an entity.
* Other links should be created elsewhere, like:
* DVB FE intf -> tuner
* DVB demux intf -> dvr
*/
if (!dvbdev->entity)
return 0;
link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf,
MEDIA_LNK_FL_ENABLED);
if (!link)
return -ENOMEM;
#endif
return 0;
}
int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
const struct dvb_device *template, void *priv, int type)
const struct dvb_device *template, void *priv, int type,
int demux_sink_pads)
{
struct dvb_device *dvbdev;
struct file_operations *dvbdevfops;
struct device *clsdev;
int minor;
int id;
int id, ret;
mutex_lock(&dvbdev_register_lock);
if ((id = dvbdev_get_free_id (adap, type)) < 0){
mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL;
printk(KERN_ERR "%s: couldn't find free device id\n", __func__);
pr_err("%s: couldn't find free device id\n", __func__);
return -ENFILE;
}
*pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
*pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
if (!dvbdev){
mutex_unlock(&dvbdev_register_lock);
@@ -256,18 +496,30 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dvb_minors[minor] = dvbdev;
up_write(&minor_rwsem);
ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
if (ret) {
pr_err("%s: dvb_register_media_device failed to create the mediagraph\n",
__func__);
dvb_media_device_free(dvbdev);
kfree(dvbdevfops);
kfree(dvbdev);
up_write(&minor_rwsem);
mutex_unlock(&dvbdev_register_lock);
return ret;
}
mutex_unlock(&dvbdev_register_lock);
clsdev = device_create(dvb_class, adap->device,
MKDEV(DVB_MAJOR, minor),
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
if (IS_ERR(clsdev)) {
printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
return PTR_ERR(clsdev);
}
dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, minor, minor);
return 0;
@@ -275,7 +527,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
EXPORT_SYMBOL(dvb_register_device);
void dvb_unregister_device(struct dvb_device *dvbdev)
void dvb_remove_device(struct dvb_device *dvbdev)
{
if (!dvbdev)
return;
@@ -284,14 +536,244 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
dvb_minors[dvbdev->minor] = NULL;
up_write(&minor_rwsem);
dvb_media_device_free(dvbdev);
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
list_del (&dvbdev->list_head);
}
EXPORT_SYMBOL(dvb_remove_device);
void dvb_free_device(struct dvb_device *dvbdev)
{
if (!dvbdev)
return;
kfree (dvbdev->fops);
kfree (dvbdev);
}
EXPORT_SYMBOL(dvb_free_device);
void dvb_unregister_device(struct dvb_device *dvbdev)
{
dvb_remove_device(dvbdev);
dvb_free_device(dvbdev);
}
EXPORT_SYMBOL(dvb_unregister_device);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
static int dvb_create_io_intf_links(struct dvb_adapter *adap,
struct media_interface *intf,
char *name)
{
struct media_device *mdev = adap->mdev;
struct media_entity *entity;
struct media_link *link;
media_device_for_each_entity(entity, mdev) {
if (entity->function == MEDIA_ENT_F_IO_DTV) {
if (strncmp(entity->name, name, strlen(name)))
continue;
link = media_create_intf_link(entity, intf,
MEDIA_LNK_FL_ENABLED);
if (!link)
return -ENOMEM;
}
}
return 0;
}
int dvb_create_media_graph(struct dvb_adapter *adap,
bool create_rf_connector)
{
struct media_device *mdev = adap->mdev;
struct media_entity *entity, *tuner = NULL, *demod = NULL, *conn;
struct media_entity *demux = NULL, *ca = NULL;
struct media_link *link;
struct media_interface *intf;
unsigned demux_pad = 0;
unsigned dvr_pad = 0;
unsigned ntuner = 0, ndemod = 0;
int ret;
static const char *connector_name = "Television";
if (!mdev)
return 0;
media_device_for_each_entity(entity, mdev) {
switch (entity->function) {
case MEDIA_ENT_F_TUNER:
tuner = entity;
ntuner++;
break;
case MEDIA_ENT_F_DTV_DEMOD:
demod = entity;
ndemod++;
break;
case MEDIA_ENT_F_TS_DEMUX:
demux = entity;
break;
case MEDIA_ENT_F_DTV_CA:
ca = entity;
break;
}
}
/*
* Prepare to signalize to media_create_pad_links() that multiple
* entities of the same type exists and a 1:n or n:1 links need to be
* created.
* NOTE: if both tuner and demod have multiple instances, it is up
* to the caller driver to create such links.
*/
if (ntuner > 1)
tuner = NULL;
if (ndemod > 1)
demod = NULL;
if (create_rf_connector) {
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
if (!conn)
return -ENOMEM;
adap->conn = conn;
adap->conn_pads = kzalloc(sizeof(*adap->conn_pads), GFP_KERNEL);
if (!adap->conn_pads)
return -ENOMEM;
conn->flags = MEDIA_ENT_FL_CONNECTOR;
conn->function = MEDIA_ENT_F_CONN_RF;
conn->name = connector_name;
adap->conn_pads->flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(conn, 1, adap->conn_pads);
if (ret)
return ret;
ret = media_device_register_entity(mdev, conn);
if (ret)
return ret;
if (!ntuner)
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
MEDIA_ENT_F_DTV_DEMOD,
demod, 0,
MEDIA_LNK_FL_ENABLED,
false);
else
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
MEDIA_ENT_F_TUNER,
tuner, TUNER_PAD_RF_INPUT,
MEDIA_LNK_FL_ENABLED,
false);
if (ret)
return ret;
}
if (ntuner && ndemod) {
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_TUNER,
tuner, TUNER_PAD_OUTPUT,
MEDIA_ENT_F_DTV_DEMOD,
demod, 0, MEDIA_LNK_FL_ENABLED,
false);
if (ret)
return ret;
}
if (ndemod && demux) {
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_DTV_DEMOD,
demod, 1,
MEDIA_ENT_F_TS_DEMUX,
demux, 0, MEDIA_LNK_FL_ENABLED,
false);
if (ret)
return ret;
}
if (demux && ca) {
ret = media_create_pad_link(demux, 1, ca,
0, MEDIA_LNK_FL_ENABLED);
if (ret)
return ret;
}
/* Create demux links for each ringbuffer/pad */
if (demux) {
media_device_for_each_entity(entity, mdev) {
if (entity->function == MEDIA_ENT_F_IO_DTV) {
if (!strncmp(entity->name, DVR_TSOUT,
strlen(DVR_TSOUT))) {
ret = media_create_pad_link(demux,
++dvr_pad,
entity, 0, 0);
if (ret)
return ret;
}
if (!strncmp(entity->name, DEMUX_TSOUT,
strlen(DEMUX_TSOUT))) {
ret = media_create_pad_link(demux,
++demux_pad,
entity, 0, 0);
if (ret)
return ret;
}
}
}
}
/* Create interface links for FE->tuner, DVR->demux and CA->ca */
media_device_for_each_intf(intf, mdev) {
if (intf->type == MEDIA_INTF_T_DVB_CA && ca) {
link = media_create_intf_link(ca, intf,
MEDIA_LNK_FL_ENABLED);
if (!link)
return -ENOMEM;
}
if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) {
link = media_create_intf_link(tuner, intf,
MEDIA_LNK_FL_ENABLED);
if (!link)
return -ENOMEM;
}
#if 0
/*
* Indirect link - let's not create yet, as we don't know how
* to handle indirect links, nor if this will
* actually be needed.
*/
if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) {
link = media_create_intf_link(demux, intf,
MEDIA_LNK_FL_ENABLED);
if (!link)
return -ENOMEM;
}
#endif
if (intf->type == MEDIA_INTF_T_DVB_DVR) {
ret = dvb_create_io_intf_links(adap, intf, DVR_TSOUT);
if (ret)
return ret;
}
if (intf->type == MEDIA_INTF_T_DVB_DEMUX) {
ret = dvb_create_io_intf_links(adap, intf, DEMUX_TSOUT);
if (ret)
return ret;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(dvb_create_media_graph);
#endif
static int dvbdev_check_free_adapter_num(int num)
{
struct list_head *entry;
@@ -347,7 +829,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
memset (adap, 0, sizeof(struct dvb_adapter));
INIT_LIST_HEAD (&adap->device_list);
printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
pr_info("DVB: registering new adapter (%s)\n", name);
adap->num = num;
adap->name = name;
@@ -406,7 +888,7 @@ int dvb_usercopy(struct file *file,
parg = sbuf;
} else {
/* too big to allocate from stack */
mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
if (NULL == mbuf)
return -ENOMEM;
parg = mbuf;
@@ -419,11 +901,8 @@ int dvb_usercopy(struct file *file,
}
/* call driver */
/* this lock is much too coarse */
//mutex_lock(&dvbdev_mutex);
if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
err = -ENOTTY;
//mutex_unlock(&dvbdev_mutex);
if (err < 0)
goto out;
@@ -454,11 +933,7 @@ static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0))
static char *dvb_devnode(struct device *dev, mode_t *mode)
#else
static char *dvb_devnode(struct device *dev, umode_t *mode)
#endif
{
struct dvb_device *dvbdev = dev_get_drvdata(dev);
@@ -473,13 +948,13 @@ static int __init init_dvbdev(void)
dev_t dev = MKDEV(DVB_MAJOR, 0);
if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
pr_err("dvb-core: unable to get major %d\n", DVB_MAJOR);
return retval;
}
cdev_init(&dvb_device_cdev, &dvb_device_fops);
if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
printk(KERN_ERR "dvb-core: unable register character device\n");
pr_err("dvb-core: unable register character device\n");
goto error;
}

View File

@@ -14,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef _DVBDEV_H_
@@ -27,13 +23,14 @@
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <media/media-device.h>
#define DVB_MAJOR 212
#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
#define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
#else
#define DVB_MAX_ADAPTERS 8
#define DVB_MAX_ADAPTERS 64
#endif
#define DVB_UNSET (-1)
@@ -60,6 +57,28 @@
struct dvb_frontend;
/**
* struct dvb_adapter - represents a Digital TV adapter using Linux DVB API
*
* @num: Number of the adapter
* @list_head: List with the DVB adapters
* @device_list: List with the DVB devices
* @name: Name of the adapter
* @proposed_mac: proposed MAC address for the adapter
* @priv: private data
* @device: pointer to struct device
* @module: pointer to struct module
* @mfe_shared: mfe shared: indicates mutually exclusive frontends
* Thie usage of this flag is currently deprecated
* @mfe_dvbdev: Frontend device in use, in the case of MFE
* @mfe_lock: Lock to prevent using the other frontends when MFE is
* used.
* @mdev: pointer to struct media_device, used when the media
* controller is used.
* @conn: RF connector. Used only if the device has no separate
* tuner.
* @conn_pads: pointer to struct media_pad associated with @conn;
*/
struct dvb_adapter {
int num;
struct list_head list_head;
@@ -75,9 +94,47 @@ struct dvb_adapter {
int mfe_shared; /* indicates mutually exclusive frontends */
struct dvb_device *mfe_dvbdev; /* frontend device in use */
struct mutex mfe_lock; /* access lock for thread creation */
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
struct media_device *mdev;
struct media_entity *conn;
struct media_pad *conn_pads;
#endif
};
/**
* struct dvb_device - represents a DVB device node
*
* @list_head: List head with all DVB devices
* @fops: pointer to struct file_operations
* @adapter: pointer to the adapter that holds this device node
* @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND,
* DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET
* @minor: devnode minor number. Major number is always DVB_MAJOR.
* @id: device ID number, inside the adapter
* @readers: Initialized by the caller. Each call to open() in Read Only mode
* decreases this counter by one.
* @writers: Initialized by the caller. Each call to open() in Read/Write
* mode decreases this counter by one.
* @users: Initialized by the caller. Each call to open() in any mode
* decreases this counter by one.
* @wait_queue: wait queue, used to wait for certain events inside one of
* the DVB API callers
* @kernel_ioctl: callback function used to handle ioctl calls from userspace.
* @name: Name to be used for the device at the Media Controller
* @entity: pointer to struct media_entity associated with the device node
* @pads: pointer to struct media_pad associated with @entity;
* @priv: private data
* @intf_devnode: Pointer to media_intf_devnode. Used by the dvbdev core to
* store the MC device node interface
* @tsout_num_entities: Number of Transport Stream output entities
* @tsout_entity: array with MC entities associated to each TS output node
* @tsout_pads: array with the source pads for each @tsout_entity
*
* This structure is used by the DVB core (frontend, CA, net, demux) in
* order to create the device nodes. Usually, driver should not initialize
* this struct diretly.
*/
struct dvb_device {
struct list_head list_head;
const struct file_operations *fops;
@@ -96,34 +153,145 @@ struct dvb_device {
/* don't really need those !? -- FIXME: use video_usercopy */
int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
/* Needed for media controller register/unregister */
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
const char *name;
/* Allocated and filled inside dvbdev.c */
struct media_intf_devnode *intf_devnode;
unsigned tsout_num_entities;
struct media_entity *entity, *tsout_entity;
struct media_pad *pads, *tsout_pads;
#endif
void *priv;
};
/**
* dvb_register_adapter - Registers a new DVB adapter
*
* @adap: pointer to struct dvb_adapter
* @name: Adapter's name
* @module: initialized with THIS_MODULE at the caller
* @device: pointer to struct device that corresponds to the device driver
* @adapter_nums: Array with a list of the numbers for @dvb_register_adapter;
* to select among them. Typically, initialized with:
* DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums)
*/
int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
struct module *module, struct device *device,
short *adapter_nums);
extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
struct module *module, struct device *device,
short *adapter_nums);
extern int dvb_unregister_adapter (struct dvb_adapter *adap);
/**
* dvb_unregister_adapter - Unregisters a DVB adapter
*
* @adap: pointer to struct dvb_adapter
*/
int dvb_unregister_adapter(struct dvb_adapter *adap);
extern int dvb_register_device (struct dvb_adapter *adap,
struct dvb_device **pdvbdev,
const struct dvb_device *template,
void *priv,
int type);
/**
* dvb_register_device - Registers a new DVB device
*
* @adap: pointer to struct dvb_adapter
* @pdvbdev: pointer to the place where the new struct dvb_device will be
* stored
* @template: Template used to create &pdvbdev;
* @priv: private data
* @type: type of the device: %DVB_DEVICE_SEC, %DVB_DEVICE_FRONTEND,
* %DVB_DEVICE_DEMUX, %DVB_DEVICE_DVR, %DVB_DEVICE_CA,
* %DVB_DEVICE_NET
* @demux_sink_pads: Number of demux outputs, to be used to create the TS
* outputs via the Media Controller.
*/
int dvb_register_device(struct dvb_adapter *adap,
struct dvb_device **pdvbdev,
const struct dvb_device *template,
void *priv,
int type,
int demux_sink_pads);
extern void dvb_unregister_device (struct dvb_device *dvbdev);
/**
* dvb_remove_device - Remove a registered DVB device
*
* This does not free memory. To do that, call dvb_free_device().
*
* @dvbdev: pointer to struct dvb_device
*/
void dvb_remove_device(struct dvb_device *dvbdev);
extern int dvb_generic_open (struct inode *inode, struct file *file);
extern int dvb_generic_release (struct inode *inode, struct file *file);
extern long dvb_generic_ioctl (struct file *file,
/**
* dvb_free_device - Free memory occupied by a DVB device.
*
* Call dvb_unregister_device() before calling this function.
*
* @dvbdev: pointer to struct dvb_device
*/
void dvb_free_device(struct dvb_device *dvbdev);
/**
* dvb_unregister_device - Unregisters a DVB device
*
* This is a combination of dvb_remove_device() and dvb_free_device().
* Using this function is usually a mistake, and is often an indicator
* for a use-after-free bug (when a userspace process keeps a file
* handle to a detached device).
*
* @dvbdev: pointer to struct dvb_device
*/
void dvb_unregister_device(struct dvb_device *dvbdev);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
/**
* dvb_create_media_graph - Creates media graph for the Digital TV part of the
* device.
*
* @adap: pointer to struct dvb_adapter
* @create_rf_connector: if true, it creates the RF connector too
*
* This function checks all DVB-related functions at the media controller
* entities and creates the needed links for the media graph. It is
* capable of working with multiple tuners or multiple frontends, but it
* won't create links if the device has multiple tuners and multiple frontends
* or if the device has multiple muxes. In such case, the caller driver should
* manually create the remaining links.
*/
__must_check int dvb_create_media_graph(struct dvb_adapter *adap,
bool create_rf_connector);
static inline void dvb_register_media_controller(struct dvb_adapter *adap,
struct media_device *mdev)
{
adap->mdev = mdev;
}
static inline struct media_device
*dvb_get_media_controller(struct dvb_adapter *adap)
{
return adap->mdev;
}
#else
static inline
int dvb_create_media_graph(struct dvb_adapter *adap,
bool create_rf_connector)
{
return 0;
};
#define dvb_register_media_controller(a, b) {}
#define dvb_get_media_controller(a) NULL
#endif
int dvb_generic_open (struct inode *inode, struct file *file);
int dvb_generic_release (struct inode *inode, struct file *file);
long dvb_generic_ioctl (struct file *file,
unsigned int cmd, unsigned long arg);
/* we don't mess with video_usercopy() any more,
we simply define out own dvb_usercopy(), which will hopefully become
generic_usercopy() someday... */
extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
int (*func)(struct file *file, unsigned int cmd, void *arg));
int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
int (*func)(struct file *file, unsigned int cmd, void *arg));
/** generic DVB attach function. */
#ifdef CONFIG_MEDIA_ATTACH
@@ -140,11 +308,15 @@ extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
__r; \
})
#define dvb_detach(FUNC) symbol_put_addr(FUNC)
#else
#define dvb_attach(FUNCTION, ARGS...) ({ \
FUNCTION(ARGS); \
})
#define dvb_detach(FUNC) {}
#endif
#endif /* #ifndef _DVBDEV_H_ */

838
frontends/Kconfig Normal file
View File

@@ -0,0 +1,838 @@
menu "Customise DVB Frontends"
visible if !MEDIA_SUBDRV_AUTOSELECT
comment "Multistandard (satellite) frontends"
depends on DVB_CORE
config DVB_STB0899
tristate "STB0899 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want
to support this demodulator based frontends
config DVB_STB6100
tristate "STB6100 based tuners"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A Silicon tuner from ST used in conjunction with the STB0899
demodulator. Say Y when you want to support this tuner.
config DVB_STV090x
tristate "STV0900/STV0903(A/B) based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
Say Y when you want to support these frontends.
config DVB_STV6110x
tristate "STV6110/(A) based tuners"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A Silicon tuner that supports DVB-S and DVB-S2 modes
config DVB_STV0910
tristate "STV0910 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
Say Y when you want to support these frontends.
config DVB_MXL5XX
tristate "MXL5XX based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
Say Y when you want to support these frontends.
config DVB_STV6111
tristate "STV6111 based tuners"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A Silicon tuner that supports DVB-S and DVB-S2 modes
config DVB_M88DS3103
tristate "Montage M88DS3103"
depends on DVB_CORE && I2C && I2C_MUX
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
comment "Multistandard (cable + terrestrial) frontends"
depends on DVB_CORE
config DVB_DRXK
tristate "Micronas DRXK based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Micronas DRX-K DVB-C/T demodulator.
Say Y when you want to support this frontend.
config DVB_TDA18271C2DD
tristate "NXP TDA18271C2 silicon tuner"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
NXP TDA18271 silicon tuner.
Say Y when you want to support this tuner.
config DVB_SI2165
tristate "Silicon Labs si2165 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-C/T demodulator.
Say Y when you want to support this frontend.
comment "DVB-S (satellite) frontends"
depends on DVB_CORE
config DVB_CX24110
tristate "Conexant CX24110 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_CX24123
tristate "Conexant CX24123 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_MT312
tristate "Zarlink VP310/MT312/ZL10313 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_ZL10036
tristate "Zarlink ZL10036 silicon tuner"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_ZL10039
tristate "Zarlink ZL10039 silicon tuner"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_S5H1420
tristate "Samsung S5H1420 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_STV0288
tristate "ST STV0288 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_STB6000
tristate "ST STB6000 silicon tuner"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
config DVB_STV0299
tristate "ST STV0299 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_STV6110
tristate "ST STV6110 silicon tuner"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
config DVB_STV0900
tristate "ST STV0900 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S/S2 demodulator. Say Y when you want to support this frontend.
config DVB_TDA8083
tristate "Philips TDA8083 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TDA10086
tristate "Philips TDA10086 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TDA8261
tristate "Philips TDA8261 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_VES1X93
tristate "VLSI VES1893 or VES1993 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TUNER_ITD1000
tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TUNER_CX24113
tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TDA826X
tristate "Philips TDA826X silicon tuner"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
config DVB_TUA6100
tristate "Infineon TUA6100 PLL"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S PLL chip.
config DVB_CX24116
tristate "Conexant CX24116 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
config DVB_CX24117
tristate "Conexant CX24117 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A Dual DVB-S/S2 tuner module. Say Y when you want to support this frontend.
config DVB_SI21XX
tristate "Silicon Labs SI21XX based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TS2020
tristate "Montage Tehnology TS2020 based tuners"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S/S2 silicon tuner. Say Y when you want to support this tuner.
config DVB_DS3000
tristate "Montage Tehnology DS3000 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
config DVB_MB86A16
tristate "Fujitsu MB86A16 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S/DSS Direct Conversion reveiver.
Say Y when you want to support this frontend.
config DVB_TDA10071
tristate "NXP TDA10071"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
config DVB_SP8870
tristate "Spase sp8870 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
This driver needs external firmware. Please use the command
"<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
download/extract it, and then copy it to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_SP887X
tristate "Spase sp887x based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
This driver needs external firmware. Please use the command
"<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
download/extract it, and then copy it to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_CX22700
tristate "Conexant CX22700 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_CX22702
tristate "Conexant cx22702 demodulator (OFDM)"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_S5H1432
tristate "Samsung s5h1432 demodulator (OFDM)"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_DRXD
tristate "Micronas DRXD driver"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
Note: this driver was based on vendor driver reference code (released
under the GPL) as opposed to the existing drx397xd driver, which
was written via reverse engineering.
config DVB_L64781
tristate "LSI L64781"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_TDA1004X
tristate "Philips TDA10045H/TDA10046H based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
This driver needs external firmware. Please use the commands
"<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
"<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
download/extract them, and then copy them to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_NXT6000
tristate "NxtWave Communications NXT6000 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_MT352
tristate "Zarlink MT352 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_ZL10353
tristate "Zarlink ZL10353 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_DIB3000MB
tristate "DiBcom 3000M-B"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
config DVB_DIB3000MC
tristate "DiBcom 3000P/M-C"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
config DVB_DIB7000M
tristate "DiBcom 7000MA/MB/PA/PB/MC"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
config DVB_DIB7000P
tristate "DiBcom 7000PC"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
config DVB_DIB9000
tristate "DiBcom 9000"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
config DVB_TDA10048
tristate "Philips TDA10048HN based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_TDA18212DD
tristate "Philips TDA18212 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_AF9013
tristate "Afatech AF9013 demodulator"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
config DVB_EC100
tristate "E3C EC100"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
config DVB_HD29L2
tristate "HDIC HD29L2"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
config DVB_STV0367
tristate "ST STV0367 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T/C tuner module. Say Y when you want to support this frontend.
config DVB_STV0367DD
tristate "ST STV0367dd based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T/C tuner module. Say Y when you want to support this frontend.
config DVB_CXD2843
tristate "Sony CXD2843"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-T/T2/C/C2 tuner module. Say Y when you want to support this frontend.
config DVB_CXD2820R
tristate "Sony CXD2820R"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
config DVB_RTL2830
tristate "Realtek RTL2830 DVB-T"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
config DVB_RTL2832
tristate "Realtek RTL2832 DVB-T"
depends on DVB_CORE && I2C && I2C_MUX
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
config DVB_RTL2832_SDR
tristate "Realtek RTL2832 SDR"
depends on DVB_CORE && I2C && I2C_MUX && VIDEO_V4L2 && MEDIA_SDR_SUPPORT && USB
select DVB_RTL2832
select VIDEOBUF2_VMALLOC
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this SDR module.
config DVB_SI2168
tristate "Silicon Labs Si2168"
depends on DVB_CORE && I2C && I2C_MUX
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
comment "DVB-C (cable) frontends"
depends on DVB_CORE
config DVB_VES1820
tristate "VLSI VES1820 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-C tuner module. Say Y when you want to support this frontend.
config DVB_TDA10021
tristate "Philips TDA10021 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-C tuner module. Say Y when you want to support this frontend.
config DVB_TDA10023
tristate "Philips TDA10023 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-C tuner module. Say Y when you want to support this frontend.
config DVB_STV0297
tristate "ST STV0297 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-C tuner module. Say Y when you want to support this frontend.
comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
depends on DVB_CORE
config DVB_NXT200X
tristate "NxtWave Communications NXT2002/NXT2004 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
This driver needs external firmware. Please use the commands
"<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
"<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
download/extract them, and then copy them to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_OR51211
tristate "Oren OR51211 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
This driver needs external firmware. Please use the command
"<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
download it, and then copy it to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_OR51132
tristate "Oren OR51132 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
This driver needs external firmware. Please use the commands
"<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or
"<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_qam" to
download firmwares for 8VSB and QAM64/256, respectively. Copy them to
/usr/lib/hotplug/firmware or /lib/firmware (depending on
configuration of firmware hotplug).
config DVB_BCM3510
tristate "Broadcom BCM3510"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
support this frontend.
config DVB_LGDT330X
tristate "LG Electronics LGDT3302/LGDT3303 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
config DVB_LGDT3305
tristate "LG Electronics LGDT3304 and LGDT3305 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
config DVB_LG2160
tristate "LG Electronics LG216x based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An ATSC/MH demodulator module. Say Y when you want
to support this frontend.
config DVB_S5H1409
tristate "Samsung S5H1409 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
config DVB_AU8522
depends on I2C
tristate
config DVB_AU8522_DTV
tristate "Auvitek AU8522 based DTV demod"
depends on DVB_CORE && I2C
select DVB_AU8522
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
you want to enable DTV demodulation support for this frontend.
config DVB_AU8522_V4L
tristate "Auvitek AU8522 based ATV demod"
depends on VIDEO_V4L2 && I2C
select DVB_AU8522
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
you want to enable ATV demodulation support for this frontend.
config DVB_S5H1411
tristate "Samsung S5H1411 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
comment "ISDB-T (terrestrial) frontends"
depends on DVB_CORE
config DVB_S921
tristate "Sharp S921 frontend"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
Say Y when you want to support this frontend.
config DVB_DIB8000
tristate "DiBcom 8000MB/MC"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator.
Say Y when you want to support this frontend.
config DVB_MB86A20S
tristate "Fujitsu mb86a20s"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
Say Y when you want to support this frontend.
comment "Digital terrestrial only tuners/PLL"
depends on DVB_CORE
config DVB_PLL
tristate "Generic I2C PLL based tuners"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
This module drives a number of tuners based on PLL chips with a
common I2C interface. Say Y when you want to support these tuners.
config DVB_TUNER_DIB0070
tristate "DiBcom DiB0070 silicon base-band tuner"
depends on I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A driver for the silicon baseband tuner DiB0070 from DiBcom.
This device is only used inside a SiP called together with a
demodulator for now.
config DVB_TUNER_DIB0090
tristate "DiBcom DiB0090 silicon base-band tuner"
depends on I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A driver for the silicon baseband tuner DiB0090 from DiBcom.
This device is only used inside a SiP called together with a
demodulator for now.
comment "SEC control devices for DVB-S"
depends on DVB_CORE
source "drivers/media/dvb-frontends/drx39xyj/Kconfig"
config DVB_LNBP21
tristate "LNBP21/LNBH24 SEC controllers"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An SEC control chips.
config DVB_LNBH25
tristate "LNBH25 SEC controllers"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An SEC control chips.
config DVB_LNBP22
tristate "LNBP22 SEC controllers"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
LNB power supply and control voltage
regulator chip with step-up converter
and I2C interface.
Say Y when you want to support this chip.
config DVB_ISL6405
tristate "ISL6405 SEC controller"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An SEC control chip.
config DVB_ISL6421
tristate "ISL6421 SEC controller"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
An SEC control chip.
config DVB_ISL6423
tristate "ISL6423 SEC controller"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A SEC controller chip from Intersil
config DVB_A8293
tristate "Allegro A8293"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
config DVB_LGS8GL5
tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DMB-TH tuner module. Say Y when you want to support this frontend.
config DVB_LGS8GXX
tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
depends on DVB_CORE && I2C
select FW_LOADER
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DMB-TH tuner module. Say Y when you want to support this frontend.
config DVB_ATBM8830
tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DMB-TH tuner module. Say Y when you want to support this frontend.
config DVB_TDA665x
tristate "TDA665x tuner"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Support for tuner modules based on Philips TDA6650/TDA6651 chips.
Say Y when you want to support this chip.
Currently supported tuners:
* Panasonic ENV57H12D5 (ET-50DT)
config DVB_IX2505V
tristate "Sharp IX2505V silicon tuner"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_M88RS2000
tristate "M88RS2000 DVB-S demodulator and tuner"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S tuner module.
Say Y when you want to support this frontend.
config DVB_AF9033
tristate "Afatech AF9033 DVB-T demodulator"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
config DVB_CXD2099
tristate "cxd2099"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
comment "Tools to develop new frontends"
config DVB_DUMMY_FE
tristate "Dummy frontend driver"
default n
endmenu

View File

@@ -14,6 +14,7 @@ EXTRA_CFLAGS += -DCONFIG_DVB_STV6111
EXTRA_CFLAGS += -DCONFIG_DVB_STV0910
EXTRA_CFLAGS += -DCONFIG_DVB_LNBH25
EXTRA_CFLAGS += -DCONFIG_DVB_MXL5XX
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2099
EXTRA_CFLAGS += -DDBVALS
NOSTDINC_FLAGS += -I$(SUBDIRS)/include -I$(SUBDIRS)/dvb-core

123
frontends/Makefile.kernel Normal file
View File

@@ -0,0 +1,123 @@
#
# Makefile for the kernel DVB frontend device drivers.
#
ccflags-y += -I$(srctree)/drivers/media/dvb-core/
ccflags-y += -I$(srctree)/drivers/media/tuners/
# FIXME: RTL2832 SDR driver uses power management directly from USB IF driver
ifdef CONFIG_DVB_RTL2832_SDR
ccflags-y += -I$(srctree)/drivers/media/usb/dvb-usb-v2
endif
stb0899-objs := stb0899_drv.o stb0899_algo.o
stv0900-objs := stv0900_core.o stv0900_sw.o
drxd-objs := drxd_firm.o drxd_hard.o
cxd2820r-objs := cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
drxk-objs := drxk_hard.o
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
obj-$(CONFIG_DVB_STB0899) += stb0899.o
obj-$(CONFIG_DVB_STB6100) += stb6100.o
obj-$(CONFIG_DVB_SP8870) += sp8870.o
obj-$(CONFIG_DVB_CX22700) += cx22700.o
obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
obj-$(CONFIG_DVB_CX24110) += cx24110.o
obj-$(CONFIG_DVB_TDA8083) += tda8083.o
obj-$(CONFIG_DVB_L64781) += l64781.o
obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o
obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o
obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o
obj-$(CONFIG_DVB_DIB9000) += dib9000.o dibx000_common.o
obj-$(CONFIG_DVB_MT312) += mt312.o
obj-$(CONFIG_DVB_VES1820) += ves1820.o
obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
obj-$(CONFIG_DVB_SP887X) += sp887x.o
obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
obj-$(CONFIG_DVB_MT352) += mt352.o
obj-$(CONFIG_DVB_ZL10036) += zl10036.o
obj-$(CONFIG_DVB_ZL10039) += zl10039.o
obj-$(CONFIG_DVB_ZL10353) += zl10353.o
obj-$(CONFIG_DVB_CX22702) += cx22702.o
obj-$(CONFIG_DVB_DRXD) += drxd.o
obj-$(CONFIG_DVB_TDA10021) += tda10021.o
obj-$(CONFIG_DVB_TDA10023) += tda10023.o
obj-$(CONFIG_DVB_STV0297) += stv0297.o
obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
obj-$(CONFIG_DVB_OR51211) += or51211.o
obj-$(CONFIG_DVB_OR51132) += or51132.o
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
obj-$(CONFIG_DVB_LG2160) += lg2160.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
obj-$(CONFIG_DVB_ISL6405) += isl6405.o
obj-$(CONFIG_DVB_ISL6421) += isl6421.o
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
obj-$(CONFIG_DVB_TDA8261) += tda8261.o
obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
obj-$(CONFIG_DVB_AU8522) += au8522_common.o
obj-$(CONFIG_DVB_AU8522_DTV) += au8522_dig.o
obj-$(CONFIG_DVB_AU8522_V4L) += au8522_decoder.o
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
obj-$(CONFIG_DVB_TDA665x) += tda665x.o
obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
obj-$(CONFIG_DVB_AF9013) += af9013.o
obj-$(CONFIG_DVB_CX24116) += cx24116.o
obj-$(CONFIG_DVB_CX24117) += cx24117.o
obj-$(CONFIG_DVB_SI21XX) += si21xx.o
obj-$(CONFIG_DVB_SI2168) += si2168.o
obj-$(CONFIG_DVB_STV0288) += stv0288.o
obj-$(CONFIG_DVB_STB6000) += stb6000.o
obj-$(CONFIG_DVB_S921) += s921.o
obj-$(CONFIG_DVB_STV6110) += stv6110.o
obj-$(CONFIG_DVB_STV0900) += stv0900.o
obj-$(CONFIG_DVB_STV090x) += stv090x.o
obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
obj-$(CONFIG_DVB_TS2020) += ts2020.o
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
obj-$(CONFIG_DVB_DRX39XYJ) += drx39xyj/
obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
obj-$(CONFIG_DVB_STV0367) += stv0367.o
obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
obj-$(CONFIG_DVB_DRXK) += drxk.o
obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
obj-$(CONFIG_DVB_SI2165) += si2165.o
obj-$(CONFIG_DVB_A8293) += a8293.o
obj-$(CONFIG_DVB_TDA10071) += tda10071.o
obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o
obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
obj-$(CONFIG_DVB_AF9033) += af9033.o
obj-$(CONFIG_DVB_STV0367DD) += stv0367dd.o
obj-$(CONFIG_DVB_TDA18212DD) += tda18212dd.o
obj-$(CONFIG_DVB_CXD2099) += cxd2099.o
obj-$(CONFIG_DVB_CXD2843) += cxd2843.o
obj-$(CONFIG_DVB_STV6111) += stv6111.o
obj-$(CONFIG_DVB_STV0910) += stv0910.o
obj-$(CONFIG_DVB_LNBH25) += lnbh25.o
obj-$(CONFIG_DVB_MXL5XX) += mxl5xx.o

View File

@@ -22,12 +22,9 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/version.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/wait.h>
#include <linux/delay.h>
@@ -36,7 +33,9 @@
#include "cxd2099.h"
//#define BUFFER_MODE 1
static int buffermode;
module_param(buffermode, int, 0444);
MODULE_PARM_DESC(buffermode, "Enable use of the CXD2099AR buffer mode (default: disabled)");
static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount);
@@ -73,8 +72,9 @@ static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2};
if (i2c_transfer(adapter, &msg, 1) != 1) {
pr_err("Failed to write to I2C register %02x@%02x!\n",
reg, adr);
dev_err(&adapter->dev,
"Failed to write to I2C register %02x@%02x!\n",
reg, adr);
return -1;
}
return 0;
@@ -86,7 +86,7 @@ static int i2c_write(struct i2c_adapter *adapter, u8 adr,
struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len};
if (i2c_transfer(adapter, &msg, 1) != 1) {
pr_err("Failed to write to I2C!\n");
dev_err(&adapter->dev, "Failed to write to I2C!\n");
return -1;
}
return 0;
@@ -101,7 +101,7 @@ static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
.buf = val, .len = 1} };
if (i2c_transfer(adapter, msgs, 2) != 2) {
pr_err("error in i2c_read_reg\n");
dev_err(&adapter->dev, "error in i2c_read_reg\n");
return -1;
}
return 0;
@@ -114,9 +114,9 @@ static int i2c_read(struct i2c_adapter *adapter, u8 adr,
.buf = &reg, .len = 1},
{.addr = adr, .flags = I2C_M_RD,
.buf = data, .len = n} };
if (i2c_transfer(adapter, msgs, 2) != 2) {
pr_err("error in i2c_read\n");
dev_err(&adapter->dev, "error in i2c_read\n");
return -1;
}
return 0;
@@ -133,9 +133,8 @@ static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
while (n) {
int len = n;
if (ci->cfg.max_i2c &&
len > ci->cfg.max_i2c)
if (ci->cfg.max_i2c && (len > ci->cfg.max_i2c))
len = ci->cfg.max_i2c;
status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, len);
if (status)
@@ -152,7 +151,6 @@ static int read_reg(struct cxd *ci, u8 reg, u8 *val)
return read_block(ci, reg, val, 1);
}
static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
{
int status;
@@ -174,7 +172,7 @@ static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
u8 buf[256] = {3};
memcpy(buf + 1, data, n);
status = i2c_write(ci->i2c, ci->cfg.adr, buf, n+1);
status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
}
return status;
}
@@ -253,7 +251,6 @@ static int write_reg(struct cxd *ci, u8 reg, u8 val)
return write_regm(ci, reg, val, 0xff);
}
#ifdef BUFFER_MODE
static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
{
int status = 0;
@@ -263,17 +260,14 @@ static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
if (status)
return status;
printk("write_block %d\n", n);
ci->lastaddress = adr;
buf[0] = 1;
while (n) {
int len = n;
if (ci->cfg.max_i2c &&
len + 1 > ci->cfg.max_i2c)
if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c))
len = ci->cfg.max_i2c - 1;
printk("write %d\n", len);
memcpy(buf + 1, data, len);
status = i2c_write(ci->i2c, ci->cfg.adr, buf, len + 1);
if (status)
@@ -283,7 +277,6 @@ static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
}
return status;
}
#endif
static void set_mode(struct cxd *ci, int mode)
{
@@ -318,7 +311,7 @@ static void cam_mode(struct cxd *ci, int mode)
if (!ci->en.read_data)
return;
ci->write_busy = 0;
pr_info("enable cam buffer mode\n");
dev_info(&ci->i2c->dev, "enable cam buffer mode\n");
write_reg(ci, 0x0d, 0x00);
write_reg(ci, 0x0e, 0x01);
write_regm(ci, 0x08, 0x40, 0x40);
@@ -331,8 +324,6 @@ static void cam_mode(struct cxd *ci, int mode)
ci->cammode = mode;
}
#define CHK_ERROR(s) if ((status = s)) break
static int init(struct cxd *ci)
{
int status;
@@ -340,67 +331,140 @@ static int init(struct cxd *ci)
mutex_lock(&ci->lock);
ci->mode = -1;
do {
CHK_ERROR(write_reg(ci, 0x00, 0x00));
CHK_ERROR(write_reg(ci, 0x01, 0x00));
CHK_ERROR(write_reg(ci, 0x02, 0x10));
CHK_ERROR(write_reg(ci, 0x03, 0x00));
CHK_ERROR(write_reg(ci, 0x05, 0xFF));
CHK_ERROR(write_reg(ci, 0x06, 0x1F));
CHK_ERROR(write_reg(ci, 0x07, 0x1F));
CHK_ERROR(write_reg(ci, 0x08, 0x28));
CHK_ERROR(write_reg(ci, 0x14, 0x20));
status = write_reg(ci, 0x00, 0x00);
if (status < 0)
break;
status = write_reg(ci, 0x01, 0x00);
if (status < 0)
break;
status = write_reg(ci, 0x02, 0x10);
if (status < 0)
break;
status = write_reg(ci, 0x03, 0x00);
if (status < 0)
break;
status = write_reg(ci, 0x05, 0xFF);
if (status < 0)
break;
status = write_reg(ci, 0x06, 0x1F);
if (status < 0)
break;
status = write_reg(ci, 0x07, 0x1F);
if (status < 0)
break;
status = write_reg(ci, 0x08, 0x28);
if (status < 0)
break;
status = write_reg(ci, 0x14, 0x20);
if (status < 0)
break;
/* TOSTRT = 8, Mode B (gated clock), falling Edge,
Serial, POL=HIGH, MSB */
CHK_ERROR(write_reg(ci, 0x0A, 0xA7));
* Serial, POL=HIGH, MSB
*/
status = write_reg(ci, 0x0A, 0xA7);
if (status < 0)
break;
CHK_ERROR(write_reg(ci, 0x0B, 0x33));
CHK_ERROR(write_reg(ci, 0x0C, 0x33));
status = write_reg(ci, 0x0B, 0x33);
if (status < 0)
break;
status = write_reg(ci, 0x0C, 0x33);
if (status < 0)
break;
CHK_ERROR(write_regm(ci, 0x14, 0x00, 0x0F));
CHK_ERROR(write_reg(ci, 0x15, ci->clk_reg_b));
CHK_ERROR(write_regm(ci, 0x16, 0x00, 0x0F));
CHK_ERROR(write_reg(ci, 0x17, ci->clk_reg_f));
status = write_regm(ci, 0x14, 0x00, 0x0F);
if (status < 0)
break;
status = write_reg(ci, 0x15, ci->clk_reg_b);
if (status < 0)
break;
status = write_regm(ci, 0x16, 0x00, 0x0F);
if (status < 0)
break;
status = write_reg(ci, 0x17, ci->clk_reg_f);
if (status < 0)
break;
if (ci->cfg.clock_mode == 2) {
/* bitrate*2^13/ 72000 */
u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000;
if (ci->cfg.polarity) {
CHK_ERROR(write_reg(ci, 0x09, 0x6f));
status = write_reg(ci, 0x09, 0x6f);
if (status < 0)
break;
} else {
CHK_ERROR(write_reg(ci, 0x09, 0x6d));
status = write_reg(ci, 0x09, 0x6d);
if (status < 0)
break;
}
CHK_ERROR(write_reg(ci, 0x20, 0x08));
CHK_ERROR(write_reg(ci, 0x21, (reg >> 8) & 0xff));
CHK_ERROR(write_reg(ci, 0x22, reg & 0xff));
status = write_reg(ci, 0x20, 0x08);
if (status < 0)
break;
status = write_reg(ci, 0x21, (reg >> 8) & 0xff);
if (status < 0)
break;
status = write_reg(ci, 0x22, reg & 0xff);
if (status < 0)
break;
} else if (ci->cfg.clock_mode == 1) {
if (ci->cfg.polarity) {
CHK_ERROR(write_reg(ci, 0x09, 0x6f)); /* D */
status = write_reg(ci, 0x09, 0x6f); /* D */
if (status < 0)
break;
} else {
CHK_ERROR(write_reg(ci, 0x09, 0x6d));
status = write_reg(ci, 0x09, 0x6d);
if (status < 0)
break;
}
CHK_ERROR(write_reg(ci, 0x20, 0x68));
CHK_ERROR(write_reg(ci, 0x21, 0x00));
CHK_ERROR(write_reg(ci, 0x22, 0x02));
status = write_reg(ci, 0x20, 0x68);
if (status < 0)
break;
status = write_reg(ci, 0x21, 0x00);
if (status < 0)
break;
status = write_reg(ci, 0x22, 0x02);
if (status < 0)
break;
} else {
if (ci->cfg.polarity) {
CHK_ERROR(write_reg(ci, 0x09, 0x4f)); /* C */
status = write_reg(ci, 0x09, 0x4f); /* C */
if (status < 0)
break;
} else {
CHK_ERROR(write_reg(ci, 0x09, 0x4d));
status = write_reg(ci, 0x09, 0x4d);
if (status < 0)
break;
}
CHK_ERROR(write_reg(ci, 0x20, 0x28));
CHK_ERROR(write_reg(ci, 0x21, 0x00));
CHK_ERROR(write_reg(ci, 0x22, 0x07));
status = write_reg(ci, 0x20, 0x28);
if (status < 0)
break;
status = write_reg(ci, 0x21, 0x00);
if (status < 0)
break;
status = write_reg(ci, 0x22, 0x07);
if (status < 0)
break;
}
CHK_ERROR(write_regm(ci, 0x20, 0x80, 0x80));
CHK_ERROR(write_regm(ci, 0x03, 0x02, 0x02));
CHK_ERROR(write_reg(ci, 0x01, 0x04));
CHK_ERROR(write_reg(ci, 0x00, 0x31));
status = write_regm(ci, 0x20, 0x80, 0x80);
if (status < 0)
break;
status = write_regm(ci, 0x03, 0x02, 0x02);
if (status < 0)
break;
status = write_reg(ci, 0x01, 0x04);
if (status < 0)
break;
status = write_reg(ci, 0x00, 0x31);
if (status < 0)
break;
/* Put TS in bypass */
CHK_ERROR(write_regm(ci, 0x09, 0x08, 0x08));
status = write_regm(ci, 0x09, 0x08, 0x08);
if (status < 0)
break;
ci->cammode = -1;
cam_mode(ci, 0);
} while (0);
@@ -504,14 +568,16 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
ci->ready = 0;
#endif
#endif
ci->ready = 0;
ci->mode = -1;
{
int i;
#if 0
u8 val;
#endif
for (i = 0; i < 100; i++) {
msleep(20);
usleep_range(10000, 11000);
#if 0
read_reg(ci, 0x06, &val);
pr_info(KERN_INFO "%d:%02x\n", i, val);
@@ -524,7 +590,10 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
}
}
mutex_unlock(&ci->lock);
/* msleep(500); */
/* Ensure cam stability after reset */
msleep(2000);
return 0;
}
@@ -532,7 +601,7 @@ static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
{
struct cxd *ci = ca->data;
pr_info("slot_shutdown\n");
dev_info(&ci->i2c->dev, "%s\n", __func__);
if (ci->cammode)
read_data(ca, slot, ci->rbuf, 0);
mutex_lock(&ci->lock);
@@ -562,7 +631,6 @@ static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
return 0;
}
static int campoll(struct cxd *ci)
{
u8 istat;
@@ -576,6 +644,7 @@ static int campoll(struct cxd *ci)
ci->dr = 1;
if (istat & 0x20)
ci->write_busy = 0;
if (istat & 2) {
u8 slotstat;
@@ -583,7 +652,7 @@ static int campoll(struct cxd *ci)
if (!(2 & slotstat)) {
if (!ci->slot_stat) {
ci->slot_stat |=
DVB_CA_EN50221_POLL_CAM_PRESENT;
DVB_CA_EN50221_POLL_CAM_PRESENT;
write_regm(ci, 0x03, 0x08, 0x08);
}
@@ -591,7 +660,7 @@ static int campoll(struct cxd *ci)
if (ci->slot_stat) {
ci->slot_stat = 0;
write_regm(ci, 0x03, 0x00, 0x08);
pr_info("NO CAM\n");
dev_info(&ci->i2c->dev, "NO CAM\n");
ci->ready = 0;
}
}
@@ -604,7 +673,6 @@ static int campoll(struct cxd *ci)
return 0;
}
static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
{
struct cxd *ci = ca->data;
@@ -634,7 +702,7 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
mutex_lock(&ci->lock);
read_reg(ci, 0x0f, &msb);
read_reg(ci, 0x10, &lsb);
len = ((u16) msb << 8) | lsb;
len = ((u16)msb << 8) | lsb;
if (len > ecount || len < 2) {
/* read it anyway or cxd may hang */
read_block(ci, 0x12, ci->rbuf, len);
@@ -644,21 +712,9 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
read_block(ci, 0x12, ebuf, len);
ci->dr = 0;
mutex_unlock(&ci->lock);
#if 0
pr_info("read_data %d\n", len);
{
int i;
for (i = 0; i < len; i++)
pr_info("%02x ", ebuf[i]);
pr_info("\n");
}
#endif
return len;
}
#ifdef BUFFER_MODE
static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
{
struct cxd *ci = ca->data;
@@ -673,7 +729,6 @@ static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
mutex_unlock(&ci->lock);
return ecount;
}
#endif
static struct dvb_ca_en50221 en_templ = {
.read_attribute_mem = read_attribute_mem,
@@ -684,43 +739,49 @@ static struct dvb_ca_en50221 en_templ = {
.slot_shutdown = slot_shutdown,
.slot_ts_enable = slot_ts_enable,
.poll_slot_status = poll_slot_status,
#ifdef BUFFER_MODE
.read_data = read_data,
.write_data = write_data,
#endif
};
struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
void *priv,
struct i2c_adapter *i2c)
{
struct cxd *ci = 0;
struct cxd *ci;
u8 val;
if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) {
pr_info("No CXD2099 detected at %02x\n", cfg->adr);
return 0;
dev_info(&i2c->dev, "No CXD2099 detected at %02x\n", cfg->adr);
return NULL;
}
ci = kzalloc(sizeof(struct cxd), GFP_KERNEL);
ci = kzalloc(sizeof(*ci), GFP_KERNEL);
if (!ci)
return 0;
return NULL;
mutex_init(&ci->lock);
memcpy(&ci->cfg, cfg, sizeof(struct cxd2099_cfg));
ci->cfg = *cfg;
ci->i2c = i2c;
ci->lastaddress = 0xff;
ci->clk_reg_b = 0x4a;
ci->clk_reg_f = 0x1b;
memcpy(&ci->en, &en_templ, sizeof(en_templ));
ci->en = en_templ;
ci->en.data = ci;
init(ci);
pr_info("Attached CXD2099AR at %02x\n", ci->cfg.adr);
dev_info(&i2c->dev, "Attached CXD2099AR at %02x\n", ci->cfg.adr);
if (!buffermode) {
ci->en.read_data = NULL;
ci->en.write_data = NULL;
} else {
dev_info(&i2c->dev, "Using CXD2099AR buffer mode");
}
return &ci->en;
}
EXPORT_SYMBOL(cxd2099_attach);
MODULE_DESCRIPTION("cxd2099");
MODULE_AUTHOR("Ralph Metzler");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

@@ -36,8 +36,18 @@ struct cxd2099_cfg {
u32 max_i2c;
};
#if defined(CONFIG_DVB_CXD2099) || \
(defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE))
struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
void *priv, struct i2c_adapter *i2c);
#else
static inline struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
void *priv, struct i2c_adapter *i2c)
{
dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
#endif

View File

@@ -270,9 +270,10 @@ static int writebitsx(struct cxd_state *cxd, u8 Bank, u8 Address,
mutex_lock(&cxd->mutex);
status = readregsx_unlocked(cxd, Bank, Address, &tmp, 1);
if (status < 0)
return status;
goto out;
tmp = (tmp & ~Mask) | Value;
status = writeregsx_unlocked(cxd, Bank, Address, &tmp, 1);
out:
mutex_unlock(&cxd->mutex);
return status;
}
@@ -286,9 +287,10 @@ static int writebitst(struct cxd_state *cxd, u8 Bank, u8 Address,
mutex_lock(&cxd->mutex);
status = readregst_unlocked(cxd, Bank, Address, &Tmp, 1);
if (status < 0)
return status;
goto out;
Tmp = (Tmp & ~Mask) | Value;
status = writeregst_unlocked(cxd, Bank, Address, &Tmp, 1);
out:
mutex_unlock(&cxd->mutex);
return status;
}
@@ -1667,17 +1669,17 @@ static int get_stats(struct dvb_frontend *fe)
str -= 108750;
p->strength.len = 1;
p->strength.stat[0].scale = FE_SCALE_DECIBEL;
p->strength.stat[0].uvalue = str;
p->strength.stat[0].svalue = str;
read_snr(fe, &val);
p->cnr.len = 1;
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
p->cnr.stat[0].uvalue = 100 * (s64) (s16) val;
p->cnr.stat[0].svalue = 100 * (s64) (s16) val;
return 0;
}
static int read_status(struct dvb_frontend *fe, fe_status_t *status)
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{
struct cxd_state *state = fe->demodulator_priv;
u8 rdata;
@@ -2177,7 +2179,7 @@ static int read_snr(struct dvb_frontend *fe, u16 *snr)
*snr = SNR;
p->cnr.len = 1;
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
p->cnr.stat[0].uvalue = 10 * (s64) SNR;
p->cnr.stat[0].svalue = 10 * (s64) SNR;
return 0;
}
@@ -2189,7 +2191,7 @@ static int read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
static int tune(struct dvb_frontend *fe, bool re_tune,
unsigned int mode_flags,
unsigned int *delay, fe_status_t *status)
unsigned int *delay, enum fe_status *status)
{
struct cxd_state *state = fe->demodulator_priv;
int r;
@@ -2201,12 +2203,13 @@ static int tune(struct dvb_frontend *fe, bool re_tune,
state->tune_time = jiffies;
}
if (*status & FE_HAS_LOCK)
return 0;
/* *delay = 50; */
r = read_status(fe, status);
if (r)
return r;
if (*status & FE_HAS_LOCK) {
*delay = HZ;
return 0;
}
return 0;
}
@@ -2214,7 +2217,7 @@ static enum dvbfe_search search(struct dvb_frontend *fe)
{
int r;
u32 loops = 20, i;
fe_status_t status;
enum fe_status status;
r = set_parameters(fe);
@@ -2238,10 +2241,9 @@ static int get_algo(struct dvb_frontend *fe)
return DVBFE_ALGO_HW;
}
static int get_fe_t2(struct cxd_state *state)
static int get_fe_t2(struct cxd_state *state, struct dtv_frontend_properties *p)
{
struct dvb_frontend *fe = &state->frontend;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u8 ofdm[5], modcod[2];
freeze_regst(state);
@@ -2310,9 +2312,6 @@ static int get_fe_t2(struct cxd_state *state)
case 5:
p->transmission_mode = TRANSMISSION_MODE_32K;
break;
case 6:
p->transmission_mode = TRANSMISSION_MODE_64K;
break;
}
switch ((ofdm[1] >> 4) & 0x07) {
@@ -2342,10 +2341,9 @@ static int get_fe_t2(struct cxd_state *state)
return 0;
}
static int get_fe_t(struct cxd_state *state)
static int get_fe_t(struct cxd_state *state, struct dtv_frontend_properties *p)
{
struct dvb_frontend *fe = &state->frontend;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u8 tps[7];
read_tps(state, tps);
@@ -2444,10 +2442,9 @@ static int get_fe_t(struct cxd_state *state)
return 0;
}
static int get_fe_c(struct cxd_state *state)
static int get_fe_c(struct cxd_state *state, struct dtv_frontend_properties *p)
{
struct dvb_frontend *fe = &state->frontend;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u8 qam;
freeze_regst(state);
@@ -2457,7 +2454,7 @@ static int get_fe_c(struct cxd_state *state)
return 0;
}
static int get_frontend(struct dvb_frontend *fe)
static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{
struct cxd_state *state = fe->demodulator_priv;
@@ -2466,13 +2463,13 @@ static int get_frontend(struct dvb_frontend *fe)
switch (state->state) {
case ActiveT:
get_fe_t(state);
get_fe_t(state, p);
break;
case ActiveT2:
get_fe_t2(state);
get_fe_t2(state, p);
break;
case ActiveC:
get_fe_c(state);
get_fe_c(state, p);
break;
case ActiveC2:
break;
@@ -2693,4 +2690,4 @@ EXPORT_SYMBOL(cxd2843_attach);
MODULE_DESCRIPTION("CXD2843/37/38 driver");
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

@@ -4892,14 +4892,14 @@ static int drxk_set_parameters (struct dvb_frontend *fe,
return 0;
}
static int drxk_c_get_frontend(struct dvb_frontend *fe)
static int drxk_c_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{
//struct drxk_state *state = fe->demodulator_priv;
//printk("%s\n", __FUNCTION__);
return 0;
}
static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
static int drxk_read_status(struct dvb_frontend *fe, enum fe_status *status)
{
struct drxk_state *state = fe->demodulator_priv;
u32 stat;
@@ -4986,7 +4986,7 @@ static int drxk_t_sleep(struct dvb_frontend* fe)
return 0;
}
static int drxk_t_get_frontend(struct dvb_frontend *fe)
static int drxk_t_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{
//struct drxk_state *state = fe->demodulator_priv;
//printk("%s\n", __FUNCTION__);
@@ -5088,6 +5088,6 @@ error:
MODULE_DESCRIPTION("DRX-K driver");
MODULE_AUTHOR("Ralph Metzler");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
EXPORT_SYMBOL(drxk_attach);

View File

@@ -62,7 +62,7 @@ static int lnbh25_write_regs(struct lnbh25 *lnbh, int reg, int len)
}
static int lnbh25_set_voltage(struct dvb_frontend *fe,
fe_sec_voltage_t voltage)
enum fe_sec_voltage voltage)
{
struct lnbh25 *lnbh = (struct lnbh25 *) fe->sec_priv;
u8 oldreg0 = lnbh->reg[0];
@@ -107,7 +107,7 @@ static int lnbh25_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
}
static int lnbh25_set_tone(struct dvb_frontend *fe,
fe_sec_tone_mode_t tone)
enum fe_sec_tone_mode tone)
{
/* struct lnbh25 *lnbh = (struct lnbh25 *) fe->sec_priv; */
@@ -146,7 +146,7 @@ struct dvb_frontend *lnbh25_attach(struct dvb_frontend *fe,
fe->ops.enable_high_lnb_voltage = lnbh25_enable_high_lnb_voltage;
fe->ops.release_sec = lnbh25_release;
pr_info("LNB25 on %02x\n", lnbh->adr);
pr_info("LNBH25 on %02x\n", lnbh->adr);
return fe;
}
@@ -154,4 +154,4 @@ EXPORT_SYMBOL(lnbh25_attach);
MODULE_DESCRIPTION("LNBH25");
MODULE_AUTHOR("Ralph Metzler");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

@@ -45,7 +45,7 @@ struct lnbp21 {
};
static int lnbp21_set_voltage(struct dvb_frontend *fe,
fe_sec_voltage_t voltage)
enum fe_sec_voltage voltage)
{
struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,
@@ -98,7 +98,7 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
}
static int lnbp21_set_tone(struct dvb_frontend *fe,
fe_sec_tone_mode_t tone)
enum fe_sec_tone_mode tone)
{
struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,

View File

@@ -424,9 +424,22 @@ static int get_algo(struct dvb_frontend *fe)
return DVBFE_ALGO_HW;
}
/*
static int cfg_scrambler(struct mxl *state)
/* This should maybe go into dvb-core/dvb_math.c */
static u32 gold2root(u32 gold)
{
u32 x, g;
if (gold >= 0x3ffff)
gold = 0;
for (g = 0, x = 1; g < gold; g++)
x = (((x ^ (x >> 7)) & 1) << 17) | (x >> 1);
return x;
}
static int cfg_scrambler(struct mxl *state, u32 gold)
{
u32 root;
u8 buf[26] = {
MXL_HYDRA_PLID_CMD_WRITE, 24,
0, MXL_HYDRA_DEMOD_SCRAMBLE_CODE_CMD, 0, 0,
@@ -435,11 +448,15 @@ static int cfg_scrambler(struct mxl *state)
0, 0, 0, 0, 1, 0, 0, 0,
};
root = gold2root(gold);
buf[25] = (root >> 24) & 0xff;
buf[24] = (root >> 16) & 0xff;
buf[23] = (root >> 8) & 0xff;
buf[22] = root & 0xff;
return send_command(state, sizeof(buf), buf);
}
*/
static int CfgDemodAbortTune(struct mxl *state)
{
MXL_HYDRA_DEMOD_ABORT_TUNE_T abortTuneCmd;
@@ -510,7 +527,7 @@ static int set_parameters(struct dvb_frontend *fe)
demodChanCfg.rollOff = MXL_HYDRA_ROLLOFF_AUTO;
demodChanCfg.modulationScheme = MXL_HYDRA_MOD_AUTO;
demodChanCfg.pilots = MXL_HYDRA_PILOTS_AUTO;
//cfg_scrambler(state);
cfg_scrambler(state, p->scrambling_sequence_index);
break;
default:
return -EINVAL;
@@ -540,7 +557,7 @@ static int set_parameters(struct dvb_frontend *fe)
static int get_stats(struct dvb_frontend *fe);
static int read_status(struct dvb_frontend *fe, fe_status_t *status)
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{
struct mxl *state = fe->demodulator_priv;
@@ -562,10 +579,10 @@ static int read_status(struct dvb_frontend *fe, fe_status_t *status)
static int tune(struct dvb_frontend *fe, bool re_tune,
unsigned int mode_flags,
unsigned int *delay, fe_status_t *status)
unsigned int *delay, enum fe_status *status)
{
struct mxl *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
/* struct dtv_frontend_properties *p = &fe->dtv_property_cache; */
int r = 0;
*delay = HZ / 2;
@@ -576,17 +593,13 @@ static int tune(struct dvb_frontend *fe, bool re_tune,
state->tune_time = jiffies;
return 0;
}
if (*status & FE_HAS_LOCK)
return 0;
r = read_status(fe, status);
if (r)
return r;
#if 0
if (*status & FE_HAS_LOCK)
return 0;
#if 0
if (p->delivery_system == SYS_DVBS)
p->delivery_system = SYS_DVBS2;
else
@@ -635,7 +648,7 @@ static int read_snr(struct dvb_frontend *fe, u16 *snr)
*snr = (s16) (regData & 0xFFFF); /* 100x dB */
p->cnr.len = 1;
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
p->cnr.stat[0].uvalue = 10 * (s64) *snr;
p->cnr.stat[0].svalue = 10 * (s64) *snr;
return stat;
}
@@ -643,7 +656,7 @@ static int read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct mxl *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 reg[8], reg2[4], n = 0, d = 0;
u32 reg[8], reg2[4];
int stat;
*ber = 0;
@@ -673,7 +686,7 @@ static int read_ber(struct dvb_frontend *fe, u32 *ber)
p->pre_bit_error.stat[0].uvalue = reg[5];
p->pre_bit_count.len = 1;
p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
p->pre_bit_count.stat[0].uvalue = reg[6] * 188 * 8;
p->pre_bit_count.stat[0].uvalue = 8 * 188 * (u64)reg[6];
break;
case SYS_DVBS2:
break;
@@ -712,7 +725,7 @@ static int read_signal_strength(struct dvb_frontend *fe, u16 *strength)
*strength = (u16) (regData & 0xFFFF); /* 10x dBm */
p->strength.len = 1;
p->strength.stat[0].scale = FE_SCALE_DECIBEL;
p->strength.stat[0].uvalue = 10 * (s64) (s16) (regData & 0xFFFF);
p->strength.stat[0].svalue = 10 * (s64) (s16) (regData & 0xFFFF);
return stat;
}
@@ -732,7 +745,7 @@ static int get_stats(struct dvb_frontend *fe)
return 0;
}
static fe_code_rate_t conv_fec(MXL_HYDRA_FEC_E fec)
static enum fe_code_rate conv_fec(MXL_HYDRA_FEC_E fec)
{
enum fe_code_rate fec2fec[11] = {
FEC_NONE, FEC_1_2, FEC_3_5, FEC_2_3,
@@ -745,10 +758,9 @@ static fe_code_rate_t conv_fec(MXL_HYDRA_FEC_E fec)
return fec2fec[fec];
}
static int get_frontend(struct dvb_frontend *fe)
static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{
struct mxl *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 regData[MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE];
u32 freq;
int stat;
@@ -841,8 +853,8 @@ static struct dvb_frontend_ops mxl_ops = {
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
.info = {
.name = "MXL5XX",
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_min = 300000,
.frequency_max = 2350000,
.frequency_stepsize = 0,
.frequency_tolerance = 0,
.symbol_rate_min = 1000000,
@@ -1933,4 +1945,4 @@ EXPORT_SYMBOL_GPL(mxl5xx_attach);
MODULE_DESCRIPTION("MXL5XX driver");
MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

@@ -58,7 +58,7 @@ enum EDemodState { Off, QAMSet, OFDMSet, QAMStarted, OFDMStarted };
struct stv_state {
struct dvb_frontend frontend;
fe_modulation_t modulation;
enum fe_modulation modulation;
u32 symbol_rate;
u32 bandwidth;
struct device *dev;
@@ -1861,7 +1861,7 @@ static int OFDM_GetLockStatus(struct stv_state *state, LOCK_STATUS* pLockStatus,
#endif
static int read_status(struct dvb_frontend *fe, fe_status_t *status)
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{
struct stv_state *state = fe->demodulator_priv;
*status=0;
@@ -2128,8 +2128,7 @@ static void init_state(struct stv_state *state, struct stv0367_cfg *cfg)
}
struct dvb_frontend *stv0367_attach(struct i2c_adapter *i2c, struct stv0367_cfg *cfg,
struct dvb_frontend **fe_t)
struct dvb_frontend *stv0367_attach(struct i2c_adapter *i2c, struct stv0367_cfg *cfg)
{
struct stv_state *state = NULL;
@@ -2153,7 +2152,7 @@ error:
MODULE_DESCRIPTION("STV0367DD driver");
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
EXPORT_SYMBOL(stv0367_attach);

View File

@@ -13,6 +13,5 @@ struct stv0367_cfg {
extern struct dvb_frontend *stv0367_attach(struct i2c_adapter *i2c,
struct stv0367_cfg *cfg,
struct dvb_frontend **fe_t);
struct stv0367_cfg *cfg);
#endif

View File

@@ -3446,11 +3446,11 @@ err:
static int stv090x_set_pls(struct stv090x_state *state, u8 pls_mode, u32 pls_code)
{
dprintk(FE_DEBUG, 1, "Set PLS code %d (mode %d)", pls_code, pls_mode);
if (STV090x_WRITE_DEMOD(state, PLROOT2, (pls_mode << 2) | (pls_code >> 16)) < 0)
if (STV090x_WRITE_DEMOD(state, PLROOT0, pls_code & 0xff) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, PLROOT1, (pls_code >> 8) & 0xff) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, PLROOT0, pls_code & 0xff) < 0)
if (STV090x_WRITE_DEMOD(state, PLROOT2, (pls_mode << 2) | (pls_code >> 16)) < 0)
goto err;
return 0;
err:
@@ -3537,8 +3537,8 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_fron
if ((props->stream_id != NO_STREAM_ID_FILTER) &&
(props->stream_id & 0xffffff00))
pls = props->stream_id >> 8;
if (props->pls != NO_SCRAMBLING_CODE)
pls = props->pls | 0x40000; /* props->pls is always gold code */
/* props->scrambling_sequence_index is always gold code */
pls = props->scrambling_sequence_index | 0x40000;
stv090x_set_pls(state, (pls >> 18) & 3, pls & 0x3ffff);
stv090x_set_mis(state, props->stream_id);
@@ -4927,15 +4927,6 @@ static int stv090x_init(struct dvb_frontend *fe)
if (stv090x_i2c_gate_ctrl(state, 0) < 0)
goto err;
#if 0
if (state->device == STV0900) {
if (stv0900_set_tspath(state) < 0)
goto err;
} else {
if (stv0903_set_tspath(state) < 0)
goto err;
}
#endif
return 0;
err_gateoff:
@@ -5081,10 +5072,9 @@ static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir,
return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg);
}
static int stv090x_get_frontend(struct dvb_frontend *fe)
static int stv090x_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{
struct stv090x_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u8 tmp;
u32 reg = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,8 @@ struct stv0910_cfg {
u8 adr;
u8 parallel;
u8 rptlvl;
u8 single;
u8 tsspeed;
};
#if defined(CONFIG_DVB_STV0910) || \

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,9 @@
#include "stv6110x.h"
#include "stv6110x_priv.h"
/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64
static unsigned int verbose;
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "Set Verbosity level");
@@ -61,7 +64,8 @@ static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 da
{
int ret;
const struct stv6110x_config *config = stv6110x->config;
u8 buf[len + 1];
u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg = {
.addr = config->addr,
.flags = 0,
@@ -69,6 +73,13 @@ static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 da
.len = len + 1
};
if (1 + len > sizeof(buf)) {
printk(KERN_WARNING
"%s: i2c wr: len=%d is too big!\n",
KBUILD_MODNAME, len);
return -EINVAL;
}
if (start + len > 8)
return -EINVAL;
@@ -324,17 +335,15 @@ static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
}
static int stv6110x_release(struct dvb_frontend *fe)
static void stv6110x_release(struct dvb_frontend *fe)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
fe->tuner_priv = NULL;
kfree(stv6110x);
return 0;
}
static struct dvb_tuner_ops stv6110x_ops = {
static const struct dvb_tuner_ops stv6110x_ops = {
.info = {
.name = "STV6110(A) Silicon Tuner",
.frequency_min = 950000,
@@ -344,7 +353,7 @@ static struct dvb_tuner_ops stv6110x_ops = {
.release = stv6110x_release
};
static struct stv6110x_devctl stv6110x_ctl = {
static const struct stv6110x_devctl stv6110x_ctl = {
.tuner_init = stv6110x_init,
.tuner_sleep = stv6110x_sleep,
.tuner_set_mode = stv6110x_set_mode,
@@ -358,7 +367,7 @@ static struct stv6110x_devctl stv6110x_ctl = {
.tuner_get_status = stv6110x_get_status,
};
struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
struct i2c_adapter *i2c)
{

View File

@@ -53,14 +53,20 @@ struct stv6110x_devctl {
};
#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE))
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0))
#define IS_REACHABLE(option) (config_enabled(option) || \
(config_enabled(option##_MODULE) && config_enabled(MODULE)))
#endif
extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
#if IS_REACHABLE(CONFIG_DVB_STV6110x)
extern const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
struct i2c_adapter *i2c);
#else
static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
static inline const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
struct i2c_adapter *i2c)
{

View File

@@ -70,7 +70,7 @@ struct stv6110x_state {
const struct stv6110x_config *config;
u8 regs[8];
struct stv6110x_devctl *devctl;
const struct stv6110x_devctl *devctl;
};
#endif /* __STV6110x_PRIV_H */

View File

@@ -203,17 +203,17 @@ static int init(struct dvb_frontend *fe)
return 0;
}
static int release(struct dvb_frontend *fe)
static void release(struct dvb_frontend *fe)
{
kfree(fe->tuner_priv);
fe->tuner_priv = NULL;
return 0;
}
static int set_bandwidth(struct dvb_frontend *fe, u32 CutOffFrequency)
{
struct stv *state = fe->tuner_priv;
u32 index = (CutOffFrequency + 999999) / 1000000;
int stat = 0;
if (index < 6)
index = 6;
@@ -225,12 +225,14 @@ static int set_bandwidth(struct dvb_frontend *fe, u32 CutOffFrequency)
state->reg[0x08] = (state->reg[0x08] & ~0xFC) | ((index-6) << 2);
state->reg[0x09] = (state->reg[0x09] & ~0x0C) | 0x08;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
write_regs(state, 0x08, 2);
wait_for_call_done(state, 0x08);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
return 0;
stat = fe->ops.i2c_gate_ctrl(fe, 1);
if (!stat) {
write_regs(state, 0x08, 2);
wait_for_call_done(state, 0x08);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
return stat;
}
static int set_lof(struct stv *state, u32 LocalFrequency, u32 CutOffFrequency)
@@ -312,6 +314,7 @@ static int set_params(struct dvb_frontend *fe)
struct stv *state = fe->tuner_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 freq, symb, cutoff;
int stat = 0;
if (p->delivery_system != SYS_DVBS && p->delivery_system != SYS_DVBS2)
return -EINVAL;
@@ -321,16 +324,20 @@ static int set_params(struct dvb_frontend *fe)
cutoff = 5000000 + MulDiv32(p->symbol_rate, 135, 200);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
set_lof(state, freq, cutoff);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
return 0;
stat = fe->ops.i2c_gate_ctrl(fe, 1);
if (!stat) {
set_lof(state, freq, cutoff);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
return stat;
}
static int get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
*frequency = 0;
struct stv *state = fe->tuner_priv;
*frequency = state->Frequency;
return 0;
}
@@ -631,15 +638,18 @@ static int get_rf_strength(struct dvb_frontend *fe, u16 *st)
// RF Mode
// Read AGC ADC
u8 Reg = 0;
int stat = 0;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
write_reg(state, 0x02, state->reg[0x02] | 0x20);
read_reg(state, 2, &Reg);
if( Reg & 0x20 )
stat = fe->ops.i2c_gate_ctrl(fe, 1);
if (!stat) {
write_reg(state, 0x02, state->reg[0x02] | 0x20);
read_reg(state, 2, &Reg);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
if (Reg & 0x20)
read_reg(state, 2, &Reg);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
if((state->reg[0x02] & 0x80) == 0)
// NF
@@ -715,7 +725,7 @@ struct dvb_frontend *stv6111_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, u8 adr)
{
struct stv *state;
int stat;
int stat = 0;
state = kzalloc(sizeof(struct stv), GFP_KERNEL);
if (!state)
@@ -726,13 +736,15 @@ struct dvb_frontend *stv6111_attach(struct dvb_frontend *fe,
init_state(state);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
stat = attach_init(state);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
stat = fe->ops.i2c_gate_ctrl(fe, 1);
if (!stat) {
stat = attach_init(state);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
if (stat < 0) {
kfree(state);
return 0;
return NULL;
}
fe->tuner_priv = state;
return fe;
@@ -741,7 +753,7 @@ EXPORT_SYMBOL_GPL(stv6111_attach);
MODULE_DESCRIPTION("STV6111 driver");
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
/*
* Local variables:

View File

@@ -790,11 +790,10 @@ static int init(struct dvb_frontend *fe)
return 0;
}
static int release(struct dvb_frontend *fe)
static void release(struct dvb_frontend *fe)
{
kfree(fe->tuner_priv);
fe->tuner_priv = NULL;
return 0;
}
static int set_params(struct dvb_frontend *fe)
@@ -934,7 +933,7 @@ EXPORT_SYMBOL_GPL(tda18212dd_attach);
MODULE_DESCRIPTION("TDA18212 driver");
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
/*
* Local variables:

View File

@@ -1144,11 +1144,10 @@ static int init(struct dvb_frontend *fe)
return 0;
}
static int release(struct dvb_frontend *fe)
static void release(struct dvb_frontend *fe)
{
kfree(fe->tuner_priv);
fe->tuner_priv = NULL;
return 0;
}
/*
@@ -1327,4 +1326,4 @@ EXPORT_SYMBOL_GPL(tda18271c2dd_attach);
MODULE_DESCRIPTION("TDA18271C2 driver");
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

@@ -24,67 +24,138 @@
#ifndef _DVBCA_H_
#define _DVBCA_H_
/* slot interface types and info */
/**
* struct ca_slot_info - CA slot interface types and info.
*
* @num: slot number.
* @type: slot type.
* @flags: flags applicable to the slot.
*
* This struct stores the CA slot information.
*
* @type can be:
*
* - %CA_CI - CI high level interface;
* - %CA_CI_LINK - CI link layer level interface;
* - %CA_CI_PHYS - CI physical layer level interface;
* - %CA_DESCR - built-in descrambler;
* - %CA_SC -simple smart card interface.
*
* @flags can be:
*
* - %CA_CI_MODULE_PRESENT - module (or card) inserted;
* - %CA_CI_MODULE_READY - module is ready for usage.
*/
typedef struct ca_slot_info {
int num; /* slot number */
int type; /* CA interface this slot supports */
#define CA_CI 1 /* CI high level interface */
#define CA_CI_LINK 2 /* CI link layer level interface */
#define CA_CI_PHYS 4 /* CI physical layer level interface */
#define CA_DESCR 8 /* built-in descrambler */
#define CA_SC 128 /* simple smart card interface */
struct ca_slot_info {
int num;
int type;
#define CA_CI 1
#define CA_CI_LINK 2
#define CA_CI_PHYS 4
#define CA_DESCR 8
#define CA_SC 128
unsigned int flags;
#define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */
#define CA_CI_MODULE_PRESENT 1
#define CA_CI_MODULE_READY 2
} ca_slot_info_t;
};
/* descrambler types and info */
typedef struct ca_descr_info {
unsigned int num; /* number of available descramblers (keys) */
unsigned int type; /* type of supported scrambling system */
/**
* struct ca_descr_info - descrambler types and info.
*
* @num: number of available descramblers (keys).
* @type: type of supported scrambling system.
*
* Identifies the number of descramblers and their type.
*
* @type can be:
*
* - %CA_ECD - European Common Descrambler (ECD) hardware;
* - %CA_NDS - Videoguard (NDS) hardware;
* - %CA_DSS - Distributed Sample Scrambling (DSS) hardware.
*/
struct ca_descr_info {
unsigned int num;
unsigned int type;
#define CA_ECD 1
#define CA_NDS 2
#define CA_DSS 4
} ca_descr_info_t;
};
typedef struct ca_caps {
unsigned int slot_num; /* total number of CA card and module slots */
unsigned int slot_type; /* OR of all supported types */
unsigned int descr_num; /* total number of descrambler slots (keys) */
unsigned int descr_type; /* OR of all supported types */
} ca_caps_t;
/**
* struct ca_caps - CA slot interface capabilities.
*
* @slot_num: total number of CA card and module slots.
* @slot_type: bitmap with all supported types as defined at
* &struct ca_slot_info (e. g. %CA_CI, %CA_CI_LINK, etc).
* @descr_num: total number of descrambler slots (keys)
* @descr_type: bitmap with all supported types as defined at
* &struct ca_descr_info (e. g. %CA_ECD, %CA_NDS, etc).
*/
struct ca_caps {
unsigned int slot_num;
unsigned int slot_type;
unsigned int descr_num;
unsigned int descr_type;
};
/* a message to/from a CI-CAM */
typedef struct ca_msg {
/**
* struct ca_msg - a message to/from a CI-CAM
*
* @index: unused
* @type: unused
* @length: length of the message
* @msg: message
*
* This struct carries a message to be send/received from a CI CA module.
*/
struct ca_msg {
unsigned int index;
unsigned int type;
unsigned int length;
unsigned char msg[256];
} ca_msg_t;
};
typedef struct ca_descr {
/**
* struct ca_descr - CA descrambler control words info
*
* @index: CA Descrambler slot
* @parity: control words parity, where 0 means even and 1 means odd
* @cw: CA Descrambler control words
*/
struct ca_descr {
unsigned int index;
unsigned int parity; /* 0 == even, 1 == odd */
unsigned int parity;
unsigned char cw[8];
} ca_descr_t;
};
typedef struct ca_pid {
struct ca_pid {
unsigned int pid;
int index; /* -1 == disable*/
} ca_pid_t;
int index;/* -1 == disable*/
};
#define CA_RESET _IO('o', 128)
#define CA_GET_CAP _IOR('o', 129, ca_caps_t)
#define CA_GET_SLOT_INFO _IOR('o', 130, ca_slot_info_t)
#define CA_GET_DESCR_INFO _IOR('o', 131, ca_descr_info_t)
#define CA_GET_MSG _IOR('o', 132, ca_msg_t)
#define CA_SEND_MSG _IOW('o', 133, ca_msg_t)
#define CA_SET_DESCR _IOW('o', 134, ca_descr_t)
#define CA_SET_PID _IOW('o', 135, ca_pid_t)
#define CA_GET_CAP _IOR('o', 129, struct ca_caps)
#define CA_GET_SLOT_INFO _IOR('o', 130, struct ca_slot_info)
#define CA_GET_DESCR_INFO _IOR('o', 131, struct ca_descr_info)
#define CA_GET_MSG _IOR('o', 132, struct ca_msg)
#define CA_SEND_MSG _IOW('o', 133, struct ca_msg)
#define CA_SET_DESCR _IOW('o', 134, struct ca_descr)
#define CA_SET_PID _IOW('o', 135, struct ca_pid)
#if !defined(__KERNEL__)
/* This is needed for legacy userspace support */
typedef struct ca_slot_info ca_slot_info_t;
typedef struct ca_descr_info ca_descr_info_t;
typedef struct ca_caps ca_caps_t;
typedef struct ca_msg ca_msg_t;
typedef struct ca_descr ca_descr_t;
typedef struct ca_pid ca_pid_t;
#endif
#endif

View File

@@ -32,27 +32,74 @@
#define DMX_FILTER_SIZE 16
typedef enum
{
DMX_OUT_DECODER, /* Streaming directly to decoder. */
DMX_OUT_TAP, /* Output going to a memory buffer */
/* (to be retrieved via the read command).*/
DMX_OUT_TS_TAP, /* Output multiplexed into a new TS */
/* (to be retrieved by reading from the */
/* logical DVR device). */
DMX_OUT_TSDEMUX_TAP /* Like TS_TAP but retrieved from the DMX device */
} dmx_output_t;
/**
* enum dmx_output - Output for the demux.
*
* @DMX_OUT_DECODER:
* Streaming directly to decoder.
* @DMX_OUT_TAP:
* Output going to a memory buffer (to be retrieved via the read command).
* Delivers the stream output to the demux device on which the ioctl
* is called.
* @DMX_OUT_TS_TAP:
* Output multiplexed into a new TS (to be retrieved by reading from the
* logical DVR device). Routes output to the logical DVR device
* ``/dev/dvb/adapter?/dvr?``, which delivers a TS multiplexed from all
* filters for which @DMX_OUT_TS_TAP was specified.
* @DMX_OUT_TSDEMUX_TAP:
* Like @DMX_OUT_TS_TAP but retrieved from the DMX device.
*/
enum dmx_output {
DMX_OUT_DECODER,
DMX_OUT_TAP,
DMX_OUT_TS_TAP,
DMX_OUT_TSDEMUX_TAP
};
typedef enum
{
DMX_IN_FRONTEND, /* Input from a front-end device. */
DMX_IN_DVR /* Input from the logical DVR device. */
} dmx_input_t;
/**
* enum dmx_input - Input from the demux.
*
* @DMX_IN_FRONTEND: Input from a front-end device.
* @DMX_IN_DVR: Input from the logical DVR device.
*/
enum dmx_input {
DMX_IN_FRONTEND,
DMX_IN_DVR
};
/**
* enum dmx_ts_pes - type of the PES filter.
*
* @DMX_PES_AUDIO0: first audio PID. Also referred as @DMX_PES_AUDIO.
* @DMX_PES_VIDEO0: first video PID. Also referred as @DMX_PES_VIDEO.
* @DMX_PES_TELETEXT0: first teletext PID. Also referred as @DMX_PES_TELETEXT.
* @DMX_PES_SUBTITLE0: first subtitle PID. Also referred as @DMX_PES_SUBTITLE.
* @DMX_PES_PCR0: first Program Clock Reference PID.
* Also referred as @DMX_PES_PCR.
*
* @DMX_PES_AUDIO1: second audio PID.
* @DMX_PES_VIDEO1: second video PID.
* @DMX_PES_TELETEXT1: second teletext PID.
* @DMX_PES_SUBTITLE1: second subtitle PID.
* @DMX_PES_PCR1: second Program Clock Reference PID.
*
* @DMX_PES_AUDIO2: third audio PID.
* @DMX_PES_VIDEO2: third video PID.
* @DMX_PES_TELETEXT2: third teletext PID.
* @DMX_PES_SUBTITLE2: third subtitle PID.
* @DMX_PES_PCR2: third Program Clock Reference PID.
*
* @DMX_PES_AUDIO3: fourth audio PID.
* @DMX_PES_VIDEO3: fourth video PID.
* @DMX_PES_TELETEXT3: fourth teletext PID.
* @DMX_PES_SUBTITLE3: fourth subtitle PID.
* @DMX_PES_PCR3: fourth Program Clock Reference PID.
*
* @DMX_PES_OTHER: any other PID.
*/
typedef enum dmx_ts_pes
{
enum dmx_ts_pes {
DMX_PES_AUDIO0,
DMX_PES_VIDEO0,
DMX_PES_TELETEXT0,
@@ -78,7 +125,7 @@ typedef enum dmx_ts_pes
DMX_PES_PCR3,
DMX_PES_OTHER
} dmx_pes_type_t;
};
#define DMX_PES_AUDIO DMX_PES_AUDIO0
#define DMX_PES_VIDEO DMX_PES_VIDEO0
@@ -87,69 +134,100 @@ typedef enum dmx_ts_pes
#define DMX_PES_PCR DMX_PES_PCR0
typedef struct dmx_filter
{
/**
* struct dmx_filter - Specifies a section header filter.
*
* @filter: bit array with bits to be matched at the section header.
* @mask: bits that are valid at the filter bit array.
* @mode: mode of match: if bit is zero, it will match if equal (positive
* match); if bit is one, it will match if the bit is negated.
*
* Note: All arrays in this struct have a size of DMX_FILTER_SIZE (16 bytes).
*/
struct dmx_filter {
__u8 filter[DMX_FILTER_SIZE];
__u8 mask[DMX_FILTER_SIZE];
__u8 mode[DMX_FILTER_SIZE];
} dmx_filter_t;
};
struct dmx_sct_filter_params
{
__u16 pid;
dmx_filter_t filter;
__u32 timeout;
__u32 flags;
/**
* struct dmx_sct_filter_params - Specifies a section filter.
*
* @pid: PID to be filtered.
* @filter: section header filter, as defined by &struct dmx_filter.
* @timeout: maximum time to filter, in milliseconds.
* @flags: extra flags for the section filter.
*
* Carries the configuration for a MPEG-TS section filter.
*
* The @flags can be:
*
* - %DMX_CHECK_CRC - only deliver sections where the CRC check succeeded;
* - %DMX_ONESHOT - disable the section filter after one section
* has been delivered;
* - %DMX_IMMEDIATE_START - Start filter immediately without requiring a
* :ref:`DMX_START`.
*/
struct dmx_sct_filter_params {
__u16 pid;
struct dmx_filter filter;
__u32 timeout;
__u32 flags;
#define DMX_CHECK_CRC 1
#define DMX_ONESHOT 2
#define DMX_IMMEDIATE_START 4
#define DMX_KERNEL_CLIENT 0x8000
};
struct dmx_pes_filter_params
{
__u16 pid;
dmx_input_t input;
dmx_output_t output;
dmx_pes_type_t pes_type;
__u32 flags;
/**
* struct dmx_pes_filter_params - Specifies Packetized Elementary Stream (PES)
* filter parameters.
*
* @pid: PID to be filtered.
* @input: Demux input, as specified by &enum dmx_input.
* @output: Demux output, as specified by &enum dmx_output.
* @pes_type: Type of the pes filter, as specified by &enum dmx_pes_type.
* @flags: Demux PES flags.
*/
struct dmx_pes_filter_params {
__u16 pid;
enum dmx_input input;
enum dmx_output output;
enum dmx_ts_pes pes_type;
__u32 flags;
};
typedef struct dmx_caps {
__u32 caps;
int num_decoders;
} dmx_caps_t;
typedef enum {
DMX_SOURCE_FRONT0 = 0,
DMX_SOURCE_FRONT1,
DMX_SOURCE_FRONT2,
DMX_SOURCE_FRONT3,
DMX_SOURCE_DVR0 = 16,
DMX_SOURCE_DVR1,
DMX_SOURCE_DVR2,
DMX_SOURCE_DVR3
} dmx_source_t;
/**
* struct dmx_stc - Stores System Time Counter (STC) information.
*
* @num: input data: number of the STC, from 0 to N.
* @base: output: divisor for STC to get 90 kHz clock.
* @stc: output: stc in @base * 90 kHz units.
*/
struct dmx_stc {
unsigned int num; /* input : which STC? 0..N */
unsigned int base; /* output: divisor for stc to get 90 kHz clock */
__u64 stc; /* output: stc in 'base'*90 kHz units */
unsigned int num;
unsigned int base;
__u64 stc;
};
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
#define DMX_SET_PES_FILTER _IOW('o', 44, struct dmx_pes_filter_params)
#define DMX_SET_BUFFER_SIZE _IO('o', 45)
#define DMX_GET_PES_PIDS _IOR('o', 47, __u16[5])
#define DMX_GET_CAPS _IOR('o', 48, dmx_caps_t)
#define DMX_SET_SOURCE _IOW('o', 49, dmx_source_t)
#define DMX_GET_STC _IOWR('o', 50, struct dmx_stc)
#define DMX_ADD_PID _IOW('o', 51, __u16)
#define DMX_REMOVE_PID _IOW('o', 52, __u16)
#if !defined(__KERNEL__)
/* This is needed for legacy userspace support */
typedef enum dmx_output dmx_output_t;
typedef enum dmx_input dmx_input_t;
typedef enum dmx_ts_pes dmx_pes_type_t;
typedef struct dmx_filter dmx_filter_t;
#endif
#endif /* _UAPI_DVBDMX_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -25,9 +25,13 @@ struct dvb_mod_channel_params {
#define MODULATOR_FREQUENCY 3
#define MODULATOR_MODULATION 4
#define MODULATOR_SYMBOL_RATE 5 /* Hz */
#define MODULATOR_BASE_FREQUENCY 6
#define MODULATOR_ATTENUATOR 32
#define MODULATOR_INPUT_BITRATE 33 /* Hz */
#define MODULATOR_PCR_MODE 34 /* 1=pcr correction enabled */
#define MODULATOR_GAIN 35
#define MODULATOR_RESET 36
#define MODULATOR_STATUS 37
#define MODULATOR_OUTPUT_ARI 64
#endif /*_UAPI_DVBMOD_H_*/

View File

@@ -26,6 +26,21 @@
#include <linux/types.h>
/**
* struct dvb_net_if - describes a DVB network interface
*
* @pid: Packet ID (PID) of the MPEG-TS that contains data
* @if_num: number of the Digital TV interface.
* @feedtype: Encapsulation type of the feed.
*
* A MPEG-TS stream may contain packet IDs with IP packages on it.
* This struct describes it, and the type of encoding.
*
* @feedtype can be:
*
* - %DVB_NET_FEEDTYPE_MPE for MPE encoding
* - %DVB_NET_FEEDTYPE_ULE for ULE encoding.
*/
struct dvb_net_if {
__u16 pid;
__u16 if_num;

View File

@@ -24,6 +24,6 @@
#define _DVBVERSION_H_
#define DVB_API_VERSION 5
#define DVB_API_VERSION_MINOR 10
#define DVB_API_VERSION_MINOR 11
#endif /*_DVBVERSION_H_*/

View File

@@ -26,7 +26,6 @@
#include <linux/types.h>
#ifndef __KERNEL__
#include <stdint.h>
#include <time.h>
#endif
@@ -139,7 +138,8 @@ struct video_event {
#define VIDEO_EVENT_FRAME_RATE_CHANGED 2
#define VIDEO_EVENT_DECODER_STOPPED 3
#define VIDEO_EVENT_VSYNC 4
__kernel_time_t timestamp;
/* unused, make sure to use atomic time for y2038 if it ever gets used */
long timestamp;
union {
video_size_t size;
unsigned int frame_rate; /* in frames per 1000sec */
@@ -211,7 +211,8 @@ typedef __u16 video_attributes_t;
/* 6 line 21-2 data present in GOP (1=yes, 0=no) */
/* 5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 */
/* 2 source letterboxed (1=yes, 0=no) */
/* 0 film/camera mode (0=camera, 1=film (625/50 only)) */
/* 0 film/camera mode (0=
*camera, 1=film (625/50 only)) */
/* bit definitions for capabilities: */