Compare commits

...

638 Commits

Author SHA1 Message Date
rjkm
710f9c6fbc add M8E 2025-02-25 15:55:23 +01:00
rjkm
849d9ec10f add M8E defines 2025-02-24 21:41:42 +01:00
rjkm
a79f57a675 add MAX M2 2025-02-24 20:25:34 +01:00
rjkm
0690bf6882 add new M8 2025-02-14 13:26:18 +01:00
rjkm
f5fcda81dc new version 2025-02-14 13:25:35 +01:00
rjkm
0b54436695 correct version number 2025-01-21 21:46:39 +01:00
rjkm
a986a98b96 return PLS in transmission_mode 2024-11-16 14:34:24 +01:00
rjkm
345c3b8e0d fix compilation with newer kernels 2024-11-16 14:25:10 +01:00
rjkm
b172e83a4b show XO2 firmware version 2024-11-16 14:24:07 +01:00
rjkm
5fef324ea0 add support for license setting via MCI commands (only FSM cards for now) 2024-10-20 22:39:37 +02:00
rjkm
63f693946c make new compiler warning settings happy 2024-09-19 10:54:57 +02:00
rjkm
17b741b01d support 16 channel DVB-T card 2024-09-19 10:53:23 +02:00
rjkm
8e4379ef3e only allow values between 0-3 2024-09-19 10:52:37 +02:00
rjkm
1022b26d7f cleanup init for FSM and DVB-T cards 2024-09-19 10:51:57 +02:00
rjkm
59cbab6383 prevent lockup 2024-09-19 10:35:39 +02:00
rjkm
0fcd9563f1 only warn about zigzag if max_drift is set 2024-09-19 10:34:30 +02:00
rjkm
cf64ad4b0e show more information about card connected at GT link 2024-09-19 10:33:25 +02:00
rjkm
1c88e05931 factor out setting of input 2024-09-19 10:31:41 +02:00
rjkm
11b8c21cb5 revert ignoring of bad packets at startup 2024-09-19 10:29:48 +02:00
rjkm
3cc98a4995 adapt to newer kernel version 2024-09-19 10:28:59 +02:00
rjkm
0c328cd989 do not allow unaligned access 2024-09-19 10:23:58 +02:00
rjkm
ffbef1488e remove unused tasklet struct 2024-09-19 10:22:46 +02:00
rjkm
8badef38a7 use correct lib name 2024-09-19 10:19:51 +02:00
rjkm
5d47dbec26 add 16 channel version of DVB-T modulator 2024-09-19 10:18:51 +02:00
drmocm
0368446256 modulator info 2024-07-11 13:57:59 +02:00
drmocm
07d5675b06 some information for DVB-T modulators 2024-07-11 13:50:17 +02:00
rjkm
ea8e877dca use dvb_filter.h only locally 2024-04-26 16:33:45 +02:00
rjkm
9ec5f40324 also install dvb_filter.h 2024-04-26 16:17:43 +02:00
rjkm
50e230b48d add dvb filter 2024-03-29 14:05:49 +01:00
rjkm
4197d9a59e make copying to/from CA device more robust, add TDT callback 2024-03-29 14:04:33 +01:00
rjkm
62b0b57c5d Add some more comments to MCI API documentation. 2024-03-26 22:36:05 +01:00
rjkm
fe63f1d0b8 Change assignment of devices when using kernel dvb-core.
Modulators are now osdX.
2024-03-26 22:34:52 +01:00
rjkm
dc384c70af Add input select via configurable DiSeqC message. 2024-03-26 22:30:23 +01:00
rjkm
4e0bf8b182 Add reset function. 2024-03-26 22:28:31 +01:00
rjkm
e7390e1cd8 Ignore errors at start, they are from aold data in buffers/FIFOs. 2024-03-26 22:27:43 +01:00
rjkm
d54905cc14 Remove ISDB entries when using kernel dvb-core because array is too small.
ISDB modes are then not enumerated but still work.
2024-03-26 22:22:52 +01:00
rjkm
7779445112 Add example for 2 regions in DVB-C and move modulator.conf to modulator-t.conf 2024-03-26 22:21:09 +01:00
rjkm
3ba2128c4e Support several channel regions. They have to start with frequency now! 2024-03-26 22:17:41 +01:00
rjkm
8f2bf94b43 Add some comments about using kernel dvb-core. 2024-03-26 22:16:18 +01:00
rjkm
a927449610 Merge branch 'internal' of hippo:rjkm/dddvb into internal 2024-03-10 21:45:55 +01:00
rjkm
3295328aa9 Merge branch 'internal' of hippo:rjkm/dddvb into internal 2024-03-10 21:45:09 +01:00
drmocm
2b53b34350 even longer device filenames 2024-03-08 09:19:46 +01:00
rjkm
a6f022941f remove gt link tasklet code 2024-03-08 00:33:57 +01:00
rjkm
da1594d424 prevent warning if KERNEL_DVB_CORE=y is used 2024-03-08 00:19:22 +01:00
drmocm
32afa3e920 changed dvb file name length to 60 2024-03-07 19:42:49 +01:00
internal
f8726493b1 adapt defines to make KERNEL_DVB_CORE (compile against kernel dvb-core) work again 2024-03-06 17:07:08 +01:00
internal
525472b9f1 0.9.39 release 2024-02-13 12:54:51 +01:00
internal
7423903c67 add ci power error bit define 2024-02-08 23:15:23 +01:00
internal
690289c338 arm64 cannot handle unaligned readl 2024-02-08 22:57:40 +01:00
internal
09021aec73 fix for older KERNELS 2024-02-05 10:33:20 +01:00
internal
a1c604f212 decoding support 2024-02-05 10:27:55 +01:00
internal
1124f00b34 increase slot reset time 2024-01-30 17:18:17 +01:00
internal
70a119c0db read back correct values if using old API emulation 2023-12-13 19:05:22 +01:00
internal
123291b26e adjust M8/M8A tuner type selection 2023-12-13 19:04:12 +01:00
internal
85f8f5d2bd do not get extra status data as default 2023-12-13 19:03:18 +01:00
internal
4d0c806262 use stricter locking in case somebody still uses redirect (deprecated) 2023-12-13 19:02:11 +01:00
internal
9e6e34b857 adjust gitignore 2023-12-13 18:54:45 +01:00
internal
327cc09d34 dvb_math functions moved to int_log 2023-12-13 16:44:12 +01:00
internal
adaeb94a54 Merge branch 'internal' 2023-11-23 21:31:01 +01:00
internal
570864a576 support gain with new MCI API 2023-11-23 21:30:20 +01:00
internal
c681e4f24a support old gain command for new MCI firmware 2023-11-23 21:27:19 +01:00
internal
0628769620 Merge branch 'internal' 2023-11-14 14:32:56 +01:00
internal
934c619bcb documentation of modulator MCI API 2023-11-14 14:31:22 +01:00
internal
847b8611bd Merge branch 'internal' 2023-11-07 23:17:35 +01:00
internal
be74b9630f increase in case somebody does not use adapter_alloc=3 and gets tons of adapters 2023-11-07 23:16:24 +01:00
internal
3d17ab8de5 add range checks 2023-11-07 23:16:12 +01:00
internal
b76aa3c0c2 Merge branch 'internal' 2023-11-07 22:41:47 +01:00
internal
ca9613d911 increase retry time to 4s 2023-11-07 22:41:03 +01:00
internal
0daf0f79ae Merge branch 'internal' 2023-11-07 22:30:09 +01:00
drmocm
3884037c93 remove warnings 2023-11-07 10:06:30 +01:00
internal
f23789e90c Merge branch 'internal' 2023-11-06 10:26:19 +01:00
internal
0c603bc421 there is no more output_tasklet 2023-11-04 21:34:20 +01:00
internal
f23648f938 only use dvb_attach if enabled 2023-11-03 14:11:25 +01:00
internal
d8f3d40352 also output set value and make timeout clearer 2023-11-03 14:10:29 +01:00
internal
de5051a85a add safety checks 2023-11-03 13:39:54 +01:00
internal
d63916cba1 re-add workqueue and make WQ or tasklet selectable by module parameter
default to WQ for ARM64
(some SOCs use only one little A53 core for all MSI IRQs and
tasklets on the same core cannot process more than 10 TS streams
in uncached coherent memory)
2023-11-03 13:33:57 +01:00
internal
3ef783c393 default to alt_dma for arm64 (coherent memory is slow/uncached) and some cleanup in alt_dma handling 2023-11-03 13:31:13 +01:00
internal
cf7f19b8bc change handling of raw_stream value so that 1 just turns it on but does not change control register 2023-11-03 13:28:09 +01:00
internal
0ad8eff8af make iq mode always lock 2023-11-03 13:04:37 +01:00
internal
a0d4605ad8 return correct error stat instead of -1 2023-11-03 11:26:45 +01:00
internal
948234d787 lock reader, write and user counts with mutex 2023-11-03 11:21:28 +01:00
internal
05718a5965 extend sample Unicable table 2023-11-03 11:15:28 +01:00
internal
aedb0a1b64 allow for longer lock time before retry 2023-11-03 11:13:56 +01:00
internal
76697f420f add some more debugging messages 2023-11-03 11:12:52 +01:00
internal
6c7a754004 add inversion and rolloff fields 2023-11-03 11:11:39 +01:00
internal
bf85718376 also show rolloff and inversion state 2023-11-03 11:10:31 +01:00
internal
5f8c0cb75a add DVB-C sample config 2023-11-03 11:01:11 +01:00
internal
accad41c2c also support CI M2 2023-11-03 11:00:14 +01:00
internal
72181bd0ad Allow workqueue on all CPUs 2023-10-24 23:36:36 +02:00
internal
100aa25176 Merge branch 'internal' 2023-10-02 11:58:43 +02:00
internal
73317671a3 Some CAMs do not reset properly. So, turn off power before slot reset. 2023-09-30 21:39:54 +02:00
internal
f77d50e526 comment out debug messages 2023-09-29 16:59:00 +02:00
drmocm
25c730789d better stream set 2023-09-16 16:19:04 +02:00
drmocm
775ddf72ef s 2023-09-16 16:09:47 +02:00
drmocm
7b23c917d3 qam 2023-09-16 16:07:54 +02:00
drmocm
d91b2b7813 wrong qam table 2023-09-16 15:55:16 +02:00
drmocm
58c608ab30 set correct delsys 2023-09-16 15:12:18 +02:00
drmocm
8dc2fd062f stuff 2023-09-16 15:08:24 +02:00
drmocm
33ed0ec27c more stuff 2023-09-16 15:00:27 +02:00
drmocm
1ca4a8cea5 more changes 2023-09-16 14:56:27 +02:00
drmocm
bb1408a98a more changes 2023-09-16 14:52:32 +02:00
drmocm
9af63d41f7 new tuning for dvbc 2023-09-16 14:41:46 +02:00
internal
95d23821b7 adapt to mainline kernel 2023-09-12 15:06:23 +02:00
internal
059bfbb76e Merge branch 'internal' 2023-09-12 14:59:10 +02:00
internal
454bb63993 use EXPORT_SYMBOL_GPL for frontends to fix problems with kernel 6.5.2 2023-09-12 14:57:09 +02:00
internal
5b83e68887 Merge branch 'internal' 2023-09-05 14:29:23 +02:00
internal
da4938e3aa use correct input 2023-09-05 14:28:05 +02:00
internal
3439fd7725 Merge branch 'internal' of hippo:rjkm/dddvb into internal 2023-08-01 22:31:15 +02:00
internal
fc043cc914 Merge branch 'internal' 2023-08-01 22:29:25 +02:00
internal
818b9cb58d support CI M2, M8 and M8A 2023-08-01 22:27:55 +02:00
internal
0bafbf534f support alternative modulation types 2023-08-01 22:27:55 +02:00
internal
e5072debc0 change lnb and ci bases to be configurable 2023-08-01 22:27:55 +02:00
internal
2f49ece88c cleanup 2023-08-01 22:27:55 +02:00
internal
52b40198eb only warn once about zigzag scanning 2023-08-01 22:27:55 +02:00
internal
98f98fea0e adjust to 6.4.0 kernel change 2023-08-01 22:27:55 +02:00
internal
ccfdc2b984 fix frontend allocation 2023-08-01 22:27:55 +02:00
internal
9c920141ca adjust usage count for frontends which do not have their own module 2023-08-01 22:27:55 +02:00
internal
6c2bbbe5b8 add ddb_mci_cmd_link_simple() 2023-08-01 22:27:55 +02:00
internal
3eaae81e6a adapt MCI defines to firmware 2023-08-01 22:27:55 +02:00
internal
aae6233b14 class has no owner field in kernel version >= 6.4.0 2023-08-01 22:27:55 +02:00
internal
c8f3c122af let SSI be set (default 0 is ste in dvb-core), correct tuner/demod settings 2023-08-01 22:27:55 +02:00
internal
7258b32045 add CI M2, M8 and M8A 2023-08-01 22:27:55 +02:00
internal
c2a2a27500 appease conversion warnings 2023-08-01 22:27:55 +02:00
internal
847aa3c044 flen was not defined yet, so move after assignment 2023-08-01 22:27:55 +02:00
internal
48d9945769 change flashdump to void 2023-08-01 22:27:55 +02:00
internal
307ce85223 select image start according to reg 0x10 2023-08-01 22:27:55 +02:00
internal
23b2e6d6a0 missing return value 2023-08-01 22:27:55 +02:00
internal
647e8d77c3 remove PCR mode setting 2023-08-01 22:27:55 +02:00
internal
4943ea294a rename M4_ defines to MX_ 2023-08-01 22:27:55 +02:00
internal
7118ecd9f5 adjust image start to card type 2023-08-01 22:27:55 +02:00
internal
02ded87d78 support CI M2, M8 and M8A 2023-07-31 22:31:44 +02:00
internal
9698b87204 support alternative modulation types 2023-07-31 22:31:23 +02:00
internal
4d087a3b8c change lnb and ci bases to be configurable 2023-07-31 22:29:08 +02:00
internal
a233c8a6f8 cleanup 2023-07-31 22:14:53 +02:00
internal
e55ef2f0fb only warn once about zigzag scanning 2023-07-31 22:10:05 +02:00
internal
a2f011f62d adjust to 6.4.0 kernel change 2023-07-31 22:08:22 +02:00
internal
7250608d53 fix frontend allocation 2023-07-31 22:07:40 +02:00
internal
5e5ff60b21 adjust usage count for frontends which do not have their own module 2023-07-31 22:04:49 +02:00
internal
060eac06b8 add ddb_mci_cmd_link_simple() 2023-07-31 22:02:11 +02:00
internal
dfde99c01e adapt MCI defines to firmware 2023-07-31 21:59:37 +02:00
internal
73f270d850 class has no owner field in kernel version >= 6.4.0 2023-07-31 21:37:50 +02:00
internal
781177ea44 let SSI be set (default 0 is ste in dvb-core), correct tuner/demod settings 2023-07-31 21:35:57 +02:00
internal
330f2c1821 add CI M2, M8 and M8A 2023-07-31 21:30:56 +02:00
internal
3fc610f546 appease conversion warnings 2023-07-31 21:30:29 +02:00
internal
c522f28d68 flen was not defined yet, so move after assignment 2023-07-31 21:29:44 +02:00
internal
0fa14cca02 change flashdump to void 2023-07-31 21:29:07 +02:00
internal
ed14095a2f select image start according to reg 0x10 2023-07-31 21:28:24 +02:00
internal
456886f4fb missing return value 2023-07-31 21:23:27 +02:00
internal
abbb9e324a remove PCR mode setting 2023-07-31 21:22:45 +02:00
internal
e18b425f41 rename M4_ defines to MX_ 2023-07-31 21:21:45 +02:00
internal
88e65b4db6 adjust image start to card type 2023-07-22 21:28:35 +02:00
internal
4d583fd5f4 Merge branch 'internal' 2023-07-22 19:52:27 +02:00
internal
f27b64b186 remove Octopus Net Pro IDs 2023-07-22 19:48:59 +02:00
internal
7478bcffb9 forgot to check in setmod1.c 2023-07-22 19:48:59 +02:00
internal
0d9b5ca619 prevent clean error in case test.ts does not exist 2023-07-22 19:48:59 +02:00
internal
e9399971f8 adapt to mainline kernel changes 2023-07-22 19:48:59 +02:00
internal
626aa6d7be device pointer is const now 2023-07-22 19:48:59 +02:00
internal
5bfa228d71 clean up app directory 2023-07-22 19:48:59 +02:00
internal
42df1e88d4 add messages to see what is going on 2023-07-22 19:48:59 +02:00
internal
57101c22b7 adapt to upstream header style 2023-07-22 19:48:59 +02:00
internal
37e423d19b add DVB-C2 2023-07-22 19:48:58 +02:00
internal
17914cb451 remove Octopus Net Pro IDs 2023-07-12 22:42:46 +02:00
internal
25009b3afd forgot to check in setmod1.c 2023-06-12 11:32:14 +02:00
internal
2c75179530 Merge branch 'internal' 2023-05-11 14:25:51 +02:00
internal
58535dd4e3 prevent clean error in case test.ts does not exist 2023-05-11 14:06:34 +02:00
internal
b51b7c0598 adapt to mainline kernel changes 2023-05-11 14:06:34 +02:00
internal
e9ed73b929 device pointer is const now 2023-05-11 14:06:34 +02:00
internal
c0e174505a clean up app directory 2023-05-11 14:06:34 +02:00
internal
87478ec63a add messages to see what is going on 2023-05-11 14:06:34 +02:00
internal
4f9cb2810e adapt to upstream header style 2023-05-11 14:06:34 +02:00
internal
5988565066 add DVB-C2 2023-05-11 14:06:34 +02:00
rjkm
6e4f8dc86b hardware DVB-T can only do 14 channels 2023-03-05 23:27:58 +01:00
drmocm
5d876b2615 edited help info 2023-03-05 23:27:58 +01:00
drmocm
2968f85c91 limit the number of modulators used with -m option 2023-03-05 23:27:58 +01:00
rjkm
a443c3e8de Merge branch 'internal' 2023-03-03 13:47:11 +01:00
rjkm
c008e44bf6 hardware DVB-T can only do 14 channels 2023-03-03 13:44:57 +01:00
internal
7e9650c841 add actual frequency and symbol rate to debug output 2023-03-03 13:44:57 +01:00
internal
a6565abde3 emulate old API for latest FSM firmware 2023-03-03 13:44:57 +01:00
internal
ee7c48e6ff return actual modulation for DVB-C 2023-03-03 13:44:57 +01:00
internal
6ce49ed990 return actual symbol rate for all delivery systems 2023-03-03 13:44:57 +01:00
internal
0b36a69c44 check if MCI interface present 2023-03-03 13:44:57 +01:00
internal
e64ceb90fb simplify dummy frontend config 2023-03-03 13:44:57 +01:00
internal
efbf312d98 include link and port number in debug message 2023-03-03 13:44:57 +01:00
drmocm
0c3c1f5753 edited help info 2023-02-04 16:13:10 +01:00
drmocm
4bf1f48926 limit the number of modulators used with -m option 2023-02-04 15:19:11 +01:00
internal
979cb7a237 Merge branch 'internal' 2022-12-13 14:18:04 +01:00
internal
7ce5232cd7 add actual frequency and symbol rate to debug output 2022-12-13 13:45:33 +01:00
internal
3f296bef62 emulate old API for latest FSM firmware 2022-12-13 13:44:34 +01:00
internal
ad01e9f508 return actual modulation for DVB-C 2022-12-13 13:34:22 +01:00
internal
e312df576c return actual symbol rate for all delivery systems 2022-12-13 13:33:57 +01:00
internal
4b5cd433f9 check if MCI interface present 2022-12-13 13:33:09 +01:00
internal
6c068c0cc3 simplify dummy frontend config 2022-12-13 13:32:03 +01:00
internal
1488f326d0 include link and port number in debug message 2022-12-13 13:31:02 +01:00
internal
c86cb59638 Merge branch 'internal' 2022-12-12 11:39:23 +01:00
internal
c78905d4a2 keep original FSM card id if old license id is 7 2022-12-12 11:24:45 +01:00
internal
31589952a8 Merge branch 'internal' 2022-11-17 15:21:27 +01:00
internal
7eb5c6e658 read back actual symbol rate 2022-11-17 15:13:15 +01:00
internal
172c6c93ba do not create test.ts by default 2022-11-10 14:15:41 +01:00
internal
f125fd503c Merge branch 'internal' 2022-10-31 21:06:38 +01:00
internal
0dd4f106ab fix port number detection on revision 1 FSM cards 2022-10-30 23:23:44 +01:00
internal
60426304db add MDIR again but use proper empty default 2022-10-30 23:22:35 +01:00
internal
00b0036b33 Merge branch 'internal' 2022-10-28 15:20:02 +02:00
internal
177e71d62a INSTALL_MOD_PATH=$(MDIR) does not work, partially revert "fix" 2022-10-28 15:18:46 +02:00
internal
83a6dc3a1d Merge branch 'internal' 2022-10-26 15:58:36 +02:00
drmocm
cc03d96de2 added modtest.c 2022-10-26 13:16:21 +02:00
internal
6336bd3689 comment out test init 2022-10-25 19:35:16 +02:00
internal
be79cec76e set legacy signal strength workaround according to channel number 2022-10-25 19:33:25 +02:00
internal
24801ab41a add error return values 2022-10-25 19:32:51 +02:00
internal
390f67c03b remove modulator calls for octonet 2022-10-25 19:32:00 +02:00
internal
fa4e3331d8 move compatibility stuff to dd_compat.h 2022-10-25 19:30:52 +02:00
internal
29cc552a6b not only used on exit, also on failed init 2022-10-25 19:29:38 +02:00
internal
42a0b65235 use correct pointer type 2022-10-25 19:28:36 +02:00
internal
b8abf46d06 add consts 2022-10-25 19:27:44 +02:00
internal
ce06e50881 remove modulator from octonet 2022-10-25 19:25:05 +02:00
internal
22ffb0ecac allow alternative modules dir 2022-10-25 19:23:06 +02:00
internal
92f2132d79 fix printf type 2022-10-25 19:23:06 +02:00
internal
727fba48be ringbuffer fix from upstream 2022-10-25 19:23:06 +02:00
internal
09e8a15d78 Add clean for apps directory. 2022-10-25 19:23:06 +02:00
internal
45c9f076bd Do not use BIT_ULL, because older kernels do not have it. 2022-10-25 19:23:06 +02:00
internal
5c2757d581 Use eth_hw_addr_set in newer kernels. 2022-10-25 19:23:06 +02:00
drmocm
817a464f4a same Makefile changes for test.ts 2022-06-21 15:19:04 +02:00
drmocm
d627e6995f added modconfig and chnaged Makefile accordingly 2022-06-21 15:08:25 +02:00
internal
ab4b0c8306 Merge branch 'internal' 2022-06-07 18:11:35 +02:00
internal
c8c1ee1835 style fixes 2022-06-07 16:37:10 +02:00
internal
002f39787a This line somehow got lost when adapting to mainline kernel version.
Signed-off-by: internal
2022-06-07 16:15:10 +02:00
internal
871821d6a0 pci_*_dma_mask no longer exists in 5.18 2022-06-07 16:12:19 +02:00
internal
2a88d220e4 allow MCI commands for SDR cards. 2022-06-04 10:42:22 +02:00
internal
e0539d5074 Merge branch 'internal' 2022-05-02 21:41:27 +02:00
internal
457cb550bb do not use diseqc for scif type 3 2022-05-02 21:38:43 +02:00
internal
d0793274d2 Merge branch 'internal' 2022-03-22 15:23:26 +01:00
internal
ffe8764c01 support bigger Winbond flashs. 2022-03-22 15:22:43 +01:00
internal
fb4f263aa3 Merge branch 'internal' 2022-03-21 17:40:59 +01:00
internal
0892a225d2 support bigger Winbond flashs. 2022-03-21 17:40:11 +01:00
drmocm
431dd4f5ee more examples 2022-03-14 18:46:05 +01:00
rjkm
e9ccab3578 Merge branch 'internal' 2022-02-20 23:22:36 +01:00
rjkm
cdc5395996 translate old attenuator propert to new MCI API 2022-02-20 23:16:52 +01:00
rjkm
a5f3b75d0a Merge branch 'internal' 2022-02-16 15:55:04 +01:00
rjkm
69fcf5d649 disable dumps 2022-02-16 15:53:20 +01:00
rjkm
d5d63ea2ef prepare new init for revision 1 FSM but do not use it for now 2022-02-16 15:52:53 +01:00
rjkm
4b69ae5399 cleanup defines, add license commands 2022-02-15 14:43:32 +01:00
rjkm
1cf0526b24 license register is different for revision 1 (MCI) cards 2022-02-15 14:42:37 +01:00
rjkm
73e8b9943e cleanup tables and add license dump 2022-02-15 14:41:25 +01:00
rjkm
4b09ad7e42 forgot to reenable disseqc 2022-02-15 14:40:32 +01:00
rjkm
c39b234fd6 add support for DVBC 2022-02-12 16:40:27 +01:00
rjkm
c2f86b6438 add MCI ioctl to be used through modX devices 2022-02-12 16:39:01 +01:00
rjkm
6a3ef9873d data64 is not definde in kernel version 2022-02-12 16:37:50 +01:00
rjkm
98b466a2d3 remove debug info 2022-02-12 16:37:00 +01:00
rjkm
78d30ff6ff remove unused function 2022-02-12 16:35:57 +01:00
rjkm
d849abd626 move device info output 2022-02-12 15:49:53 +01:00
rjkm
9517d698dc update modulator defines and structs 2022-02-12 15:47:09 +01:00
rjkm
75821a6e3c properly round SCR frequencies 2022-02-12 15:37:49 +01:00
rjkm
2194f8e03a correct ddB 2022-02-12 15:37:04 +01:00
rjkm
d9a846d199 use MCI interface for modulators with revision 1 2022-02-12 15:28:05 +01:00
rjkm
31a781c2e3 remove non-static definition of mci card configs 2022-02-12 15:19:05 +01:00
rjkm
9b458a72de allow compilation against kerne dvb_core if KERNEL_DVB_CORE defined 2022-02-12 15:14:44 +01:00
rjkm
e0fd8a0f35 snr define was deleted by mistake 2022-02-12 15:09:36 +01:00
rjkm
1b49bfb8f1 use dd_compat file and adjust fallthroughs 2022-02-12 15:07:59 +01:00
rjkm
4ce76407e2 add mci irq for fsm cards 2022-02-11 21:37:06 +01:00
rjkm
a6c53f5ece add backwards compatibility include 2022-02-11 16:08:50 +01:00
rjkm
86579d353e add SNR reading for XO2 CI and use correct I2C device 2022-02-07 19:55:31 +01:00
rjkm
63df691561 add type name for second input of dual CI 2022-02-07 19:15:45 +01:00
rjkm
4aa7a68e21 set roll-off to auto or dvb-core will select default
Signed-off-by: rjkm <none>
2022-01-14 20:23:32 +01:00
rjkm
b6d2a37ac2 adapt to latest mainline dvb-core 2022-01-14 20:23:32 +01:00
rjkm
90e6d4806b allow setting CMDREG_SW during init (disabled for now) 2022-01-14 20:23:32 +01:00
rjkm
d995849fdb add comment about IOMMU 2022-01-14 20:23:32 +01:00
rjkm
b5bb500106 move ns.h to ddbridge directory 2022-01-14 20:23:32 +01:00
rjkm
24b7f979c4 process output_start fails (input cannot fail) 2022-01-14 20:23:32 +01:00
rjkm
be19cdb31d define macro for older kernels 2022-01-14 20:23:32 +01:00
rjkm
56afb2acc1 style cleanup 2022-01-14 20:23:32 +01:00
rjkm
08b3218e5a use already resolved link and info 2022-01-14 20:23:32 +01:00
rjkm
e17abdbbb9 return start error 2022-01-14 20:23:32 +01:00
rjkm
811bea8010 show bb header info 2022-01-14 20:23:32 +01:00
drmocm
e89a868ad5 fixed pam and continuity options 2021-12-10 13:56:05 +01:00
rjkm
f02b135bdb Merge branch 'internal' 2021-12-06 15:15:18 +01:00
rjkm
8bda007f05 add MCI registers for FSM 2021-12-06 14:54:51 +01:00
rjkm
ec655e1438 Merge branch 'internal' 2021-09-23 15:07:58 +02:00
rjkm
b606a7b2b2 increase wit time after powerup and before reset to 300ms
Signed-off-by: rjkm <none>
2021-09-23 15:07:00 +02:00
rjkm
81793729e6 Merge branch 'internal' 2021-09-19 19:06:35 +02:00
rjkm
3757c4671e change printfs to debugging messages 2021-09-19 19:05:50 +02:00
rjkm
719ac4d231 remove workqueue and threaded interrupt modes, they are too laggy 2021-09-19 19:05:05 +02:00
root
a3c6b5acc1 use inttypes 2021-09-07 18:08:58 +02:00
rjkm
8986494cd3 Merge branch 'internal' 2021-08-20 14:36:46 +02:00
rjkm
eeb013e0fa always allocate 64 adapters
this is for people who do not want to change the config by hand
it is preferred to use adapter_alloc=3 to have one adapter for
each physical DVB card
2021-08-20 14:29:29 +02:00
rjkm
7f40a54b39 standard is 1 for DVB-S, 0 or 2 otherwise 2021-08-20 14:28:28 +02:00
rjkm
1518ba54a4 hexdump complete BIST info for debugging 2021-08-20 14:27:36 +02:00
rjkm
a97787c3b6 add entries for more frontends (there is overlap but it is only for testing) 2021-08-20 14:26:04 +02:00
rjkm
d676919e72 provide kernel version when calling depmod 2021-08-20 14:24:29 +02:00
rjkm
fbc39f71f4 Merge branch 'internal' 2021-08-09 09:04:33 +02:00
rjkm
19eea5d42d add getiq to get IQ values from MCI cards 2021-08-09 09:03:02 +02:00
rjkm
b23187a049 Add module paramaters for SX8 tuner flags and gain. 2021-08-08 22:14:42 +02:00
rjkm
0165538f13 prepare to get roll off for SDR mode from parameters but use fixed one
for now
2021-08-07 23:00:29 +02:00
rjkm
0b9d3ffa6b move lut for use in other functions 2021-08-07 22:57:40 +02:00
rjkm
61fd25836f report proper frontend number 2021-08-07 22:49:43 +02:00
rjkm
d4aa1c634e style fix 2021-08-07 22:49:03 +02:00
rjkm
5bb0a95b02 remove obsolete debugging line 2021-08-07 22:36:10 +02:00
rjkm
0a5fb7d6b9 add debugging output for actually tuned frequency 2021-08-07 22:35:22 +02:00
rjkm
fd21dbbd5e add more documentation for use of stream number in SDR modes 2021-08-07 22:32:41 +02:00
rjkm
f7fcc1511d add extended stats 2021-08-07 22:30:10 +02:00
rjkm
37ae102d57 use correct u8 type 2021-08-07 22:30:01 +02:00
rjkm
66b1cf3623 new signal loss counter field 2021-08-07 22:29:17 +02:00
rjkm
7f002f1356 add 7/8 to offset 4 2021-08-07 22:28:42 +02:00
rjkm
418bd83b40 only set tuner flags once 2021-07-05 18:42:05 +02:00
none
ccc13aed48 Merge branch 'internal' 2021-06-23 16:30:26 +02:00
none
442b1c3bf6 add more S2 info and support cards via GT link 2021-06-23 11:19:55 +02:00
none
c23435e275 handle revision 1 mods differently 2021-06-23 11:18:35 +02:00
none
0fe2c2feb3 Merge branch 'internal' 2021-06-22 20:52:59 +02:00
none
8f5af7742d do not use workqueues by dfault, they can lead to dma overflows 2021-06-22 20:51:28 +02:00
none
4a93d1056a Merge branch 'internal' 2021-06-08 14:02:28 +02:00
none
309713674c remove unused include 2021-06-08 14:02:01 +02:00
none
bfddf62f64 Merge branch 'internal' 2021-06-08 10:49:43 +02:00
none
2b0e5eb9d2 removed, use ddinfo 2021-06-08 10:49:06 +02:00
none
1d96274993 Merge branch 'internal' 2021-06-07 17:12:12 +02:00
none
3ff4d900a5 add more info 2021-06-06 20:24:07 +02:00
none
e1e569975f add FW version to output 2021-06-06 20:23:43 +02:00
none
b9998ee9e2 add new structs 2021-06-06 20:23:06 +02:00
none
dfe6b385a9 rename sx8info to ddinfo and add to Makefile 2021-06-05 22:36:01 +02:00
none
6e926c1452 add DVB-T parameters 2021-06-05 22:32:46 +02:00
none
8039097426 add support for FE_TIMEDOUT 2021-05-26 22:39:27 +02:00
mvoelkel
f3d5adc777 added puncture_rate to modulator stream setup 2021-04-17 21:03:05 +02:00
mvoelkel
e974925430 Merge branch 'internal' of https://github.com/DigitalDevices/internal_dddvb into internal 2021-04-10 19:08:23 +02:00
none
23bdd90595 Merge branch 'internal' 2021-04-09 12:54:23 +02:00
none
7bafb76461 change to floating point for frequency and signal strength
add comments to example config
2021-04-09 12:53:06 +02:00
mvoelkel
9cde52a6d8 Merge branch 'internal' of https://github.com/DigitalDevices/internal_dddvb into internal 2021-04-07 19:59:08 +02:00
none
50e354c49a cleanup 2021-04-07 19:29:53 +02:00
none
03d84ba75a add example modulator config file 2021-04-07 19:29:18 +02:00
none
c4f82de8b0 add modconfig 2021-04-07 19:28:49 +02:00
none
a5ad0b0584 show MCI firmware version 2021-04-07 19:28:12 +02:00
none
3cb3df51cf use correct kernel integer types 2021-04-07 19:27:21 +02:00
none
2311b94970 add modulator MCI commands 2021-04-07 19:25:32 +02:00
none
f12fe91b51 use PCI revision to determine major firmware version 2021-04-07 19:21:24 +02:00
none
35c283bf2f remove test command 2021-04-07 19:20:38 +02:00
none
41a9626be4 remove unnused variable 2021-04-07 19:20:24 +02:00
none
0d66d5bab0 Merge branch 'internal' 2021-03-18 19:03:57 +01:00
none
91af1be97e simple sx8 status info tool 2021-03-18 14:02:26 +01:00
none
a6c3b82f83 make include usable in user space 2021-03-18 13:48:09 +01:00
none
e863a2037a add byte array to union 2021-03-18 13:47:45 +01:00
none
92cd675f5d move ddbridge ioctls to separate file 2021-03-18 12:39:41 +01:00
none
dda8698514 add timeout status 2021-03-18 10:45:53 +01:00
none
fc9a89c870 add per demod lock for more fine-grained locking 2021-03-18 10:44:11 +01:00
none
4b0a0c4ff2 allow explicit setting of roll-off 2021-03-18 10:39:07 +01:00
none
2ac970ef83 typo 2021-03-18 10:36:51 +01:00
none
c3c734b0e8 remove unsused variables and code 2021-03-11 23:23:30 +01:00
none
8380cb185f change direct_mode to module parameter 2021-03-11 23:22:03 +01:00
none
f9eb03a065 remove unused entries 2021-03-11 23:20:31 +01:00
none
f8c97ad3d6 remove init dump, cannot access regs directly on all platforms 2021-03-11 22:43:12 +01:00
none
60646a6b26 experimental diseqc receive code 2021-03-11 22:33:13 +01:00
none
de0e970999 change input locked in fmode=4 and do not send emulated sequence as diseqc 2021-03-11 22:31:52 +01:00
none
cf35c3038b only get status if demod started 2021-03-10 22:03:56 +01:00
none
4c96f54ddf increase L-BAND to 3GHz 2021-03-10 21:46:29 +01:00
none
eb427a8df2 properly handle flash size limits 2021-03-10 21:38:19 +01:00
none
b200ce3596 allow source selection in non-unicable mode 2021-03-10 16:20:44 +01:00
none
31f36de0d7 set default source to undef 2021-03-10 16:20:44 +01:00
mocm
9269270c79 Added install link 2021-03-09 22:14:14 +01:00
drmocm
04fa5041d3 fixes 2021-03-09 22:06:10 +01:00
none
8f4cd19539 Merge branch 'internal' 2021-03-09 22:05:45 +01:00
drmocm
f3cbbf3ba7 Merge branch 'internal' of http://hippo:3000/rjkm/dddvb into internal 2021-03-09 21:40:52 +01:00
none
a2d39f90d5 add module parameter for disabling voltage output in Max cards. 2021-03-09 20:21:09 +01:00
none
7af71dfdcb lock ldpc bitrate adjustment to prevent race condition during tuner stop 2021-03-09 14:23:06 +01:00
drmocm
acb5931ed0 added README.md 2021-03-08 14:29:27 +01:00
none
476a105de7 Merge branch 'internal' 2021-03-01 13:06:05 +01:00
none
b025599e9f dump more buffer bytes in case of misalignment 2021-03-01 12:58:54 +01:00
none
9028e75f63 always use unaligned processing if detected once 2021-03-01 12:58:21 +01:00
none
177e6b0fd6 check if memory is aligned to 4K 2021-03-01 12:57:45 +01:00
none
de82a50b4e Set allocated memory to zero. 2021-03-01 12:57:20 +01:00
none
5714b85238 Merge branch 'internal' 2021-02-25 15:00:30 +01:00
none
01ca1b8805 Detect and report TS misalignment and switch to unaligned processing. 2021-02-25 14:58:42 +01:00
none
28e09191af Do not attach dummy with dvb attach. 2021-02-25 14:57:33 +01:00
none
abb2c56ddc output overflow as warning 2021-02-24 20:30:45 +01:00
none
c6ada48892 remove check for MCI base 2021-02-24 20:27:42 +01:00
none
baf6a090b8 use packet loss function 2021-02-24 20:25:27 +01:00
none
d259d69808 add packet loss function 2021-02-24 20:24:14 +01:00
none
f72c7b2256 print MCI info 2021-02-24 20:22:36 +01:00
none
c82c9d3218 old GCC does not like init in struct 2021-02-24 20:22:08 +01:00
none
1598ab98bc print MCI information at init 2021-02-24 20:21:57 +01:00
none
7efa935a30 remove debug messages 2021-02-24 20:20:10 +01:00
none
fc728ab51e only report I2C errors after probing is done 2021-02-24 20:19:06 +01:00
none
ea41e57ba3 disable master at driver shutdown 2021-02-24 20:17:50 +01:00
none
cd3868afff reenable gain control 2021-02-24 20:17:22 +01:00
none
b72f0365ea correctly check id 2021-02-24 20:16:43 +01:00
none
b3f2580e84 add flash name 2021-02-24 20:16:26 +01:00
none
f1976b5f74 always return if help requested 2021-02-24 20:13:24 +01:00
none
ee6787d2d0 add usage for force option 2021-02-24 20:12:54 +01:00
none
37eb11fb4b set iq_mode to 2 in start_iq() 2021-02-09 17:40:49 +01:00
none
a276a370cb always return lock with SDR mode 2021-02-09 17:30:48 +01:00
none
1863ad2270 Merge branch 'internal' 2021-02-04 10:43:26 +01:00
none
8b787bbc0d Bodo patches 2021-02-03 18:03:51 +01:00
none
e5e6e44b76 forgot isi 2021-02-02 16:44:03 +01:00
none
cfbe430b4a more flags in SDR mode 2021-02-01 21:30:52 +01:00
none
2a1b96a6ad correct FSM4 name 2021-02-01 21:30:23 +01:00
none
7d8a151127 git push
Merge branch 'internal'
2021-01-20 17:42:47 +01:00
rjkm
cbfd9b18ea report back inversion state 2021-01-13 14:59:27 +01:00
rjkm
bfa8cec850 always use the copy loop with 32bit accesses
64bit access produces errors on some platforms
2021-01-13 14:56:57 +01:00
rjkm
e413baeab9 fix error for unaligned accesses 2021-01-13 14:56:22 +01:00
rjkm
46c42c6ef0 - remove comment
- assume unset input if not explicitely set
2020-12-18 16:44:57 +01:00
rjkm
4b053c68ef use F output as default 2020-12-01 16:00:17 +01:00
rjkm
46a4f7476a support new SDR modulator image with MCI 2020-12-01 15:58:35 +01:00
rjkm
65b3128cbe allow 64 bit consisten mem addresses 2020-12-01 15:57:31 +01:00
rjkm
22c52fbf86 how partial isdbs lock 2020-12-01 15:56:21 +01:00
rjkm
766ca0e652 simplify check expression 2020-12-01 15:56:06 +01:00
rjkm
4459f50538 shorter retry time 2020-12-01 15:54:03 +01:00
rjkm
b0e1770268 simplify 2020-12-01 15:53:54 +01:00
rjkm
9b50e3bdc7 add isdbs 2020-12-01 15:53:31 +01:00
rjkm
3b1fcec9e1 add isdbs 2020-12-01 15:52:55 +01:00
rjkm
0a9fd4c2e1 support reboot and fast erase 2020-12-01 15:51:13 +01:00
rjkm
b1b3e92a50 add ddupdate 2020-11-23 21:58:30 +01:00
rjkm
50fe2d6ebe git push
Merge branch 'internal'
2020-11-10 15:52:35 +01:00
rjkm
1d3e21894c missing file from mainline kernel 2020-11-10 15:52:00 +01:00
rjkm
0e13bdcb08 Merge branch 'internal' 2020-11-10 15:49:53 +01:00
rjkm
d2e6c9b2cb add fallback 2020-11-10 15:42:56 +01:00
rjkm
55aec3cf72 remove unneeded include 2020-11-10 15:42:56 +01:00
rjkm
c93f96b6ec add some symbol rate modes 2020-11-10 15:42:56 +01:00
rjkm
310a5e0f05 add some symbol rate modes 2020-11-10 15:42:56 +01:00
rjkm
22475860d5 adjust kernel version check 2020-11-10 15:42:56 +01:00
rjkm
a375cd1716 remove debug mesage 2020-11-10 15:42:56 +01:00
rjkm
e0e9b82f5a add link to mci_base to ddb_link 2020-11-10 15:42:56 +01:00
rjkm
b60efcdaad fix j83b tuning 2020-11-10 15:42:56 +01:00
rjkm
527f6a47a3 adapt to latest upstream header file 2020-11-10 15:42:56 +01:00
none
16909b37a0 get PLS code and show as debug message 2020-11-10 15:42:56 +01:00
none
d808f1d37a wrong kernel version cheked 2020-11-10 15:42:56 +01:00
none
b46b89d4b5 return no modulation for DVB-S2X modes, no defines available in LINUX API yet 2020-11-10 15:42:56 +01:00
none
1b11064b83 let files be bigger 2020-11-10 15:42:56 +01:00
none
072689735c prevent memory fault from card name if file name is given 2020-11-10 15:42:56 +01:00
none
8e39e291a0 change to new function call 2020-11-10 15:42:56 +01:00
drmocm
97a88de738 add --pam (-a) option for IQ data output in pam format to stdout.
Needs a number >0 as argument.
2020-10-10 17:32:56 +02:00
none
7f19a0c04b adapt to current mainline kernel dvb-core 2020-08-29 15:32:42 +02:00
none
83f5b45928 adapt to current mainline kernel version 2020-08-29 15:20:58 +02:00
none
dc300198a9 rest of raw support ... 2020-08-29 15:18:59 +02:00
none
4747cbd553 fix init 2020-08-29 14:59:45 +02:00
none
ddac58d082 add raw mode, selected either via module option or input parameter 2020-08-29 14:57:02 +02:00
none
982dc4d366 fix tscheck and add option to not open dvr demux 2020-08-29 14:38:09 +02:00
none
bb5e9e7f39 - correct style
- bug in header check
2020-08-29 14:34:53 +02:00
none
ed8bb5af82 add new flash types and consolidate old duplicate functions 2020-08-29 14:33:15 +02:00
none
67a13e4f34 use uint32_t for sizes 2020-08-29 14:32:18 +02:00
none
cbf73572b7 allow input selection in normal LNB mode 2020-08-26 10:30:22 +02:00
none
c1100645be typo 2020-08-03 17:47:19 +02:00
mvoelkel
d20457544e Corrected name for cineS2 V7A 2020-07-17 20:39:54 +02:00
none
54e8bb1575 add packet loss and stall counter 2020-03-31 21:20:22 +02:00
none
ee6eab9ead change IQ mode setting 2020-03-31 21:20:22 +02:00
none
93335e856e add TS_STAT 2020-03-31 21:20:22 +02:00
none
5138ba3f91 support high voltage setting on MAX cards 2020-03-31 21:20:22 +02:00
none
02329a7d55 check if link exists 2020-03-31 21:20:22 +02:00
none
8c950053a7 cleanup 2020-03-31 21:20:22 +02:00
none
5abf74a952 add yesno 2020-03-31 21:20:22 +02:00
drmocm
b43160a03a added continuity check option with (-a l) and without (t) display line
fixed some warnings
2020-02-05 19:00:51 +01:00
none
938090b5e6 too few arguments 2020-01-27 09:41:32 +01:00
none
5f648d7a02 cleanup 2020-01-22 10:34:20 +01:00
Manfred
83cfff7082 tscheck stupid error on previous commit 2020-01-21 19:09:16 +01:00
Manfred
03cc9ae142 tscheck don't check cc if payload bit not set 2020-01-21 19:05:56 +01:00
Manfred
ed5f89a0c4 tschecker added 2020-01-21 18:36:05 +01:00
rjkm
5b17d32804 init fname 2020-01-18 16:36:16 +01:00
none
6e57fd96b9 ddupdate test version 2020-01-18 16:24:54 +01:00
none
ade4caa718 add some SPDX headers 2020-01-18 16:24:54 +01:00
none
aa1b5369ac make ddbridge device access count atomic 2020-01-18 16:24:54 +01:00
none
b946de7e44 comment cleanup 2020-01-18 16:24:54 +01:00
none
0522573b46 show GT link state on change 2020-01-18 16:24:54 +01:00
none
2610424e1c adapt to mainline kernel version 2020-01-18 16:24:54 +01:00
none
b3848a362d add multistream flags
some user space software needs this for T2 mutlistream
(although it makes no sense, T2 always demands multistream capability)
2020-01-18 16:24:54 +01:00
none
fe80bc1154 - remove unused code
- only report warning on FW failure
2020-01-18 16:24:54 +01:00
none
b185b5fb66 undef bandwidth
add H/V as alternatives for h/v
2020-01-18 16:24:54 +01:00
none
75a4a733f2 add bandwidth defaults 2020-01-18 16:24:54 +01:00
none
a5d0a9718b add a DVB-S2 22 MSymb mode 2020-01-18 16:24:54 +01:00
Marcus Metzler
2c6530aa8d write tuning info to stderr instead of stdout when writing dvr to stdout 2020-01-15 15:47:13 +01:00
none
74e040f020 unset iq_mode flag in stop_iq 2020-01-15 15:27:01 +01:00
none
ee3e352c0c add some fallthrough comments 2020-01-15 12:32:34 +01:00
Marcus Metzler
e4b1c1a077 set output of tuning information to stderr when ddzap write dvr device to stdout 2020-01-15 09:12:37 +01:00
none
e9f2f5788c new release 2019-12-20 22:47:08 +01:00
none
e736554ff0 report MCI error codes 2019-12-11 09:11:34 +01:00
none
1b9d2782ba use higher bandwidth if symbol rate selected > 5500000 2019-12-11 09:08:25 +01:00
none
569674e427 handle bandwidth also if mangled by dvb-core 2019-12-11 09:07:17 +01:00
none
154ea8f3c9 oops, wrong id 2019-11-14 14:00:41 +01:00
none
5a536040b5 enable TS for SX8 Basic 2019-11-14 11:50:27 +01:00
none
2886f9daef add device id for SX8 Basic 2019-11-12 18:16:39 +01:00
none
86eaeed6c1 change name for SX8 basic 2019-11-12 18:15:54 +01:00
Ralph Metzler
71fc781e4b MAX SX8 basic 2019-11-12 13:59:53 +01:00
Ralph Metzler
44d5488c4a misuse small bandwidth_hz setting as frequency search range setting in kHz 2019-11-08 13:51:11 +01:00
Ralph Metzler
f11ed620f2 let bandwidth_hz setting from application override setting from SR and rollof 2019-11-08 13:51:11 +01:00
Ralph Metzler
2186362136 fix gain on SDR modulator 2019-11-08 13:51:11 +01:00
Ralph Metzler
d2337b6620 add SPDX header 2019-11-08 13:51:11 +01:00
Ralph Metzler
e3da57495f add SPDX headers 2019-11-08 13:51:11 +01:00
Ralph Metzler
ca24ca8029 correct typo: base->freq 2019-11-08 13:51:11 +01:00
Ralph Metzler
e0481f37bb allow larger images 2019-11-08 13:51:11 +01:00
Ralph Metzler
1784a361ad add block error counts 2019-11-08 13:51:11 +01:00
Ralph Metzler
7925537b58 add support to select higher S2/X modulation types 2019-11-08 13:51:11 +01:00
Ralph Metzler
960ee48a10 don't readout modulation too soon 2019-11-08 13:46:52 +01:00
Ralph Metzler
4ce013bbb7 adjust flags to latest firmware version 2019-11-08 13:46:52 +01:00
Marcus Metzler
1a41b8af21 add description for -o 2019-10-24 16:07:32 +02:00
Marcus Metzler
269e66ddca add the -o option to write the dvr device to stdout 2019-10-24 16:05:19 +02:00
Ralph Metzler
11bd28ea82 move dvb_netstream to ddbridge 2019-09-05 10:12:11 +02:00
Ralph Metzler
3422b8d138 mv dvb_netstream files to ddbridge 2019-08-13 21:59:28 +02:00
Ralph Metzler
60b374ac2a initialize cnr_db 2019-08-13 21:39:10 +02:00
Ralph Metzler
1fa617abef remove unused variables 2019-08-13 21:38:46 +02:00
Ralph Metzler
1b849c6ef2 comment out currently unused function 2019-08-13 21:38:18 +02:00
Ralph Metzler
ab0f16099b paasify gcc regarding supposedly possibly undefined adap (can actually never happen) 2019-08-13 21:37:10 +02:00
Ralph Metzler
2e392cfe43 add some pcie debugging 2019-08-12 21:40:09 +02:00
Ralph Metzler
a19a066b39 adjust some copyright years 2019-08-12 21:39:33 +02:00
Ralph Metzler
d3d574c13c change KBUILD_EXTMOD 2019-08-12 21:37:16 +02:00
Ralph Metzler
8b0550222d Merge branch 'master' of https://github.com/DigitalDevices/dddvb 2019-08-05 16:21:03 +02:00
Ralph Metzler
123e46e7a9 Merge branch 'internal' 2019-08-05 16:11:26 +02:00
Ralph Metzler
a153bfd7b2 Merge pull request #35 from drmpeg/fix-dvbnet
Fix kernel crash in dvb_net driver.
2019-08-05 16:10:53 +02:00
Ralph Metzler
0cc91fbe5f Merge branch 'internal' 2019-08-05 16:06:26 +02:00
Ralph Metzler
b86ea4524f update some headers to 2019 2019-08-05 16:04:44 +02:00
Ralph Metzler
d293b9a702 add options to setmod app for type 3 mods 2019-08-05 16:02:34 +02:00
Ralph Metzler
35e0de3968 change fan control to go down faster 2019-08-05 16:01:12 +02:00
Ralph Metzler
4196458803 add IQ output rate property 2019-08-05 16:00:23 +02:00
Ralph Metzler
83344e1349 add sample rate defines 2019-08-05 15:59:06 +02:00
Marcus Metzler
9c462b89ec bugfixes 2019-08-03 14:47:05 +02:00
Ralph Metzler
bf8460adfb bug 2019-08-03 14:04:44 +02:00
Ralph Metzler
5ccf01a7f5 get section length 2019-08-03 14:01:17 +02:00
Ralph Metzler
78866a12b4 add get_stat_num to get several stats at once 2019-08-01 21:44:29 +02:00
Ralph Metzler
ecc5aeb15a use correct fd 2019-08-01 21:43:53 +02:00
Ralph Metzler
1cb42ad5bf implement ca_read/write 2019-08-01 11:39:35 +02:00
Ralph Metzler
36e3205574 add source and verbosity 2019-07-24 15:44:40 +02:00
Ralph Metzler
5d1fdcb961 add libdddvb-clean 2019-07-24 15:44:40 +02:00
Ralph Metzler
a8c7d06316 add basic CI support and signal quality 2019-07-24 15:44:40 +02:00
drmocm
31a833acfd TUNER_PAD_RF_INPUT and TUNER_PAD_OUTPUT are no longer used in kernels >5.2
use media_get_pad_index() function instead
2019-07-24 07:03:02 +02:00
Ralph Metzler
e7f6f67a49 change new SDR modulator to type 18 2019-07-08 10:09:18 +02:00
Ralph Metzler
4de414351c separate property function for SDR type modulators 2019-07-08 10:08:59 +02:00
Ralph Metzler
565cf88969 adapt to latest firmware 2019-07-08 10:07:24 +02:00
Ralph Metzler
d5c6dc7905 add -l dvben50221 -l dvbapi -l ucsi 2019-07-08 10:06:04 +02:00
Ralph Metzler
710d08c5a9 add DEBUG_CA 2019-07-08 10:05:16 +02:00
Ralph Metzler
0595603734 add MODULATOR_INFO 2019-07-08 10:04:46 +02:00
Ralph Metzler
1064f47fd9 add sendlen/sendstring 2019-07-08 10:03:17 +02:00
Ralph Metzler
f2ca278710 correct typo 2019-07-08 10:01:22 +02:00
Ralph Metzler
f57b5c8b20 change SDR modulator version to 18 2019-07-08 10:01:01 +02:00
Ralph Metzler
d350eef406 add DVB-S and Max M4 to dummy device handling 2019-07-08 10:00:11 +02:00
Ralph Metzler
cb24f29e84 correct file name for mini GT 2019-07-08 09:58:36 +02:00
Ralph Metzler
e68df13ad0 remove wrong check 2019-04-12 20:13:03 +02:00
Ralph Metzler
0248e43bc7 use correct i2c num entry 2019-04-12 20:11:27 +02:00
rjkm
040a1c58b6
Merge pull request #35 from drmpeg/fix-dvbnet
Fix kernel crash in dvb_net driver.
2019-04-09 22:35:20 +02:00
Ralph Metzler
4783d0eab2 make default modulations a module parameter 2019-04-03 15:16:10 +02:00
Ralph Metzler
ad0d1316a7 need parantheses around expression 2019-04-03 15:15:19 +02:00
Ralph Metzler
8cab284a65 remove & 2019-04-03 15:14:26 +02:00
Ralph Metzler
c0af1d7e45 add recent changes to interface 2019-04-03 15:12:29 +02:00
Ralph Metzler
ab59d9b705 add debugging to MCI timeout 2019-04-03 15:12:02 +02:00
Ron Economos
e746d013ec Fix kernel crash in dvb_net driver. 2019-03-26 02:17:13 -07:00
Ralph Metzler
16b15dfcc0 add serial number attribute for cards at GT link ports 2019-03-14 12:47:48 +01:00
Ralph Metzler
af0a513d12 add DVBT modulator card 2019-03-14 12:47:00 +01:00
Ralph Metzler
da39fb4c0d add acheck for PCIe link lost in case of MCI timeout 2019-03-14 12:45:30 +01:00
Ralph Metzler
1d4fa8f5a3 SDR cards start at 16 2019-03-14 12:44:46 +01:00
Ralph Metzler
2508919151 change attach handling 2019-03-14 12:44:21 +01:00
Ralph Metzler
2e3c59ecc3 reduce ts speed, some motherboard chipsets cannot handle it 2019-03-14 12:42:52 +01:00
Ralph Metzler
6e5dc4e367 correct file name for Octopus CI 2019-03-14 12:41:31 +01:00
Ralph Metzler
3bba565cc5 alternative payload for tsting 2019-03-14 12:40:38 +01:00
Ralph Metzler
a6f981eb04 comment out unused parts 2019-02-14 20:53:43 +01:00
Ralph Metzler
d422786f00 comment out unused parts 2019-02-14 20:53:10 +01:00
Ralph Metzler
530f9d130a remove burst (does not work with some switches) 2019-02-13 12:01:38 +01:00
Ralph Metzler
f2d3efd577 comment out unused function 2019-02-13 12:01:22 +01:00
Ralph Metzler
4e95332ced comment out unused function 2019-02-13 12:00:22 +01:00
Ralph Metzler
6d09ef98fc add help 2019-02-13 11:59:37 +01:00
Ralph Metzler
3c3430cdbc remove or comment out some unused code 2019-02-13 11:58:57 +01:00
Ralph Metzler
46641db50e add DVB-T SDR Modulator 2019-02-13 11:57:15 +01:00
Ralph Metzler
e360182847 Merge branch 'internal' 2019-01-18 13:11:05 +01:00
Ralph Metzler
6e39d83c7b new version 2019-01-18 13:10:13 +01:00
Ralph Metzler
e73ae1a4c6 set base frequency
initialize mod pointers
2019-01-18 13:09:17 +01:00
Ralph Metzler
e554de3138 add bandwidth parameter 2019-01-17 19:11:45 +01:00
Ralph Metzler
1672bdfcb8 add missing struct element 2019-01-17 19:10:10 +01:00
Ralph Metzler
0b042c1fc3 add new SDR card id 2019-01-17 19:08:07 +01:00
Ralph Metzler
89401e8478 Merge branch 'internal' 2019-01-10 17:49:01 +01:00
Ralph Metzler
a783a02679 support Winbond flash 2019-01-10 17:48:00 +01:00
Ralph Metzler
e11c70c118 support Winbond flash 2019-01-10 17:11:55 +01:00
Ralph Metzler
c914fc9b13 Merge branch 'internal' 2018-12-05 10:55:35 +01:00
Ralph Metzler
67f0820a53 use default FPGA image values 2018-11-19 19:10:29 +01:00
Ralph Metzler
448b07091d initial support for SDR IQ card 2018-10-07 18:07:14 +02:00
Ralph Metzler
dc45a08c10 add more delivery systems for M4 2018-09-28 00:28:18 +02:00
Ralph Metzler
0fa1f815c5 remove debugging messages 2018-09-28 00:27:58 +02:00
Ralph Metzler
bbb551ce8a disable debuging messages 2018-09-28 00:27:09 +02:00
Ralph Metzler
21aefddd4b Merge branch 'internal' 2018-09-17 15:31:25 +02:00
Ralph Metzler
42a0b24511 use unified MCI defines 2018-09-17 15:30:21 +02:00
Ralph Metzler
405eb3e5b4 Merge branch 'internal' 2018-09-17 14:35:04 +02:00
Ralph Metzler
0d8987862f add libdddvb 2018-09-17 13:46:27 +02:00
Ralph Metzler
010cdf1ce8 adapt to latest M4 firmware 2018-09-17 13:46:27 +02:00
Ralph Metzler
f17d1e8ee1 experimental adapter alloc type 4 for one adapter per GT link 2018-09-17 13:46:27 +02:00
Ralph Metzler
821793ec96 use octopus type for GT mini 2018-09-17 13:46:27 +02:00
Ralph Metzler
f670b28603 no input callback for M4 card 2018-09-17 13:46:27 +02:00
Ralph Metzler
7e0b402256 add GT mini support 2018-09-17 13:46:27 +02:00
drmocm
065dd1a238 include version.h in dmxdev.c 2018-09-10 09:50:47 +02:00
drmocm
f291491231 include version.h in dmxdev.c to fix compilation error 2018-09-10 08:25:01 +02:00
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
141 changed files with 18333 additions and 5880 deletions

10
.gitignore vendored
View File

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

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.

6
Kbuild
View File

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

View File

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

View File

@ -1,17 +1,33 @@
# DDBridge Driver
Device driver for all Digital Devices DVB demodulator and modulator cards.
### 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
For installation instructions see:
TBD
### Building
http://support.digital-devices.eu/index.php?article=152
TBD
To compile against the dvb-core of a current kernel compile with KERNEL_DVB_CORE=y:
make KERNEL_DVB_CORE=y install
This will only work with current mainline kernels.
Some features will also not work correctly with the mainline kernel dvb-core:
- some devices will have fewer delivery systems enumerated
if one you need is missing you will have to fix it yourself
- the DTV_INPUT property will not work
- local bugfixes in dvb-core will be missing
- Some device names will be different because they do not exist in the kernel
Also, do not forget to delete old dvb-core modules from e.g. /lib/modules/x.y.z-amd64/updates/ !

View File

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

View File

@ -10,8 +10,9 @@
#include <sys/ioctl.h>
#include <pthread.h>
#include <getopt.h>
#include <linux/dvb/ca.h>
uint32_t adapter = 0, device = 0, snum = 256, rnum = 256;
uint32_t adapter = 0, device = 0, snum = 256, rnum = 256, do_reset = 0;
uint8_t fill[188]={0x47, 0x1f, 0xff, 0x10,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
@ -27,6 +28,7 @@ uint8_t fill[188]={0x47, 0x1f, 0xff, 0x10,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff };
#if 0
uint8_t ts[188]={0x47, 0x0a, 0xaa, 0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
@ -40,6 +42,21 @@ uint8_t ts[188]={0x47, 0x0a, 0xaa, 0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff };
#else
uint8_t ts[188]={0x47, 0x0a, 0xaa, 0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa };
#endif
void proc_buf(uint8_t *buf, uint32_t *d)
{
@ -67,6 +84,8 @@ void proc_buf(uint8_t *buf, uint32_t *d)
c=(buf[4]<<24)|(buf[5]<<16)|(buf[6]<<8)|buf[7];
if (c!=*d) {
printf("CONT ERROR: got %08x expected %08x\n", c, *d);
//if (!*d && (c+100) > 100)
// return;
*d=c;
} else {
if (memcmp(ts+8, buf+8, 180))
@ -153,6 +172,34 @@ int send(void)
}
void reset()
{
char fname[80];
int fd, i;
sprintf(fname, "/dev/dvb/adapter%u/ca%u", adapter, device);
fd=open(fname, O_WRONLY);
if (fd < 0)
return;
ioctl(fd, CA_RESET);
for (i=0; i<24; i++) {
ca_slot_info_t info;
usleep(500000);
info.num = 0;
if (ioctl(fd, CA_GET_SLOT_INFO, &info))
return;
if (info.flags & CA_CI_MODULE_READY)
break;
}
if (i==24)
dprintf(2, "RESET failed\n");
}
int main(int argc, char **argv)
{
pthread_t th;
@ -165,11 +212,12 @@ int main(int argc, char **argv)
{"device", required_argument, 0, 'd'},
{"snum", required_argument, 0, 's'},
{"rnum", required_argument, 0, 'r'},
{"reset", no_argument, 0, 'R'},
{"help", no_argument , 0, 'h'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"a:d:h",
"a:d:hs:R",
long_options, &option_index);
if (c==-1)
break;
@ -187,6 +235,9 @@ int main(int argc, char **argv)
case 'r':
rnum = strtoul(optarg, NULL, 10);
break;
case 'R':
do_reset = 1;
break;
case 'h':
printf("cit -a<adapter> -d<device>\n");
exit(-1);
@ -198,6 +249,11 @@ int main(int argc, char **argv)
if (optind < argc) {
printf("Warning: unused arguments\n");
}
if (do_reset) {
reset();
exit(0);
}
printf("adapter %d, device: %d\n", adapter, device);
memset(ts+8, 180, 0x5a);
pthread_create(&th, NULL, get_ts, NULL);

View File

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

View File

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

View File

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

593
apps/ddinfo.c Normal file
View File

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

255
apps/ddlicense.c Normal file
View File

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

View File

@ -1,341 +0,0 @@
/*
/* flashprog - Programmer for flash on Digital Devices Octopus
*
* Copyright (C) 2010-2011 Digital Devices GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include "flash.h"
void get_id(int ddb, struct ddb_id *ddbid) {
uint8_t id[4];
if (ioctl(ddb, IOCTL_DDB_ID, ddbid)>=0)
return;
memset(ddbid, 0, sizeof(*ddbid));
flashread(ddb, id, 0, 4);
printf("%02x %02x %02x %02x\n",
id[0], id[1], id[2], id[3]);
ddbid->subvendor=(id[0] << 8) | id[1];
ddbid->subdevice=(id[2] << 8) | id[3];
}
int sure()
{
char c;
printf("\n\nWARNING! Flashing a new FPGA image might make your card unusable!\n");
printf("\n\nWARNUNG! Das Flashen eines neuen FPGA-Images kann Ihre Karte unbrauchbar machen.\n");
printf("\n\nAre you sure? y/n?");
printf("\n\nSind Sie sicher? y/n?");
fflush(0);
c = getchar();
if (c!='y') {
printf("\nFlashing aborted.\n\n");
return -1;
}
printf("\nStarting to flash\n\n");
return 0;
}
int main(int argc, char **argv)
{
char ddbname[80];
int type = 0;
struct ddb_id ddbid;
uint8_t *buffer;
int BufferSize = 0;
int BlockErase = 0;
uint32_t FlashOffset = 0x10000;
int ddb;
int i, err;
uint32_t SectorSize=0;
uint32_t FlashSize=0;
int Flash;
uint32_t svid=0, jump=0, dump=0;
int bin;
int ddbnum = 0;
int force = 0;
char *fname = NULL;
while (1) {
int option_index = 0;
int c;
static struct option long_options[] = {
{"svid", required_argument, NULL, 's'},
{"help", no_argument , NULL, 'h'},
{"force", no_argument , NULL, 'f'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"d:n:s:o:l:dfhjb:",
long_options, &option_index);
if (c==-1)
break;
switch (c) {
case 'b':
fname = optarg;
break;
case 'd':
dump = strtoul(optarg, NULL, 16);
break;
case 's':
svid = strtoul(optarg, NULL, 16);
break;
case 'o':
FlashOffset = strtoul(optarg, NULL, 16);
break;
case 'n':
ddbnum = strtol(optarg, NULL, 0);
break;
case 'l':
linknr = strtol(optarg, NULL, 0);
break;
case 'f':
force = 1;
break;
case 'j':
jump = 1;
break;
case 'h':
default:
break;
}
}
if (optind<argc) {
printf("Warning: unused arguments\n");
}
sprintf(ddbname, "/dev/ddbridge/card%d", ddbnum);
ddb=open(ddbname, O_RDWR);
if (ddb < 0) {
printf("Could not open device\n");
return -1;
}
Flash = flashdetect(ddb, &SectorSize, &FlashSize);
get_id(ddb, &ddbid);
#if 1
printf("%04x %04x %04x %04x %08x %08x\n",
ddbid.vendor, ddbid.device,
ddbid.subvendor, ddbid.subdevice,
ddbid.hw, ddbid.regmap);
#endif
if (dump) {
flashdump(ddb, dump, 128);
return 0;
}
if (!SectorSize)
return 0;
if (jump) {
uint32_t Jump = 0x200000;
BufferSize = SectorSize;
FlashOffset = FlashSize - SectorSize;
buffer = malloc(BufferSize);
if (!buffer) {
printf("out of memory\n");
return 0;
}
memset(buffer, 0xFF, BufferSize);
memset(&buffer[BufferSize - 256 + 0x10], 0x00, 16);
buffer[BufferSize - 256 + 0x10] = 0xbd;
buffer[BufferSize - 256 + 0x11] = 0xb3;
buffer[BufferSize - 256 + 0x12] = 0xc4;
buffer[BufferSize - 256 + 0x1a] = 0xfe;
buffer[BufferSize - 256 + 0x1e] = 0x03;
buffer[BufferSize - 256 + 0x1f] = ( ( Jump >> 16 ) & 0xFF );
buffer[BufferSize - 256 + 0x20] = ( ( Jump >> 8 ) & 0xFF );
buffer[BufferSize - 256 + 0x21] = ( ( Jump ) & 0xFF );
} else if (svid) {
BufferSize = SectorSize;
FlashOffset = 0;
buffer = malloc(BufferSize);
if (!buffer) {
printf("out of memory\n");
return 0;
}
memset(buffer,0xFF,BufferSize);
buffer[0] = ((svid >> 24 ) & 0xFF);
buffer[1] = ((svid >> 16 ) & 0xFF);
buffer[2] = ((svid >> 8 ) & 0xFF);
buffer[3] = ((svid ) & 0xFF);
} else {
int fh, i;
int fsize;
if (!fname)
switch (ddbid.device) {
case 0x0002:
fname="DVBBridgeV1A_DVBBridgeV1A.bit";
printf("Octopus 35\n");
break;
case 0x0003:
fname="DVBBridgeV1B_DVBBridgeV1B.fpga";
printf("Octopus\n");
break;
case 0x0005:
fname="DVBBridgeV2A_DD01_0005_STD.fpga";
printf("Octopus Classic\n");
break;
case 0x0006:
fname="DVBBridgeV2A_DD01_0006_STD.fpga";
printf("CineS2 V7\n");
break;
case 0x0007:
fname="DVBBridgeV2A_DD01_0007_MXL.fpga";
printf("Octopus 4/8\n");
break;
case 0x0008:
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 0x0011:
fname="CIBridgeV1B_CIBridgeV1B.fpga";
printf("Octopus CI\n");
break;
case 0x0012:
fname="DVBBridgeV2B_DD01_0012_STD.fpga";
printf("Octopus CI\n");
break;
case 0x0013:
fname="DVBBridgeV2B_DD01_0013_PRO.fpga";
printf("Octopus PRO\n");
break;
case 0x0201:
fname="DVBModulatorV1B_DVBModulatorV1B.bit";
printf("Modulator\n");
break;
case 0x0203:
fname="DVBModulatorV1B_DD01_0203.fpga";
printf("Modulator Test\n");
break;
case 0x0210:
fname="DVBModulatorV2A_DD01_0210.fpga";
printf("Modulator V2\n");
break;
case 0x0220:
fname="SDRModulatorV1A_DD01_0220.fpga";
printf("SDRModulator\n");
break;
default:
printf("UNKNOWN\n");
break;
}
fh = open(fname, O_RDONLY);
if (fh < 0 ) {
printf("File %s not found \n", fname);
return 0;
}
printf("Using bitstream %s\n", fname);
fsize = lseek(fh,0,SEEK_END);
if( fsize > 4000000 || fsize < SectorSize )
{
close(fh);
printf("Invalid File Size \n");
return 0;
}
if( Flash == ATMEL_AT45DB642D ) {
BlockErase = fsize >= 8192;
if( BlockErase )
BufferSize = (fsize + 8191) & ~8191;
else
BufferSize = (fsize + 1023) & ~1023;
} else {
BufferSize = (fsize + SectorSize - 1 ) & ~(SectorSize - 1);
}
printf(" Size %08x, target %08x\n", BufferSize, FlashOffset);
buffer = malloc(BufferSize);
if( buffer == NULL ) {
close(fh);
printf("out of memory\n");
return 0;
}
memset(buffer, 0xFF, BufferSize);
lseek(fh, 0, SEEK_SET);
read(fh, buffer, fsize);
close(fh);
if (BufferSize >= 0x10000) {
for(i = 0; i < 0x200; i += 1 ) {
if ( *(uint16_t *) (&buffer[i]) == 0xFFFF )
break;
buffer[i] = 0xFF;
}
}
}
if (!force && sure()<0)
return 0;
switch(Flash) {
case ATMEL_AT45DB642D:
err = FlashWriteAtmel(ddb,FlashOffset,buffer,BufferSize);
break;
case SSTI_SST25VF016B:
case SSTI_SST25VF032B:
err = FlashWriteSSTI_B(ddb,FlashOffset,buffer,BufferSize);
break;
case SSTI_SST25VF064C:
err = FlashWritePageMode(ddb,FlashOffset,buffer,BufferSize,0x3C);
break;
case SPANSION_S25FL116K:
case SPANSION_S25FL164K:
err = FlashWritePageMode(ddb,FlashOffset,buffer,BufferSize,0x1C);
break;
}
if (err < 0)
printf("Programming Error\n");
else
printf("Programming Done\n");
free(buffer);
return 0;
}

100
apps/getiq.c Normal file
View File

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

550
apps/modconfig.c Normal file
View File

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

View File

@ -1,36 +0,0 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#define SNUM 1000
//671
void send(void)
{
uint8_t buf[188*SNUM], *cts;
int i;
uint32_t c=0;
int fdo;
fdo=open("/dev/dvb/adapter0/mod0", O_WRONLY);
while (1) {
read(0, buf, sizeof(buf));
write(fdo, buf, 188*SNUM);
}
}
int main()
{
send();
}

1277
apps/modtest.c Normal file

File diff suppressed because it is too large Load Diff

63
apps/modulator-c.conf Normal file
View File

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

54
apps/modulator-t.conf Normal file
View File

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

View File

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

View File

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

View File

@ -10,8 +10,10 @@
#include <string.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <errno.h>
#include "flash.h"
#include "flash.c"
typedef int (*COMMAND_FUNCTION)(int dev, int argc, char* argv[], uint32_t Flags);
@ -43,7 +45,7 @@ int ReadFlash(int ddb, int argc, char *argv[], uint32_t Flags)
Start = strtoul(argv[0],NULL,16);
Len = strtoul(argv[1],NULL,16);
if (argc == 3) {
fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC);
fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
if (fd < 0) {
printf("Could not open file %s\n", argv[2]);
return -1;
@ -51,7 +53,7 @@ int ReadFlash(int ddb, int argc, char *argv[], uint32_t Flags)
}
Buffer = malloc(Len);
if (flashread(ddb, Buffer, Start, Len) < 0) {
if (flashread(ddb, linknr, Buffer, Start, Len) < 0) {
printf("flashread error\n");
free(Buffer);
return 0;
@ -81,7 +83,7 @@ int ReadSave(int ddb, int argc, char *argv[], uint32_t Flags)
Len = strtoul(argv[1],NULL,16);
Buffer = malloc(Len);
if (flashread(ddb, Buffer, Start, Len) < 0) {
if (flashread(ddb, linknr, Buffer, Start, Len) < 0) {
printf("flashread error\n");
free(Buffer);
return 0;
@ -108,12 +110,12 @@ int FlashChipEraseAtmel(int dev)
Cmd[1] = ( (( i ) >> 16) & 0xFF );
Cmd[2] = ( (( i ) >> 8) & 0xFF );
Cmd[3] = 0x00;
err = flashio(dev,Cmd,4,NULL,0);
err = flashio(dev,linknr, Cmd,4,NULL,0);
if( err < 0 )
break;
while (1) {
Cmd[0] = 0xD7; // Read Status register
err = flashio(dev,Cmd,1,&Cmd[0],1);
err = flashio(dev,linknr, Cmd,1,&Cmd[0],1);
if( err < 0 ) break;
if( (Cmd[0] & 0x80) == 0x80 ) break;
}
@ -131,25 +133,25 @@ int FlashChipEraseSSTI(int dev)
do {
Cmd[0] = 0x50; // EWSR
err = flashio(dev,Cmd,1,NULL,0);
err = flashio(dev, linknr, Cmd,1,NULL,0);
if( err < 0 ) break;
Cmd[0] = 0x01; // WRSR
Cmd[1] = 0x00; // BPx = 0, Unlock all blocks
err = flashio(dev,Cmd,2,NULL,0);
err = flashio(dev, linknr, Cmd,2,NULL,0);
if( err < 0 ) break;
Cmd[0] = 0x06; // WREN
err = flashio(dev,Cmd,1,NULL,0);
err = flashio(dev, linknr, Cmd,1,NULL,0);
if( err < 0 ) break;
Cmd[0] = 0x60; // CHIP Erase
err = flashio(dev,Cmd,1,NULL,0);
err = flashio(dev, linknr, Cmd,1,NULL,0);
if( err < 0 ) break;
while(1) {
Cmd[0] = 0x05; // RDRS
err = flashio(dev,Cmd,1,&Cmd[0],1);
err = flashio(dev, linknr, Cmd,1,&Cmd[0],1);
if( err < 0 ) break;
if( (Cmd[0] & 0x01) == 0 ) break;
}
@ -157,12 +159,12 @@ int FlashChipEraseSSTI(int dev)
break;
Cmd[0] = 0x50; // EWSR
err = flashio(dev,Cmd,1,NULL,0);
err = flashio(dev, linknr, Cmd,1,NULL,0);
if( err < 0 ) break;
Cmd[0] = 0x01; // WRSR
Cmd[1] = 0x1C; // BPx = 0, Lock all blocks
err = flashio(dev,Cmd,2,NULL,0);
err = flashio(dev, linknr, Cmd,2,NULL,0);
}
while(0);
@ -332,7 +334,7 @@ int flashioc(int dev,int argc, char* argv[],uint32_t Flags)
Buffer[i] = (uint8_t) tmp;
}
if( flashio(dev,Buffer,WriteLen,Buffer,ReadLen) < 0 )
if( flashio(dev, linknr, Buffer,WriteLen,Buffer,ReadLen) < 0 )
{
return 0;
}
@ -384,8 +386,8 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
int BufferSize = 0;
int BlockErase = 0;
uint32_t FlashOffset = 0x10000;
int SectorSize = 0;
int FlashSize = 0;
uint32_t SectorSize = 0;
uint32_t FlashSize = 0;
int ValidateFPGAType = 1;
int Flash;
uint32_t Id1, Id2;
@ -402,6 +404,10 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
case SPANSION_S25FL116K: SectorSize = 4096; FlashSize = 0x200000; break;
case SPANSION_S25FL132K: SectorSize = 4096; FlashSize = 0x400000; break;
case SPANSION_S25FL164K: SectorSize = 4096; FlashSize = 0x800000; break;
case WINBOND_W25Q16JV: SectorSize = 4096; FlashSize = 0x200000; break;
case WINBOND_W25Q32JV: SectorSize = 4096; FlashSize = 0x400000; break;
case WINBOND_W25Q64JV: SectorSize = 4096; FlashSize = 0x800000; break;
case WINBOND_W25Q128JV: SectorSize = 4096; FlashSize = 0x1000000; break;
}
if (SectorSize == 0)
return 0;
@ -476,7 +482,7 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
int fsize = lseek(fh,0,SEEK_END);
if( fsize > 4000000 || fsize < SectorSize )
if( fsize > 5000000 || fsize < SectorSize )
{
close(fh);
printf("Invalid File Size \n");
@ -532,7 +538,7 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
printf("out of memory\n");
return 0;
}
if (flashread(dev, CmpBuffer, FlashOffset, 0x10000)<0) {
if (flashread(dev, linknr, CmpBuffer, FlashOffset, 0x10000)<0) {
printf("Ioctl returns error\n");
free(Buffer);
free(CmpBuffer);
@ -571,6 +577,10 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
case SPANSION_S25FL116K:
case SPANSION_S25FL132K:
case SPANSION_S25FL164K:
case WINBOND_W25Q16JV:
case WINBOND_W25Q32JV:
case WINBOND_W25Q64JV:
case WINBOND_W25Q128JV:
err = FlashWritePageMode(dev,FlashOffset,Buffer,BufferSize,0x1C); break;
}
@ -658,7 +668,7 @@ int FlashVerify(int dev,int argc, char* argv[],uint32_t Flags)
// Place our own header
}
#endif
if (flashread(dev, Buffer2, FlashOffset, BufferSize)<0) {
if (flashread(dev, linknr, Buffer2, FlashOffset, BufferSize)<0) {
printf("Ioctl returns error\n");
free(Buffer);
free(Buffer2);
@ -722,9 +732,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 +750,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;
}
@ -1092,7 +1120,7 @@ char *GetSerNbr(int dev)
int i;
memset(Buffer,0,sizeof(Buffer));
if (flashread(dev, Buffer, Start, sizeof(Buffer) - 1))
if (flashread(dev, linknr, Buffer, Start, sizeof(Buffer) - 1))
{
printf("Ioctl returns error\n");
return NULL;
@ -1266,10 +1294,10 @@ int lic_erase(int dev, int argc, char* argv[], uint32_t Flags)
static int read_sfpd(int dev, uint8_t adr, uint8_t *val)
{
uint8_t cmd[5] = { 0x5a, 0, 0, adr, 00 };
uint8_t cmd[5] = { 0x5a, 0, 0, adr, 0 };
int r;
r = flashio(dev, cmd, 5, val, 1);
r = flashio(dev, linknr, cmd, 5, val, 1);
if (r < 0)
return r;
return 0;
@ -1281,13 +1309,24 @@ static int read_sst_id(int dev, uint8_t *id)
uint8_t buf[9];
int r;
r = flashio(dev, cmd, 2, buf, 9);
r = flashio(dev, linknr, cmd, 2, buf, 9);
if (r < 0)
return r;
memcpy(id, buf + 1, 8);
return 0;
}
static int read_winbd(int dev, uint8_t *val)
{
uint8_t cmd[5] = { 0x4b, 0, 0, 0, 0 };
int r;
r = flashio(dev, linknr, cmd, 5, val, 8);
if (r < 0)
return r;
return 0;
}
int read_id(int dev, int argc, char* argv[], uint32_t Flags)
{
int Flash = FlashDetect(dev);
@ -1295,8 +1334,15 @@ int read_id(int dev, int argc, char* argv[], uint32_t Flags)
uint8_t Id[8];
uint32_t len, i, adr;
switch(Flash) {
case WINBOND_W25Q16JV:
case WINBOND_W25Q32JV:
case WINBOND_W25Q64JV:
case WINBOND_W25Q128JV:
read_winbd(dev, Id);
len = 8;
break;
case SPANSION_S25FL116K:
case SPANSION_S25FL132K:
case SPANSION_S25FL164K:
@ -1316,7 +1362,7 @@ int read_id(int dev, int argc, char* argv[], uint32_t Flags)
for (i = 0; i < len; i++)
printf("%02x ", Id[i]);
printf("\n");
return 0;
}
int i2cread(int dev, int argc, char* argv[], uint32_t Flags)

295
apps/octonet/ddupdate.c Normal file
View File

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

File diff suppressed because it is too large Load Diff

View File

@ -62,4 +62,46 @@ struct ddb_i2c_msg {
#define IOCTL_DDB_READ_I2C _IOWR(DDB_MAGIC, 0x0a, struct ddb_i2c_msg)
#define IOCTL_DDB_WRITE_I2C _IOR(DDB_MAGIC, 0x0b, struct ddb_i2c_msg)
#include "flash.c"
enum {
UNKNOWN_FLASH = 0,
ATMEL_AT45DB642D = 1,
SSTI_SST25VF016B = 2,
SSTI_SST25VF032B = 3,
SSTI_SST25VF064C = 4,
SPANSION_S25FL116K = 5,
SPANSION_S25FL132K = 6,
SPANSION_S25FL164K = 7,
WINBOND_W25Q16JV = 8,
WINBOND_W25Q32JV = 9,
WINBOND_W25Q64JV = 10,
WINBOND_W25Q128JV = 11,
};
struct flash_info {
uint8_t id[3];
uint32_t type;
uint32_t ssize;
uint32_t fsize;
char *name;
};
struct ddflash {
int fd;
uint32_t link;
char *fname;
int force;
struct ddb_id id;
uint32_t version;
char *flash_name;
uint32_t flash_type;
uint32_t sector_size;
uint32_t size;
uint32_t bufsize;
uint32_t block_erase;
uint8_t *buffer;
};

View File

@ -1,167 +0,0 @@
/*
* 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");
}

View File

@ -10,6 +10,7 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <getopt.h>
#include <linux/dvb/mod.h>
@ -31,17 +32,134 @@ static int set_property(int fd, uint32_t cmd, uint32_t data)
return 0;
}
int main()
static int get_property(int fd, uint32_t cmd, uint32_t *data)
{
struct dtv_property p;
struct dtv_properties c;
int ret;
p.cmd = cmd;
c.num = 1;
c.props = &p;
ret = ioctl(fd, FE_GET_PROPERTY, &c);
if (ret < 0) {
fprintf(stderr, "FE_GET_PROPERTY returned %d\n", ret);
return -1;
}
*data = p.u.data;
return 0;
}
int main(int argc, char*argv[])
{
int fd;
struct dvb_mod_params mp;
struct dvb_mod_channel_params mc;
uint32_t data;
int32_t adapter = 0, channel = 0, gain = -1, att=-1, mod=-1;
int32_t base = -1, freq = -1, rate = -1, srate = -1;
char mod_name[128];
while (1) {
int cur_optind = optind ? optind : 1;
int option_index = 0;
int c;
static struct option long_options[] = {
{"adapter", required_argument, 0, 'a'},
{"channel", required_argument, 0, 'c'},
{"att", required_argument, 0, 't'},
{"gain", required_argument, 0, 'g'},
{"base", required_argument, 0, 'b'},
{"frequency", required_argument, 0, 'f'},
{"rate", required_argument, 0, 'r'},
{"modulation", required_argument, 0, 'm'},
{"symbolrate", required_argument, 0, 's'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"a:c:g:b:f:r:t:m:s:",
long_options, &option_index);
if (c==-1)
break;
fd = open("/dev/dvb/adapter0/mod0", O_RDONLY);
switch (c) {
case 'a':
adapter = strtoul(optarg, NULL, 0);
break;
case 'c':
channel = strtoul(optarg, NULL, 0);
break;
case 'g':
gain = strtoul(optarg, NULL, 0);
break;
case 't':
att = strtoul(optarg, NULL, 0);
break;
case 'b':
base = strtoul(optarg, NULL, 0);
break;
case 'f':
freq = strtoul(optarg, NULL, 0);
break;
case 'm':
mod = strtoul(optarg, NULL, 0);
break;
case 's':
srate = strtoul(optarg, NULL, 0);
break;
case 'r':
if (!strcmp(optarg, "DVBT_8"))
rate = SYS_DVBT_8;
else if (!strcmp(optarg, "DVBT_7"))
rate = SYS_DVBT_7;
else if (!strcmp(optarg, "DVBT_6"))
rate = SYS_DVBT_6;
else if (!strcmp(optarg, "ISDBT_6"))
rate = SYS_ISDBT_6;
else rate = strtoul(optarg, NULL, 0);
break;
default:
break;
}
}
if (optind < argc) {
printf("too many arguments\n");
exit(1);
}
set_property(fd, MODULATOR_MODULATION, QAM_256);
set_property(fd, MODULATOR_SYMBOL_RATE, 6900000);
set_property(fd, MODULATOR_FREQUENCY, 114000000);
snprintf(mod_name, 127, "/dev/dvb/adapter%d/mod%d", adapter, channel);
fd = open(mod_name, O_RDONLY);
if (fd < 0) {
printf("Could not open modulator device.\n");
exit(1);
}
/* gain 0-255 */
//get_property(fd, MODULATOR_GAIN, &data);
//printf("Modulator gain = %u\n", data);
//set_property(fd, MODULATOR_GAIN, 100);
//get_property(fd, MODULATOR_ATTENUATOR, &data);
//printf("Modulator attenuator = %u\n", data);
if (att >= 0)
set_property(fd, MODULATOR_ATTENUATOR, att);
if (gain >= 0)
set_property(fd, MODULATOR_GAIN, gain);
if (base > 0)
set_property(fd, MODULATOR_BASE_FREQUENCY, base);
if (freq > 0)
set_property(fd, MODULATOR_FREQUENCY, freq);
if (rate > 0)
set_property(fd, MODULATOR_OUTPUT_RATE, rate);
if (mod >= 0)
set_property(fd, MODULATOR_MODULATION, mod);
if (srate > 0)
set_property(fd, MODULATOR_SYMBOL_RATE, srate);
close(fd);
}

View File

@ -1,83 +0,0 @@
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <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,11 +1,15 @@
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
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2843 -DCONFIG_DVB_LNBP21 -DCONFIG_DVB_STV090x -DCONFIG_DVB_STV6110x -DCONFIG_DVB_DRXK -DCONFIG_DVB_STV0910 -DCONFIG_DVB_STV6111 -DCONFIG_DVB_LNBH25 -DCONFIG_DVB_MXL5XX -DCONFIG_DVB_CXD2099 -DCONFIG_DVB_NET -DCONFIG_DVB_TDA18271C2DD
ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o
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-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
obj-$(CONFIG_DVB_OCTONET) += octonet.o
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends
EXTRA_CFLAGS += -Idrivers/media/common/tuners
NOSTDINC_FLAGS += -I$(SUBDIRS)/frontends -I$(SUBDIRS)/include -I$(SUBDIRS)/dvb-core
ifneq ($(KERNEL_DVB_CORE),y)
obj-$(CONFIG_DVB_OCTONET) += octonet.o
endif
#EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends
#EXTRA_CFLAGS += -Idrivers/media/common/tuners
#NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core

View File

@ -2,13 +2,12 @@
# 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-ci.o ddbridge-max.o ddbridge-mci.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-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o
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/

View File

@ -2,8 +2,8 @@
# 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
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-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
obj-$(CONFIG_DVB_OCTONET) += octonet.o
@ -11,4 +11,5 @@ obj-$(CONFIG_DVB_OCTONET) += octonet.o
ccflags-y += -Idrivers/media/dvb-core/
ccflags-y += -Idrivers/media/dvb-frontends/
ccflags-y += -Idrivers/media/tuners/
ccflags-y += --include=dd_compat.h

View File

@ -1,24 +1,22 @@
// SPDX-License-Identifier: GPL-2.0
/*
* 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>
* 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
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ddbridge.h"
@ -34,7 +32,7 @@ static int wait_ci_ready(struct ddb_ci *ci)
ndelay(500);
do {
if (ddbreadl(ci->port->dev,
CI_CONTROL(ci->nr)) & CI_READY)
CI_CONTROL(ci)) & CI_READY)
break;
usleep_range(1, 2);
if ((--count) == 0)
@ -47,14 +45,15 @@ 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);
u32 off = (address >> 1) & (CI_BUFFER_SIZE - 1);
u8 val;
if (address > CI_BUFFER_SIZE)
return -1;
ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address,
CI_DO_READ_ATTRIBUTES(ci->nr));
CI_DO_READ_ATTRIBUTES(ci));
wait_ci_ready(ci);
val = 0xff & ddbreadl(ci->port->dev, CI_BUFFER(ci->nr) + off);
ddbcpyfrom(ci->port->dev, &val, CI_BUFFER(ci->nr) + off, 1);
return val;
}
@ -64,7 +63,7 @@ static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
struct ddb_ci *ci = ca->data;
ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,
CI_DO_ATTRIBUTE_RW(ci->nr));
CI_DO_ATTRIBUTE_RW(ci));
wait_ci_ready(ci);
return 0;
}
@ -77,10 +76,10 @@ static int read_cam_control(struct dvb_ca_en50221 *ca,
u32 res;
ddbwritel(ci->port->dev, CI_READ_CMD | address,
CI_DO_IO_RW(ci->nr));
CI_DO_IO_RW(ci));
ndelay(500);
do {
res = ddbreadl(ci->port->dev, CI_READDATA(ci->nr));
res = ddbreadl(ci->port->dev, CI_READDATA(ci));
if (res & CI_READY)
break;
usleep_range(1, 2);
@ -96,7 +95,7 @@ static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,
struct ddb_ci *ci = ca->data;
ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,
CI_DO_IO_RW(ci->nr));
CI_DO_IO_RW(ci));
wait_ci_ready(ci);
return 0;
}
@ -106,15 +105,15 @@ 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);
CI_CONTROL(ci));
msleep(300);
ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM,
CI_CONTROL(ci->nr));
CI_CONTROL(ci));
ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM,
CI_CONTROL(ci->nr));
usleep_range(20, 25);
CI_CONTROL(ci));
msleep(20);
ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON,
CI_CONTROL(ci->nr));
CI_CONTROL(ci));
return 0;
}
@ -122,7 +121,7 @@ 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));
ddbwritel(ci->port->dev, 0, CI_CONTROL(ci));
msleep(300);
return 0;
}
@ -130,17 +129,17 @@ static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
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));
u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci));
ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE,
CI_CONTROL(ci->nr));
CI_CONTROL(ci));
return 0;
}
static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
{
struct ddb_ci *ci = ca->data;
u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr));
u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci));
int stat = 0;
if (val & CI_CAM_DETECT)
@ -164,6 +163,8 @@ static struct dvb_ca_en50221 en_templ = {
static void ci_attach(struct ddb_port *port)
{
struct ddb_ci *ci;
const struct ddb_info *info = port->dev->link[port->lnr].info;
u32 off = info->ci_base ? info->ci_base : 0x400;
ci = kzalloc(sizeof(*ci), GFP_KERNEL);
if (!ci)
@ -173,6 +174,7 @@ static void ci_attach(struct ddb_port *port)
port->en = &ci->en;
ci->port = port;
ci->nr = port->nr - 2;
ci->regs = DDB_LINK_TAG(port->lnr) | (off + 32 * ci->nr);
}
/* DuoFlex Dual CI support */
@ -236,9 +238,11 @@ static int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot)
{
struct ddb_ci *ci = ca->data;
write_creg(ci, 0x00, 0x01);
msleep(300);
write_creg(ci, 0x01, 0x01);
write_creg(ci, 0x04, 0x04);
msleep(20);
msleep(300);
write_creg(ci, 0x02, 0x02);
write_creg(ci, 0x00, 0x04);
write_creg(ci, 0x18, 0x18);
@ -331,7 +335,7 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate)
case DDB_CI_EXTERNAL_XO2_B:
ci_xo2_attach(port);
break;
case DDB_CI_INTERNAL:
ci_attach(port);
break;

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-hw.c: Digital Devices device information tables
*
@ -18,8 +19,7 @@
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ddbridge.h"
@ -124,6 +124,32 @@ static const struct ddb_regset octopus_i2c_buf = {
/****************************************************************************/
static const struct ddb_regset max_mci = {
.base = 0x500,
.num = 0x01,
.size = 0x04,
};
static const struct ddb_regset max_mci_buf = {
.base = 0x600,
.num = 0x01,
.size = 0x100,
};
static const struct ddb_regset sdr_mci = {
.base = 0x260,
.num = 0x01,
.size = 0x04,
};
static const struct ddb_regset sdr_mci_buf = {
.base = 0x300,
.num = 0x01,
.size = 0x100,
};
/****************************************************************************/
static const struct ddb_regset octopro_input = {
.base = 0x400,
.num = 0x14,
@ -181,6 +207,33 @@ static const struct ddb_regset octopro_gtl = {
/****************************************************************************/
/****************************************************************************/
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,
@ -196,6 +249,25 @@ static const struct ddb_regmap octopus_map = {
.output = &octopus_output,
};
static const struct ddb_regmap octopus_mci_map = {
.irq_version = 1,
.irq_base_i2c = 0,
.irq_base_idma = 8,
.irq_base_odma = 16,
.irq_base_mci = 0,
.i2c = &octopus_i2c,
.i2c_buf = &octopus_i2c_buf,
.idma = &octopus_idma,
.idma_buf = &octopus_idma_buf,
.odma = &octopus_odma,
.odma_buf = &octopus_odma_buf,
.input = &octopus_input,
.output = &octopus_output,
.mci = &max_mci,
.mci_buf = &max_mci_buf,
};
static const struct ddb_regmap octopro_map = {
.irq_version = 2,
.irq_base_i2c = 32,
@ -242,20 +314,40 @@ static const struct ddb_regmap octopus_mod_2_map = {
.irq_version = 2,
.irq_base_odma = 64,
.irq_base_rate = 32,
.irq_base_mci = 10,
.output = &octopus_output,
.odma = &octopus_mod_2_odma,
.odma_buf = &octopus_mod_2_odma_buf,
.channel = &octopus_mod_2_channel,
.mci = &sdr_mci,
.mci_buf = &sdr_mci_buf,
};
static const struct ddb_regmap octopus_sdr_map = {
.irq_version = 2,
.irq_base_odma = 64,
.irq_base_rate = 32,
.irq_base_mci = 10,
.output = &octopus_sdr_output,
.odma = &octopus_mod_2_odma,
.odma_buf = &octopus_mod_2_odma_buf,
.channel = &octopus_mod_2_channel,
.mci = &sdr_mci,
.mci_buf = &sdr_mci_buf,
};
static const struct ddb_regmap gtl_mini = {
.irq_version = 2,
.irq_base_i2c = 32,
.irq_base_idma = 64,
.irq_base_odma = 128,
.irq_base_gtl = 8,
.idma = &gtl_mini_idma,
.idma_buf = &gtl_mini_idma_buf,
.input = &gtl_mini_input,
.gtl = &gtl_mini_gtl,
};
/****************************************************************************/
@ -336,6 +428,7 @@ static const struct ddb_info ddb_v7a = {
.board_control = 2,
.board_control_2 = 4,
.ts_quirks = TS_QUIRK_REVERSED,
.hw_min = 0x010007,
};
static const struct ddb_info ddb_v7 = {
@ -347,6 +440,7 @@ static const struct ddb_info ddb_v7 = {
.board_control = 2,
.board_control_2 = 4,
.ts_quirks = TS_QUIRK_REVERSED,
.hw_min = 0x010007,
};
static const struct ddb_info ddb_ctv7 = {
@ -368,39 +462,45 @@ static const struct ddb_info ddb_satixs2v3 = {
};
static const struct ddb_info ddb_ci = {
.type = DDB_OCTOPUS_CI,
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus CI",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x03,
.ci_mask = 0x0c,
};
static const struct ddb_info ddb_cis = {
.type = DDB_OCTOPUS_CI,
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus CI single",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x03,
.ci_mask = 0x04,
};
static const struct ddb_info ddb_ci_s2_pro = {
.type = DDB_OCTOPUS_CI,
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus CI S2 Pro",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x01,
.board_control = 2,
.board_control_2 = 4,
.hw_min = 0x010007,
.ci_mask = 0x0c,
};
static const struct ddb_info ddb_ci_s2_pro_a = {
.type = DDB_OCTOPUS_CI,
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus CI S2 Pro Advanced",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x01,
.board_control = 2,
.board_control_2 = 4,
.hw_min = 0x010007,
.ci_mask = 0x0c,
};
static const struct ddb_info ddb_dvbct = {
@ -464,7 +564,7 @@ static const struct ddb_info ddb_mod_fsm_8 = {
static const struct ddb_info ddb_mod_fsm_4 = {
.type = DDB_MOD,
.name = "Digital Devices DVB-C modulator FSM-8",
.name = "Digital Devices DVB-C modulator FSM-4",
.version = 2,
.regmap = &octopus_mod_2_map,
.port_num = 4,
@ -473,42 +573,76 @@ static const struct ddb_info ddb_mod_fsm_4 = {
.lostlock_irq = 9,
};
static const struct ddb_info ddb_sdr = {
static const struct ddb_info ddb_mod_fsm = {
.type = DDB_MOD,
.name = "Digital Devices SDR",
.version = 3,
.name = "Digital Devices DVB-C FSM",
.version = 2,
.regmap = &octopus_mod_2_map,
.port_num = 0,
.temp_num = 1,
.tempmon_irq = 8,
.lostlock_irq = 9,
};
static const struct ddb_info ddb_sdr_atv = {
.type = DDB_MOD,
.name = "Digital Devices SDR ATV",
.version = 16,
.regmap = &octopus_sdr_map,
.port_num = 16,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_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 const struct ddb_info ddb_sdr_iq = {
.type = DDB_MOD,
.name = "Digital Devices SDR IQ",
.version = 17,
.regmap = &octopus_sdr_map,
.port_num = 16,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_octopro = {
.type = DDB_OCTOPRO,
.name = "Digital Devices OctopusNet Pro",
.regmap = &octopro_map,
.port_num = 10,
.i2c_mask = 0x3ff,
.mdio_num = 1,
static const struct ddb_info ddb_sdr_iq2 = {
.type = DDB_MOD,
.name = "Digital Devices SDR IQ2",
.version = 17,
.regmap = &octopus_sdr_map,
.port_num = 4,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_sdr_dvbt = {
.type = DDB_MOD,
.name = "Digital Devices DVBT",
.version = 18,
.regmap = &octopus_sdr_map,
.port_num = 14,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_sdr_dvbt_16 = {
.type = DDB_MOD,
.name = "Digital Devices DVBT",
.version = 18,
.regmap = &octopus_sdr_map,
.port_num = 16,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_s2_48 = {
.type = DDB_OCTOPUS_MAX,
.name = "Digital Devices MAX S8 4/8",
.regmap = &octopus_map,
.regmap = &octopus_mci_map,
.port_num = 4,
.i2c_mask = 0x01,
.board_control = 1,
.tempmon_irq = 24,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_ct2_8 = {
@ -571,14 +705,119 @@ static const struct ddb_info ddb_c2t2i_8 = {
.tempmon_irq = 24,
};
/****************************************************************************/
static const struct ddb_info ddb_s2x_48 = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX SX8",
.regmap = &octopus_map,
.regmap = &octopus_mci_map,
.port_num = 4,
.i2c_mask = 0x00,
.tempmon_irq = 24,
.mci = 4,
.mci_ports = 4,
.mci_type = DDB_TUNER_MCI_SX8,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_s2x_48_b = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX SX8 Basic",
.regmap = &octopus_mci_map,
.port_num = 4,
.i2c_mask = 0x00,
.tempmon_irq = 24,
.mci_ports = 4,
.mci_type = DDB_TUNER_MCI_SX8,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_m4 = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX M4",
.regmap = &octopus_mci_map,
.port_num = 2,
.i2c_mask = 0x00,
.tempmon_irq = 24,
.mci_ports = 2,
.mci_type = DDB_TUNER_MCI_M4,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_m8 = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX M8",
.regmap = &octopus_mci_map,
.port_num = 4,
.i2c_mask = 0x00,
.tempmon_irq = 24,
.mci_ports = 4,
.mci_type = DDB_TUNER_MCI_M8,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_m8a = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX M8A",
.regmap = &octopus_mci_map,
.port_num = 4,
.tempmon_irq = 24,
.mci_ports = 4,
.mci_type = DDB_TUNER_MCI_M8A,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_m8e = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices MAX M8E",
.regmap = &octopus_mci_map,
.port_num = 4,
.tempmon_irq = 24,
.mci_ports = 4,
.mci_type = DDB_TUNER_MCI_M8E,
.temp_num = 1,
.lnb_base = 0x400,
};
static const struct ddb_info ddb_ci_m2 = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices Octopus CI M2",
.regmap = &octopus_mci_map,
.port_num = 4,
.tempmon_irq = 24,
.mci_ports = 1,
.mci_type = DDB_TUNER_MCI_M2,
.temp_num = 1,
.ci_mask = 0x0c,
.ci_base = 0x400,
.lnb_base = 0x480,
};
static const struct ddb_info ddb_m2 = {
.type = DDB_OCTOPUS_MCI,
.name = "Digital Devices Octopus M2",
.regmap = &octopus_mci_map,
.port_num = 4,
.tempmon_irq = 24,
.mci_ports = 1,
.mci_type = DDB_TUNER_MCI_M2,
.temp_num = 1,
.lnb_base = 0x480,
};
/****************************************************************************/
static const struct ddb_info ddb_gtl_mini = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus GT Mini",
.regmap = &gtl_mini,
.port_num = 0,
.i2c_mask = 0x00,
.ns_num = 0,
};
/****************************************************************************/
@ -617,7 +856,7 @@ static const struct ddb_info ddb_octonet = {
.port_num = 4,
.i2c_mask = 0x0f,
.ns_num = 12,
.mdio_num = 1,
.mdio_base = 0x20,
};
static const struct ddb_info ddb_octonet_jse = {
@ -627,7 +866,7 @@ static const struct ddb_info ddb_octonet_jse = {
.port_num = 4,
.i2c_mask = 0x0f,
.ns_num = 15,
.mdio_num = 1,
.mdio_base = 0x20,
};
static const struct ddb_info ddb_octonet_gtl = {
@ -637,7 +876,7 @@ static const struct ddb_info ddb_octonet_gtl = {
.port_num = 4,
.i2c_mask = 0x05,
.ns_num = 12,
.mdio_num = 1,
.mdio_base = 0x20,
.con_clock = 1,
};
@ -693,43 +932,51 @@ static const struct ddb_device_id ddb_device_ids[] = {
DDB_DEVID(0x0008, 0x0038, ddb_c2t2i_8),
DDB_DEVID(0x0009, 0x0025, ddb_s2x_48),
DDB_DEVID(0x0006, 0x0039, ddb_ctv7),
DDB_DEVID(0x000a, 0x0050, ddb_m4),
DDB_DEVID(0x000b, 0x0026, ddb_s2x_48_b),
DDB_DEVID(0x0011, 0x0040, ddb_ci),
DDB_DEVID(0x0011, 0x0041, ddb_cis),
DDB_DEVID(0x0012, 0x0042, ddb_ci),
DDB_DEVID(0x0013, 0x0043, ddb_ci_s2_pro),
DDB_DEVID(0x0013, 0x0044, ddb_ci_s2_pro_a),
DDB_DEVID(0x0014, 0x0045, ddb_ci_m2),
DDB_DEVID(0x0020, 0x0012, ddb_gtl_mini),
DDB_DEVID(0x0022, 0x0052, ddb_m8),
DDB_DEVID(0x0024, 0x0053, ddb_m8a),
DDB_DEVID(0x0025, 0x0054, ddb_m2),
DDB_DEVID(0x0026, 0x0055, ddb_m8e),
/* Modulators */
/* Modulators */
DDB_DEVID(0x0201, 0x0001, ddb_mod),
DDB_DEVID(0x0201, 0x0002, ddb_mod),
DDB_DEVID(0x0201, 0x0004, ddb_mod_4), /* dummy entry ! */
DDB_DEVID(0x0203, 0x0001, ddb_mod),
DDB_DEVID(0x0210, 0x0004, ddb_mod_fsm), /* dummy entry ! */
DDB_DEVID(0x0210, 0x0000, ddb_mod_fsm_4), /* dummy entry ! */
DDB_DEVID(0x0210, 0x0001, ddb_mod_fsm_24),
DDB_DEVID(0x0210, 0x0002, ddb_mod_fsm_16),
DDB_DEVID(0x0210, 0x0003, ddb_mod_fsm_8),
DDB_DEVID(0x0220, 0x0001, ddb_sdr),
DDB_DEVID(0x0220, 0x0001, ddb_sdr_atv),
DDB_DEVID(0x0221, 0x0001, ddb_sdr_iq),
DDB_DEVID(0x0222, 0x0001, ddb_sdr_dvbt),
DDB_DEVID(0x0222, 0x0002, ddb_sdr_dvbt_16), /* dummy entry ! */
DDB_DEVID(0x0223, 0x0001, ddb_sdr_iq2),
/* 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),
DDB_DEVID(0xffff, 0xffff, ddb_none),
};
const struct ddb_info *get_ddb_info(u16 vendor, u16 device,
u16 subvendor, u16 subdevice)
{
int i;
for (i = 0; i < ARRAY_SIZE(ddb_device_ids); i++) {
const struct ddb_device_id *id = &ddb_device_ids[i];
if (vendor == id->vendor &&
device == id->device &&
subvendor == id->subvendor &&
(subvendor == id->subvendor ||
id->subvendor == 0xffff) &&
(subdevice == id->subdevice ||
id->subdevice == 0xffff))
return id->info;

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-i2c.c: Digital Devices bridge i2c driver
*
@ -5,6 +6,7 @@
* 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.
@ -17,8 +19,7 @@
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ddbridge.h"
@ -34,36 +35,36 @@ 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) {
u32 istat = ddbreadl(dev, INTERRUPT_STATUS);
dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n",
dev->nr, i2c->nr, i2c->link);
#if 1
{
u32 istat = ddbreadl(dev, INTERRUPT_STATUS);
dev_err(dev->dev, "DDBridge IRS %08x\n", istat);
dev_err(dev->dev, "DDBridge IRS %08x\n", istat);
if (i2c->link) {
u32 listat =
ddbreadl(dev,
DDB_LINK_TAG(i2c->link) |
INTERRUPT_STATUS);
dev_err(dev->dev,
"DDBridge link %u IRS %08x\n",
i2c->link, listat);
}
if (istat & 1) {
ddbwritel(dev, istat & 1, INTERRUPT_ACK);
} else {
u32 mon = ddbreadl(dev,
i2c->regs + I2C_MONITOR);
dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n",
val, mon);
}
if (i2c->link) {
u32 listat =
ddbreadl(dev,
DDB_LINK_TAG(i2c->link) |
INTERRUPT_STATUS);
dev_err(dev->dev,
"DDBridge link %u IRS %08x\n",
i2c->link, listat);
}
if (istat & 1) {
ddbwritel(dev, istat & 1, INTERRUPT_ACK);
} else {
u32 mon = ddbreadl(dev,
i2c->regs + I2C_MONITOR);
dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n",
val, mon);
}
#endif
return -EIO;
}
if (val & 0x70000)
val &= 0x70000;
if (val == 0x20000)
dev_err(dev->dev, "I2C bus error\n");
if (val)
return -EIO;
return 0;
}

View File

@ -1,9 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ddbridge-i2c.h: Digital Devices bridge i2c driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* 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
@ -17,8 +19,7 @@
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _DDBRIDGE_I2C_H_

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-io.c: Digital Devices bridge I/O functions
*
@ -62,9 +63,11 @@ u32 ddbreadl(struct ddb *dev, u32 adr)
{
if (unlikely(adr & 0xf0000000)) {
unsigned long flags;
u32 val, l = (adr >> DDB_LINK_SHIFT);
u32 val, l = (adr >> DDB_LINK_SHIFT) & 3;
struct ddb_link *link = &dev->link[l];
if (!link->regs)
return 0;
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddblwritel0(link, adr & 0xfffc, link->regs + 0x14);
@ -84,6 +87,8 @@ void ddbwritel(struct ddb *dev, u32 val, u32 adr)
u32 l = (adr >> DDB_LINK_SHIFT);
struct ddb_link *link = &dev->link[l];
if (!link->regs)
return;
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
@ -134,8 +139,8 @@ void gtlcpyfrom(struct ddb *dev, u8 *buf, u32 adr, long count)
u32 a = p & 3;
if (a) {
val = ddbreadl(dev, p) >> (8 * a);
while (p & 3 && count) {
val = ddbreadl(dev, p & ~3) >> (8 * a);
while ((p & 3) && count) {
*buf = val & 0xff;
val >>= 8;
p++;
@ -172,7 +177,12 @@ void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count)
void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count)
{
return gtlcpyfrom(dev, dst, adr, count);
/* The possible 64 bit read in memcpy_fromio produces errors
on some platforms, i.e. arm64 rpi4
if (unlikely(adr & 0xf0000000))
return gtlcpyfrom(dev, dst, adr, count);
return memcpy_fromio(dst, dev->regs + adr, count);
return memcpy_fromio(dst, dev->regs + adr, count);
*/
}

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ddbridge-io.h: Digital Devices bridge I/O functions
*
@ -64,7 +65,7 @@ static inline u32 ddblreadl0(struct ddb_link *link, u32 adr)
return readl(link->dev->regs + adr);
}
#if 0
#ifdef DEBUG_GTLW
static inline void gtlw(struct ddb_link *link)
{
u32 count = 0;

74
ddbridge/ddbridge-ioctl.h Normal file
View File

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

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

@ -0,0 +1,666 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-m4.c: Digital Devices MAX M4 driver
*
* Copyright (C) 2018 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
#include "ddbridge-io.h"
#include "ddbridge-mci.h"
struct m4_base {
struct mci_base mci_base;
};
struct m4 {
struct mci mci;
int started;
int t2_signalling_valid;
int iq_constellation_point;
int iq_constellation_point_max;
int iq_constellation_tap;
int first_time_lock;
};
static int stop(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct mci_command cmd;
if (!state->started)
return -1;
state->started = 0;
state->t2_signalling_valid = 0;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_STOP;
cmd.demod = state->mci.demod;
ddb_mci_cmd(&state->mci, &cmd, NULL);
return 0;
}
static int search_s2(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_DVBS;
cmd.dvbs2_search.flags = 3;
cmd.dvbs2_search.s2_modulation_mask = 3;
cmd.dvbs2_search.retry = 0;
cmd.dvbs2_search.frequency = p->frequency * 1000;
cmd.dvbs2_search.symbol_rate = p->symbol_rate;
cmd.dvbs2_search.scrambling_sequence_index =
p->scrambling_sequence_index;
if (p->stream_id != NO_STREAM_ID_FILTER)
cmd.dvbs2_search.input_stream_id = p->stream_id;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_c(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_DVBC;
if (p->bandwidth_hz <= 6000000)
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_6MHZ;
else if (p->bandwidth_hz <= 7000000)
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_7MHZ;
else
cmd.dvbc_search.bandwidth = MCI_BANDWIDTH_8MHZ;
cmd.dvbc_search.retry = 0;
cmd.dvbc_search.frequency = p->frequency;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_t(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_DVBT;
switch (p->bandwidth_hz) {
case 5000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_5MHZ;
break;
case 6000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_6MHZ;
break;
case 7000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_7MHZ;
break;
default:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_8MHZ;
break;
}
cmd.dvbt_search.retry = 0;
cmd.dvbt_search.frequency = p->frequency;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_isdbs(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_ISDBS;
cmd.isdbs_search.retry = 0;
if (p->stream_id != NO_STREAM_ID_FILTER) {
cmd.isdbs_search.flags = (p->stream_id & 0xffff0000) ? 0 : 1;
cmd.isdbs_search.tsid = p->stream_id;
}
cmd.isdbs_search.frequency = p->frequency * 1000;
cmd.tuner = state->mci.nr;
cmd.demod = state->mci.tuner;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_isdbc(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_ISDBC;
cmd.isdbc_search.retry = 0;
if (p->stream_id != NO_STREAM_ID_FILTER) {
cmd.isdbc_search.flags = (p->stream_id & 0xffff0000) ? 0 : 1;
cmd.isdbc_search.tsid = p->stream_id;
cmd.isdbc_search.onid = (p->stream_id & 0x10000) >> 16;
}
cmd.isdbc_search.bandwidth = MCI_BANDWIDTH_6MHZ;
cmd.isdbc_search.frequency = p->frequency;
cmd.demod = state->mci.tuner;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_j83b(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_J83B;
cmd.j83b_search.flags = 0;
cmd.j83b_search.retry = 0;
cmd.j83b_search.bandwidth = MCI_BANDWIDTH_6MHZ;
if (p->symbol_rate > 5500000)
cmd.j83b_search.bandwidth |= MCI_BANDWIDTH_EXTENSION;
cmd.j83b_search.frequency = p->frequency;
cmd.demod = state->mci.tuner;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_t2(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_DVBT2;
switch (p->bandwidth_hz) {
case 1700000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_1_7MHZ;
break;
case 5000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_5MHZ;
break;
case 6000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_6MHZ;
break;
case 7000000:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_7MHZ;
break;
default:
cmd.dvbt_search.bandwidth = MCI_BANDWIDTH_8MHZ;
break;
}
cmd.dvbt2_search.retry = 0;
cmd.dvbt2_search.frequency = p->frequency;
if (p->stream_id != NO_STREAM_ID_FILTER) {
cmd.dvbt2_search.plp = p->stream_id & 0xff;
cmd.dvbt2_search.flags |= 0x80;
cmd.dvbt2_search.flags |= (p->stream_id >> 8) & 1;
}
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_c2(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_DVBC2;
switch (p->bandwidth_hz) {
case 6000000:
cmd.dvbc2_search.bandwidth = MCI_BANDWIDTH_6MHZ;
break;
default:
cmd.dvbc2_search.bandwidth = MCI_BANDWIDTH_8MHZ;
break;
}
cmd.dvbc2_search.retry = 0;
cmd.dvbc2_search.frequency = p->frequency;
if (p->stream_id != NO_STREAM_ID_FILTER) {
cmd.dvbc2_search.plp = p->stream_id & 0xff;
cmd.dvbc2_search.data_slice = (p->stream_id >> 8) & 0xff;
}
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int search_isdbt(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_command cmd;
int stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_SEARCH_ISDBT;
switch (p->bandwidth_hz) {
case 8000000:
cmd.isdbt_search.bandwidth = MCI_BANDWIDTH_8MHZ;
break;
case 7000000:
cmd.isdbt_search.bandwidth = MCI_BANDWIDTH_7MHZ;
break;
default:
cmd.isdbt_search.bandwidth = MCI_BANDWIDTH_6MHZ;
break;
}
cmd.isdbt_search.retry = 0;
cmd.isdbt_search.frequency = p->frequency;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int set_parameters(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
int res;
//struct dtv_frontend_properties *p = &fe->dtv_property_cache;
stop(fe);
state->t2_signalling_valid = 0;
state->iq_constellation_point = 0;
state->iq_constellation_point_max = 0;
state->iq_constellation_tap = 0;
//printk("bw = %u\n", p->bandwidth_hz);
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBS:
case SYS_DVBS2:
res = search_s2(fe);
break;
case SYS_DVBC_ANNEX_A:
res = search_c(fe);
break;
case SYS_DVBC_ANNEX_B:
res = search_j83b(fe);
break;
case SYS_DVBT:
state->iq_constellation_tap = 5;
res = search_t(fe);
break;
case SYS_DVBT2:
res = search_t2(fe);
break;
case SYS_DVBC2:
res = search_c2(fe);
break;
case SYS_ISDBT:
res = search_isdbt(fe);
break;
case SYS_ISDBS:
res = search_isdbs(fe);
break;
case SYS_DVBC_ANNEX_C:
case SYS_ISDBC:
res = search_isdbc(fe);
break;
default:
return -EINVAL;
}
if (!res) {
state->started = 1;
state->first_time_lock = 1;
}
return res;
}
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{
int stat;
struct m4 *state = fe->demodulator_priv;
struct mci_result res;
*status = 0x00;
if (!state->started)
return 0;
stat = ddb_mci_get_status(&state->mci, &res);
if (stat)
return stat;
stat = ddb_mci_get_info(&state->mci);
if (stat)
return stat;
ddb_mci_get_strength(fe);
if (res.status == MCI_DEMOD_WAIT_SIGNAL)
*status = 0x01;
else if (res.status == MX_DEMOD_WAIT_TS)
*status = 0x03;
else if (res.status == MCI_DEMOD_TIMEOUT)
*status = FE_TIMEDOUT;
else if (res.status == MCI_DEMOD_LOCKED) {
*status = 0x1f;
ddb_mci_get_snr(fe);
}
return stat;
}
static int tune(struct dvb_frontend *fe, bool re_tune,
unsigned int mode_flags,
unsigned int *delay, enum fe_status *status)
{
int r;
if (re_tune) {
r = set_parameters(fe);
if (r)
return r;
}
r = read_status(fe, status);
if (r)
return r;
if (*status & FE_HAS_LOCK)
return 0;
*delay = HZ / 10;
return 0;
}
static int sleep(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
if (state->started)
stop(fe);
return 0;
}
static void release(struct dvb_frontend *fe)
{
struct m4 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
mci_base->count--;
if (mci_base->count == 0) {
list_del(&mci_base->mci_list);
kfree(mci_base);
}
kfree(state);
#ifdef CONFIG_MEDIA_ATTACH
__module_get(THIS_MODULE);
#endif
}
static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{
return DVBFE_ALGO_HW;
}
static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{
struct m4 *state = fe->demodulator_priv;
ddb_mci_proc_info(&state->mci, p);
return 0;
}
static struct dvb_frontend_ops m4_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_B, SYS_DVBC_ANNEX_C,
SYS_DVBC2, SYS_DVBT, SYS_DVBT2, SYS_DVBS, SYS_DVBS2,
#ifndef KERNEL_DVB_CORE
SYS_ISDBC, SYS_ISDBS, SYS_ISDBT,
#endif
},
.info = {
.name = "M4",
.frequency_min_hz = 47125000, /* DVB-T: 47125000 */
.frequency_max_hz = 2150000000, /* DVB-C: 862000000 */
.symbol_rate_min = 100000,
.symbol_rate_max = 100000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 0,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_4_5 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION
},
.release = release,
.get_frontend_algo = get_algo,
.get_frontend = get_frontend,
.read_status = read_status,
.tune = tune,
.sleep = sleep,
};
static int init(struct mci *mci)
{
//struct m4 *state = (struct m4 *) mci;
return 0;
}
static int base_init(struct mci_base *mci_base)
{
//struct m4_base *base = (struct m4_base *) mci_base;
return 0;
}
static struct mci_cfg ddb_max_m4_cfg = {
.type = 0,
.fe_ops = &m4_ops,
.base_size = sizeof(struct m4_base),
.state_size = sizeof(struct m4),
.init = init,
.base_init = base_init,
};
static struct dvb_frontend_ops m_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_B, SYS_DVBC_ANNEX_C,
SYS_DVBT, SYS_DVBT2, SYS_DVBS, SYS_DVBS2,
#ifndef KERNEL_DVB_CORE
SYS_ISDBC, SYS_ISDBS, SYS_ISDBT,
#endif
},
.info = {
.name = "M_AS",
.frequency_min_hz = 47125000, /* DVB-T: 47125000 */
.frequency_max_hz = 2150000000, /* DVB-C: 862000000 */
.symbol_rate_min = 100000,
.symbol_rate_max = 100000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 0,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_4_5 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION
},
.release = release,
.get_frontend_algo = get_algo,
.get_frontend = get_frontend,
.read_status = read_status,
.tune = tune,
.sleep = sleep,
};
static struct mci_cfg ddb_max_m_cfg = {
.type = 0,
.fe_ops = &m_ops,
.base_size = sizeof(struct m4_base),
.state_size = sizeof(struct m4),
.init = init,
.base_init = base_init,
};
static struct dvb_frontend_ops m_s_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2, SYS_ISDBS },
.info = {
.name = "M_S",
.frequency_min_hz = 47125000, /* DVB-T: 47125000 */
.frequency_max_hz = 2150000000, /* DVB-C: 862000000 */
.symbol_rate_min = 100000,
.symbol_rate_max = 100000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 0,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_4_5 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION
},
.release = release,
.get_frontend_algo = get_algo,
.get_frontend = get_frontend,
.read_status = read_status,
.tune = tune,
.sleep = sleep,
};
static struct mci_cfg ddb_max_m_s_cfg = {
.type = 0,
.fe_ops = &m_s_ops,
.base_size = sizeof(struct m4_base),
.state_size = sizeof(struct m4),
.init = init,
.base_init = base_init,
};
static struct dvb_frontend_ops m_a_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_B, SYS_DVBC_ANNEX_C,
SYS_ISDBC,
SYS_DVBT, SYS_DVBT2, SYS_ISDBT,
},
.info = {
.name = "M_A",
.frequency_min_hz = 47125000, /* DVB-T: 47125000 */
.frequency_max_hz = 2150000000, /* DVB-C: 862000000 */
.symbol_rate_min = 100000,
.symbol_rate_max = 100000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 0,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_4_5 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION
},
.release = release,
.get_frontend_algo = get_algo,
.get_frontend = get_frontend,
.read_status = read_status,
.tune = tune,
.sleep = sleep,
};
static struct mci_cfg ddb_max_m_a_cfg = {
.type = 0,
.fe_ops = &m_a_ops,
.base_size = sizeof(struct m4_base),
.state_size = sizeof(struct m4),
.init = init,
.base_init = base_init,
};
static struct mci_cfg *ddb_max_cfgs [] = {
&ddb_max_m4_cfg,
&ddb_max_m_a_cfg,
&ddb_max_m_s_cfg,
&ddb_max_m_cfg,
};
struct dvb_frontend *ddb_mx_attach(struct ddb_input *input, int nr, int tuner, int type)
{
return ddb_mci_attach(input, ddb_max_cfgs[type & 3], nr, tuner);
}
EXPORT_SYMBOL(ddb_mx_attach);

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge.c: Digital Devices PCIe bridge driver
*
@ -5,22 +6,19 @@
* 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
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ddbridge.h"
#include "ddbridge-io.h"
@ -86,7 +84,7 @@ int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
/****************************************************************************/
/****************************************************************************/
static void __devexit ddb_irq_disable(struct ddb *dev)
static void ddb_irq_disable(struct ddb *dev)
{
if (dev->link[0].info->regmap->irq_version == 2) {
ddbwritel(dev, 0x00000000, INTERRUPT_V2_CONTROL);
@ -116,7 +114,7 @@ static void __devexit ddb_msi_exit(struct ddb *dev)
#endif
}
static void __devexit ddb_irq_exit(struct ddb *dev)
static void ddb_irq_exit(struct ddb *dev)
{
ddb_irq_disable(dev);
if (dev->msi == 2)
@ -141,6 +139,7 @@ static void __devexit ddb_remove(struct pci_dev *pdev)
ddb_buffers_free(dev);
ddb_unmap(dev);
pci_clear_master(pdev);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
}
@ -256,17 +255,9 @@ static int __devinit ddb_irq_init(struct ddb *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;
}
@ -292,9 +283,17 @@ static int __devinit ddb_probe(struct pci_dev *pdev,
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;
#if (KERNEL_VERSION(5, 18, 0) <= LINUX_VERSION_CODE)
if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)))
if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
#else
if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
} else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
} else
#endif
return -ENODEV;
dev = vzalloc(sizeof(*dev));
if (!dev)
@ -311,11 +310,11 @@ static int __devinit ddb_probe(struct pci_dev *pdev,
dev->link[0].ids.subvendor = id->subvendor;
dev->link[0].ids.subdevice = pdev->subsystem_device;
dev->link[0].ids.devid = (id->device << 16) | id->vendor;
dev->link[0].ids.revision = pdev->revision;
dev->link[0].dev = dev;
dev->link[0].info = get_ddb_info(id->vendor, id->device,
id->subvendor, pdev->subsystem_device);
dev_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),
@ -335,8 +334,13 @@ static int __devinit ddb_probe(struct pci_dev *pdev,
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);
@ -346,33 +350,27 @@ static int __devinit ddb_probe(struct pci_dev *pdev,
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 (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;
}
if (dev->link[0].info->type == DDB_MOD &&
dev->link[0].info->version == 2) {
if (dev->link[0].ids.revision == 1)
dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0004);
else if ((ddbreadl(dev, 0x1c) & 7) != 7)
dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0004);
}
dev_info(dev->dev, "%s\n", dev->link[0].info->name);
dev_info(dev->dev, "HW %08x REGMAP %08x FW %u.%u\n",
dev->link[0].ids.hwid, dev->link[0].ids.regmapid,
(dev->link[0].ids.hwid & 0xff0000) >> 16,
dev->link[0].ids.hwid & 0xffff);
stat = ddb_irq_init(dev);
if (stat < 0)
goto fail0;
@ -390,13 +388,19 @@ fail:
ddb_unmap(dev);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
return -1;
return stat;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
#ifndef PCI_DEVICE_SUB
#define PCI_DEVICE_SUB(vend, dev, subvend, subdev) \
.vendor = (vend), .device = (dev), \
.subvendor = (subvend), .subdevice = (subdev)
#endif
#define DDB_DEVICE_ANY(_device) \
{ PCI_DEVICE_SUB(0xdd01, _device, 0xdd01, PCI_ANY_ID) }
@ -408,28 +412,73 @@ static const struct pci_device_id ddb_id_table[] __devinitconst = {
DDB_DEVICE_ANY(0x0007),
DDB_DEVICE_ANY(0x0008),
DDB_DEVICE_ANY(0x0009),
DDB_DEVICE_ANY(0x000a),
DDB_DEVICE_ANY(0x000b),
DDB_DEVICE_ANY(0x0011),
DDB_DEVICE_ANY(0x0012),
DDB_DEVICE_ANY(0x0013),
DDB_DEVICE_ANY(0x0014),
DDB_DEVICE_ANY(0x0020),
DDB_DEVICE_ANY(0x0022),
DDB_DEVICE_ANY(0x0024),
DDB_DEVICE_ANY(0x0025),
DDB_DEVICE_ANY(0x0026),
DDB_DEVICE_ANY(0x0201),
DDB_DEVICE_ANY(0x0203),
DDB_DEVICE_ANY(0x0210),
DDB_DEVICE_ANY(0x0220),
DDB_DEVICE_ANY(0x0320),
DDB_DEVICE_ANY(0x0321),
DDB_DEVICE_ANY(0x0322),
DDB_DEVICE_ANY(0x0323),
DDB_DEVICE_ANY(0x0328),
DDB_DEVICE_ANY(0x0329),
DDB_DEVICE_ANY(0x0221),
DDB_DEVICE_ANY(0x0222),
DDB_DEVICE_ANY(0x0223),
{0}
};
MODULE_DEVICE_TABLE(pci, ddb_id_table);
static pci_ers_result_t ddb_pci_slot_reset(struct pci_dev *dev)
{
pr_info("pci_slot_reset\n");
return PCI_ERS_RESULT_RECOVERED;
}
static void ddb_pci_resume(struct pci_dev *dev)
{
pr_info("pci_resume\n");
}
static pci_ers_result_t ddb_pci_mmio_enabled(struct pci_dev *pdev)
{
pr_info("pci_mmio_enabled\n");
return PCI_ERS_RESULT_NEED_RESET;
}
static pci_ers_result_t ddb_pci_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
switch (state) {
case pci_channel_io_frozen:
return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_perm_failure:
return PCI_ERS_RESULT_DISCONNECT;
case pci_channel_io_normal:
default:
break;
}
return PCI_ERS_RESULT_NEED_RESET;
}
static const struct pci_error_handlers ddb_error = {
.error_detected = ddb_pci_error_detected,
.mmio_enabled = ddb_pci_mmio_enabled,
.slot_reset = ddb_pci_slot_reset,
.resume = ddb_pci_resume,
};
static struct pci_driver ddb_pci_driver = {
.name = "ddbridge",
.id_table = ddb_id_table,
.probe = ddb_probe,
.remove = ddb_remove,
.err_handler = &ddb_error,
};
static __init int module_init_ddbridge(void)
@ -438,7 +487,7 @@ static __init int module_init_ddbridge(void)
pr_info("Digital Devices PCIE bridge driver "
DDBRIDGE_VERSION
", Copyright (C) 2010-17 Digital Devices GmbH\n");
", Copyright (C) 2010-19 Digital Devices GmbH\n");
stat = ddb_init_ddbridge();
if (stat < 0)
return stat;
@ -459,5 +508,5 @@ 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_LICENSE("GPL v2");
MODULE_VERSION(DDBRIDGE_VERSION);

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-max.c: Digital Devices MAX card line support functions
*
@ -24,10 +25,13 @@
#include "ddbridge.h"
#include "ddbridge-io.h"
#include "ddbridge-i2c.h"
#include "ddbridge-mci.h"
/* MAX LNB interface related module parameters */
static int delmode;
module_param(delmode, int, 0444);
MODULE_PARM_DESC(delmode, "frontend delivery system mode");
static int fmode;
module_param(fmode, int, 0444);
MODULE_PARM_DESC(fmode, "frontend emulation mode");
@ -40,24 +44,51 @@ static int old_quattro;
module_param(old_quattro, int, 0444);
MODULE_PARM_DESC(old_quattro, "old quattro LNB input order ");
static int no_voltage;
module_param(no_voltage, int, 0444);
MODULE_PARM_DESC(no_voltage, "Do not enable voltage on LNBH (will also disable 22KHz tone).");
static u8 input_diseqc_sequence[6] = { 0x00 };
static int input_diseqc_sequence_length = 1;
module_param_array(input_diseqc_sequence, byte, &input_diseqc_sequence_length, 0444);
MODULE_PARM_DESC(input_diseqc_sequence, "DiSEqC sequence to select input. Last byte & 15 selects input.");
/* MAX LNB interface related functions */
static int lnb_command(struct ddb *dev, u32 link, u32 lnb, u32 cmd)
{
u32 c, v = 0, tag = DDB_LINK_TAG(link);
u32 base = dev->link[link].info->lnb_base;
v = LNB_TONE & (dev->link[link].lnb.tone << (15 - lnb));
ddbwritel(dev, cmd | v, tag | LNB_CONTROL(lnb));
ddbwritel(dev, cmd | v, tag | base | LNB_CONTROL(lnb));
for (c = 0; c < 10; c++) {
v = ddbreadl(dev, tag | LNB_CONTROL(lnb));
v = ddbreadl(dev, tag | base | LNB_CONTROL(lnb));
if ((v & LNB_BUSY) == 0)
break;
msleep(20);
}
if (c == 10)
dev_info(dev->dev,
"%s lnb = %08x cmd = %08x\n",
__func__, lnb, cmd);
"%s lnb = %08x cmd = %08x timed out\n",
__func__, lnb, cmd | v);
return 0;
}
static int max_set_input(struct dvb_frontend *fe, int in);
static int max_emulate_switch(struct dvb_frontend *fe, u8 *cmd, u32 len)
{
int input;
if (len != 4)
return -1;
if ((cmd[0] != 0xe0) || (cmd[1] != 0x10) || (cmd[2] != 0x39))
return -1;
input = cmd[3] & 3;
max_set_input(fe, input);
return 0;
}
@ -69,18 +100,29 @@ static int max_send_master_cmd(struct dvb_frontend *fe,
struct ddb *dev = port->dev;
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
u32 tag = DDB_LINK_TAG(port->lnr);
u32 base = dev->link[port->lnr].info->lnb_base;
int i;
u32 fmode = dev->link[port->lnr].lnb.fmode;
if (fmode == 2 || fmode == 1)
return 0;
if (fmode == 4)
if (!max_emulate_switch(fe, cmd->msg, cmd->msg_len))
return 0;
if (cmd->msg_len &&
cmd->msg_len == input_diseqc_sequence_length &&
!memcmp(cmd->msg, input_diseqc_sequence, cmd->msg_len - 1))
return max_set_input(fe, cmd->msg[cmd->msg_len - 1] & 0x0f);
if (dvb->diseqc_send_master_cmd)
dvb->diseqc_send_master_cmd(fe, cmd);
mutex_lock(&dev->link[port->lnr].lnb.lock);
ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(dvb->input));
ddbwritel(dev, 0, tag | base | LNB_BUF_LEVEL(dvb->input));
for (i = 0; i < cmd->msg_len; i++)
ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(dvb->input));
ddbwritel(dev, cmd->msg[i], tag | base | LNB_BUF_WRITE(dvb->input));
lnb_command(dev, port->lnr, dvb->input, LNB_CMD_DISEQC);
mutex_unlock(&dev->link[port->lnr].lnb.lock);
return 0;
@ -90,11 +132,12 @@ static int lnb_send_diseqc(struct ddb *dev, u32 link, u32 input,
struct dvb_diseqc_master_cmd *cmd)
{
u32 tag = DDB_LINK_TAG(link);
u32 base = dev->link[link].info->lnb_base;
int i;
ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(input));
ddbwritel(dev, 0, tag | base | LNB_BUF_LEVEL(input));
for (i = 0; i < cmd->msg_len; i++)
ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(input));
ddbwritel(dev, cmd->msg[i], tag | base | LNB_BUF_WRITE(input));
lnb_command(dev, link, input, LNB_CMD_DISEQC);
return 0;
}
@ -142,6 +185,8 @@ static int lnb_set_voltage(struct ddb *dev, u32 link, u32 input,
{
int s = 0;
if (no_voltage)
voltage = SEC_VOLTAGE_OFF;
if (dev->link[link].lnb.oldvoltage[input] == voltage)
return 0;
switch (voltage) {
@ -182,7 +227,8 @@ static int max_set_input_unlocked(struct dvb_frontend *fe, int in)
dvb->input = in;
dev->link[port->lnr].lnb.voltage[dvb->input] |= obit;
}
res = dvb->set_input(fe, in);
if (dvb->set_input)
res = dvb->set_input(fe, in);
return res;
}
@ -335,6 +381,30 @@ static int max_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage)
static int max_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
{
struct ddb_input *input = fe->sec_priv;
struct ddb_port *port = input->port;
struct ddb *dev = port->dev;
u32 tag = DDB_LINK_TAG(port->lnr);
u32 base = dev->link[port->lnr].info->lnb_base;
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
u32 fmode = dev->link[port->lnr].lnb.fmode;
mutex_lock(&dev->link[port->lnr].lnb.lock);
switch (fmode) {
default:
case 0:
case 3:
ddbwritel(dev, arg ? 0x34 : 0x01, tag | base | LNB_CONTROL(dvb->input));
break;
case 1:
case 2:
ddbwritel(dev, arg ? 0x34 : 0x01, tag | base | LNB_CONTROL(0));
ddbwritel(dev, arg ? 0x34 : 0x01, tag | base | LNB_CONTROL(1));
ddbwritel(dev, arg ? 0x34 : 0x01, tag | base | LNB_CONTROL(2));
ddbwritel(dev, arg ? 0x34 : 0x01, tag | base | LNB_CONTROL(3));
break;
}
mutex_unlock(&dev->link[port->lnr].lnb.lock);
return 0;
}
@ -412,14 +482,20 @@ int ddb_fe_attach_mxl5xx(struct ddb_input *input)
cfg = mxl5xx;
cfg.fw_priv = link;
if (dev->link[0].info->type == DDB_OCTONET)
if (dev->link[0].info->type == DDB_OCTONET) {
;/*cfg.ts_clk = 69;*/
}
demod = input->nr;
tuner = demod & 3;
if (fmode == 3)
if (fmode >= 3)
tuner = 0;
dvb->fe = dvb_attach(mxl5xx_attach, i2c, &cfg, demod, tuner);
#ifdef CONFIG_MEDIA_ATTACH
dvb->fe = dvb_attach(mxl5xx_attach, i2c, &cfg,
demod, tuner, &dvb->set_input);
#else
dvb->fe = mxl5xx_attach(i2c, &cfg, demod, tuner, &dvb->set_input);
#endif
if (!dvb->fe) {
dev_err(dev->dev, "No MXL5XX found!\n");
return -ENODEV;
@ -437,47 +513,91 @@ int ddb_fe_attach_mxl5xx(struct ddb_input *input)
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;
#ifndef KERNEL_DVB_CORE
dvb->fe->ops.set_input = max_set_input;
#endif
dvb->input = tuner;
return 0;
}
/* MAX MCI related functions */
struct dvb_frontend *ddb_sx8_attach(struct ddb_input *input, int nr, int tuner,
int (**fn_set_input)(struct dvb_frontend *fe, int input));
struct dvb_frontend *ddb_mx_attach(struct ddb_input *input, int nr, int tuner, int type);
static struct mci_cfg maxsx8 = {
};
int ddb_fe_attach_mci(struct ddb_input *input)
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;
cfg = maxsx8;
demod = input->nr;
tuner = demod & 3;
if (fmode == 3)
tuner = 0;
#if 0
dvb->fe = dvb_attach(ddb_mci_attach, input, 0, demod);
#else
dvb->fe = ddb_mci_attach(input, 0, demod);
#endif
switch (type) {
case DDB_TUNER_MCI_SX8:
if (fm >= 3)
tuner = 0;
dvb->fe = ddb_sx8_attach(input, demod, tuner, &dvb->set_input);
dvb->input = tuner;
break;
case DDB_TUNER_MCI_M4:
fm = 0;
dvb->fe = ddb_mx_attach(input, demod, tuner, 0);
dvb->input = tuner;
break;
case DDB_TUNER_MCI_M8:
fm = 3;
if (!demod)
ddb_mci_cmd_link_simple(link, MCI_CMD_SET_INPUT_CONFIG,
0xff, (delmode & 0x10) | 3);
dvb->fe = ddb_mx_attach(input, demod, tuner, 3);
dvb->input = 0;
break;
case DDB_TUNER_MCI_M8A:
case DDB_TUNER_MCI_M8E:
fm = 3;
dvb->fe = ddb_mx_attach(input, demod, tuner, 3);
dvb->input = 0;
break;
case DDB_TUNER_MCI_M2:
{
u32 mode, mmode;
// delmode: 0 - sat,sat 1-cable,cable/sat
switch (delmode & 1) {
case 0:
mode = 2;
mmode = 2; /* M_S */
break;
case 1:
mode = 1;
mmode = demod ? 3 : 1; /* demod 1=M/0=M_A */
break;
}
if (!demod)
ddb_mci_cmd_link_simple(link, MCI_CMD_SET_INPUT_CONFIG,
0xff, mode | (delmode & 0x10));
dvb->fe = ddb_mx_attach(input, demod, tuner, mmode);
dvb->input = tuner;
fm = 0;
break;
}
default:
return -EINVAL;
}
if (!dvb->fe) {
dev_err(dev->dev, "No MAXSX8 found!\n");
dev_err(dev->dev, "No MCI card found!\n");
return -ENODEV;
}
if (input->nr < 4) {
if (!input->nr || (input->nr < 4 && type != DDB_TUNER_MCI_M8)) {
lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT);
lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF);
}
ddb_lnb_init_fmode(dev, link, fmode);
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;
@ -486,9 +606,10 @@ int ddb_fe_attach_mci(struct ddb_input *input)
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;
if (type == DDB_TUNER_MCI_SX8) {
#ifndef KERNEL_DVB_CORE
dvb->fe->ops.set_input = max_set_input;
#endif
}
return 0;
}

View File

@ -1,9 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-mci.c: Digital Devices microcode interface
*
* Copyright (C) 2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
* 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
@ -27,570 +28,382 @@
static LIST_HEAD(mci_list);
static const u32 MCLK = (1550000000/12);
static const u32 MAX_LDPC_BITRATE = (720000000);
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;
u8 adr;
struct mutex mci_lock;
int count;
u8 tuner_use_count[4];
u8 assigned_demod[8];
u32 used_ldpc_bitrate[8];
u8 demod_in_use[8];
u32 iq_mode;
};
struct mci {
struct mci_base *base;
struct dvb_frontend fe;
int nr;
int demod;
int tuner;
int first_time_lock;
int started;
struct mci_result signal_info;
u32 bb_mode;
};
static int mci_reset(struct mci *state)
static int mci_reset(struct ddb_link *link)
{
struct ddb_link *link = state->base->link;
const struct ddb_regmap *regmap = link->info->regmap;
u32 control;
u32 status = 0;
u32 timeout = 40;
union {
u32 u[4];
char s[16];
} version;
u32 vaddr;
if (!regmap || !regmap->mci)
return -EINVAL;
control = regmap->mci->base;
vaddr = regmap->mci_buf->base + 0xf0;
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 ((link->info->type == DDB_OCTOPUS_MCI) &&
(ddblreadl(link, control) & MCI_CONTROL_START_COMMAND)) {
ddblwritel(link, MCI_CONTROL_RESET, control);
ddblwritel(link, 0, control + 4); /* 1= no internal init */
msleep(300);
}
ddblwritel(link, 0, control);
while (1) {
status = ddblreadl(link, control);
if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY)
break;
if (--timeout == 0)
break;
msleep(50);
}
if ((status & MCI_CONTROL_READY) == 0 )
dev_info(link->dev->dev, "MCI control port @ %08x\n", control);
if ((status & MCI_CONTROL_READY) == 0) {
dev_err(link->dev->dev, "MCI init failed!\n");
return -1;
if (link->ids.device == 0x0009)
ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG);
}
version.u[0] = ddblreadl(link, vaddr);
version.u[1] = ddblreadl(link, vaddr + 4);
version.u[2] = ddblreadl(link, vaddr + 8);
version.u[3] = ddblreadl(link, vaddr + 12);
dev_info(link->dev->dev, "MCI port OK, init time %u msecs\n", (40 - timeout) * 50);
dev_info(link->dev->dev, "MCI firmware version %s.%d\n", version.s, version.s[15]);
return 0;
}
static int mci_config(struct mci *state, u32 config)
static int ddb_mci_cmd_raw_unlocked(struct ddb_link *link,
u32 *cmd, u32 cmd_len,
u32 *res, u32 res_len)
{
struct ddb_link *link = state->base->link;
if (link->ids.device != 0x0009)
return -EINVAL;
ddblwritel(link, config, SX8_TSCONFIG);
return 0;
}
static int _mci_cmd_unlocked(struct mci *state,
u32 *cmd, u32 cmd_len,
u32 *res, u32 res_len)
{
struct ddb_link *link = state->base->link;
const struct ddb_regmap *regmap = link->info->regmap;
u32 control, command, result;
u32 i, val;
unsigned long stat;
val = ddblreadl(link, MCI_CONTROL);
if (!regmap || ! regmap->mci)
return -EINVAL;
control = regmap->mci->base;
command = regmap->mci_buf->base;
result = command + MCI_COMMAND_SIZE;
val = ddblreadl(link, control);
if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND))
return -EIO;
if (cmd && cmd_len)
for (i = 0; i < cmd_len; i++)
ddblwritel(link, cmd[i], 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);
ddblwritel(link, cmd[i], command + i * 4);
val |= (MCI_CONTROL_START_COMMAND |
MCI_CONTROL_ENABLE_DONE_INTERRUPT);
ddblwritel(link, val, control);
stat = wait_for_completion_timeout(&link->mci_completion, HZ);
if (stat == 0) {
printk("MCI timeout\n");
return -EIO;
u32 istat = ddblreadl(link, INTERRUPT_STATUS);
dev_err(link->dev->dev, "MCI timeout\n");
val = ddblreadl(link, control);
if (val == 0xffffffff) {
dev_err(link->dev->dev,
"Lost PCIe link!\n");
return -EIO;
} else {
dev_err(link->dev->dev,
"DDBridge IRS %08x link %u\n",
istat, link->nr);
if (istat & 1)
ddblwritel(link, istat, INTERRUPT_ACK);
if (link->nr)
ddbwritel(link->dev,
0xffffff, INTERRUPT_ACK);
}
}
//print_hex_dump(KERN_INFO, "MCI", DUMP_PREFIX_OFFSET, 16, 1, cmd, cmd_len, false);
if (res && res_len)
for (i = 0; i < res_len; i++)
res[i] = ddblreadl(link, MCI_RESULT + i * 4);
res[i] = ddblreadl(link, result + i * 4);
return 0;
}
static int mci_cmd_unlocked(struct mci *state,
struct mci_command *command,
struct mci_result *result)
{
u32 *cmd = (u32 *) command;
u32 *res = (u32 *) result;
return _mci_cmd_unlocked(state, cmd, sizeof(*command)/sizeof(u32),
res, sizeof(*result)/sizeof(u32));
}
static int mci_cmd(struct mci *state,
struct mci_command *command,
struct mci_result *result)
int ddb_mci_cmd_link(struct ddb_link *link,
struct mci_command *command,
struct mci_result *result)
{
struct mci_result res;
int stat;
mutex_lock(&state->base->mci_lock);
stat = _mci_cmd_unlocked(state,
(u32 *)command, sizeof(*command)/sizeof(u32),
(u32 *)result, sizeof(*result)/sizeof(u32));
mutex_unlock(&state->base->mci_lock);
if (!link->mci_ok)
return -EFAULT;
if (!result)
result = &res;
mutex_lock(&link->mci_lock);
stat = ddb_mci_cmd_raw_unlocked(link,
(u32 *)command,
sizeof(*command)/sizeof(u32),
(u32 *)result,
sizeof(*result)/sizeof(u32));
mutex_unlock(&link->mci_lock);
if (command && result && (result->status & 0x80))
dev_warn(link->dev->dev,
"mci_command 0x%02x, error=0x%02x\n",
command->command, result->status);
return stat;
}
static int _mci_cmd(struct mci *state,
struct mci_command *command, u32 command_len,
struct mci_result *result, u32 result_len)
int ddb_mci_cmd_link_simple(struct ddb_link *link, u8 command, u8 demod, u8 value)
{
int stat;
struct mci_command cmd;
mutex_lock(&state->base->mci_lock);
stat = _mci_cmd_unlocked(state,
(u32 *)command, command_len,
(u32 *)result, result_len);
mutex_unlock(&state->base->mci_lock);
return stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = command;
cmd.demod = demod;
cmd.params8[0] = value;
return ddb_mci_cmd_link(link, &cmd, 0);
}
static void mci_handler(void *priv)
{
struct mci_base *base = (struct mci_base *)priv;
struct ddb_link *link = (struct ddb_link *) priv;
complete(&base->completion);
complete(&link->mci_completion);
}
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,
int mci_init(struct ddb_link *link)
{
int result;
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 mci *state = fe->demodulator_priv;
state->base->count--;
if (state->base->count == 0) {
list_del(&state->base->mci_list);
kfree(state->base);
}
kfree(state);
mutex_init(&link->mci_lock);
init_completion(&link->mci_completion);
result = mci_reset(link);
if (result < 0)
return result;
if (link->ids.device == 0x0009 || link->ids.device == 0x000b)
ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG);
ddb_irq_set(link->dev, link->nr,
link->info->regmap->irq_base_mci,
mci_handler, link);
link->mci_ok = 1;
return result;
}
static int get_info(struct dvb_frontend *fe)
int mci_cmd_val(struct ddb_link *link, uint32_t cmd, uint32_t val)
{
int stat;
struct mci *state = fe->demodulator_priv;
struct mci_command cmd;
struct mci_result result;
struct mci_command command;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_GETSIGNALINFO;
cmd.demod = state->demod;
stat = mci_cmd(state, &cmd, &state->signal_info);
command.command_word = cmd;
command.params[0] = val;
return ddb_mci_cmd_link(link, &command, &result);
}
/****************************************************************************/
/****************************************************************************/
int ddb_mci_cmd(struct mci *state,
struct mci_command *command,
struct mci_result *result)
{
return ddb_mci_cmd_link(state->base->link, command, result);
}
static int ddb_mci_cmd_raw(struct mci *state,
struct mci_command *command, u32 command_len,
struct mci_result *result, u32 result_len)
{
struct ddb_link *link = state->base->link;
int stat;
mutex_lock(&link->mci_lock);
stat = ddb_mci_cmd_raw_unlocked(link,
(u32 *)command, command_len,
(u32 *)result, result_len);
mutex_unlock(&link->mci_lock);
return stat;
}
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
int ddb_mci_get_status(struct mci *mci, struct mci_result *res)
{
int stat;
struct mci *state = fe->demodulator_priv;
struct mci_command cmd;
u32 val;
struct mci_result *res = (struct mci_result *)&val;
cmd.command = MCI_CMD_GETSTATUS;
cmd.demod = state->demod;
stat = _mci_cmd(state, &cmd, 1, res, 1);
if (stat)
return stat;
*status = 0x00;
if (res->status == SX8_DEMOD_WAIT_MATYPE)
*status = 0x0f;
if (res->status == SX8_DEMOD_LOCKED)
*status = 0x1f;
return stat;
cmd.demod = mci->demod;
return ddb_mci_cmd_raw(mci, &cmd, 1, res, 1);
}
static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on)
int ddb_mci_get_snr(struct dvb_frontend *fe)
{
struct mci *state = fe->demodulator_priv;
struct mci_command cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.tuner = state->tuner;
cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE;
return mci_cmd(state, &cmd, NULL);
}
static int stop(struct dvb_frontend *fe)
{
struct mci *state = fe->demodulator_priv;
struct mci_command cmd;
u32 input = state->tuner;
memset(&cmd, 0, sizeof(cmd));
if (state->demod != 0xff) {
cmd.command = MCI_CMD_STOP;
cmd.demod = state->demod;
mci_cmd(state, &cmd, NULL);
if (state->base->iq_mode) {
cmd.command = MCI_CMD_STOP;
cmd.demod = state->demod;
cmd.output = 0;
mci_cmd(state, &cmd, NULL);
mci_config(state, SX8_TSCONFIG_MODE_NORMAL);
}
}
mutex_lock(&state->base->tuner_lock);
state->base->tuner_use_count[input]--;
if (!state->base->tuner_use_count[input])
mci_set_tuner(fe, input, 0);
state->base->demod_in_use[state->demod] = 0;
state->base->used_ldpc_bitrate[state->nr] = 0;
state->demod = 0xff;
state->base->assigned_demod[state->nr] = 0xff;
state->base->iq_mode = 0;
mutex_unlock(&state->base->tuner_lock);
state->started = 0;
return 0;
}
static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
{
struct mci *state = fe->demodulator_priv;
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->tuner;
u32 bits_per_symbol = 0;
int i, 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(&state->base->tuner_lock);
if (state->base->iq_mode) {
stat = -EBUSY;
goto unlock;
}
for (i = 0; i < 8; i++) {
used_ldpc_bitrate += state->base->used_ldpc_bitrate[i];
if (state->base->demod_in_use[i])
used_demods++;
}
if ((used_ldpc_bitrate >= MAX_LDPC_BITRATE) ||
((ts_config & SX8_TSCONFIG_MODE_MASK) >
SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) {
stat = -EBUSY;
goto unlock;
}
free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate;
if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE)
free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE;
while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate)
bits_per_symbol--;
if (bits_per_symbol < 2) {
stat = -EBUSY;
goto unlock;
}
i = (p->symbol_rate > MCLK / 2) ? 3 : 7;
while (i >= 0 && state->base->demod_in_use[i])
i--;
if (i < 0) {
stat = -EBUSY;
goto unlock;
}
state->base->demod_in_use[i] = 1;
state->base->used_ldpc_bitrate[state->nr] = p->symbol_rate * bits_per_symbol;
state->demod = state->base->assigned_demod[state->nr] = i;
if (!state->base->tuner_use_count[input])
mci_set_tuner(fe, input, 1);
state->base->tuner_use_count[input]++;
state->base->iq_mode = (ts_config > 1);
unlock:
mutex_unlock(&state->base->tuner_lock);
if (stat)
return stat;
memset(&cmd, 0, sizeof(cmd));
if (state->base->iq_mode) {
cmd.command = SX8_CMD_SELECT_IQOUT;
cmd.demod = state->demod;
cmd.output = 0;
mci_cmd(state, &cmd, NULL);
mci_config(state, 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->nr, state->tuner, state->demod);
cmd.command = MCI_CMD_SEARCH_DVBS;
cmd.dvbs2_search.flags = flags;
cmd.dvbs2_search.s2_modulation_mask = modmask & ((1 << (bits_per_symbol - 1)) - 1);
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;
cmd.dvbs2_search.input_stream_id = p->stream_id;
cmd.tuner = state->tuner;
cmd.demod = state->demod;
cmd.output = state->nr;
if (p->stream_id == 0x80000000)
cmd.output |= 0x80;
stat = mci_cmd(state, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int start_iq(struct dvb_frontend *fe, u32 ts_config)
{
struct mci *state = fe->demodulator_priv;
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->tuner;
int i, stat = 0;
mutex_lock(&state->base->tuner_lock);
if (state->base->iq_mode) {
stat = -EBUSY;
goto unlock;
}
for (i = 0; i < 8; i++)
if (state->base->demod_in_use[i])
used_demods++;
if (used_demods > 0) {
stat = -EBUSY;
goto unlock;
}
state->demod = state->base->assigned_demod[state->nr] = 0;
if (!state->base->tuner_use_count[input])
mci_set_tuner(fe, input, 1);
state->base->tuner_use_count[input]++;
state->base->iq_mode = (ts_config > 1);
unlock:
mutex_unlock(&state->base->tuner_lock);
if (stat)
return stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = SX8_CMD_START_IQ;
cmd.dvbs2_search.frequency = p->frequency * 1000;
cmd.dvbs2_search.symbol_rate = p->symbol_rate;
cmd.tuner = state->tuner;
cmd.demod = state->demod;
cmd.output = 7;
mci_config(state, ts_config);
stat = mci_cmd(state, &cmd, NULL);
if (stat)
stop(fe);
return stat;
}
static int set_parameters(struct dvb_frontend *fe)
{
int stat = 0;
struct mci *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 ts_config, iq_mode = 0, isi;
if (state->started)
stop(fe);
isi = p->stream_id;
if (isi != NO_STREAM_ID_FILTER) {
iq_mode = (isi & 0x30000000) >> 28;
}
switch (iq_mode) {
case 1:
ts_config = (SX8_TSCONFIG_TSHEADER|SX8_TSCONFIG_MODE_IQ);
break;
case 2:
ts_config = (SX8_TSCONFIG_TSHEADER|SX8_TSCONFIG_MODE_IQ);
break;
default:
ts_config = SX8_TSCONFIG_MODE_NORMAL;
break;
}
if (iq_mode != 2) {
u32 flags = 3;
u32 mask = 3;
if (p->modulation == APSK_16 ||
p->modulation == APSK_32) {
flags = 2;
mask = 15;
}
stat = start(fe, flags, mask, ts_config);
} else {
stat = start_iq(fe, ts_config);
}
if (!stat) {
state->started = 1;
state->first_time_lock = 1;
state->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 mci *state = fe->demodulator_priv;
struct mci *mci = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
state->tuner = p->input = input;
printk("fe %u, input = %u\n", state->nr, input);
return 0;
}
static int sleep(struct dvb_frontend *fe)
{
struct mci *state = fe->demodulator_priv;
}
static int get_snr(struct dvb_frontend *fe)
{
struct mci *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
s32 snr;
get_info(fe);
p->cnr.len = 1;
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
p->cnr.stat[0].svalue = (s64) state->signal_info.dvbs2_signal_info.signal_to_noise * 100;
p->cnr.stat[0].svalue =
(s64) mci->signal_info.dvbs2_signal_info.signal_to_noise * 10;
return 0;
}
static int get_strength(struct dvb_frontend *fe)
int ddb_mci_get_strength(struct dvb_frontend *fe)
{
struct mci *state = fe->demodulator_priv;
struct mci *mci = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
s32 str;
get_info(fe);
str = 100000 - (state->signal_info.dvbs2_signal_info.channel_power * 10 + 108750);
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;
}
static struct dvb_frontend_ops mci_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2 },
.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,
.tune = tune,
.release = release,
.read_status = read_status,
.set_input = set_input,
};
int ddb_mci_get_info(struct mci *mci)
{
int stat;
struct mci_command cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_GETSIGNALINFO;
cmd.demod = mci->demod;
stat = ddb_mci_cmd(mci, &cmd, &mci->signal_info);
return stat;
}
/****************************************************************************/
/****************************************************************************/
void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p)
{
const enum fe_modulation modcod2mod[0x20] = {
QPSK, QPSK, QPSK, QPSK,
QPSK, QPSK, QPSK, QPSK,
QPSK, QPSK, QPSK, QPSK,
PSK_8, PSK_8, PSK_8, PSK_8,
PSK_8, PSK_8, APSK_16, APSK_16,
APSK_16, APSK_16, APSK_16, APSK_16,
APSK_32, APSK_32, APSK_32, APSK_32,
APSK_32,
};
const enum fe_code_rate modcod2fec[0x20] = {
FEC_NONE, FEC_1_4, FEC_1_3, FEC_2_5,
FEC_1_2, FEC_3_5, FEC_2_3, FEC_3_4,
FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10,
FEC_3_5, FEC_2_3, FEC_3_4, FEC_5_6,
FEC_8_9, FEC_9_10, FEC_2_3, FEC_3_4,
FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10,
FEC_3_4, FEC_4_5, FEC_5_6, FEC_8_9,
FEC_9_10, FEC_NONE, FEC_NONE, FEC_NONE,
};
const enum fe_code_rate dvbs_fec_lut[8] = {
FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6,
FEC_7_8, FEC_7_8, FEC_NONE, FEC_NONE,
};
const enum fe_rolloff ro_lut[8] = {
ROLLOFF_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_10,
ROLLOFF_5, ROLLOFF_15, ROLLOFF_35, ROLLOFF_35
};
p->frequency =
mci->signal_info.dvbs2_signal_info.frequency;
p->symbol_rate =
mci->signal_info.dvbs2_signal_info.symbol_rate;
switch (p->delivery_system) {
case SYS_DVBS:
case SYS_DVBS2:
{
u32 pls_code =
mci->signal_info.dvbs2_signal_info.pls_code;
p->frequency =
mci->signal_info.dvbs2_signal_info.frequency / 1000;
p->delivery_system =
(mci->signal_info.dvbs2_signal_info.standard == 2) ?
SYS_DVBS2 : SYS_DVBS;
p->inversion = (mci->signal_info.dvbs2_signal_info.roll_off & 0x80) ?
INVERSION_ON : INVERSION_OFF;
if (mci->signal_info.dvbs2_signal_info.standard == 2) {
u32 modcod;
p->delivery_system = SYS_DVBS2;
p->transmission_mode = pls_code;
p->rolloff =
ro_lut[mci->signal_info.dvbs2_signal_info.roll_off & 7];
p->pilot = (pls_code & 1) ? PILOT_ON : PILOT_OFF;
if (pls_code & 0x80) {
/* no suitable values defined in Linux DVB API yet */
/* modcod = (0x7f & pls_code) >> 1; */
p->fec_inner = FEC_NONE;
p->modulation = 0;
if (pls_code >= 250)
p->pilot = PILOT_ON;
} else {
modcod = (0x7c & pls_code) >> 2;
p->fec_inner = modcod2fec[modcod];
p->modulation = modcod2mod[modcod];
}
} else {
p->delivery_system = SYS_DVBS;
p->rolloff = ROLLOFF_35;
p->pilot = PILOT_OFF;
p->fec_inner = dvbs_fec_lut[pls_code & 7];
p->modulation = QPSK;
}
break;
}
case SYS_DVBC_ANNEX_A:
p->modulation =
mci->signal_info.dvbc_signal_info.constellation + 1;
break;
case SYS_DVBT:
break;
case SYS_DVBT2:
break;
case SYS_DVBC2:
break;
case SYS_ISDBT:
break;
default:
break;
}
/* post is correct, we cannot provide both pre and post at the same time */
/* set pre and post the same for now */
p->pre_bit_error.len = 1;
p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
p->pre_bit_error.stat[0].uvalue =
mci->signal_info.dvbs2_signal_info.ber_numerator;
p->pre_bit_count.len = 1;
p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
p->pre_bit_count.stat[0].uvalue =
mci->signal_info.dvbs2_signal_info.ber_denominator;
p->post_bit_error.len = 1;
p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
p->post_bit_error.stat[0].uvalue =
mci->signal_info.dvbs2_signal_info.ber_numerator;
p->post_bit_count.len = 1;
p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
p->post_bit_count.stat[0].uvalue =
mci->signal_info.dvbs2_signal_info.ber_denominator;
p->block_error.len = 1;
p->block_error.stat[0].scale = FE_SCALE_COUNTER;
p->block_error.stat[0].uvalue =
mci->signal_info.dvbs2_signal_info.packet_errors;
p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
p->cnr.len = 1;
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
p->cnr.stat[0].svalue = (s64)
mci->signal_info.dvbs2_signal_info.signal_to_noise * 10;
p->strength.len = 1;
p->strength.stat[0].scale = FE_SCALE_DECIBEL;
p->strength.stat[0].svalue = (s64)
mci->signal_info.dvbs2_signal_info.channel_power * 10;
}
static struct mci_base *match_base(void *key)
{
@ -602,22 +415,17 @@ static struct mci_base *match_base(void *key)
return NULL;
}
static int probe(struct mci *state)
{
mci_reset(state);
return 0;
}
struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, int mci_type, int nr)
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 = mci_type ? (void *) port : (void *) link;
void *key = cfg->type ? (void *) port : (void *) link;
state = kzalloc(sizeof(*state), GFP_KERNEL);
state = kzalloc(cfg->state_size, GFP_KERNEL);
if (!state)
return NULL;
@ -626,30 +434,32 @@ struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, int mci_type, int n
base->count++;
state->base = base;
} else {
base = kzalloc(sizeof(*base), GFP_KERNEL);
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);
link->mci_base = base;
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) {
if (!link->mci_ok) {
kfree(base);
goto fail;
}
list_add(&base->mci_list, &mci_list);
if (cfg->base_init)
cfg->base_init(base);
}
state->fe.ops = mci_ops;
memcpy(&state->fe.ops, cfg->fe_ops, sizeof(struct dvb_frontend_ops));
state->fe.demodulator_priv = state;
state->nr = nr;
state->tuner = nr;
state->demod = nr;
state->tuner = tuner;
state->input = input;
if (cfg->init)
cfg->init(state);
return &state->fe;
fail:
kfree(state);

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* ddbridge-modulator.c: Digital Devices modulator cards
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Copyright (C) 2010-2018 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
@ -23,8 +23,13 @@
#include "ddbridge.h"
#include "ddbridge-io.h"
#include "ddbridge-ioctl.h"
#ifdef KERNEL_DVB_CORE
#include "../include/linux/dvb/mod.h"
#else
#include <linux/dvb/mod.h>
#endif
#include <linux/gcd.h>
/****************************************************************************/
@ -164,11 +169,6 @@ static void mod_calc_rateinc(struct ddb_mod *mod)
{
u32 ri;
dev_info(mod->port->dev->dev,
"ibitrate %llu\n", mod->ibitrate);
dev_info(mod->port->dev->dev,
"obitrate %llu\n", mod->obitrate);
if (mod->ibitrate != 0) {
u64 d = mod->obitrate - mod->ibitrate;
@ -195,6 +195,48 @@ static int mod_calc_obitrate(struct ddb_mod *mod)
return 0;
}
static int mod_set_stream(struct ddb_output *output)
{
struct ddb *dev = output->port->dev;
u32 stream = output->nr;
struct ddb_mod *mod = &dev->mod[output->nr];
struct ddb_link *link = &dev->link[0];
struct mci_result res;
u32 channel;
struct mci_command cmd = {
.mod_command = MOD_SETUP_STREAM,
.mod_channel = stream,
.mod_stream = stream,
.mod_setup_stream = {
.standard = MOD_STANDARD_DVBC_8,
.symbol_rate = mod->symbolrate,
.qam = {
.modulation = mod->modulation - 1,
.rolloff = 13,
}
},
};
if (dev->link[0].info->version != 2)
return 0;
if (dev->link[0].ids.revision != 1)
return 0;
if ((dev->link[0].ids.hwid & 0xffffff) < 9065)
return 0;
if (!mod->frequency && !mod->symbolrate && !mod->modulation)
return 0;
if (mod->frequency)
channel = (mod->frequency - 114000000) / 8000000;
if (!mod->symbolrate)
mod->symbolrate = 6900000;
if (!mod->modulation)
mod->modulation = 5;
cmd.mod_channel = channel;
cmd.mod_setup_stream.symbol_rate = mod->symbolrate;
cmd.mod_setup_stream.qam.modulation = mod->modulation - 1;
return ddb_mci_cmd_link(link, &cmd, &res);
}
static int mod_set_symbolrate(struct ddb_mod *mod, u32 srate)
{
struct ddb *dev = mod->port->dev;
@ -210,6 +252,7 @@ static int mod_set_symbolrate(struct ddb_mod *mod, u32 srate)
}
mod->symbolrate = srate;
mod_calc_obitrate(mod);
mod_set_stream(mod->port->output);
return 0;
}
@ -227,6 +270,7 @@ static int mod_set_modulation(struct ddb_mod *mod,
ddbwritel(dev, qamtab[modulation],
CHANNEL_SETTINGS(mod->port->nr));
mod_calc_obitrate(mod);
mod_set_stream(mod->port->output);
return 0;
}
@ -241,6 +285,7 @@ static int mod_set_frequency(struct ddb_mod *mod, u32 frequency)
if ((freq < 114) || (freq > 874))
return -EINVAL;
mod->frequency = frequency;
mod_set_stream(mod->port->output);
return 0;
}
@ -292,7 +337,7 @@ int ddbridge_mod_output_start(struct ddb_output *output)
struct ddb_mod *mod = &dev->mod[output->nr];
u32 Symbolrate = mod->symbolrate;
if (dev->link[0].info->version < 3)
if (dev->link[0].info->version < 16)
mod_calc_rateinc(mod);
mod->LastInPacketCount = 0;
@ -311,7 +356,7 @@ int ddbridge_mod_output_start(struct ddb_output *output)
mod->State = CM_STARTUP;
mod->StateCounter = CM_STARTUP_DELAY;
if (dev->link[0].info->version == 3)
if (dev->link[0].info->version >= 16)
mod->Control = 0xfffffff0 &
ddbreadl(dev, CHANNEL_CONTROL(output->nr));
else
@ -322,14 +367,27 @@ int ddbridge_mod_output_start(struct ddb_output *output)
CHANNEL_CONTROL(output->nr));
udelay(10);
ddbwritel(dev, mod->Control, CHANNEL_CONTROL(output->nr));
if (dev->link[0].info->version == 2) {
switch (dev->link[0].info->version) {
case 2:
{
u32 Output = (mod->frequency - 114000000) / 8000000;
u32 KF = Symbolrate;
u32 LF = 9000000UL;
u32 d = gcd(KF, LF);
u32 checkLF;
if ((dev->link[0].ids.revision == 1)) {
if ((dev->link[0].info->version == 2)) {
if ((dev->link[0].ids.hwid & 0xffffff) >= 9065) {
mod->Control |= CHANNEL_CONTROL_ENABLE_DVB;
break;
}
} else {
mod->Control |= CHANNEL_CONTROL_ENABLE_DVB;
break;
}
}
ddbwritel(dev, mod->modulation - 1, CHANNEL_SETTINGS(Channel));
ddbwritel(dev, Output, CHANNEL_SETTINGS2(Channel));
@ -356,18 +414,23 @@ int ddbridge_mod_output_start(struct ddb_output *output)
CHANNEL_CONTROL_CMD_SETUP))
return -EINVAL;
mod->Control |= CHANNEL_CONTROL_ENABLE_DVB;
} else if (dev->link[0].info->version <= 1) {
break;
}
case 0:
case 1:
/* QAM: 600 601 602 903 604 = 16 32 64 128 256 */
/* ddbwritel(dev, 0x604, CHANNEL_SETTINGS(output->nr)); */
ddbwritel(dev, qamtab[mod->modulation],
CHANNEL_SETTINGS(output->nr));
mod->Control |= (CHANNEL_CONTROL_ENABLE_IQ |
CHANNEL_CONTROL_ENABLE_DVB);
} else if (dev->link[0].info->version == 3) {
break;
default:
mod->Control |= (CHANNEL_CONTROL_ENABLE_IQ |
CHANNEL_CONTROL_ENABLE_DVB);
break;
}
if (dev->link[0].info->version < 3) {
if (dev->link[0].info->version < 16) {
mod_set_rateinc(dev, output->nr);
mod_set_incs(output);
}
@ -389,18 +452,20 @@ int ddbridge_mod_output_start(struct ddb_output *output)
static int mod_write_max2871(struct ddb *dev, u32 val)
{
u32 retry = 100;
ddbwritel(dev, val, MAX2871_OUTDATA);
ddbwritel(dev, MAX2871_CONTROL_CE | MAX2871_CONTROL_WRITE,
MAX2871_CONTROL);
while (1) {
while (--retry) {
u32 ControlReg = ddbreadl(dev, MAX2871_CONTROL);
if (ControlReg == 0xFFFFFFFF)
return -EIO;
if ((ControlReg & MAX2871_CONTROL_WRITE) == 0)
break;
if ((ControlReg & MAX2871_CONTROL_WRITE) == 0)
return 0;
udelay(10);
}
return 0;
return -EIO;
}
static u32 max2871_fsm[6] = {
@ -435,7 +500,7 @@ static int mod_setup_max2871(struct ddb *dev, u32 *reg)
if (j == 4)
val &= 0xFFFFFEDF;
status = mod_write_max2871(dev, reg[j]);
status = mod_write_max2871(dev, val);
if (status)
break;
msleep(30);
@ -511,11 +576,38 @@ static int mod_fsm_setup(struct ddb *dev, u32 MaxUsedChannels)
return status;
}
static int mod_set_vga(struct ddb *dev, u32 Gain)
static int mod_set_power(struct ddb *dev)
{
if (Gain > 255)
struct ddb_link *link = &dev->link[0];
struct mod_base *base = &dev->mod_base;
struct mci_result res;
struct mci_command cmd = {
.mod_command = MOD_SETUP_OUTPUT,
.mod_channel = 0,
.mod_stream = 0,
.mod_setup_output = {
.connector = MOD_CONNECTOR_F,
.num_channels = dev->link[0].info->port_num,
.unit = MOD_UNIT_DBUV,
.channel_power = 9000,
},
};
if (!link->mci_ok)
return -EFAULT;
cmd.mod_setup_output.channel_power =
8232 - base->attenuation * 1000 + base->gain * 12;
return ddb_mci_cmd_link(link, &cmd, &res);
}
static int mod_set_vga(struct ddb *dev, u32 gain)
{
if (gain > 255)
return -EINVAL;
ddbwritel(dev, Gain, RF_VGA);
if (dev->link[0].ids.revision == 1) {
dev->mod_base.gain = gain;
return mod_set_power(dev);
}
ddbwritel(dev, gain, RF_VGA);
return 0;
}
@ -622,7 +714,46 @@ static int mod_set_attenuator(struct ddb *dev, u32 Value)
{
if (Value > 31)
return -EINVAL;
ddbwritel(dev, Value, RF_ATTENUATOR);
if (dev->link[0].ids.revision == 1) {
dev->mod_base.attenuation = Value;
return mod_set_power(dev);
} else
ddbwritel(dev, Value, RF_ATTENUATOR);
return 0;
}
static int mod_set_sdr_attenuator(struct ddb *dev, u32 value)
{
u32 control;
if (value > 31)
return -EINVAL;
control = ddbreadl(dev, SDR_CONTROL);
if (control & 0x01000000) {
ddbwritel(dev, 0x03, SDR_CONTROL);
} else {
ddbwritel(dev, value, RF_ATTENUATOR);
}
return 0;
}
static int mod_set_sdr_gain(struct ddb *dev, u32 gain)
{
u32 control = ddbreadl(dev, SDR_CONTROL);
if (control & 0x01000000) {
if (gain > 511)
return -EINVAL;
ddbwritel(dev, 0x03, SDR_CONTROL);
ddbwritel(dev, gain, SDR_GAIN_F);
if (gain > 255)
gain = 255;
ddbwritel(dev, gain, SDR_GAIN_SMA);
} else {
if (gain > 255)
return -EINVAL;
ddbwritel(dev, gain, SDR_GAIN_F);
}
return 0;
}
@ -1423,7 +1554,9 @@ static int mod3_set_base_frequency(struct ddb *dev, u32 frequency)
if (frequency % 1000)
return -EINVAL;
if ((frequency < 114000000) || (frequency > 874000000))
if (frequency < 114000000)
return -EINVAL;
if (frequency > 1874000000)
return -EINVAL;
dev->mod_base.frequency = frequency;
tmp = frequency;
@ -1445,7 +1578,8 @@ static void mod3_set_cfcw(struct ddb_mod *mod, u32 f)
tmp = ((s64) (freq - dcf)) << 32;
tmp = div64_s64(tmp, srdac);
cfcw = (u32) tmp;
dev_info(dev->dev, "f=%u cfcw = %08x nr = %u\n", f, cfcw, mod->port->nr);
dev_info(dev->dev, "f=%u cfcw = %08x dcf = %08x, nr = %u\n",
f, cfcw, dcf, mod->port->nr);
ddbwritel(dev, cfcw, SDR_CHANNEL_CFCW(mod->port->nr));
}
@ -1476,12 +1610,111 @@ static int mod3_set_ari(struct ddb_mod *mod, u32 rate)
}
static int mod3_set_sample_rate(struct ddb_mod *mod, u32 rate)
{
struct ddb *dev = mod->port->dev;
u32 cic, inc, bypass = 0;
switch (rate) {
/* 2^31 * freq*4*cic / 245.76Mhz */
case SYS_DVBT_6:
inc = 0x72492492;
cic = 8;
break;
case SYS_DVBT_7:
inc = 1957341867;
cic = 7;
break;
case SYS_DVBT_8:
//rate = 8126984;
inc = 1917396114;
cic = 6;
break;
case SYS_DVBC_6900:
inc = 0x73000000; //1929379840;
cic = 8;
break;
case 9:
inc = 0x47e00000; //1929379840;
cic = 10;
bypass = 2;
break;
case SYS_J83B_64_6: /* 5056941 */
inc = 0x695a5a1d;
cic = 10;
break;
case SYS_J83B_256_6: /* 5360537 */
inc = 0x6fad87da;
cic = 10;
break;
case SYS_ISDBT_6:
inc = 0x7684BD82; //1988410754;
cic = 7;
break;
case SYS_DVB_22:
inc = 0x72955555; // 1922389333;
cic = 5;
bypass = 2;
break;
case SYS_DVB_24:
inc = 0x7d000000;
cic = 5;
bypass = 2;
break;
case SYS_DVB_30:
inc = 0x7d000000;
cic = 4;
bypass = 2;
break;
case SYS_ISDBS_2886:
inc = 0x78400000;
cic = 4;
bypass = 2;
break;
default:
{
u64 a;
if (rate < 1000000)
return -EINVAL;
if (rate > 30720000)
return -EINVAL;
bypass = 2;
if (rate > 24576000)
cic = 4;
else if (rate > 20480000)
cic = 5;
else if (rate > 17554286)
cic = 6;
else if (rate > 15360000)
cic = 7;
else
cic = 8;
a = (1ULL << 31) * rate * 2 * cic;
inc = div_s64(a, 245760000);
break;
}
}
dev_info(dev->dev, "inc = %08x, cic = %u, bypass = %u\n", inc, cic, bypass);
ddbwritel(mod->port->dev, inc, SDR_CHANNEL_ARICW(mod->port->nr));
ddbwritel(mod->port->dev, (cic << 8) | (bypass << 4),
SDR_CHANNEL_CONFIG(mod->port->nr));
return 0;
}
static int mod3_prop_proc(struct ddb_mod *mod, struct dtv_property *tvp)
{
switch (tvp->cmd) {
case MODULATOR_OUTPUT_ARI:
return mod3_set_ari(mod, tvp->u.data);
case MODULATOR_OUTPUT_RATE:
return mod3_set_sample_rate(mod, tvp->u.data);
case MODULATOR_FREQUENCY:
return mod3_set_frequency(mod, tvp->u.data);
@ -1489,17 +1722,18 @@ static int mod3_prop_proc(struct ddb_mod *mod, struct dtv_property *tvp)
return mod3_set_base_frequency(mod->port->dev, tvp->u.data);
case MODULATOR_ATTENUATOR:
return mod_set_attenuator(mod->port->dev, tvp->u.data);
return mod_set_sdr_attenuator(mod->port->dev, tvp->u.data);
case MODULATOR_GAIN:
return mod_set_vga(mod->port->dev, tvp->u.data);
return mod_set_sdr_gain(mod->port->dev, tvp->u.data);
}
return -EINVAL;
}
static int mod_prop_proc(struct ddb_mod *mod, struct dtv_property *tvp)
{
if (mod->port->dev->link[0].info->version == 3)
if (mod->port->dev->link[0].info->version >= 16)
return mod3_prop_proc(mod, tvp);
switch (tvp->cmd) {
case MODULATOR_SYMBOL_RATE:
@ -1515,13 +1749,17 @@ static int mod_prop_proc(struct ddb_mod *mod, struct dtv_property *tvp)
return mod_set_attenuator(mod->port->dev, tvp->u.data);
case MODULATOR_INPUT_BITRATE:
#ifdef KERNEL_DVB_CORE
return mod_set_ibitrate(mod, *(u64 *) &tvp->u.buffer.data[0]);
#else
return mod_set_ibitrate(mod, tvp->u.data64);
#endif
case MODULATOR_GAIN:
if (mod->port->dev->link[0].info->version == 2)
return mod_set_vga(mod->port->dev, tvp->u.data);
return -EINVAL;
case MODULATOR_RESET:
if (mod->port->dev->link[0].info->version == 2)
return mod_fsm_setup(mod->port->dev,0 );
@ -1541,19 +1779,47 @@ static int mod_prop_proc(struct ddb_mod *mod, struct dtv_property *tvp)
return 0;
}
static int mod_prop_get3(struct ddb_mod *mod, struct dtv_property *tvp)
{
struct ddb *dev = mod->port->dev;
switch (tvp->cmd) {
case MODULATOR_INFO:
tvp->u.data = dev->link[0].info->version;
return 0;
case MODULATOR_GAIN:
tvp->u.data = 0xff & ddbreadl(dev, RF_VGA);
return 0;
default:
return -1;
}
}
static int mod_prop_get(struct ddb_mod *mod, struct dtv_property *tvp)
{
struct ddb *dev = mod->port->dev;
if (mod->port->dev->link[0].info->version >= 16)
return mod_prop_get3(mod, tvp);
if (mod->port->dev->link[0].info->version != 2)
return -1;
switch (tvp->cmd) {
case MODULATOR_INFO:
tvp->u.data = 2;
return 0;
case MODULATOR_GAIN:
tvp->u.data = 0xff & ddbreadl(dev, RF_VGA);;
if (dev->link[0].ids.revision == 1)
tvp->u.data = dev->mod_base.gain;
else
tvp->u.data = 0xff & ddbreadl(dev, RF_VGA);
return 0;
case MODULATOR_ATTENUATOR:
tvp->u.data = 0x1f & ddbreadl(dev, RF_ATTENUATOR);
if (dev->link[0].ids.revision == 1)
tvp->u.data = dev->mod_base.attenuation;
else
tvp->u.data = 0x1f & ddbreadl(dev, RF_ATTENUATOR);
return 0;
case MODULATOR_STATUS:
@ -1592,7 +1858,8 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg)
(struct dtv_properties __user *) parg;
int i, ret = 0;
if (dev->link[0].info->version == 3 && cmd != FE_SET_PROPERTY)
if (dev->link[0].info->version >= 16 &&
(cmd != FE_SET_PROPERTY && cmd != IOCTL_DDB_MCI_CMD))
return -EINVAL;
mutex_lock(&dev->ioctl_mutex);
switch (cmd) {
@ -1684,6 +1951,28 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg)
mod->pcr_correction = cp->pcr_correction;
break;
}
case IOCTL_DDB_MCI_CMD:
{
struct ddb_mci_msg *msg =
(struct ddb_mci_msg __user *) parg;
struct ddb_link *link;
if (dev->link[0].ids.revision != 1) {
ret = -EINVAL;
break;
}
if (msg->link > 3) {
ret = -EFAULT;
break;
}
link = &dev->link[msg->link];
if (!link->mci_ok) {
ret = -EFAULT;
break;
}
ret = ddb_mci_cmd_link(link, &msg->cmd, &msg->res);
break;
}
default:
ret = -EINVAL;
break;
@ -1692,6 +1981,22 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg)
return ret;
}
static int mod_init_2_1(struct ddb *dev, u32 Frequency)
{
int i, streams = dev->link[0].info->port_num;
dev->mod_base.frequency = Frequency;
dev->mod_base.gain = 64;
dev->mod_base.attenuation = 0;
mod_set_power(dev);
for (i = 0; i < streams; i++) {
struct ddb_mod *mod = &dev->mod[i];
mod->port = &dev->port[i];
}
return 0;
}
static int mod_init_2(struct ddb *dev, u32 Frequency)
{
int i, status, streams = dev->link[0].info->port_num;
@ -1776,7 +2081,7 @@ static int rfdac_init(struct ddb *dev)
}
if (tmp & 0x80)
return -1;
dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
//dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
ddbwritel(dev, RFDAC_CMD_RESET, RFDAC_CONTROL);
for (i = 0; i < 10; i++) {
msleep(20);
@ -1786,7 +2091,7 @@ static int rfdac_init(struct ddb *dev)
}
if (tmp & 0x80)
return -1;
dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
//dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
ddbwritel(dev, RFDAC_CMD_SETUP, RFDAC_CONTROL);
for (i = 0; i < 10; i++) {
msleep(20);
@ -1796,7 +2101,7 @@ static int rfdac_init(struct ddb *dev)
}
if (tmp & 0x80)
return -1;
dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
//dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
ddbwritel(dev, 0x01, JESD204B_BASE);
for (i = 0; i < 400; i++) {
msleep(20);
@ -1804,7 +2109,7 @@ static int rfdac_init(struct ddb *dev)
if ((tmp & 0xc0000000) == 0xc0000000)
break;
}
dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
//dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
if ((tmp & 0xc0000000) != 0xc0000000)
return -1;
return 0;
@ -1847,21 +2152,74 @@ static int mod_init_3(struct ddb *dev, u32 Frequency)
ddbwritel(dev, 0x00002000, SDR_CHANNEL_FM1GAIN(i));
ddbwritel(dev, 0x00001000, SDR_CHANNEL_FM2GAIN(i));
}
mod_set_attenuator(dev, 0);
mod_set_vga(dev, 64);
mod_set_sdr_attenuator(dev, 0);
mod_set_sdr_gain(dev, 64);
return ret;
}
static int mod_init_sdr_iq(struct ddb *dev)
{
int streams = dev->link[0].info->port_num;
int i, ret = 0;
ret = mod_setup_max2871(dev, max2871_sdr);
if (ret)
dev_err(dev->dev, "PLL setup failed\n");
ret = rfdac_init(dev);
if (ret)
ret = rfdac_init(dev);
if (ret)
dev_err(dev->dev, "RFDAC setup failed\n");
ddbwritel(dev, 0x01, 0x240);
//mod3_set_base_frequency(dev, 602000000);
dev->mod_base.frequency = 570000000;
for (i = 0; i < streams; i++) {
struct ddb_mod *mod = &dev->mod[i];
mod->port = &dev->port[i];
if (dev->link[0].ids.revision != 1)
ddbwritel(dev, 0x00, SDR_CHANNEL_CONTROL(i));
}
if (dev->link[0].ids.revision == 1)
return ret;
mod_set_sdr_attenuator(dev, 0);
udelay(10);
mod_set_sdr_gain(dev, 120);
ddb_mci_cmd_link_simple(&dev->link[0], 0xc0, 0x00, 90);
return ret;
}
static int mod_init_dvbt(struct ddb *dev)
{
int i;
dev->mod_base.frequency = 570000000;
for (i = 0; i < dev->link[0].info->port_num; i++)
dev->mod[i].port = &dev->port[i];
return 0;
}
int ddbridge_mod_init(struct ddb *dev)
{
dev_info(dev->dev, "Revision: %u\n", dev->link[0].ids.revision);
switch (dev->link[0].info->version) {
case 0:
case 1:
return mod_init_1(dev, 722000000);
case 2:
case 2: /* FSM */
if (dev->link[0].ids.revision == 1) {
if ((dev->link[0].ids.hwid & 0xffffff) >= 9065)
return mod_init_2_1(dev, 114000000);
}
return mod_init_2(dev, 114000000);
case 3:
case 16: /* PAL */
return mod_init_3(dev, 503250000);
case 17: /* raw IQ */
return mod_init_sdr_iq(dev);
case 18: /* IQ+FFT (DVB-T) */
return mod_init_dvbt(dev);
default:
return -1;
}

View File

@ -1,9 +1,9 @@
/*
* ddbridge-ns.c: Digital Devices PCIe bridge driver net streaming
*
* Copyright (C) 2010-2017Marcus Metzler <mocm@metzlerbros.de>
* Copyright (C) 2010-2017 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
* Digital Devices GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -44,7 +44,7 @@ static u16 calc_pcs16(struct dvb_ns_params *p, int ipv)
u32 sum = 0, i;
u16 pcs;
for (i = 0; i < ipv ? 16 : 4; i += 2) {
for (i = 0; i < (ipv ? 16 : 4); i += 2) {
sum += (p->sip[i] << 8) | p->sip[i + 1];
sum += (p->dip[i] << 8) | p->dip[i + 1];
}
@ -441,11 +441,11 @@ static int ns_start(struct dvbnss *nss)
reg |= 0x40;
if (nss->params.flags & DVB_NS_IPV6)
reg |= 0x80;
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
STREAM_CONTROL(dns->nr));
if (dns->fe != input)
ddb_dvb_ns_input_start(dns->fe);
ddb_dvb_ns_input_start(input);
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
STREAM_CONTROL(dns->nr));
return 0;
}

View File

@ -21,12 +21,16 @@
/* Register Definitions */
#define CUR_REGISTERMAP_VERSION_V1 0x00010001
#define CUR_REGISTERMAP_VERSION_V2 0x00020000
#define CUR_REGISTERMAP_VERSION_022X 0x00020001
#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 */
@ -44,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
/* ------------------------------------------------------------------------- */
@ -148,7 +152,9 @@
#define TEMPMON_CONTROL_SCAN (0x00000001)
#define TEMPMON_CONTROL_AUTOSCAN (0x00000002)
#define TEMPMON_CONTROL_INTENABLE (0x00000004)
#define TEMPMON_CONTROL_CLEAR (0x00000008)
#define TEMPMON_CONTROL_OVERTEMP (0x00008000)
#define TEMPMON_STATUS_SHUTDOWN (0x00008000)
/* Temperature in C x 256 */
#define TEMPMON_CORE (TEMPMON_BASE + 0x04)
@ -160,6 +166,9 @@
#define TEMPMON_FANPWM (0x00000F00) /* PWM speed in 10% steps */
#define TEMPMON_FANTACHO (0x000000FF) /* Rotations in 100/min steps */
#define TEMPMON_INTERRUPT_V1 (24)
#define TEMPMON_INTERRUPT_V1_MASK (1<<24)
/* V1 Temperature Monitor
* Temperature Monitor TEMPMON_CONTROL & 0x8000 == 0 : ( 2x LM75A @ 0x90,0x92 )
* Temperature Monitor TEMPMON_CONTROL & 0x8000 == 1 :
@ -184,6 +193,7 @@
/* SHORT Temperature in C x 256 (ADM1032 ext) */
#define TEMPMON2_DACCORE (TEMPMON_SENSOR2)
/* ------------------------------------------------------------------------- */
/* I2C Master Controller */
@ -222,6 +232,11 @@
#define TS_CONTROL(_io) ((_io)->regs + 0x00)
#define TS_CONTROL2(_io) ((_io)->regs + 0x04)
#define TS_STAT(_io) ((_io)->regs + 0x08)
#define TS_INPUT_CONTROL_ENABLE (0x00000001)
#define TS_INPUT_CONTROL_RESET (0x00000002)
#define TS_INPUT_CONTROL_SKIPERROR (0x00000008)
/* ------------------------------------------------------------------------- */
/* DMA Buffer */
@ -233,8 +248,7 @@
/* ------------------------------------------------------------------------- */
#define LNB_BASE (0x400)
#define LNB_CONTROL(i) (LNB_BASE + (i) * 0x20 + 0x00)
#define LNB_CONTROL(i) ((i) * 0x20 + 0x00)
#define LNB_CMD (7ULL << 0)
#define LNB_CMD_NOP 0
#define LNB_CMD_INIT 1
@ -245,25 +259,31 @@
#define LNB_CMD_DISEQC 6
#define LNB_CMD_SCIF 7
#define LNB_BUSY BIT_ULL(4)
#define LNB_TONE BIT_ULL(15)
#define LNB_BUSY (1ULL << 4)
#define LNB_TONE (1ULL << 15)
#define LNB_STATUS(i) (LNB_BASE + (i) * 0x20 + 0x04)
#define LNB_VOLTAGE(i) (LNB_BASE + (i) * 0x20 + 0x08)
#define LNB_CONFIG(i) (LNB_BASE + (i) * 0x20 + 0x0c)
#define LNB_BUF_LEVEL(i) (LNB_BASE + (i) * 0x20 + 0x10)
#define LNB_BUF_WRITE(i) (LNB_BASE + (i) * 0x20 + 0x14)
#define LNB_INTERRUPT_BASE 4
#define LNB_STATUS(i) ((i) * 0x20 + 0x04)
#define LNB_VOLTAGE(i) ((i) * 0x20 + 0x08)
#define LNB_CONFIG(i) ((i) * 0x20 + 0x0c)
#define LNB_BUF_LEVEL(i) ((i) * 0x20 + 0x10)
#define LNB_BUF_WRITE(i) ((i) * 0x20 + 0x14)
#define LNB_SETTING(i) ((i) * 0x20 + 0x0c)
#define LNB_FIFO_LEVEL(i) ((i) * 0x20 + 0x10)
#define LNB_RESET_FIFO(i) ((i) * 0x20 + 0x10)
#define LNB_WRITE_FIFO(i) ((i) * 0x20 + 0x14)
/* ------------------------------------------------------------------------- */
/* CI Interface (only CI-Bridge) */
#define CI_BASE (0x400)
#define CI_CONTROL(i) (CI_BASE + (i) * 32 + 0x00)
#define CI_CONTROL(_ci) ((_ci)->regs + 0x00)
#define CI_DO_ATTRIBUTE_RW(i) (CI_BASE + (i) * 32 + 0x04)
#define CI_DO_IO_RW(i) (CI_BASE + (i) * 32 + 0x08)
#define CI_READDATA(i) (CI_BASE + (i) * 32 + 0x0c)
#define CI_DO_READ_ATTRIBUTES(i) (CI_BASE + (i) * 32 + 0x10)
#define CI_DO_ATTRIBUTE_RW(_ci) ((_ci)->regs + 0x04)
#define CI_DO_IO_RW(_ci) ((_ci)->regs + 0x08)
#define CI_READDATA(_ci) ((_ci)->regs + 0x0c)
#define CI_DO_READ_ATTRIBUTES(_ci) ((_ci)->regs + 0x10)
#define CI_RESET_CAM (0x00000001)
#define CI_POWER_ON (0x00000002)
@ -274,6 +294,7 @@
#define CI_CAM_READY (0x00010000)
#define CI_CAM_DETECT (0x00020000)
#define CI_POWER_ERROR (0x00100000)
#define CI_READY (0x80000000)
#define CI_BLOCKIO_ACTIVE (0x40000000)
#define CI_BLOCKIO_RCVDATA (0x20000000)
@ -283,8 +304,8 @@
#define CI_READ_CMD (0x40000000)
#define CI_WRITE_CMD (0x80000000)
#define CI_BLOCKIO_SEND(i) (CI_BASE + (i) * 32 + 0x14)
#define CI_BLOCKIO_RECEIVE(i) (CI_BASE + (i) * 32 + 0x18)
#define CI_BLOCKIO_SEND(_ci) ((_ci)->regs + 0x14)
#define CI_BLOCKIO_RECEIVE(_ci) ((_ci)->regs + 0x18)
#define CI_BLOCKIO_SEND_COMMAND (0x80000000)
#define CI_BLOCKIO_SEND_COMPLETE_ACK (0x40000000)
@ -386,7 +407,6 @@
/* Attenuator/VGA */
#define RF_ATTENUATOR (0xD8)
#define RF_ATTENUATOR (0xD8)
/* 0x00 = 0 dB
* 0x01 = 1 dB
@ -622,3 +642,10 @@
0 \
)
/* SDR_CONTROL */
#define SDR_CONTROL (0xd0)
#define SDR_GAIN_SMA (0xd4)
#define SDR_ATTENUATER (0xd8)
#define SDR_GAIN_F (0xdc)

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

@ -0,0 +1,663 @@
/*
* ddbridge-sx8.c: Digital Devices MAX SX8 driver
*
* Copyright (C) 2018 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
#include "ddbridge-io.h"
#include "ddbridge-mci.h"
static int default_mod = 3;
module_param(default_mod, int, 0444);
MODULE_PARM_DESC(default_mod, "default modulations enabled, default is 3 (1 = QPSK, 2 = 8PSK, 4 = 16APSK, ...)");
static int direct_mode;
module_param(direct_mode, int, 0444);
MODULE_PARM_DESC(direct_mode, "Ignore LDPC limits and assign high speed demods according to needed symbolrate.");
static u32 sx8_tuner_flags;
module_param(sx8_tuner_flags, int, 0664);
MODULE_PARM_DESC(sx8_tuner_flags, "Change SX8 tuner flags.");
static u32 sx8_tuner_gain;
module_param(sx8_tuner_gain, int, 0664);
MODULE_PARM_DESC(sx8_tuner_gain, "Change SX8 tuner gain.");
static const u32 MCLK = (1550000000 / 12);
/* Add 2MBit/s overhead allowance (minimum factor is 90/32400 for QPSK w/o Pilots) */
static const u32 MAX_LDPC_BITRATE = (720000000 + 2000000);
static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6);
#define SX8_TUNER_NUM 4
#define SX8_DEMOD_NUM 8
#define SX8_DEMOD_NONE 0xff
struct sx8_base {
struct mci_base mci_base;
u8 tuner_use_count[SX8_TUNER_NUM];
u32 used_ldpc_bitrate[SX8_DEMOD_NUM];
u8 demod_in_use[SX8_DEMOD_NUM];
u32 iq_mode;
};
struct sx8 {
struct mci mci;
struct mutex lock;
int first_time_lock;
int started;
int iq_started;
};
static const u8 dvbs2_bits_per_symbol[] = {
0, 0, 0, 0,
/* S2 QPSK */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* S2 8PSK */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
/* S2 16APSK */
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
/* S2 32APSK */
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3, 0, 4, 0,
2, 2, 2, 2, 2, 2, // S2X QPSK
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // S2X 8PSK
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // S2X 16APSK
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // S2X 32APSK
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // S2X 64APSK
7, 7, 7, 7, // S2X 128APSK
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // S2X 256APSK
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // S2X QPSK
3, 3, 3, 3, 3, 3, 3, 3, // S2X 8PSK
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // S2X 16APSK
5, 5, 5, 5, // S2X 32APSK
3, 4, 5, 6, 8, 10,
};
static void release(struct dvb_frontend *fe)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
mci_base->count--;
if (mci_base->count == 0) {
list_del(&mci_base->mci_list);
kfree(mci_base);
}
kfree(state);
#ifdef CONFIG_MEDIA_ATTACH
__module_get(THIS_MODULE);
#endif
}
static int ddb_mci_tsconfig(struct mci *state, u32 config)
{
struct ddb_link *link = state->base->link;
if (link->ids.device != 0x0009 && link->ids.device != 0x000b)
return -EINVAL;
ddblwritel(link, config, SX8_TSCONFIG);
return 0;
}
static int read_status(struct dvb_frontend *fe, enum fe_status *status)
{
int stat = 0;
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mci_result res;
*status = 0x00;
mutex_lock(&state->lock);
if (!state->started && !state->iq_started)
goto unlock;
stat = ddb_mci_get_status(&state->mci, &res);
if (stat)
goto unlock;
ddb_mci_get_info(&state->mci);
if (stat)
goto unlock;
if (res.status == MCI_DEMOD_LOCKED || res.status == SX8_DEMOD_IQ_MODE) {
//if (res.status == MCI_DEMOD_LOCKED || sx8_base->iq_mode) {
*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI |
FE_HAS_CARRIER | FE_HAS_SIGNAL;
if (res.status == MCI_DEMOD_LOCKED) {
mutex_lock(&mci_base->tuner_lock);
if (state->first_time_lock && state->started) {
if (state->mci.signal_info.dvbs2_signal_info.standard == 2) {
sx8_base->used_ldpc_bitrate[state->mci.nr] =
p->symbol_rate *
dvbs2_bits_per_symbol[
state->mci.signal_info.
dvbs2_signal_info.pls_code];
} else
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
state->first_time_lock = 0;
}
mutex_unlock(&mci_base->tuner_lock);
}
} else if (res.status == MCI_DEMOD_TIMEOUT)
*status = FE_TIMEDOUT;
else if (res.status >= SX8_DEMOD_WAIT_MATYPE) {
*status = FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
if (sx8_base->iq_mode)
*status |= FE_HAS_LOCK;
}
unlock:
mutex_unlock(&state->lock);
return stat;
}
static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on,
u8 flags, u8 gain)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_command cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.tuner = state->mci.tuner;
cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE;
cmd.sx8_input_enable.flags = flags;
cmd.sx8_input_enable.rf_gain = gain;
return ddb_mci_cmd(&state->mci, &cmd, NULL);
}
static int stop_iq(struct dvb_frontend *fe)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct mci_command cmd;
u32 input = state->mci.tuner;
if (!state->iq_started)
return -1;
memset(&cmd, 0, sizeof(cmd));
cmd.command = SX8_CMD_STOP_IQ;
cmd.demod = state->mci.demod;
ddb_mci_cmd(&state->mci, &cmd, NULL);
ddb_mci_tsconfig(&state->mci, SX8_TSCONFIG_MODE_NORMAL);
mutex_lock(&mci_base->tuner_lock);
sx8_base->tuner_use_count[input]--;
if (!sx8_base->tuner_use_count[input])
mci_set_tuner(fe, input, 0, 0, 0);
if (state->mci.demod != SX8_DEMOD_NONE) {
sx8_base->demod_in_use[state->mci.demod] = 0;
state->mci.demod = SX8_DEMOD_NONE;
}
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
mutex_unlock(&mci_base->tuner_lock);
sx8_base->iq_mode = 0;
state->iq_started = 0;
return 0;
}
static int stop(struct dvb_frontend *fe)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct mci_command cmd;
u32 input;
input = state->mci.tuner;
if (!state->started)
return -1;
if (state->mci.demod != SX8_DEMOD_NONE) {
memset(&cmd, 0, sizeof(cmd));
cmd.command = MCI_CMD_STOP;
cmd.demod = state->mci.demod;
ddb_mci_cmd(&state->mci, &cmd, NULL);
if (sx8_base->iq_mode) {
cmd.command = SX8_CMD_DISABLE_IQOUTPUT;
cmd.demod = state->mci.demod;
cmd.output = 0;
ddb_mci_cmd(&state->mci, &cmd, NULL);
ddb_mci_tsconfig(&state->mci, SX8_TSCONFIG_MODE_NORMAL);
}
}
mutex_lock(&mci_base->tuner_lock);
sx8_base->tuner_use_count[input]--;
if (!sx8_base->tuner_use_count[input])
mci_set_tuner(fe, input, 0, 0, 0);
if (state->mci.demod != SX8_DEMOD_NONE) {
sx8_base->demod_in_use[state->mci.demod] = 0;
state->mci.demod = SX8_DEMOD_NONE;
}
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
sx8_base->iq_mode = 0;
state->started = 0;
mutex_unlock(&mci_base->tuner_lock);
return 0;
}
static const u8 ro_lut[8] = {
8 | SX8_ROLLOFF_35, 8 | SX8_ROLLOFF_20, 8 | SX8_ROLLOFF_25, 0,
8 | SX8_ROLLOFF_15, 8 | SX8_ROLLOFF_10, 8 | SX8_ROLLOFF_05, 0,
};
static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6);
u32 used_ldpc_bitrate = 0, free_ldpc_bitrate;
u32 used_demods = 0;
struct mci_command cmd;
u32 input = state->mci.tuner;
u32 bits_per_symbol = 0;
int i = -1, stat = 0;
struct ddb_link *link = state->mci.base->link;
if (link->ids.device == 0x000b) {
/* Mask out higher modulations and MIS for Basic
or search command will fail */
modmask &= 3;
p->stream_id = NO_STREAM_ID_FILTER;
}
if (p->symbol_rate >= MCLK / 2)
flags &= ~1;
if ((flags & 3) == 0)
return -EINVAL;
if (flags & 2) {
u32 tmp = modmask;
bits_per_symbol = 1;
while (tmp & 1) {
tmp >>= 1;
bits_per_symbol++;
}
}
mutex_lock(&mci_base->tuner_lock);
if (sx8_base->iq_mode) {
stat = -EBUSY;
goto unlock;
}
if (direct_mode) {
if (p->symbol_rate >= MCLK / 2) {
if (state->mci.nr < 4)
i = state->mci.nr;
} else {
i = state->mci.nr;
}
} else {
for (i = 0; i < SX8_DEMOD_NUM; i++) {
used_ldpc_bitrate += sx8_base->used_ldpc_bitrate[i];
if (sx8_base->demod_in_use[i])
used_demods++;
}
if ((used_ldpc_bitrate >= MAX_LDPC_BITRATE) ||
((ts_config & SX8_TSCONFIG_MODE_MASK) >
SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) {
stat = -EBUSY;
goto unlock;
}
free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate;
if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE)
free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE;
while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate)
bits_per_symbol--;
if (bits_per_symbol < 2) {
stat = -EBUSY;
goto unlock;
}
modmask &= ((1 << (bits_per_symbol - 1)) - 1);
if (((flags & 0x02) != 0) && (modmask == 0)) {
stat = -EBUSY;
goto unlock;
}
i = (p->symbol_rate > MCLK / 2) ? 3 : 7;
while (i >= 0 && sx8_base->demod_in_use[i])
i--;
}
if (i < 0) {
stat = -EBUSY;
goto unlock;
}
sx8_base->demod_in_use[i] = 1;
sx8_base->used_ldpc_bitrate[state->mci.nr] = p->symbol_rate * bits_per_symbol;
state->mci.demod = i;
if (!sx8_base->tuner_use_count[input])
mci_set_tuner(fe, input, 1, sx8_tuner_flags, sx8_tuner_gain);
sx8_base->tuner_use_count[input]++;
sx8_base->iq_mode = (ts_config > 1);
unlock:
mutex_unlock(&mci_base->tuner_lock);
if (stat)
return stat;
memset(&cmd, 0, sizeof(cmd));
if (sx8_base->iq_mode) {
cmd.command = SX8_CMD_ENABLE_IQOUTPUT;
cmd.demod = state->mci.demod;
cmd.output = p->stream_id & 0x0f;
ddb_mci_cmd(&state->mci, &cmd, NULL);
ddb_mci_tsconfig(&state->mci, ts_config);
}
if (p->stream_id != NO_STREAM_ID_FILTER && !(p->stream_id & 0xf0000000))
flags |= 0x80;
//printk("bw %u\n", p->bandwidth_hz);
if (p->bandwidth_hz && (p->bandwidth_hz < 20000)) {
flags |= 0x40;
/* +/- range, so multiply bandwidth_hz (actually in kHz) by 500 */
cmd.dvbs2_search.frequency_range = p->bandwidth_hz * 500;
//printk("range %u\n", cmd.dvbs2_search.frequency_range);
}
cmd.command = MCI_CMD_SEARCH_DVBS;
cmd.dvbs2_search.flags = flags;
cmd.dvbs2_search.s2_modulation_mask = modmask;
cmd.dvbs2_search.rsvd1 = ro_lut[p->rolloff & 7];
cmd.dvbs2_search.retry = 2;
if (sx8_base->iq_mode)
cmd.dvbs2_search.retry = 255;
cmd.dvbs2_search.frequency = p->frequency * 1000;
cmd.dvbs2_search.symbol_rate = p->symbol_rate;
cmd.dvbs2_search.scrambling_sequence_index =
p->scrambling_sequence_index | 0x80000000;
cmd.dvbs2_search.input_stream_id = p->stream_id;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
cmd.output = state->mci.nr;
if ((p->stream_id != NO_STREAM_ID_FILTER) &&
(p->stream_id & 0x80000000))
cmd.output |= 0x80;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
state->started = 1;
state->first_time_lock = 1;
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
if (stat)
stop(fe);
return stat;
}
static int start_iq(struct dvb_frontend *fe, u32 flags,
u32 ts_config)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 used_demods = 0;
struct mci_command cmd;
u32 input = state->mci.tuner;
int i, stat = 0;
mutex_lock(&mci_base->tuner_lock);
if (!state->iq_started) {
if (sx8_base->iq_mode) {
stat = -EBUSY;
goto unlock;
}
for (i = 0; i < SX8_DEMOD_NUM; i++)
if (sx8_base->demod_in_use[i])
used_demods++;
if (used_demods > 0) {
stat = -EBUSY;
goto unlock;
}
state->mci.demod = 0;
sx8_base->tuner_use_count[input]++;
sx8_base->iq_mode = 2;
mci_set_tuner(fe, input, 1, flags & 0xff, 0x40);
} else {
if ((state->iq_started & 0x07) != state->mci.nr) {
stat = -EBUSY;
goto unlock;
}
}
unlock:
mutex_unlock(&mci_base->tuner_lock);
if (stat)
return stat;
memset(&cmd, 0, sizeof(cmd));
cmd.command = SX8_CMD_START_IQ;
cmd.sx8_start_iq.flags = (flags >> 16) & 0xff;
cmd.sx8_start_iq.roll_off = 5;
//cmd.sx8_start_iq.roll_off = ro_lut[p->rolloff & 7];
cmd.sx8_start_iq.frequency = p->frequency * 1000;
cmd.sx8_start_iq.symbol_rate = p->symbol_rate;
cmd.sx8_start_iq.gain = (flags >> 8) & 0xff;
cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
state->iq_started = 8 | state->mci.nr;
state->first_time_lock = 1;
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
if (stat)
stop_iq(fe);
ddb_mci_tsconfig(&state->mci, ts_config);
return stat;
}
static int set_lna(struct dvb_frontend *fe)
{
printk("set_lna\n");
return 0;
}
static int set_parameters(struct dvb_frontend *fe)
{
int stat = 0;
struct sx8 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 ts_config = SX8_TSCONFIG_MODE_NORMAL, iq_mode = 0, isi, ts_mode = 0;
isi = p->stream_id;
if (isi != NO_STREAM_ID_FILTER) {
iq_mode = (isi & 0x30000000) >> 28;
ts_mode = (isi & 0x03000000) >> 24;
}
state->mci.input->con = ts_mode << 8;
if (iq_mode)
ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
mutex_lock(&state->lock);
stop(fe);
if (iq_mode < 2) {
u32 mask;
stop_iq(fe);
switch (p->modulation) {
case APSK_256:
case APSK_256_L:
mask = 0x7f;
break;
case APSK_128:
mask = 0x3f;
break;
case APSK_64:
case APSK_64_L:
mask = 0x1f;
break;
case APSK_32:
mask = 0x0f;
break;
case APSK_16:
case APSK_16_L:
mask = 0x07;
break;
default:
mask = default_mod;
break;
}
stat = start(fe, 3, mask, ts_config);
} else {
stat = start_iq(fe, isi & 0xffffff, ts_config);
}
mutex_unlock(&state->lock);
return stat;
}
static int tune(struct dvb_frontend *fe, bool re_tune,
unsigned int mode_flags,
unsigned int *delay, enum fe_status *status)
{
int r;
if (re_tune) {
r = set_parameters(fe);
if (r)
return r;
}
r = read_status(fe, status);
if (r)
return r;
if (*status & FE_HAS_LOCK)
return 0;
*delay = HZ / 10;
return 0;
}
static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{
return DVBFE_ALGO_HW;
}
static int set_input(struct dvb_frontend *fe, int input)
{
struct sx8 *state = fe->demodulator_priv;
#ifndef KERNEL_DVB_CORE
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
#endif
if (input >= SX8_TUNER_NUM)
return -EINVAL;
if (state->mci.tuner == input)
return 0;
mutex_lock(&state->lock);
stop_iq(fe);
stop(fe);
state->mci.tuner = input;
#ifndef KERNEL_DVB_CORE
p->input = input;
#endif
mutex_unlock(&state->lock);
return 0;
}
static int sleep(struct dvb_frontend *fe)
{
struct sx8 *state = fe->demodulator_priv;
mutex_lock(&state->lock);
stop_iq(fe);
stop(fe);
mutex_unlock(&state->lock);
return 0;
}
static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{
struct sx8 *state = fe->demodulator_priv;
ddb_mci_proc_info(&state->mci, p);
return 0;
}
static struct dvb_frontend_ops sx8_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2 },
.info = {
.name = "DVB-S/S2X",
.frequency_min_hz = 950000000,
.frequency_max_hz = 2150000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 0,
.symbol_rate_min = 100000,
.symbol_rate_max = 100000000,
.caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_AUTO |
FE_CAN_QPSK |
FE_CAN_2G_MODULATION |
FE_CAN_MULTISTREAM,
},
.get_frontend_algo = get_algo,
.get_frontend = get_frontend,
.tune = tune,
.release = release,
.read_status = read_status,
#ifndef KERNEL_DVB_CORE
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
.set_input = set_input,
#endif
.set_lna = set_lna,
.sleep = sleep,
};
static int init(struct mci *mci)
{
struct sx8 *state = (struct sx8 *) mci;
state->mci.demod = SX8_DEMOD_NONE;
#ifndef KERNEL_DVB_CORE
mci->fe.ops.xbar[1] = mci->nr;
mci->fe.dtv_property_cache.input = mci->tuner;
#endif
mutex_init(&state->lock);
return 0;
}
static int base_init(struct mci_base *mci_base)
{
//struct sx8_base *base = (struct sx8_base *) mci_base;
return 0;
}
static struct mci_cfg ddb_max_sx8_cfg = {
.type = 0,
.fe_ops = &sx8_ops,
.base_size = sizeof(struct sx8_base),
.state_size = sizeof(struct sx8),
.init = init,
.base_init = base_init,
};
struct dvb_frontend *ddb_sx8_attach(struct ddb_input *input, int nr, int tuner,
int (**fn_set_input)(struct dvb_frontend *fe, int input))
{
*fn_set_input = set_input;
return ddb_mci_attach(input, &ddb_max_sx8_cfg, nr, tuner);
}

View File

@ -1,8 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ddbridge.h: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rmetzler@digitaldevices.de>
* 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
@ -14,18 +16,13 @@
* 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
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _DDBRIDGE_H_
#define _DDBRIDGE_H_
#define DDB_USE_WORK
/*#define DDB_TEST_THREADED*/
#include <linux/version.h>
#if (KERNEL_VERSION(3, 8, 0) <= LINUX_VERSION_CODE)
@ -60,22 +57,20 @@
#include <linux/mutex.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/dvb/ca.h>
#include <linux/socket.h>
#include <linux/device.h>
#include <linux/io.h>
#include "dvb_netstream.h"
#include "dmxdev.h"
#include "dvbdev.h"
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include "dvb_ringbuffer.h"
#include "dvb_ca_en50221.h"
#include "dvb_net.h"
#include <media/dmxdev.h>
#include <media/dvbdev.h>
#include <media/dvb_demux.h>
#include <media/dvb_frontend.h>
#include <media/dvb_ringbuffer.h>
#include <media/dvb_ca_en50221.h>
#include <media/dvb_net.h>
#include "tda18271c2dd.h"
#include "stv6110x.h"
@ -92,6 +87,7 @@
#include "mxl5xx.h"
#include "ddbridge-regs.h"
#include "ddbridge-mci.h"
#define DDB_MAX_I2C 32
#define DDB_MAX_PORT 32
@ -115,6 +111,7 @@ struct ddb_regmap {
u32 irq_base_odma;
u32 irq_base_gtl;
u32 irq_base_rate;
u32 irq_base_mci;
const struct ddb_regset *i2c;
const struct ddb_regset *i2c_buf;
@ -128,6 +125,9 @@ struct ddb_regmap {
const struct ddb_regset *channel;
const struct ddb_regset *gtl;
const struct ddb_regset *mci;
const struct ddb_regset *mci_buf;
};
struct ddb_ids {
@ -140,41 +140,46 @@ struct ddb_ids {
u32 regmapid;
u32 devid;
u32 mac;
u8 revision;
};
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_OCTOPUS_MCI 9
u32 version;
char *name;
u32 i2c_mask;
u32 board_control;
u32 board_control_2;
u8 port_num;
u8 led_num;
u8 fan_num;
u8 temp_num;
u8 temp_bus;
u32 board_control;
u32 board_control_2;
u8 ns_num;
u8 mdio_num;
u8 con_clock; /* use a continuous clock */
u8 ts_quirks;
#define TS_QUIRK_SERIAL 1
#define TS_QUIRK_REVERSED 2
#define TS_QUIRK_NO_OUTPUT 4
#define TS_QUIRK_ALT_OSC 8
u8 mci_ports;
u8 mci_type;
u8 ci_mask;
u32 tempmon_irq;
u32 lostlock_irq;
u8 mci;
u32 mdio_base;
u32 hw_min;
u32 ci_base;
u32 lnb_base;
const struct ddb_regmap *regmap;
};
@ -197,11 +202,8 @@ struct ddb_dma {
u32 div;
u32 bufval;
#ifdef DDB_USE_WORK
struct work_struct work;
#else
struct tasklet_struct tasklet;
#endif
spinlock_t lock; /* DMA lock */
wait_queue_head_t wq;
int running;
@ -209,6 +211,10 @@ struct ddb_dma {
u32 ctrl;
u32 cbuf;
u32 coff;
u32 stall_count;
u32 packet_loss;
u32 unaligned;
};
struct ddb_dvb {
@ -230,7 +236,7 @@ struct ddb_dvb {
enum fe_sec_tone_mode tone;
enum fe_sec_voltage voltage;
int (*i2c_gate_ctrl)(struct dvb_frontend *, int);
int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int val);
int (*set_voltage)(struct dvb_frontend *fe,
enum fe_sec_voltage voltage);
int (*set_input)(struct dvb_frontend *fe, int input);
@ -242,12 +248,14 @@ struct ddb_ci {
struct dvb_ca_en50221 en;
struct ddb_port *port;
u32 nr;
u32 regs;
};
struct ddb_io {
struct ddb_port *port;
u32 nr;
u32 regs;
u32 con;
struct ddb_dma *dma;
struct ddb_io *redo;
struct ddb_io *redi;
@ -302,7 +310,6 @@ struct ddb_port {
#define DDB_CI_EXTERNAL_XO2_B 13
#define DDB_TUNER_DVBS_STV0910_PR 14
#define DDB_TUNER_DVBC2T2I_SONY_P 15
#define DDB_TUNER_MCI 16
#define DDB_TUNER_XO2 32
#define DDB_TUNER_DVBS_STV0910 (DDB_TUNER_XO2 + 0)
@ -312,6 +319,14 @@ 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)
#define DDB_TUNER_MCI_M8 (DDB_TUNER_MCI + 2)
#define DDB_TUNER_MCI_M8A (DDB_TUNER_MCI + 3)
#define DDB_TUNER_MCI_M2 (DDB_TUNER_MCI + 4)
#define DDB_TUNER_MCI_M8E (DDB_TUNER_MCI + 5)
struct ddb_input *input[2];
struct ddb_output *output;
struct dvb_ca_en50221 *en;
@ -325,6 +340,8 @@ struct mod_base {
u32 frequency;
u32 flat_start;
u32 flat_end;
u32 attenuation;
u32 gain;
};
struct ddb_mod {
@ -396,7 +413,7 @@ struct ddb_lnb {
};
struct ddb_irq {
void (*handler)(void *);
void (*handler)(void *data);
void *data;
};
@ -408,13 +425,17 @@ struct ddb_link {
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; /* lock temp chip access */
int over_temperature_error;
u8 temp_tab[11];
struct ddb_irq irq[256];
struct mci_base *mci_base;
struct completion mci_completion;
struct mutex mci_lock;
int mci_ok;
};
struct ddb {
@ -441,7 +462,7 @@ struct ddb {
struct ddb_dma odma[DDB_MAX_OUTPUT];
struct device *ddb_dev;
u32 ddb_dev_users;
atomic_t ddb_dev_users;
u32 nr;
u8 iobuf[1028];
@ -516,7 +537,7 @@ struct DDMOD_FLASH {
int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
#define DDBRIDGE_VERSION "0.9.33"
#define DDBRIDGE_VERSION "0.9.41"
/* linked function prototypes */
@ -530,7 +551,7 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg);
int ddbridge_mod_init(struct ddb *dev);
void ddbridge_mod_output_stop(struct ddb_output *output);
int ddbridge_mod_output_start(struct ddb_output *output);
void ddbridge_mod_rate_handler(void *);
void ddbridge_mod_rate_handler(void *data);
void ddb_device_destroy(struct ddb *dev);
void ddb_nsd_detach(struct ddb *dev);
@ -553,10 +574,17 @@ void ddb_i2c_release(struct ddb *dev);
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);
int ddb_fe_attach_mci(struct ddb_input *input, u32 type);
int ddb_lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm);
struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr,
void (*handler)(void *), void *data);
struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, struct mci_cfg *cfg, int nr, int tuner);
struct dvb_frontend *ddb_sx8_attach(struct ddb_input *input, int nr, int tuner,
int (**fn_set_input)(struct dvb_frontend *fe, int input));
struct dvb_frontend *ddb_mx_attach(struct ddb_input *input, int nr, int tuner, int type);
int ddb_dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
int (*func)(struct file *file, unsigned int cmd, void *arg));
#endif

View File

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

View File

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

76
ddbridge/ns.h Normal file
View File

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

View File

@ -24,7 +24,11 @@
#include "ddbridge.h"
#include "ddbridge-io.h"
#if (KERNEL_VERSION(6, 11, 0) > LINUX_VERSION_CODE)
static int __exit octonet_remove(struct platform_device *pdev)
#else
static void __exit octonet_remove(struct platform_device *pdev)
#endif
{
struct ddb *dev;
@ -43,7 +47,9 @@ static int __exit octonet_remove(struct platform_device *pdev)
ddb_ports_release(dev);
ddb_unmap(dev);
platform_set_drvdata(pdev, 0);
#if (KERNEL_VERSION(6, 11, 0) > LINUX_VERSION_CODE)
return 0;
#endif
}
static int __init octonet_probe(struct platform_device *pdev)
@ -165,5 +171,5 @@ module_exit(exit_octonet);
MODULE_DESCRIPTION("GPL");
MODULE_AUTHOR("Marcus and Ralph Metzler, Metzler Brothers Systementwicklung GbR");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(DDBRIDGE_VERSION);

View File

@ -1,15 +1,16 @@
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 is available on supported cards as firmware update.
This feature is currently considered experimental.
This feature is available on supported cards as firmware update and
is currently considered experimental.
Supported hardware:
Cine V7A (>=1.7 FW)
cineS2 V7A (>=1.7 FW)
OctopusCI S2 Pro Advanced (>=1.7 FW)
Duoflex S2 v4 Advanced (TBA)
MaxSX8 (NOT the MAXS8!)
The following cards are based on the broadcast version of the
DVB-S2 demodulator. The BBFrame output is working but
@ -80,3 +81,24 @@ 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.

13
docs/firmware Normal file
View File

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

27
docs/iq_samples Normal file
View File

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

View File

@ -83,6 +83,7 @@ limit depends on # of channels active.
MODULATOR_INPUT_BITRATE:
THIS FEATURE ONLY WORKS FOR DVB-C MODULATORS
The modulator will ALWAY insert null packets if it
does not get enough data.
@ -94,6 +95,21 @@ So, this property should be set last.
unit - 2^-32 Hz
FOR DVB-T MODULATORS THIS FEATURE DOES NOT WORK
You should write a steady stream of transport packets with the
rate given by the modulation. The easiest way to keep a steady rate
is to write as much as the device will receive until it blocks. In that
way you ensure that the device will not get an underrun of data and
you can use the acceptance rate as a guide for you input rate.
All you should do is to correct the PCR of your transport stream according
to the calculated packet rate and use a buffer that assures that you are
always ready to write as sson as the modulator device allows it.
E.g you have a circular output buffer that you fill to say 50% and than start
writing into the device in a seperate thread. You feed the output buffer
with you input TS and see that it does not underrun, you may need to insert
empty packets to do that. The output thread should always have enough data
to write to the device as soon as it no longer blocks.
Debugging features:

181
docs/modulator_mci_api Normal file
View File

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

View File

@ -1,9 +1,9 @@
- NAND flash
0x00000000 - 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 -

View File

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

View File

@ -1,7 +1,34 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# DVB device configuration
#
config DVB_MMAP
bool "Enable DVB memory-mapped API (EXPERIMENTAL)"
depends on DVB_CORE
depends on VIDEO_DEV=y || VIDEO_DEV=DVB_CORE
select VIDEOBUF2_VMALLOC
help
This option enables DVB experimental memory-mapped API, which
reduces the number of context switches to read DVB buffers, as
the buffers can use mmap() syscalls.
Support for it is experimental. Use with care. If unsure,
say N.
config DVB_NET
bool "DVB Network Support"
default (NET && INET)
depends on NET && INET && DVB_CORE
help
This option enables DVB Network Support which is a part of the DVB
standard. It is used, for example, by automatic firmware updates used
on Set-Top-Boxes. It can also be used to access the Internet via the
DVB card, if the network provider supports it.
You may want to disable the network support on embedded devices. If
unsure say Y.
config DVB_MAX_ADAPTERS
int "maximum number of DVB/ATSC adapters"
depends on DVB_CORE
@ -18,7 +45,7 @@ config DVB_MAX_ADAPTERS
config DVB_DYNAMIC_MINORS
bool "Dynamic DVB minor allocation"
depends on DVB_CORE
default n
default y
help
If you say Y here, the DVB subsystem will use dynamic minor
allocation for any device that uses the DVB major number.
@ -31,7 +58,6 @@ config DVB_DYNAMIC_MINORS
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.
@ -40,3 +66,15 @@ config DVB_DEMUX_SECTION_LOSS_LOG
be very verbose.
If you are unsure about this, say N here.
config DVB_ULE_DEBUG
bool "Enable DVB net ULE packet debug messages"
depends on DVB_CORE
help
Enable extra log messages meant to detect problems while
handling DVB network ULE packet loss inside the Kernel.
Should not be enabled on normal cases, as logs can
be very verbose.
If you are unsure about this, say N here.

View File

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

View File

@ -4,9 +4,11 @@
dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \
dvb_ca_en50221.o dvb_frontend.o \
$(dvb-net-y) dvb_ringbuffer.o dvb_math.o \
dvb_netstream.o
$(dvb-net-y) dvb_ringbuffer.o dvb_math.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o
ccflags-y += -Idrivers/media/dvb-core/
ccflags-y += --include=dd_compat.h

View File

@ -1,23 +1,14 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* dmxdev.c - DVB demultiplexer device
*
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#define pr_fmt(fmt) "dmxdev: " fmt
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@ -27,7 +18,10 @@
#include <linux/ioctl.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include "dmxdev.h"
#include <media/dmxdev.h>
#ifdef CONFIG_DVB_MMAP
#include <media/dvb_vb2.h>
#endif
static int debug;
@ -127,6 +121,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
struct dmx_frontend *front;
bool need_ringbuffer = false;
dprintk("%s\n", __func__);
@ -138,14 +133,33 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
return -ENODEV;
}
if ((file->f_flags & O_ACCMODE) == O_RDWR) {
dmxdev->may_do_mmap = 0;
/*
* The logic here is a little tricky due to the ifdef.
*
* The ringbuffer is used for both read and mmap.
*
* It is not needed, however, on two situations:
* - Write devices (access with O_WRONLY);
* - For duplex device nodes, opened with O_RDWR.
*/
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
need_ringbuffer = true;
else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
#ifdef CONFIG_DVB_MMAP
dmxdev->may_do_mmap = 1;
need_ringbuffer = true;
#else
mutex_unlock(&dmxdev->mutex);
return -EOPNOTSUPP;
#endif
}
}
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
if (need_ringbuffer) {
void *mem;
if (!dvbdev->readers) {
@ -158,6 +172,11 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
return -ENOMEM;
}
dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
#ifdef CONFIG_DVB_MMAP
if (dmxdev->may_do_mmap)
dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr",
file->f_flags & O_NONBLOCK);
#endif
dvbdev->readers--;
}
@ -195,7 +214,15 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
dmxdev->demux->connect_frontend(dmxdev->demux,
dmxdev->dvr_orig_fe);
}
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
dmxdev->may_do_mmap) {
#ifdef CONFIG_DVB_MMAP
if (dmxdev->may_do_mmap) {
if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx);
dvb_vb2_release(&dmxdev->dvr_vb2_ctx);
}
#endif
dvbdev->readers++;
if (dmxdev->dvr_buffer.data) {
void *mem = dmxdev->dvr_buffer.data;
@ -332,23 +359,23 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
#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);
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;
dmxdevfilter->timer.expires =
jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
add_timer(&dmxdevfilter->timer);
}
}
@ -367,7 +394,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;
@ -378,14 +405,21 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
}
}
#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)
struct dmx_section_filter *filter,
u32 *buffer_flags)
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
int ret;
#ifdef CONFIG_DVB_MMAP
if (!dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx) &&
dmxdevfilter->buffer.error) {
#else
if (dmxdevfilter->buffer.error) {
#endif
wake_up(&dmxdevfilter->buffer.queue);
return 0;
}
@ -396,12 +430,31 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
}
del_timer(&dmxdevfilter->timer);
dprintk("section callback %*ph\n", 6, buffer1);
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) {
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
buffer1, buffer1_len,
buffer_flags);
if (ret == buffer1_len)
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
buffer2, buffer2_len,
buffer_flags);
} else {
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
buffer1, buffer1_len);
if (ret == buffer1_len) {
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
buffer2, buffer2_len);
}
}
#else
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
buffer1_len);
if (ret == buffer1_len) {
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
buffer2_len);
}
#endif
if (ret < 0)
dmxdevfilter->buffer.error = ret;
if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
@ -413,10 +466,14 @@ 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)
struct dmx_ts_feed *feed,
u32 *buffer_flags)
{
struct dmxdev_filter *dmxdevfilter = feed->priv;
struct dvb_ringbuffer *buffer;
#ifdef CONFIG_DVB_MMAP
struct dvb_vb2_ctx *ctx;
#endif
int ret;
spin_lock(&dmxdevfilter->dev->lock);
@ -425,19 +482,40 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
return 0;
}
if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
|| dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
if (dmxdevfilter->params.pes.output == DMX_OUT_TAP ||
dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
buffer = &dmxdevfilter->buffer;
else
#ifdef CONFIG_DVB_MMAP
ctx = &dmxdevfilter->vb2_ctx;
#endif
} else {
buffer = &dmxdevfilter->dev->dvr_buffer;
if (buffer->error) {
spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&buffer->queue);
return 0;
#ifdef CONFIG_DVB_MMAP
ctx = &dmxdevfilter->dev->dvr_vb2_ctx;
#endif
}
ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
if (ret == buffer1_len)
ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(ctx)) {
ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len,
buffer_flags);
if (ret == buffer1_len)
ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len,
buffer_flags);
} else {
#endif
if (buffer->error) {
spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&buffer->queue);
return 0;
}
ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
if (ret == buffer1_len)
ret = dvb_dmxdev_buffer_write(buffer,
buffer2, buffer2_len);
#ifdef CONFIG_DVB_MMAP
}
#endif
if (ret < 0)
buffer->error = ret;
spin_unlock(&dmxdevfilter->dev->lock);
@ -584,7 +662,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
struct dmxdev_filter *filter,
struct dmxdev_feed *feed)
{
ktime_t timeout;
ktime_t timeout = ktime_set(0, 0);
struct dmx_pes_filter_params *para = &filter->params.pes;
enum dmx_output otype;
int ret;
@ -592,7 +670,6 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
enum dmx_ts_pes ts_pes;
struct dmx_ts_feed *tsfeed;
timeout = ktime_set(0, 0);
feed->ts = NULL;
otype = para->output;
@ -683,7 +760,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
secfeed,
dvb_dmxdev_section_callback);
if (ret < 0) {
if (!*secfeed) {
pr_err("DVB (%s): could not alloc feed\n",
__func__);
return ret;
@ -763,6 +840,11 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
if (dmxdev->exit) {
mutex_unlock(&dmxdev->mutex);
return -ENODEV;
}
for (i = 0; i < dmxdev->filternum; i++)
if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
break;
@ -776,7 +858,17 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
mutex_init(&dmxdevfilter->mutex);
file->private_data = dmxdevfilter;
#ifdef CONFIG_DVB_MMAP
dmxdev->may_do_mmap = 1;
#else
dmxdev->may_do_mmap = 0;
#endif
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
#ifdef CONFIG_DVB_MMAP
dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter",
file->f_flags & O_NONBLOCK);
#endif
dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
@ -796,6 +888,11 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
{
mutex_lock(&dmxdev->mutex);
mutex_lock(&dmxdevfilter->mutex);
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
dvb_vb2_stream_off(&dmxdevfilter->vb2_ctx);
dvb_vb2_release(&dmxdevfilter->vb2_ctx);
#endif
dvb_dmxdev_filter_stop(dmxdevfilter);
dvb_dmxdev_filter_reset(dmxdevfilter);
@ -1083,8 +1180,56 @@ static int dvb_demux_do_ioctl(struct file *file,
mutex_unlock(&dmxdevfilter->mutex);
break;
#ifdef CONFIG_DVB_MMAP
case DMX_REQBUFS:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_reqbufs(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_QUERYBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_querybuf(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_EXPBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_expbuf(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_QBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_qbuf(&dmxdevfilter->vb2_ctx, parg);
if (ret == 0 && !dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
ret = dvb_vb2_stream_on(&dmxdevfilter->vb2_ctx);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_DQBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_dqbuf(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
#endif
default:
ret = -EINVAL;
ret = -ENOTTY;
break;
}
mutex_unlock(&dmxdev->mutex);
@ -1097,30 +1242,70 @@ static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
}
static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0))
typedef unsigned int __poll_t;
#define EPOLLIN POLLIN
#define EPOLLERR POLLERR
#define EPOLLPRI POLLPRI
#define EPOLLRDNORM POLLRDNORM
#define EPOLLWRNORM POLLWRNORM
#define EPOLLOUT POLLOUT
#endif
static __poll_t dvb_demux_poll(struct file *file, poll_table *wait)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
unsigned int mask = 0;
if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
return POLLERR;
__poll_t mask = 0;
poll_wait(file, &dmxdevfilter->buffer.queue, wait);
if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
return EPOLLERR;
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
return dvb_vb2_poll(&dmxdevfilter->vb2_ctx, file, wait);
#endif
if (dmxdevfilter->state != DMXDEV_STATE_GO &&
dmxdevfilter->state != DMXDEV_STATE_DONE &&
dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
return 0;
if (dmxdevfilter->buffer.error)
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
mask |= (POLLIN | POLLRDNORM | POLLPRI);
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
return mask;
}
#ifdef CONFIG_DVB_MMAP
static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev = dmxdevfilter->dev;
int ret;
if (!dmxdev->may_do_mmap)
return -ENOTTY;
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_mmap(&dmxdevfilter->vb2_ctx, vma);
mutex_unlock(&dmxdevfilter->mutex);
mutex_unlock(&dmxdev->mutex);
return ret;
}
#endif
static int dvb_demux_release(struct inode *inode, struct file *file)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
@ -1145,10 +1330,14 @@ static const struct file_operations dvb_demux_fops = {
.owner = THIS_MODULE,
.read = dvb_demux_read,
.unlocked_ioctl = dvb_demux_ioctl,
.compat_ioctl = dvb_demux_ioctl,
.open = dvb_demux_open,
.release = dvb_demux_release,
.poll = dvb_demux_poll,
.llseek = default_llseek,
#ifdef CONFIG_DVB_MMAP
.mmap = dvb_demux_mmap,
#endif
};
static const struct dvb_device dvbdev_demux = {
@ -1177,8 +1366,31 @@ static int dvb_dvr_do_ioctl(struct file *file,
ret = dvb_dvr_set_buffer_size(dmxdev, arg);
break;
#ifdef CONFIG_DVB_MMAP
case DMX_REQBUFS:
ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg);
break;
case DMX_QUERYBUF:
ret = dvb_vb2_querybuf(&dmxdev->dvr_vb2_ctx, parg);
break;
case DMX_EXPBUF:
ret = dvb_vb2_expbuf(&dmxdev->dvr_vb2_ctx, parg);
break;
case DMX_QBUF:
ret = dvb_vb2_qbuf(&dmxdev->dvr_vb2_ctx, parg);
if (ret == 0 && !dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
ret = dvb_vb2_stream_on(&dmxdev->dvr_vb2_ctx);
break;
case DMX_DQBUF:
ret = dvb_vb2_dqbuf(&dmxdev->dvr_vb2_ctx, parg);
break;
#endif
default:
ret = -EINVAL;
ret = -ENOTTY;
break;
}
mutex_unlock(&dmxdev->mutex);
@ -1191,31 +1403,58 @@ static long dvb_dvr_ioctl(struct file *file,
return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
}
static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait)
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
unsigned int mask = 0;
__poll_t mask = 0;
dprintk("%s\n", __func__);
if (dmxdev->exit)
return POLLERR;
poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
if (dmxdev->exit)
return EPOLLERR;
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
return dvb_vb2_poll(&dmxdev->dvr_vb2_ctx, file, wait);
#endif
if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
dmxdev->may_do_mmap) {
if (dmxdev->dvr_buffer.error)
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
mask |= (POLLIN | POLLRDNORM | POLLPRI);
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
} else
mask |= (POLLOUT | POLLWRNORM | POLLPRI);
mask |= (EPOLLOUT | EPOLLWRNORM | EPOLLPRI);
return mask;
}
#ifdef CONFIG_DVB_MMAP
static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma)
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
int ret;
if (!dmxdev->may_do_mmap)
return -ENOTTY;
if (dmxdev->exit)
return -ENODEV;
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
ret = dvb_vb2_mmap(&dmxdev->dvr_vb2_ctx, vma);
mutex_unlock(&dmxdev->mutex);
return ret;
}
#endif
static const struct file_operations dvb_dvr_fops = {
.owner = THIS_MODULE,
.read = dvb_dvr_read,
@ -1225,6 +1464,9 @@ static const struct file_operations dvb_dvr_fops = {
.release = dvb_dvr_release,
.poll = dvb_dvr_poll,
.llseek = default_llseek,
#ifdef CONFIG_DVB_MMAP
.mmap = dvb_dvr_mmap,
#endif
};
static const struct dvb_device dvbdev_dvr = {
@ -1236,14 +1478,20 @@ static const struct dvb_device dvbdev_dvr = {
#endif
.fops = &dvb_dvr_fops
};
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
{
int i;
int i, ret;
if (dmxdev->demux->open(dmxdev->demux) < 0)
return -EUSERS;
dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0))
dmxdev->filter = vmalloc(sizeof(struct dmxdev_filter) * dmxdev->filternum);
#else
dmxdev->filter = vmalloc(array_size(sizeof(struct dmxdev_filter),
dmxdev->filternum));
#endif
if (!dmxdev->filter)
return -ENOMEM;
@ -1256,21 +1504,36 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
DMXDEV_STATE_FREE);
}
dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
ret = dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
DVB_DEVICE_DEMUX, dmxdev->filternum);
dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
if (ret < 0)
goto err_register_dvbdev;
ret = dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
dmxdev, DVB_DEVICE_DVR, dmxdev->filternum);
if (ret < 0)
goto err_register_dvr_dvbdev;
dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
return 0;
err_register_dvr_dvbdev:
dvb_unregister_device(dmxdev->dvbdev);
err_register_dvbdev:
vfree(dmxdev->filter);
dmxdev->filter = NULL;
return ret;
}
EXPORT_SYMBOL(dvb_dmxdev_init);
void dvb_dmxdev_release(struct dmxdev *dmxdev)
{
mutex_lock(&dmxdev->mutex);
dmxdev->exit = 1;
mutex_unlock(&dmxdev->mutex);
if (dmxdev->dvbdev->users > 1) {
wait_event(dmxdev->dvbdev->wait_queue,
dmxdev->dvbdev->users == 1);

View File

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

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* dvb_ca.c: generic DVB functions for EN50221 CAM interfaces
*
@ -11,18 +12,6 @@
*
* Copyright (C) 1999-2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General 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.
* To obtain the license, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#define pr_fmt(fmt) "dvb_ca_en50221: " fmt
@ -31,10 +20,13 @@
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
#include <linux/nospec.h>
#endif
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
#include <linux/sched/signal.h>
#else
@ -42,8 +34,8 @@
#endif
#include <linux/kthread.h>
#include "dvb_ca_en50221.h"
#include "dvb_ringbuffer.h"
#include <media/dvb_ca_en50221.h>
#include <media/dvb_ringbuffer.h>
static int dvb_ca_en50221_debug;
@ -166,13 +158,19 @@ struct dvb_ca_private {
/* mutex serializing ioctls */
struct mutex ioctl_mutex;
/* A mutex used when a device is disconnected */
struct mutex remove_mutex;
/* Whether the device is disconnected */
int exit;
};
static void dvb_ca_private_free(struct dvb_ca_private *ca)
{
unsigned int i;
dvb_free_device(ca->dvbdev);
dvb_device_put(ca->dvbdev);
for (i = 0; i < ca->slot_count; i++)
vfree(ca->slot_info[i].rx_buffer.data);
@ -202,16 +200,16 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
u8 *ebuf, int ecount);
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
u8 *ebuf, int ecount);
u8 *ebuf, int ecount, int size_write_flag);
/**
* Safely find needle in haystack.
* findstr - Safely find needle in haystack.
*
* @haystack: Buffer to look in.
* @hlen: Number of bytes in haystack.
* @needle: Buffer to find.
* @nlen: Number of bytes in needle.
* @return Pointer into haystack needle was found at, or NULL if not found.
* return: Pointer into haystack needle was found at, or NULL if not found.
*/
static char *findstr(char *haystack, int hlen, char *needle, int nlen)
{
@ -231,7 +229,7 @@ static char *findstr(char *haystack, int hlen, char *needle, int nlen)
/* ************************************************************************** */
/* EN50221 physical interface functions */
/**
/*
* dvb_ca_en50221_check_camstatus - Check CAM status.
*/
static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
@ -280,9 +278,9 @@ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
* @ca: CA instance.
* @slot: Slot on interface.
* @waitfor: Flags to wait for.
* @timeout_ms: Timeout in milliseconds.
* @timeout_hz: Timeout in milliseconds.
*
* @return 0 on success, nonzero on error.
* return: 0 on success, nonzero on error.
*/
static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
u8 waitfor, int timeout_hz)
@ -330,7 +328,7 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
* @ca: CA instance.
* @slot: Slot id.
*
* @return 0 on success, nonzero on failure.
* return: 0 on success, nonzero on failure.
*/
static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
{
@ -385,7 +383,7 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10);
if (ret)
return ret;
ret = dvb_ca_en50221_write_data(ca, slot, buf, 2);
ret = dvb_ca_en50221_write_data(ca, slot, buf, 2, CMDREG_SW);
if (ret != 2)
return -EIO;
ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
@ -402,11 +400,11 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
* @ca: CA instance.
* @slot: Slot id.
* @address: Address to read from. Updated.
* @tupleType: Tuple id byte. Updated.
* @tupleLength: Tuple length. Updated.
* @tuple_type: Tuple id byte. Updated.
* @tuple_length: Tuple length. Updated.
* @tuple: Dest buffer for tuple (must be 256 bytes). Updated.
*
* @return 0 on success, nonzero on error.
* return: 0 on success, nonzero on error.
*/
static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
int *address, int *tuple_type,
@ -460,7 +458,7 @@ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
* @ca: CA instance.
* @slot: Slot id.
*
* @return 0 on success, <0 on failure.
* return: 0 on success, <0 on failure.
*/
static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
{
@ -637,10 +635,11 @@ static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
* @ca: CA instance.
* @slot: Slot to read from.
* @ebuf: If non-NULL, the data will be written to this buffer. If NULL,
* the data will be added into the buffering system as a normal fragment.
* the data will be added into the buffering system as a normal
* fragment.
* @ecount: Size of ebuf. Ignored if ebuf is NULL.
*
* @return Number of bytes read, or < 0 on error
* return: Number of bytes read, or < 0 on error
*/
static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
u8 *ebuf, int ecount)
@ -789,21 +788,22 @@ exit:
*
* @ca: CA instance.
* @slot: Slot to write to.
* @ebuf: The data in this buffer is treated as a complete link-level packet to
* be written.
* @count: Size of ebuf.
* @buf: The data in this buffer is treated as a complete link-level packet to
* be written.
* @bytes_write: Size of ebuf.
* @size_write_flag: A flag on Command Register which says whether the link size
* information will be writen or not.
*
* @return Number of bytes written, or < 0 on error.
* return: Number of bytes written, or < 0 on error.
*/
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
u8 *buf, int bytes_write)
u8 *buf, int bytes_write, int size_write_flag)
{
struct dvb_ca_slot *sl = &ca->slot_info[slot];
int status;
int i;
dprintk("%s\n", __func__);
/* sanity check */
if (bytes_write > sl->link_buf_size)
return -EINVAL;
@ -831,7 +831,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
/* OK, set HC bit */
status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
IRQEN | CMDREG_HC);
IRQEN | CMDREG_HC | size_write_flag);
if (status)
goto exit;
@ -938,7 +938,7 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
/**
* dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred.
*
* @ca: CA instance.
* @pubca: CA instance.
* @slot: Slot concerned.
* @change_type: One of the DVB_CA_CAMCHANGE_* values.
*/
@ -968,7 +968,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
/**
* dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred.
*
* @ca: CA instance.
* @pubca: CA instance.
* @slot: Slot concerned.
*/
void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot)
@ -988,7 +988,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
/**
* dvb_ca_en50221_frda_irq - An FR or DA IRQ has occurred.
*
* @ca: CA instance.
* @pubca: CA instance.
* @slot: Slot concerned.
*/
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot)
@ -1020,7 +1020,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
/* EN50221 thread functions */
/**
* Wake up the DVB CA thread
* dvb_ca_en50221_thread_wakeup - Wake up the DVB CA thread
*
* @ca: CA instance.
*/
@ -1034,7 +1034,7 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
}
/**
* Update the delay used by the thread.
* dvb_ca_en50221_thread_update_delay - Update the delay used by the thread.
*
* @ca: CA instance.
*/
@ -1092,11 +1092,11 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
}
/**
* Poll if the CAM is gone.
* dvb_ca_en50221_poll_cam_gone - Poll if the CAM is gone.
*
* @ca: CA instance.
* @slot: Slot to process.
* @return: 0 .. no change
* return:: 0 .. no change
* 1 .. CAM state changed
*/
@ -1123,7 +1123,8 @@ static int dvb_ca_en50221_poll_cam_gone(struct dvb_ca_private *ca, int slot)
}
/**
* Thread state machine for one CA slot to perform the data transfer.
* dvb_ca_en50221_thread_state_machine - Thread state machine for one CA slot
* to perform the data transfer.
*
* @ca: CA instance.
* @slot: Slot to process.
@ -1274,8 +1275,8 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca,
ca->pub->slot_ts_enable(ca->pub, slot);
sl->slot_state = DVB_CA_SLOTSTATE_RUNNING;
dvb_ca_en50221_thread_update_delay(ca);
pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n",
ca->dvbdev->adapter->num);
pr_info("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n",
ca->dvbdev->adapter->num);
break;
case DVB_CA_SLOTSTATE_RUNNING:
@ -1317,7 +1318,7 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca,
mutex_unlock(&sl->slot_lock);
}
/**
/*
* Kernel thread which monitors CA slots for CAM changes, and performs data
* transfers.
*/
@ -1354,15 +1355,15 @@ static int dvb_ca_en50221_thread(void *data)
/* EN50221 IO interface functions */
/**
* Real ioctl implementation.
* NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
* dvb_ca_en50221_io_do_ioctl - Real ioctl implementation.
*
* @inode: Inode concerned.
* @file: File concerned.
* @cmd: IOCTL command.
* @arg: Associated argument.
* @parg: Associated argument.
*
* @return 0 on success, <0 on error.
* NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
*
* return: 0 on success, <0 on error.
*/
static int dvb_ca_en50221_io_do_ioctl(struct file *file,
unsigned int cmd, void *parg)
@ -1411,10 +1412,13 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file,
struct dvb_ca_slot *sl;
slot = info->num;
if ((slot > ca->slot_count) || (slot < 0)) {
if ((slot >= ca->slot_count) || (slot < 0)) {
err = -EINVAL;
goto out_unlock;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
slot = array_index_nospec(slot, ca->slot_count);
#endif
info->type = CA_CI_LINK;
info->flags = 0;
@ -1439,14 +1443,13 @@ out_unlock:
}
/**
* Wrapper for ioctl implementation.
* dvb_ca_en50221_io_ioctl - Wrapper for ioctl implementation.
*
* @inode: Inode concerned.
* @file: File concerned.
* @cmd: IOCTL command.
* @arg: Associated argument.
*
* @return 0 on success, <0 on error.
* return: 0 on success, <0 on error.
*/
static long dvb_ca_en50221_io_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
@ -1455,14 +1458,14 @@ static long dvb_ca_en50221_io_ioctl(struct file *file,
}
/**
* Implementation of write() syscall.
* dvb_ca_en50221_io_write - Implementation of write() syscall.
*
* @file: File structure.
* @buf: Source buffer.
* @count: Size of source buffer.
* @ppos: Position in file (ignored).
*
* @return Number of bytes read, or <0 on error.
* return: Number of bytes read, or <0 on error.
*/
static ssize_t dvb_ca_en50221_io_write(struct file *file,
const char __user *buf, size_t count,
@ -1495,6 +1498,12 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
return -EFAULT;
buf += 2;
count -= 2;
if (slot >= ca->slot_count)
return -EINVAL;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
slot = array_index_nospec(slot, ca->slot_count);
#endif
sl = &ca->slot_info[slot];
/* check if the slot is actually running */
@ -1533,7 +1542,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
mutex_lock(&sl->slot_lock);
status = dvb_ca_en50221_write_data(ca, slot, fragbuf,
fraglen + 2);
fraglen + 2, 0);
mutex_unlock(&sl->slot_lock);
if (status == (fraglen + 2)) {
written = 1;
@ -1557,7 +1566,7 @@ exit:
return status;
}
/**
/*
* Condition for waking up in dvb_ca_en50221_io_read_condition
*/
static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
@ -1607,14 +1616,14 @@ nextslot:
}
/**
* Implementation of read() syscall.
* dvb_ca_en50221_io_read - Implementation of read() syscall.
*
* @file: File structure.
* @buf: Destination buffer.
* @count: Size of destination buffer.
* @ppos: Position in file (ignored).
*
* @return Number of bytes read, or <0 on error.
* return: Number of bytes read, or <0 on error.
*/
static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
@ -1718,12 +1727,12 @@ exit:
}
/**
* Implementation of file open syscall.
* dvb_ca_en50221_io_open - Implementation of file open syscall.
*
* @inode: Inode concerned.
* @file: File concerned.
*
* @return 0 on success, <0 on failure.
* return: 0 on success, <0 on failure.
*/
static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
{
@ -1734,12 +1743,22 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
dprintk("%s\n", __func__);
if (!try_module_get(ca->pub->owner))
mutex_lock(&ca->remove_mutex);
if (ca->exit) {
mutex_unlock(&ca->remove_mutex);
return -ENODEV;
}
if (!try_module_get(ca->pub->owner)) {
mutex_unlock(&ca->remove_mutex);
return -EIO;
}
err = dvb_generic_open(inode, file);
if (err < 0) {
module_put(ca->pub->owner);
mutex_unlock(&ca->remove_mutex);
return err;
}
@ -1764,16 +1783,17 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
dvb_ca_private_get(ca);
mutex_unlock(&ca->remove_mutex);
return 0;
}
/**
* Implementation of file close syscall.
* dvb_ca_en50221_io_release - Implementation of file close syscall.
*
* @inode: Inode concerned.
* @file: File concerned.
*
* @return 0 on success, <0 on failure.
* return: 0 on success, <0 on failure.
*/
static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
{
@ -1783,6 +1803,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
dprintk("%s\n", __func__);
mutex_lock(&ca->remove_mutex);
/* mark the CA device as closed */
ca->open = 0;
dvb_ca_en50221_thread_update_delay(ca);
@ -1793,39 +1815,49 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
dvb_ca_private_put(ca);
if (dvbdev->users == 1 && ca->exit == 1) {
mutex_unlock(&ca->remove_mutex);
wake_up(&dvbdev->wait_queue);
} else {
mutex_unlock(&ca->remove_mutex);
}
return err;
}
/**
* Implementation of poll() syscall.
* dvb_ca_en50221_io_poll - Implementation of poll() syscall.
*
* @file: File concerned.
* @wait: poll wait table.
*
* @return Standard poll mask.
* return: Standard poll mask.
*/
static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait)
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0))
typedef unsigned int __poll_t;
#define EPOLLIN POLLIN
#endif
static __poll_t dvb_ca_en50221_io_poll(struct file *file, poll_table *wait)
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_ca_private *ca = dvbdev->priv;
unsigned int mask = 0;
__poll_t mask = 0;
int slot;
int result = 0;
dprintk("%s\n", __func__);
poll_wait(file, &ca->wait_queue, wait);
if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1)
mask |= POLLIN;
mask |= EPOLLIN;
/* if there is something, return now */
if (mask)
return mask;
/* wait for something to happen */
poll_wait(file, &ca->wait_queue, wait);
if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1)
mask |= POLLIN;
mask |= EPOLLIN;
return mask;
}
@ -1856,14 +1888,14 @@ static const struct dvb_device dvbdev_ca = {
/* Initialisation/shutdown functions */
/**
* Initialise a new DVB CA EN50221 interface device.
* dvb_ca_en50221_init - Initialise a new DVB CA EN50221 interface device.
*
* @dvb_adapter: DVB adapter to attach the new CA device to.
* @ca: The dvb_ca instance.
* @pubca: The dvb_ca instance.
* @flags: Flags describing the CA device (DVB_CA_FLAG_*).
* @slot_count: Number of slots supported.
*
* @return 0 on success, nonzero on failure
* return: 0 on success, nonzero on failure
*/
int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
struct dvb_ca_en50221 *pubca, int flags, int slot_count)
@ -1917,6 +1949,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
}
mutex_init(&ca->ioctl_mutex);
mutex_init(&ca->remove_mutex);
if (signal_pending(current)) {
ret = -EINTR;
@ -1948,10 +1981,9 @@ exit:
EXPORT_SYMBOL(dvb_ca_en50221_init);
/**
* Release a DVB CA EN50221 interface device.
* dvb_ca_en50221_release - Release a DVB CA EN50221 interface device.
*
* @ca_dev: The dvb_device_t instance for the CA device.
* @ca: The associated dvb_ca instance.
* @pubca: The associated dvb_ca instance.
*/
void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
{
@ -1960,6 +1992,14 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
dprintk("%s\n", __func__);
mutex_lock(&ca->remove_mutex);
ca->exit = 1;
mutex_unlock(&ca->remove_mutex);
if (ca->dvbdev->users < 1)
wait_event(ca->dvbdev->wait_queue,
ca->dvbdev->users == 1);
/* shutdown the thread if there was one */
kthread_stop(ca->thread);

View File

@ -1,20 +1,10 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* dvb_demux.c - DVB kernel demux API
*
* Copyright (C) 2000-2001 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#define pr_fmt(fmt) "dvb_demux: " fmt
@ -35,7 +25,7 @@
#include <linux/uaccess.h>
#include <asm/div64.h>
#include "dvb_demux.h"
#include <media/dvb_demux.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
@ -68,6 +58,17 @@ MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
dprintk(x); \
} while (0)
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
# define dprintk_sect_loss(x...) dprintk(x)
#else
# define dprintk_sect_loss(x...)
#endif
#define set_buf_flags(__feed, __flag) \
do { \
(__feed)->buffer_flags |= (__flag); \
} while (0)
/******************************************************************************
* static inlined helper functions
******************************************************************************/
@ -117,30 +118,30 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
{
int count = payload(buf);
int p;
#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;
if (!ccok) {
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("missed packet: %d instead of %d!\n",
cc, (feed->cc + 1) & 0x0f);
}
feed->cc = cc;
if (!ccok)
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);
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts,
&feed->buffer_flags);
}
static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
@ -162,7 +163,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);
NULL, 0, &f->filter, &feed->buffer_flags);
}
static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
@ -181,8 +182,10 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
if (sec->check_crc) {
section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
if (section_syntax_indicator &&
demux->check_crc32(feed, sec->secbuf, sec->seclen))
demux->check_crc32(feed, sec->secbuf, sec->seclen)) {
set_buf_flags(feed, DMX_BUFFER_FLAG_HAD_CRC32_DISCARD);
return -1;
}
}
do {
@ -199,9 +202,8 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
{
struct dmx_section_feed *sec = &feed->feed.sec;
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
if (sec->secbufp < sec->tsfeedp) {
int i, n = sec->tsfeedp - sec->secbufp;
int n = sec->tsfeedp - sec->secbufp;
/*
* Section padding is done with 0xff bytes entirely.
@ -209,15 +211,13 @@ 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) {
dprintk("dvb_demux.c section ts padding loss: %d/%d\n",
n, sec->tsfeedp);
dprintk("dvb_demux.c pad data:");
for (i = 0; i < n; i++)
pr_cont(" %02x", sec->secbuf[i]);
pr_cont("\n");
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("section ts padding loss: %d/%d\n",
n, sec->tsfeedp);
dprintk_sect_loss("pad data: %*ph\n", n, sec->secbuf);
}
}
#endif
sec->tsfeedp = sec->secbufp = sec->seclen = 0;
sec->secbuf = sec->secbuf_base;
@ -236,27 +236,26 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
* when the second packet arrives.
*
* Fix:
* when demux is started, let feed->pusi_seen = 0 to
* when demux is started, let feed->pusi_seen = false to
* prevent initial feeding of garbage from the end of
* previous section. When you for the first time see PUSI=1
* then set feed->pusi_seen = 1
* then set feed->pusi_seen = true
*/
static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
const u8 *buf, u8 len)
{
struct dvb_demux *demux = feed->demux;
struct dmx_section_feed *sec = &feed->feed.sec;
u16 limit, seclen, n;
u16 limit, seclen;
if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
return 0;
if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
#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
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("section buffer full loss: %d/%d\n",
sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
DMX_MAX_SECFEED_SIZE);
len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
}
@ -276,7 +275,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
/* to be sure always set secbuf */
sec->secbuf = sec->secbuf_base + sec->secbufp;
for (n = 0; sec->secbufp + 2 < limit; n++) {
while (sec->secbufp + 2 < limit) {
seclen = section_length(sec->secbuf);
if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
|| seclen + sec->secbufp > limit)
@ -284,12 +283,13 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
sec->seclen = seclen;
sec->crc_val = ~0;
/* dump [secbuf .. secbuf+seclen) */
if (feed->pusi_seen)
if (feed->pusi_seen) {
dvb_dmx_swfilter_section_feed(feed);
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
else
dprintk("dvb_demux.c pusi not seen, discarding section data\n");
#endif
} else {
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("pusi not seen, discarding section data\n");
}
sec->secbufp += seclen; /* secbufp and secbuf moving together is */
sec->secbuf += seclen; /* redundant but saves pointer arithmetic */
}
@ -313,7 +313,6 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
cc = buf[3] & 0x0f;
ccok = ((feed->cc + 1) & 0x0f) == cc;
feed->cc = cc;
if (buf[3] & 0x20) {
/* adaption field present, check for discontinuity_indicator */
@ -322,21 +321,34 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
}
if (!ccok || dc_i) {
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
dprintk("dvb_demux.c discontinuity detected %d bytes lost\n",
count);
if (dc_i) {
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR);
dprintk_sect_loss("%d frame with disconnect indicator\n",
cc);
} else {
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("discontinuity: %d instead of %d. %d bytes lost\n",
cc, (feed->cc + 1) & 0x0f, count + 4);
}
/*
* those bytes under sume circumstances will again be reported
* those bytes under some circumstances will again be reported
* in the following dvb_dmx_swfilter_section_new
*/
#endif
/*
* Discontinuity detected. Reset pusi_seen = 0 to
* Discontinuity detected. Reset pusi_seen to
* stop feeding of suspicious data until next PUSI=1 arrives
*
* FIXME: does it make sense if the MPEG-TS is the one
* reporting discontinuity?
*/
feed->pusi_seen = 0;
feed->pusi_seen = false;
dvb_dmx_swfilter_section_new(feed);
}
feed->cc = cc;
if (buf[1] & 0x40) {
/* PUSI=1 (is set), section boundary is here */
@ -348,17 +360,16 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
dvb_dmx_swfilter_section_copy_dump(feed, before,
before_len);
/* before start of new section, set pusi_seen = 1 */
feed->pusi_seen = 1;
/* before start of new section, set pusi_seen */
feed->pusi_seen = true;
dvb_dmx_swfilter_section_new(feed);
dvb_dmx_swfilter_section_copy_dump(feed, after,
after_len);
} else if (count > 0) {
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("PUSI=1 but %d bytes lost\n", count);
}
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
else if (count > 0)
dprintk("dvb_demux.c PUSI=1 but %d bytes lost\n",
count);
#endif
} else {
/* PUSI=0 (is not set), no section boundary */
dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
@ -378,8 +389,10 @@ 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);
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
&feed->buffer_flags);
}
/* Used only on full-featured devices */
if (feed->ts_type & TS_DECODER)
if (feed->demux->write_to_decoder)
feed->demux->write_to_decoder(feed, buf, 188);
@ -426,9 +439,10 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
1024);
speed_timedelta = ktime_ms_delta(cur_time,
demux->speed_last_time);
dprintk("TS speed %llu Kbits/sec \n",
div64_u64(speed_bytes,
speed_timedelta));
if (speed_timedelta)
dprintk("TS speed %llu Kbits/sec \n",
div64_u64(speed_bytes,
speed_timedelta));
}
demux->speed_last_time = cur_time;
@ -437,6 +451,11 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
}
if (buf[1] & 0x80) {
list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
continue;
set_buf_flags(feed, DMX_BUFFER_FLAG_TEI);
}
dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n",
pid, buf[1]);
/* data in this packet can't be trusted - drop it unless
@ -452,9 +471,16 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
(demux->cnt_storage[pid] + 1) & 0xf;
if ((buf[3] & 0xf) != demux->cnt_storage[pid]) {
list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
continue;
set_buf_flags(feed,
DMX_BUFFER_PKT_COUNTER_MISMATCH);
}
dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n",
pid, demux->cnt_storage[pid],
buf[3] & 0xf);
pid, demux->cnt_storage[pid],
buf[3] & 0xf);
demux->cnt_storage[pid] = buf[3] & 0xf;
}
}
@ -473,7 +499,8 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
if (feed->pid == pid)
dvb_dmx_swfilter_packet_type(feed, buf);
else if (feed->pid == 0x2000)
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
&feed->buffer_flags);
}
}
@ -592,7 +619,16 @@ void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
spin_lock_irqsave(&demux->lock, flags);
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts);
#if 1
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts,
&demux->feed->buffer_flags);
#else
struct dvb_demux_feed *feed;
list_for_each_entry(feed, &demux->feed_list, list_head) {
feed->cb.ts(buf, count, NULL, 0, &feed->feed.ts,
&feed->buffer_flags);
}
#endif
spin_unlock_irqrestore(&demux->lock, flags);
}
@ -792,6 +828,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
feed->demux = demux;
feed->pid = 0xffff;
feed->peslen = 0xfffa;
feed->buffer_flags = 0;
(*ts_feed) = &feed->feed.ts;
(*ts_feed)->parent = dmx;
@ -911,14 +948,14 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
return;
do {
sf = &f->filter;
doneq = 0;
doneq = false;
for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
mode = sf->filter_mode[i];
mask = sf->filter_mask[i];
f->maskandmode[i] = mask & mode;
doneq |= f->maskandnotmode[i] = mask & ~mode;
}
f->doneq = doneq ? 1 : 0;
f->doneq = doneq ? true : false;
} while ((f = f->next));
}
@ -945,6 +982,7 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
dvbdmxfeed->feed.sec.secbufp = 0;
dvbdmxfeed->feed.sec.seclen = 0;
dvbdmxfeed->pusi_seen = false;
if (!dvbdmx->start_feed) {
mutex_unlock(&dvbdmx->mutex);
@ -1049,6 +1087,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
dvbdmxfeed->cb.sec = callback;
dvbdmxfeed->demux = dvbdmx;
dvbdmxfeed->pid = 0xffff;
dvbdmxfeed->buffer_flags = 0;
dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
dvbdmxfeed->feed.sec.tsfeedp = 0;
@ -1220,12 +1259,25 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
dvbdemux->cnt_storage = NULL;
dvbdemux->users = 0;
dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0))
dvbdemux->filter = vmalloc(sizeof(struct dvb_demux_filter) *
dvbdemux->filternum);
if (!dvbdemux->filter)
return -ENOMEM;
dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed));
dvbdemux->feed = vmalloc(sizeof(struct dvb_demux_feed) *
dvbdemux->feednum);
#else
dvbdemux->filter = vmalloc(array_size(sizeof(struct dvb_demux_filter),
dvbdemux->filternum));
if (!dvbdemux->filter)
return -ENOMEM;
dvbdemux->feed = vmalloc(array_size(sizeof(struct dvb_demux_feed),
dvbdemux->feednum));
#endif
if (!dvbdemux->feed) {
vfree(dvbdemux->filter);
dvbdemux->filter = NULL;

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* dvb_net.c
*
@ -13,18 +14,6 @@
* and Wolfram Stering <wstering@cosy.sbg.ac.at>
*
* ULE Decaps according to RFC 4326.
*
* 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.
* To obtain the license, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
/*
@ -38,7 +27,7 @@
* Competence Center for Advanced Satellite Communications.
* Bugfixes and robustness improvements.
* Filtering on dest MAC addresses, if present (D-Bit = 0)
* ULE_DEBUG compile-time option.
* DVB_ULE_DEBUG compile-time option.
* Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by
* Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
* Paris Lodron University of Salzburg.
@ -69,8 +58,11 @@
#include <linux/mutex.h>
#include <linux/sched.h>
#include "dvb_demux.h"
#include "dvb_net.h"
#include <media/dvb_demux.h>
#include <media/dvb_net.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
#include <linux/nospec.h>
#endif
static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
{
@ -83,15 +75,20 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
#define DVB_NET_MULTICAST_MAX 10
#undef ULE_DEBUG
#undef DVB_ULE_DEBUG
#ifdef ULE_DEBUG
#ifdef DVB_ULE_DEBUG
/*
* The code inside DVB_ULE_DEBUG keeps a history of the
* last 100 TS cells processed.
*/
static unsigned char ule_hist[100*TS_SZ] = { 0 };
static unsigned char *ule_where = ule_hist, ule_dump;
static void hexdump(const unsigned char *buf, unsigned short len)
{
print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true);
}
#endif
struct dvb_net_priv {
@ -130,7 +127,7 @@ struct dvb_net_priv {
};
/**
/*
* Determine the packet's protocol ID. The rule here is that we
* assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol.
@ -160,7 +157,7 @@ static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
rawp = skb->data;
/**
/*
* This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
@ -169,7 +166,7 @@ static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
if (*(unsigned short *)rawp == 0xFFFF)
return htons(ETH_P_802_3);
/**
/*
* Real 802.2 LLC
*/
return htons(ETH_P_802_2);
@ -220,7 +217,8 @@ static int ule_exthdr_padding(struct dvb_net_priv *p)
return 0;
}
/** Handle ULE extension headers.
/*
* Handle ULE extension headers.
* Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
* Returns: >= 0: nr. of bytes consumed by next extension header
* -1: Mandatory extension header that is not recognized or TEST SNDU; discard.
@ -284,11 +282,9 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
if (l < 0)
return l; /* Stop extension header processing and discard SNDU. */
total_ext_len += l;
#ifdef ULE_DEBUG
pr_debug("ule_next_hdr=%p, ule_sndu_type=%i, l=%i, total_ext_len=%i\n",
p->ule_next_hdr, (int)p->ule_sndu_type,
l, total_ext_len);
#endif
} while (p->ule_sndu_type < ETH_P_802_3_MIN);
@ -296,7 +292,7 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
}
/** Prepare for a new ULE SNDU: reset the decoder state. */
/* Prepare for a new ULE SNDU: reset the decoder state. */
static inline void reset_ule( struct dvb_net_priv *p )
{
p->ule_skb = NULL;
@ -309,7 +305,7 @@ static inline void reset_ule( struct dvb_net_priv *p )
p->ule_bridged = 0;
}
/**
/*
* Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of
* TS cells of a single PID.
*/
@ -324,29 +320,21 @@ struct dvb_net_ule_handle {
const u8 *ts, *ts_end, *from_where;
u8 ts_remain, how_much, new_ts;
bool error;
#ifdef ULE_DEBUG
/*
* The code inside ULE_DEBUG keeps a history of the
* last 100 TS cells processed.
*/
static unsigned char ule_hist[100*TS_SZ];
static unsigned char *ule_where = ule_hist, ule_dump;
#endif
};
static int dvb_net_ule_new_ts_cell(struct dvb_net_ule_handle *h)
{
/* We are about to process a new TS cell. */
#ifdef ULE_DEBUG
if (h->ule_where >= &h->ule_hist[100*TS_SZ])
h->ule_where = h->ule_hist;
memcpy(h->ule_where, h->ts, TS_SZ);
if (h->ule_dump) {
hexdump(h->ule_where, TS_SZ);
h->ule_dump = 0;
#ifdef DVB_ULE_DEBUG
if (ule_where >= &ule_hist[100*TS_SZ])
ule_where = ule_hist;
memcpy(ule_where, h->ts, TS_SZ);
if (ule_dump) {
hexdump(ule_where, TS_SZ);
ule_dump = 0;
}
h->ule_where += TS_SZ;
ule_where += TS_SZ;
#endif
/*
@ -568,7 +556,7 @@ static int dvb_net_ule_new_payload(struct dvb_net_ule_handle *h)
h->priv->ule_sndu_type_1 = 1;
h->ts_remain -= 1;
h->from_where += 1;
/* fallthrough */
fallthrough;
case 0:
h->new_ts = 1;
h->ts += TS_SZ;
@ -664,6 +652,7 @@ static int dvb_net_ule_should_drop(struct dvb_net_ule_handle *h)
static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h,
struct kvec iov[3],
u32 ule_crc, u32 expected_crc)
{
u8 dest_addr[ETH_ALEN];
@ -675,25 +664,25 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h,
h->ts_remain,
h->ts_remain > 2 ?
*(unsigned short *)h->from_where : 0);
#ifdef ULE_DEBUG
#ifdef DVB_ULE_DEBUG
hexdump(iov[0].iov_base, iov[0].iov_len);
hexdump(iov[1].iov_base, iov[1].iov_len);
hexdump(iov[2].iov_base, iov[2].iov_len);
if (h->ule_where == h->ule_hist) {
hexdump(&h->ule_hist[98*TS_SZ], TS_SZ);
hexdump(&h->ule_hist[99*TS_SZ], TS_SZ);
} else if (h->ule_where == &h->ule_hist[TS_SZ]) {
hexdump(&h->ule_hist[99*TS_SZ], TS_SZ);
hexdump(h->ule_hist, TS_SZ);
if (ule_where == ule_hist) {
hexdump(&ule_hist[98*TS_SZ], TS_SZ);
hexdump(&ule_hist[99*TS_SZ], TS_SZ);
} else if (ule_where == &ule_hist[TS_SZ]) {
hexdump(&ule_hist[99*TS_SZ], TS_SZ);
hexdump(ule_hist, TS_SZ);
} else {
hexdump(h->ule_where - TS_SZ - TS_SZ, TS_SZ);
hexdump(h->ule_where - TS_SZ, TS_SZ);
hexdump(ule_where - TS_SZ - TS_SZ, TS_SZ);
hexdump(ule_where - TS_SZ, TS_SZ);
}
h->ule_dump = 1;
#endif
ule_dump = 1;
#endif
h->dev->stats.rx_errors++;
h->dev->stats.rx_crc_errors++;
dev_kfree_skb(h->priv->ule_skb);
@ -709,11 +698,9 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h,
if (!h->priv->ule_dbit) {
if (dvb_net_ule_should_drop(h)) {
#ifdef ULE_DEBUG
netdev_dbg(h->dev,
"Dropping SNDU: MAC destination address does not match: dest addr: %pM, h->dev addr: %pM\n",
h->priv->ule_skb->data, h->dev->dev_addr);
#endif
dev_kfree_skb(h->priv->ule_skb);
return;
}
@ -783,6 +770,8 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
int ret;
struct dvb_net_ule_handle h = {
.dev = dev,
.priv = netdev_priv(dev),
.ethh = NULL,
.buf = buf,
.buf_len = buf_len,
.skipped = 0L,
@ -792,11 +781,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
.ts_remain = 0,
.how_much = 0,
.new_ts = 1,
.ethh = NULL,
.error = false,
#ifdef ULE_DEBUG
.ule_where = ule_hist,
#endif
};
/*
@ -868,7 +853,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
*(tail - 2) << 8 |
*(tail - 1);
dvb_net_ule_check_crc(&h, ule_crc, expected_crc);
dvb_net_ule_check_crc(&h, iov, ule_crc, expected_crc);
/* Prepare for next SNDU. */
reset_ule(h.priv);
@ -901,7 +886,8 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len,
struct dmx_ts_feed *feed)
struct dmx_ts_feed *feed,
u32 *buffer_flags)
{
struct net_device *dev = feed->priv;
@ -1010,11 +996,11 @@ static void dvb_net_sec(struct net_device *dev,
static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len,
struct dmx_section_filter *filter)
struct dmx_section_filter *filter, u32 *buffer_flags)
{
struct net_device *dev = filter->priv;
/**
/*
* we rely on the DVB API definition where exactly one complete
* section is delivered in buffer1
*/
@ -1022,7 +1008,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
return 0;
}
static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
static netdev_tx_t dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
{
dev_kfree_skb(skb);
return NETDEV_TX_OK;
@ -1035,7 +1021,7 @@ static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static int dvb_net_filter_sec_set(struct net_device *dev,
struct dmx_section_filter **secfilter,
u8 *mac, u8 *mac_mask)
const u8 *mac, u8 *mac_mask)
{
struct dvb_net_priv *priv = netdev_priv(dev);
int ret;
@ -1079,7 +1065,7 @@ static int dvb_net_feed_start(struct net_device *dev)
int ret = 0, i;
struct dvb_net_priv *priv = netdev_priv(dev);
struct dmx_demux *demux = priv->demux;
unsigned char *mac = (unsigned char *) dev->dev_addr;
const unsigned char *mac = (const unsigned char *) dev->dev_addr;
netdev_dbg(dev, "rx_mode %i\n", priv->rx_mode);
mutex_lock(&priv->mutex);
@ -1299,7 +1285,11 @@ static int dvb_net_set_mac (struct net_device *dev, void *p)
struct dvb_net_priv *priv = netdev_priv(dev);
struct sockaddr *addr=p;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0))
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
#else
eth_hw_addr_set(dev, addr->sa_data);
#endif
if (netif_running(dev))
schedule_work(&priv->restart_net_feed_wq);
@ -1398,8 +1388,11 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
dvbnet->dvbdev->adapter->num, if_num);
net->addr_len = 6;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0))
memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6);
#else
eth_hw_addr_set(net, dvbnet->dvbdev->adapter->proposed_mac);
#endif
dvbnet->device[if_num] = net;
priv = netdev_priv(net);
@ -1494,14 +1487,21 @@ static int dvb_net_do_ioctl(struct file *file,
struct net_device *netdev;
struct dvb_net_priv *priv_data;
struct dvb_net_if *dvbnetif = parg;
int if_num = dvbnetif->if_num;
if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
!dvbnet->state[dvbnetif->if_num]) {
if (if_num >= DVB_NET_DEVICES_MAX) {
ret = -EINVAL;
goto ioctl_error;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
if_num = array_index_nospec(if_num, DVB_NET_DEVICES_MAX);
#endif
if (!dvbnet->state[if_num]) {
ret = -EINVAL;
goto ioctl_error;
}
netdev = dvbnet->device[dvbnetif->if_num];
netdev = dvbnet->device[if_num];
priv_data = netdev_priv(netdev);
dvbnetif->pid=priv_data->pid;
@ -1554,14 +1554,21 @@ static int dvb_net_do_ioctl(struct file *file,
struct net_device *netdev;
struct dvb_net_priv *priv_data;
struct __dvb_net_if_old *dvbnetif = parg;
int if_num = dvbnetif->if_num;
if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
!dvbnet->state[dvbnetif->if_num]) {
if (if_num >= DVB_NET_DEVICES_MAX) {
ret = -EINVAL;
goto ioctl_error;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
if_num = array_index_nospec(if_num, DVB_NET_DEVICES_MAX);
#endif
if (!dvbnet->state[if_num]) {
ret = -EINVAL;
goto ioctl_error;
}
netdev = dvbnet->device[dvbnetif->if_num];
netdev = dvbnet->device[if_num];
priv_data = netdev_priv(netdev);
dvbnetif->pid=priv_data->pid;
@ -1583,15 +1590,43 @@ static long dvb_net_ioctl(struct file *file,
return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
}
static int locked_dvb_net_open(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_net *dvbnet = dvbdev->priv;
int ret;
if (mutex_lock_interruptible(&dvbnet->remove_mutex))
return -ERESTARTSYS;
if (dvbnet->exit) {
mutex_unlock(&dvbnet->remove_mutex);
return -ENODEV;
}
ret = dvb_generic_open(inode, file);
mutex_unlock(&dvbnet->remove_mutex);
return ret;
}
static int dvb_net_close(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_net *dvbnet = dvbdev->priv;
mutex_lock(&dvbnet->remove_mutex);
dvb_generic_release(inode, file);
if(dvbdev->users == 1 && dvbnet->exit == 1)
if (dvbdev->users == 1 && dvbnet->exit == 1) {
mutex_unlock(&dvbnet->remove_mutex);
wake_up(&dvbdev->wait_queue);
} else {
mutex_unlock(&dvbnet->remove_mutex);
}
return 0;
}
@ -1599,7 +1634,7 @@ static int dvb_net_close(struct inode *inode, struct file *file)
static const struct file_operations dvb_net_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = dvb_net_ioctl,
.open = dvb_generic_open,
.open = locked_dvb_net_open,
.release = dvb_net_close,
.llseek = noop_llseek,
};
@ -1618,10 +1653,13 @@ void dvb_net_release (struct dvb_net *dvbnet)
{
int i;
mutex_lock(&dvbnet->remove_mutex);
dvbnet->exit = 1;
mutex_unlock(&dvbnet->remove_mutex);
if (dvbnet->dvbdev->users < 1)
wait_event(dvbnet->dvbdev->wait_queue,
dvbnet->dvbdev->users==1);
dvbnet->dvbdev->users == 1);
dvb_unregister_device(dvbnet->dvbdev);
@ -1640,6 +1678,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
int i;
mutex_init(&dvbnet->ioctl_mutex);
mutex_init(&dvbnet->remove_mutex);
dvbnet->demux = dmx;
for (i=0; i<DVB_NET_DEVICES_MAX; i++)

View File

@ -1,63 +0,0 @@
/*
* dvb_net.h
*
* Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _DVB_NET_H_
#define _DVB_NET_H_
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include "dvbdev.h"
#define DVB_NET_DEVICES_MAX 10
#ifdef CONFIG_DVB_NET
struct dvb_net {
struct dvb_device *dvbdev;
struct net_device *device[DVB_NET_DEVICES_MAX];
int state[DVB_NET_DEVICES_MAX];
unsigned int exit:1;
struct dmx_demux *demux;
struct mutex ioctl_mutex;
};
void dvb_net_release(struct dvb_net *);
int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
#else
struct dvb_net {
struct dvb_device *dvbdev;
};
static inline void dvb_net_release(struct dvb_net *dvbnet)
{
}
static inline int dvb_net_init(struct dvb_adapter *adap,
struct dvb_net *dvbnet, struct dmx_demux *dmx)
{
return 0;
}
#endif /* ifdef CONFIG_DVB_NET */
#endif

View File

@ -34,7 +34,7 @@
#include <linux/uaccess.h>
#endif
#include "dvb_ringbuffer.h"
#include <media/dvb_ringbuffer.h>
#define PKT_READY 0
#define PKT_DISPOSED 1
@ -63,7 +63,7 @@ int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
* 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
* for memory barriers also see Documentation/core-api/circular-buffers.rst
*/
return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
#endif
@ -75,7 +75,7 @@ ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
{
ssize_t free;
/* ACCESS_ONCE() to load read pointer on writer side
/* READ_ONCE() to load read pointer on writer side
* this pairs with smp_store_release() in dvb_ringbuffer_read(),
* dvb_ringbuffer_read_user(), dvb_ringbuffer_flush(),
* or dvb_ringbuffer_reset()
@ -115,7 +115,7 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pread = smp_load_acquire(&rbuf->pwrite;
rbuf->pread = rbuf->pwrite;
#else
/* dvb_ringbuffer_flush() counts as read operation
* smp_load_acquire() to load write pointer
@ -171,7 +171,7 @@ ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, si
#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()
* this pairs with READ_ONCE() in dvb_ringbuffer_free()
*/
smp_store_release(&rbuf->pread, 0);
#endif
@ -203,7 +203,7 @@ void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
#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()
* this pairs with READ_ONCE() in dvb_ringbuffer_free()
*/
smp_store_release(&rbuf->pread, 0);
#endif
@ -391,7 +391,9 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t*
idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
}
consumed = (idx - rbuf->pread) % rbuf->size;
consumed = (idx - rbuf->pread);
if (consumed < 0)
consumed += rbuf->size;
while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {

448
dvb-core/dvb_vb2.c Normal file
View File

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

View File

@ -1,20 +1,10 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* dvbdev.c
*
* Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#define pr_fmt(fmt) "dvbdev: " fmt
@ -24,6 +14,7 @@
#include <linux/string.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
@ -31,7 +22,7 @@
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/version.h>
#include "dvbdev.h"
#include <media/dvbdev.h>
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0))
/* Due to enum tuner_pad_index */
@ -39,6 +30,7 @@
#endif
static DEFINE_MUTEX(dvbdev_mutex);
static LIST_HEAD(dvbdevfops_list);
static int dvbdev_debug;
module_param(dvbdev_debug, int, 0644);
@ -54,17 +46,47 @@ static LIST_HEAD(dvb_adapter_list);
static DEFINE_MUTEX(dvbdev_register_lock);
static const char * const dnames[] = {
"video", "audio", "sec", "frontend", "demux", "dvr", "ca",
"net", "osd", "ci", "mod", "ns", "nsd"
[DVB_DEVICE_VIDEO] = "video",
[DVB_DEVICE_AUDIO] = "audio",
[DVB_DEVICE_SEC] = "sec",
[DVB_DEVICE_FRONTEND] = "frontend",
[DVB_DEVICE_DEMUX] = "demux",
[DVB_DEVICE_DVR] = "dvr",
[DVB_DEVICE_CA] = "ca",
[DVB_DEVICE_NET] = "net",
[DVB_DEVICE_OSD] = "osd",
[DVB_DEVICE_CI] = "ci",
[DVB_DEVICE_MOD] = "mod",
[DVB_DEVICE_NS] = "ns",
[DVB_DEVICE_NSD] = "nsd",
};
#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 MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
static const u8 minor_type[] = {
[DVB_DEVICE_VIDEO] = 0,
[DVB_DEVICE_AUDIO] = 1,
[DVB_DEVICE_SEC] = 2,
[DVB_DEVICE_FRONTEND] = 3,
[DVB_DEVICE_DEMUX] = 4,
[DVB_DEVICE_DVR] = 5,
[DVB_DEVICE_CA] = 6,
[DVB_DEVICE_NET] = 7,
[DVB_DEVICE_OSD] = 8,
[DVB_DEVICE_CI] = 9,
[DVB_DEVICE_MOD] = 10,
[DVB_DEVICE_NS] = 11,
[DVB_DEVICE_NSD] = 12,
};
#define nums2minor(num, type, id) \
(((num) << 6) | ((id) << 4) | minor_type[type])
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS * 64)
#endif
static struct class *dvb_class;
@ -87,7 +109,7 @@ static int dvb_device_open(struct inode *inode, struct file *file)
new_fops = fops_get(dvbdev->fops);
if (!new_fops)
goto fail;
file->private_data = dvbdev;
file->private_data = dvb_device_get(dvbdev);
replace_fops(file, new_fops);
if (file->f_op->open)
err = file->f_op->open(inode, file);
@ -101,9 +123,7 @@ fail:
return -ENODEV;
}
static const struct file_operations dvb_device_fops =
{
static const struct file_operations dvb_device_fops = {
.owner = THIS_MODULE,
.open = dvb_device_open,
.llseek = noop_llseek,
@ -114,29 +134,38 @@ static struct cdev dvb_device_cdev;
int dvb_generic_open(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
int ret = 0;
if (!dvbdev)
return -ENODEV;
if (!dvbdev->users)
return -EBUSY;
mutex_lock(&dvbdev->lock);
if (!dvbdev->users) {
ret = -EBUSY;
goto unlock;
}
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
if (!dvbdev->readers)
return -EBUSY;
if (!dvbdev->readers) {
ret = -EBUSY;
goto unlock;
}
dvbdev->readers--;
} else {
if (!dvbdev->writers)
return -EBUSY;
if (!dvbdev->writers) {
ret = -EBUSY;
goto unlock;
}
dvbdev->writers--;
}
dvbdev->users--;
return 0;
unlock:
mutex_unlock(&dvbdev->lock);
return ret;
}
EXPORT_SYMBOL(dvb_generic_open);
int dvb_generic_release(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
@ -144,18 +173,21 @@ int dvb_generic_release(struct inode *inode, struct file *file)
if (!dvbdev)
return -ENODEV;
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
mutex_lock(&dvbdev->lock);
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
dvbdev->readers++;
} else {
else
dvbdev->writers++;
}
dvbdev->users++;
mutex_unlock(&dvbdev->lock);
dvb_device_put(dvbdev);
return 0;
}
EXPORT_SYMBOL(dvb_generic_release);
long dvb_generic_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@ -171,13 +203,13 @@ long dvb_generic_ioctl(struct file *file,
}
EXPORT_SYMBOL(dvb_generic_ioctl);
static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
static int dvbdev_get_free_id(struct dvb_adapter *adap, int type)
{
u32 id = 0;
while (id < DVB_MAX_IDS) {
struct dvb_device *dev;
list_for_each_entry(dev, &adap->device_list, list_head)
if (dev->type == type && dev->id == id)
goto skip;
@ -221,6 +253,7 @@ static void dvb_media_device_free(struct dvb_device *dvbdev)
if (dvbdev->adapter->conn) {
media_device_unregister_entity(dvbdev->adapter->conn);
kfree(dvbdev->adapter->conn);
dvbdev->adapter->conn = NULL;
kfree(dvbdev->adapter->conn_pads);
dvbdev->adapter->conn_pads = NULL;
@ -230,9 +263,9 @@ static void dvb_media_device_free(struct dvb_device *dvbdev)
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
const char *name, int npads)
const char *name, int npads)
{
int i, ret = 0;
int i;
dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads),
GFP_KERNEL);
@ -249,6 +282,7 @@ static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
for (i = 0; i < npads; i++) {
struct media_pad *pads = &dvbdev->tsout_pads[i];
struct media_entity *entity = &dvbdev->tsout_entity[i];
int ret;
entity->name = kasprintf(GFP_KERNEL, "%s #%d", name, i);
if (!entity->name)
@ -319,8 +353,11 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
if (npads) {
dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
GFP_KERNEL);
if (!dvbdev->pads)
if (!dvbdev->pads) {
kfree(dvbdev->entity);
dvbdev->entity = NULL;
return -ENOMEM;
}
}
switch (type) {
@ -368,7 +405,7 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
static int dvb_register_media_device(struct dvb_device *dvbdev,
int type, int minor,
unsigned demux_sink_pads)
unsigned int demux_sink_pads)
{
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
struct media_link *link;
@ -420,8 +457,10 @@ static int dvb_register_media_device(struct dvb_device *dvbdev,
if (!dvbdev->entity)
return 0;
link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf,
MEDIA_LNK_FL_ENABLED);
link = media_create_intf_link(dvbdev->entity,
&dvbdev->intf_devnode->intf,
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (!link)
return -ENOMEM;
#endif
@ -429,18 +468,20 @@ static int dvb_register_media_device(struct dvb_device *dvbdev,
}
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)
const struct dvb_device *template, void *priv,
enum dvb_device_type type, int demux_sink_pads)
{
struct dvb_device *dvbdev;
struct file_operations *dvbdevfops;
struct file_operations *dvbdevfops = NULL;
struct dvbdevfops_node *node = NULL, *new_node = NULL;
struct device *clsdev;
int minor;
int id, ret;
mutex_lock(&dvbdev_register_lock);
if ((id = dvbdev_get_free_id (adap, type)) < 0){
id = dvbdev_get_free_id(adap, type);
if (id < 0) {
mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL;
pr_err("%s: couldn't find free device id\n", __func__);
@ -448,41 +489,69 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
}
*pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
if (!dvbdev){
if (!dvbdev) {
mutex_unlock(&dvbdev_register_lock);
return -ENOMEM;
}
dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
/*
* When a device of the same type is probe()d more than once,
* the first allocated fops are used. This prevents memory leaks
* that can occur when the same device is probe()d repeatedly.
*/
list_for_each_entry(node, &dvbdevfops_list, list_head) {
if (node->fops->owner == adap->module &&
node->type == type && node->template == template) {
dvbdevfops = node->fops;
break;
}
}
if (!dvbdevfops){
kfree (dvbdev);
mutex_unlock(&dvbdev_register_lock);
return -ENOMEM;
if (!dvbdevfops) {
dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
if (!dvbdevfops) {
kfree(dvbdev);
mutex_unlock(&dvbdev_register_lock);
return -ENOMEM;
}
new_node = kzalloc(sizeof(*new_node), GFP_KERNEL);
if (!new_node) {
kfree(dvbdevfops);
kfree(dvbdev);
mutex_unlock(&dvbdev_register_lock);
return -ENOMEM;
}
new_node->fops = dvbdevfops;
new_node->type = type;
new_node->template = template;
list_add_tail(&new_node->list_head, &dvbdevfops_list);
}
memcpy(dvbdev, template, sizeof(struct dvb_device));
kref_init(&dvbdev->ref);
dvbdev->type = type;
dvbdev->id = id;
dvbdev->adapter = adap;
dvbdev->priv = priv;
dvbdev->fops = dvbdevfops;
init_waitqueue_head (&dvbdev->wait_queue);
memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
mutex_init(&dvbdev->lock);
init_waitqueue_head(&dvbdev->wait_queue);
dvbdevfops->owner = adap->module;
list_add_tail (&dvbdev->list_head, &adap->device_list);
list_add_tail(&dvbdev->list_head, &adap->device_list);
down_write(&minor_rwsem);
#ifdef CONFIG_DVB_DYNAMIC_MINORS
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
if (dvb_minors[minor] == NULL)
if (!dvb_minors[minor])
break;
if (minor == MAX_DVB_MINORS) {
kfree(dvbdevfops);
if (new_node) {
list_del(&new_node->list_head);
kfree(dvbdevfops);
kfree(new_node);
}
list_del(&dvbdev->list_head);
kfree(dvbdev);
up_write(&minor_rwsem);
mutex_unlock(&dvbdev_register_lock);
@ -491,42 +560,51 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
#else
minor = nums2minor(adap->num, type, id);
#endif
dvbdev->minor = minor;
dvb_minors[minor] = dvbdev;
dvb_minors[minor] = dvb_device_get(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__);
__func__);
if (new_node) {
list_del(&new_node->list_head);
kfree(dvbdevfops);
kfree(new_node);
}
dvb_media_device_free(dvbdev);
kfree(dvbdevfops);
list_del(&dvbdev->list_head);
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)) {
pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
if (new_node) {
list_del(&new_node->list_head);
kfree(dvbdevfops);
kfree(new_node);
}
dvb_media_device_free(dvbdev);
list_del(&dvbdev->list_head);
kfree(dvbdev);
mutex_unlock(&dvbdev_register_lock);
return PTR_ERR(clsdev);
}
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, minor, minor);
mutex_unlock(&dvbdev_register_lock);
return 0;
}
EXPORT_SYMBOL(dvb_register_device);
void dvb_remove_device(struct dvb_device *dvbdev)
{
if (!dvbdev)
@ -534,36 +612,44 @@ void dvb_remove_device(struct dvb_device *dvbdev)
down_write(&minor_rwsem);
dvb_minors[dvbdev->minor] = NULL;
dvb_device_put(dvbdev);
up_write(&minor_rwsem);
dvb_media_device_free(dvbdev);
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
list_del (&dvbdev->list_head);
list_del(&dvbdev->list_head);
}
EXPORT_SYMBOL(dvb_remove_device);
void dvb_free_device(struct dvb_device *dvbdev)
static void dvb_free_device(struct kref *ref)
{
if (!dvbdev)
return;
struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref);
kfree (dvbdev->fops);
kfree (dvbdev);
kfree(dvbdev);
}
EXPORT_SYMBOL(dvb_free_device);
struct dvb_device *dvb_device_get(struct dvb_device *dvbdev)
{
kref_get(&dvbdev->ref);
return dvbdev;
}
EXPORT_SYMBOL(dvb_device_get);
void dvb_device_put(struct dvb_device *dvbdev)
{
if (dvbdev)
kref_put(&dvbdev->ref, dvb_free_device);
}
void dvb_unregister_device(struct dvb_device *dvbdev)
{
dvb_remove_device(dvbdev);
dvb_free_device(dvbdev);
dvb_device_put(dvbdev);
}
EXPORT_SYMBOL(dvb_unregister_device);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
static int dvb_create_io_intf_links(struct dvb_adapter *adap,
@ -579,7 +665,8 @@ static int dvb_create_io_intf_links(struct dvb_adapter *adap,
if (strncmp(entity->name, name, strlen(name)))
continue;
link = media_create_intf_link(entity, intf,
MEDIA_LNK_FL_ENABLED);
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (!link)
return -ENOMEM;
}
@ -595,10 +682,10 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
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;
unsigned int demux_pad = 0;
unsigned int dvr_pad = 0;
unsigned int ntuner = 0, ndemod = 0;
int ret, pad_source, pad_sink;
static const char *connector_name = "Television";
if (!mdev)
@ -658,7 +745,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
if (ret)
return ret;
if (!ntuner)
if (!ntuner) {
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
@ -666,22 +753,41 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
demod, 0,
MEDIA_LNK_FL_ENABLED,
false);
else
} else {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
pad_sink = media_get_pad_index(tuner, MEDIA_PAD_FL_SINK,
PAD_SIGNAL_ANALOG);
if (pad_sink < 0)
return -EINVAL;
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
MEDIA_ENT_F_TUNER,
tuner, TUNER_PAD_RF_INPUT,
tuner, pad_sink,
MEDIA_LNK_FL_ENABLED,
false);
#else
pad_sink = TUNER_PAD_RF_INPUT;
#endif
}
if (ret)
return ret;
}
if (ntuner && ndemod) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
/* NOTE: first found tuner source pad presumed correct */
pad_source = media_get_pad_index(tuner, MEDIA_PAD_FL_SOURCE,
PAD_SIGNAL_ANALOG);
if (pad_source < 0)
return -EINVAL;
#else
pad_source = TUNER_PAD_OUTPUT;
#endif
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_TUNER,
tuner, TUNER_PAD_OUTPUT,
tuner, pad_source,
MEDIA_ENT_F_DTV_DEMOD,
demod, 0, MEDIA_LNK_FL_ENABLED,
false);
@ -711,18 +817,18 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
media_device_for_each_entity(entity, mdev) {
if (entity->function == MEDIA_ENT_F_IO_DTV) {
if (!strncmp(entity->name, DVR_TSOUT,
strlen(DVR_TSOUT))) {
strlen(DVR_TSOUT))) {
ret = media_create_pad_link(demux,
++dvr_pad,
entity, 0, 0);
++dvr_pad,
entity, 0, 0);
if (ret)
return ret;
}
if (!strncmp(entity->name, DEMUX_TSOUT,
strlen(DEMUX_TSOUT))) {
strlen(DEMUX_TSOUT))) {
ret = media_create_pad_link(demux,
++demux_pad,
entity, 0, 0);
++demux_pad,
entity, 0, 0);
if (ret)
return ret;
}
@ -734,14 +840,16 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
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);
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (!link)
return -ENOMEM;
}
if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) {
link = media_create_intf_link(tuner, intf,
MEDIA_LNK_FL_ENABLED);
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (!link)
return -ENOMEM;
}
@ -753,7 +861,8 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
*/
if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) {
link = media_create_intf_link(demux, intf,
MEDIA_LNK_FL_ENABLED);
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (!link)
return -ENOMEM;
}
@ -777,8 +886,10 @@ EXPORT_SYMBOL_GPL(dvb_create_media_graph);
static int dvbdev_check_free_adapter_num(int num)
{
struct list_head *entry;
list_for_each(entry, &dvb_adapter_list) {
struct dvb_adapter *adap;
adap = list_entry(entry, struct dvb_adapter, list_head);
if (adap->num == num)
return 0;
@ -786,7 +897,7 @@ static int dvbdev_check_free_adapter_num(int num)
return 1;
}
static int dvbdev_get_free_adapter_num (void)
static int dvbdev_get_free_adapter_num(void)
{
int num = 0;
@ -799,7 +910,6 @@ static int dvbdev_get_free_adapter_num (void)
return -ENFILE;
}
int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
struct module *module, struct device *device,
short *adapter_nums)
@ -826,8 +936,8 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
return -ENFILE;
}
memset (adap, 0, sizeof(struct dvb_adapter));
INIT_LIST_HEAD (&adap->device_list);
memset(adap, 0, sizeof(struct dvb_adapter));
INIT_LIST_HEAD(&adap->device_list);
pr_info("DVB: registering new adapter (%s)\n", name);
@ -837,9 +947,13 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
adap->device = device;
adap->mfe_shared = 0;
adap->mfe_dvbdev = NULL;
mutex_init (&adap->mfe_lock);
mutex_init(&adap->mfe_lock);
list_add_tail (&adap->list_head, &dvb_adapter_list);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
mutex_init(&adap->mdev_lock);
#endif
list_add_tail(&adap->list_head, &dvb_adapter_list);
mutex_unlock(&dvbdev_register_lock);
@ -847,25 +961,26 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
}
EXPORT_SYMBOL(dvb_register_adapter);
int dvb_unregister_adapter(struct dvb_adapter *adap)
{
mutex_lock(&dvbdev_register_lock);
list_del (&adap->list_head);
list_del(&adap->list_head);
mutex_unlock(&dvbdev_register_lock);
return 0;
}
EXPORT_SYMBOL(dvb_unregister_adapter);
/* if the miracle happens and "generic_usercopy()" is included into
the kernel, then this can vanish. please don't make the mistake and
define this as video_usercopy(). this will introduce a dependecy
to the v4l "videodev.o" module, which is unnecessary for some
cards (ie. the budget dvb-cards don't need the v4l module...) */
/*
* if the miracle happens and "generic_usercopy()" is included into
* the kernel, then this can vanish. please don't make the mistake and
* define this as video_usercopy(). this will introduce a dependency
* to the v4l "videodev.o" module, which is unnecessary for some
* cards (ie. the budget dvb-cards don't need the v4l module...)
*/
int dvb_usercopy(struct file *file,
unsigned int cmd, unsigned long arg,
int (*func)(struct file *file,
unsigned int cmd, void *arg))
unsigned int cmd, unsigned long arg,
int (*func)(struct file *file,
unsigned int cmd, void *arg))
{
char sbuf[128];
void *mbuf = NULL;
@ -879,7 +994,7 @@ int dvb_usercopy(struct file *file,
* For this command, the pointer is actually an integer
* argument.
*/
parg = (void *) arg;
parg = (void *)arg;
break;
case _IOC_READ: /* some v4l ioctls are marked wrong ... */
case _IOC_WRITE:
@ -889,7 +1004,7 @@ int dvb_usercopy(struct file *file,
} else {
/* too big to allocate from stack */
mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
if (NULL == mbuf)
if (!mbuf)
return -ENOMEM;
parg = mbuf;
}
@ -901,15 +1016,15 @@ int dvb_usercopy(struct file *file,
}
/* call driver */
if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
err = func(file, cmd, parg);
if (err == -ENOIOCTLCMD)
err = -ENOTTY;
if (err < 0)
goto out;
/* Copy results into user buffer */
switch (_IOC_DIR(cmd))
{
switch (_IOC_DIR(cmd)) {
case _IOC_READ:
case (_IOC_WRITE | _IOC_READ):
if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
@ -921,11 +1036,65 @@ out:
kfree(mbuf);
return err;
}
EXPORT_SYMBOL(dvb_usercopy);
static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
#if IS_ENABLED(CONFIG_I2C)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0))
struct i2c_client *dvb_module_probe(const char *module_name,
const char *name,
struct i2c_adapter *adap,
unsigned char addr,
void *platform_data)
{
struct dvb_device *dvbdev = dev_get_drvdata(dev);
struct i2c_client *client;
struct i2c_board_info *board_info;
board_info = kzalloc(sizeof(*board_info), GFP_KERNEL);
if (!board_info)
return NULL;
if (name)
strscpy(board_info->type, name, I2C_NAME_SIZE);
else
strscpy(board_info->type, module_name, I2C_NAME_SIZE);
board_info->addr = addr;
board_info->platform_data = platform_data;
request_module(module_name);
client = i2c_new_client_device(adap, board_info);
if (!i2c_client_has_driver(client)) {
kfree(board_info);
return NULL;
}
if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client);
client = NULL;
}
kfree(board_info);
return client;
}
EXPORT_SYMBOL_GPL(dvb_module_probe);
void dvb_module_release(struct i2c_client *client)
{
if (!client)
return;
module_put(client->dev.driver->owner);
i2c_unregister_device(client);
}
EXPORT_SYMBOL_GPL(dvb_module_release);
#endif
#endif
#if (KERNEL_VERSION(6, 2, 0) > LINUX_VERSION_CODE)
static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
#else
static int dvb_uevent(const struct device *dev, struct kobj_uevent_env *env)
#endif
{
const struct dvb_device *dvbdev = dev_get_drvdata(dev);
add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]);
@ -933,9 +1102,13 @@ static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
#if (KERNEL_VERSION(6, 2, 0) > LINUX_VERSION_CODE)
static char *dvb_devnode(struct device *dev, umode_t *mode)
#else
static char *dvb_devnode(const struct device *dev, umode_t *mode)
#endif
{
struct dvb_device *dvbdev = dev_get_drvdata(dev);
const struct dvb_device *dvbdev = dev_get_drvdata(dev);
return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);
@ -947,18 +1120,24 @@ static int __init init_dvbdev(void)
int retval;
dev_t dev = MKDEV(DVB_MAJOR, 0);
if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB");
if (retval != 0) {
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) {
retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS);
if (retval != 0) {
pr_err("dvb-core: unable register character device\n");
goto error;
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0))
dvb_class = class_create(THIS_MODULE, "dvb");
#else
dvb_class = class_create("dvb");
#endif
if (IS_ERR(dvb_class)) {
retval = PTR_ERR(dvb_class);
goto error;
@ -973,12 +1152,19 @@ error:
return retval;
}
static void __exit exit_dvbdev(void)
{
struct dvbdevfops_node *node, *next;
class_destroy(dvb_class);
cdev_del(&dvb_device_cdev);
unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
list_for_each_entry_safe(node, next, &dvbdevfops_list, list_head) {
list_del(&node->list_head);
kfree(node->fops);
kfree(node);
}
}
subsys_initcall(init_dvbdev);

View File

@ -9,6 +9,7 @@ EXTRA_CFLAGS += -DCONFIG_DVB_STV6110x
EXTRA_CFLAGS += -DCONFIG_DVB_STV0367DD
#EXTRA_CFLAGS += -DCONFIG_DVB_TDA18212
EXTRA_CFLAGS += -DCONFIG_DVB_TDA18212DD
EXTRA_CFLAGS += -DCONFIG_DVB_TDA18271C2DD
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2843
EXTRA_CFLAGS += -DCONFIG_DVB_STV6111
EXTRA_CFLAGS += -DCONFIG_DVB_STV0910
@ -16,7 +17,6 @@ EXTRA_CFLAGS += -DCONFIG_DVB_LNBH25
EXTRA_CFLAGS += -DCONFIG_DVB_MXL5XX
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2099
EXTRA_CFLAGS += -DDBVALS
NOSTDINC_FLAGS += -I$(SUBDIRS)/include -I$(SUBDIRS)/dvb-core
drxk-objs := drxk_hard.o
obj-$(CONFIG_DVB_DRXK) += drxk.o

View File

@ -4,6 +4,7 @@
ccflags-y += -I$(srctree)/drivers/media/dvb-core/
ccflags-y += -I$(srctree)/drivers/media/tuners/
ccflags-y += --include=dd_compat.h
# FIXME: RTL2832 SDR driver uses power management directly from USB IF driver
ifdef CONFIG_DVB_RTL2832_SDR

View File

@ -590,6 +590,10 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
}
}
mutex_unlock(&ci->lock);
/* Ensure cam stability after reset */
msleep(2000);
return 0;
}
@ -776,8 +780,8 @@ struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
return &ci->en;
}
EXPORT_SYMBOL(cxd2099_attach);
EXPORT_SYMBOL_GPL(cxd2099_attach);
MODULE_DESCRIPTION("cxd2099");
MODULE_AUTHOR("Ralph Metzler");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

@ -25,7 +25,7 @@
#ifndef _CXD2099_H_
#define _CXD2099_H_
#include <dvb_ca_en50221.h>
#include <media/dvb_ca_en50221.h>
struct cxd2099_cfg {
u32 bitrate;

View File

@ -35,8 +35,12 @@
#include <linux/mutex.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
#include "dvb_math.h"
#include <media/dvb_frontend.h>
#if (KERNEL_VERSION(6, 6, 0) > LINUX_VERSION_CODE)
#include <media/dvb_math.h>
#else
#include <linux/int_log.h>
#endif
#include "cxd2843.h"
#define Log10x100(x) ((s32)(((((u64) intlog2(x) * 0x1e1a5e2e) >> 47 ) + 1) >> 1))
@ -54,6 +58,7 @@ struct cxd_state {
struct dvb_frontend frontend;
struct i2c_adapter *i2c;
struct mutex mutex;
int repi2cerr;
u8 adrt;
u8 curbankt;
@ -91,12 +96,13 @@ struct cxd_state {
u8 is24MHz;
};
static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len, int flag)
{
struct i2c_msg msg = {
.addr = adr, .flags = 0, .buf = data, .len = len};
if (i2c_transfer(adap, &msg, 1) != 1) {
pr_err("cxd2843: i2c_write error adr %02x data %02x\n", adr, data[0]);
if (flag)
pr_err("cxd2843: i2c_write error adr %02x data %02x\n", adr, data[0]);
return -1;
}
return 0;
@ -105,18 +111,22 @@ static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
static int writeregs(struct cxd_state *state, u8 adr, u8 reg,
u8 *regd, u16 len)
{
u8 data[len + 1];
u8 data[16];
if (len >= 15) {
pr_err("cxd2843: writeregs length %u too large\n", len);
return -1;
}
data[0] = reg;
memcpy(data + 1, regd, len);
return i2c_write(state->i2c, adr, data, len + 1);
return i2c_write(state->i2c, adr, data, len + 1, state->repi2cerr);
}
static int writereg(struct cxd_state *state, u8 adr, u8 reg, u8 dat)
{
u8 mm[2] = {reg, dat};
return i2c_write(state->i2c, adr, mm, 2);
return i2c_write(state->i2c, adr, mm, 2, state->repi2cerr);
}
static int i2c_read(struct i2c_adapter *adap,
@ -126,17 +136,19 @@ static int i2c_read(struct i2c_adapter *adap,
.buf = msg, .len = len},
{ .addr = adr, .flags = I2C_M_RD,
.buf = answ, .len = alen } };
if (i2c_transfer(adap, msgs, 2) != 2) {
pr_err("cxd2843: i2c_read error\n");
if (i2c_transfer(adap, msgs, 2) != 2)
return -1;
}
return 0;
}
static int readregs(struct cxd_state *state, u8 adr, u8 reg,
u8 *val, int count)
{
return i2c_read(state->i2c, adr, &reg, 1, val, count);
int ret = i2c_read(state->i2c, adr, &reg, 1, val, count);
if (ret && state->repi2cerr)
pr_err("cxd2843: i2c_read error\n");
return ret;
}
static int readregst_unlocked(struct cxd_state *cxd, u8 bank,
@ -355,6 +367,7 @@ static int read_tps(struct cxd_state *state, u8 *tps)
/* OFDMInfo[3] [3:0] OFDM_NDSYM[11:8] */
/* OFDMInfo[4] [7:0] OFDM_NDSYM[7:0] */
#if 0
static int read_t2_ofdm_info(struct cxd_state *state, u8 *ofdm)
{
if (state->last_status != 0x1f)
@ -365,6 +378,7 @@ static int read_t2_ofdm_info(struct cxd_state *state, u8 *ofdm)
unfreeze_regst(state);
return 0;
}
#endif
/* Read DVBT2 QAM,
Data PLP
@ -390,6 +404,7 @@ static int read_t2_ofdm_info(struct cxd_state *state, u8 *ofdm)
19-37 same for common PLP
*/
#if 0
static int read_t2_tlp_info(struct cxd_state *state, u8 off, u8 count, u8 *tlp)
{
if (state->last_status != 0x1f)
@ -400,6 +415,7 @@ static int read_t2_tlp_info(struct cxd_state *state, u8 off, u8 count, u8 *tlp)
unfreeze_regst(state);
return 0;
}
#endif
static void Active_to_Sleep(struct cxd_state *state)
{
@ -1636,7 +1652,7 @@ static void init_state(struct cxd_state *state, struct cxd2843_cfg *cfg)
/* IF Fullscale 0x50 = 1.4V, 0x39 = 1V, 0x28 = 0.7V */
state->IF_FS = 0x50;
state->is24MHz = (cfg->osc == 24000000) ? 1 : 0;
printk("is24Mhz = %u\n", state->is24MHz);
printk("is24Mhz = %u, adr = %02x\n", state->is24MHz, cfg->adr);
}
static int get_tune_settings(struct dvb_frontend *fe,
@ -2236,14 +2252,14 @@ static enum dvbfe_search search(struct dvb_frontend *fe)
return DVBFE_ALGO_SEARCH_AGAIN;
}
static int get_algo(struct dvb_frontend *fe)
static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{
return DVBFE_ALGO_HW;
}
static int get_fe_t2(struct cxd_state *state, struct dtv_frontend_properties *p)
{
struct dvb_frontend *fe = &state->frontend;
//struct dvb_frontend *fe = &state->frontend;
u8 ofdm[5], modcod[2];
freeze_regst(state);
@ -2343,7 +2359,7 @@ static int get_fe_t2(struct cxd_state *state, struct dtv_frontend_properties *p)
static int get_fe_t(struct cxd_state *state, struct dtv_frontend_properties *p)
{
struct dvb_frontend *fe = &state->frontend;
//struct dvb_frontend *fe = &state->frontend;
u8 tps[7];
read_tps(state, tps);
@ -2444,7 +2460,7 @@ static int get_fe_t(struct cxd_state *state, struct dtv_frontend_properties *p)
static int get_fe_c(struct cxd_state *state, struct dtv_frontend_properties *p)
{
struct dvb_frontend *fe = &state->frontend;
//struct dvb_frontend *fe = &state->frontend;
u8 qam;
freeze_regst(state);
@ -2485,9 +2501,9 @@ static struct dvb_frontend_ops common_ops_2854 = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2, SYS_DVBC2, SYS_ISDBT },
.info = {
.name = "CXD2854 DVB-C/C2 DVB-T/T2 ISDB-T",
.frequency_stepsize = 166667, /* DVB-T only */
.frequency_min = 47000000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */
.frequency_stepsize_hz = 166667, /* DVB-T only */
.frequency_min_hz = 47000000, /* DVB-T: 47125000 */
.frequency_max_hz = 865000000, /* DVB-C: 862000000 */
.symbol_rate_min = 870000,
.symbol_rate_max = 11700000,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
@ -2498,7 +2514,8 @@ static struct dvb_frontend_ops common_ops_2854 = {
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
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION |
FE_CAN_MULTISTREAM
},
.release = release,
.sleep = sleep,
@ -2518,9 +2535,9 @@ static struct dvb_frontend_ops common_ops_2843 = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2, SYS_DVBC2 },
.info = {
.name = "CXD2843 DVB-C/C2 DVB-T/T2",
.frequency_stepsize = 166667, /* DVB-T only */
.frequency_min = 47000000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */
.frequency_stepsize_hz = 166667, /* DVB-T only */
.frequency_min_hz = 47000000, /* DVB-T: 47125000 */
.frequency_max_hz = 865000000, /* DVB-C: 862000000 */
.symbol_rate_min = 870000,
.symbol_rate_max = 11700000,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
@ -2531,7 +2548,8 @@ static struct dvb_frontend_ops common_ops_2843 = {
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
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION |
FE_CAN_MULTISTREAM
},
.release = release,
.sleep = sleep,
@ -2556,9 +2574,9 @@ static struct dvb_frontend_ops common_ops_2837 = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2 },
.info = {
.name = "CXD2837 DVB-C DVB-T/T2",
.frequency_stepsize = 166667, /* DVB-T only */
.frequency_min = 47000000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */
.frequency_stepsize_hz = 166667, /* DVB-T only */
.frequency_min_hz = 47000000, /* DVB-T: 47125000 */
.frequency_max_hz = 865000000, /* DVB-C: 862000000 */
.symbol_rate_min = 870000,
.symbol_rate_max = 11700000,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
@ -2569,7 +2587,8 @@ static struct dvb_frontend_ops common_ops_2837 = {
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
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION |
FE_CAN_MULTISTREAM
},
.release = release,
.sleep = sleep,
@ -2594,9 +2613,9 @@ static struct dvb_frontend_ops common_ops_2838 = {
.delsys = { SYS_ISDBT },
.info = {
.name = "CXD2838 ISDB-T",
.frequency_stepsize = 166667,
.frequency_min = 47000000,
.frequency_max = 865000000,
.frequency_stepsize_hz = 166667,
.frequency_min_hz = 47000000,
.frequency_max_hz = 865000000,
.symbol_rate_min = 870000,
.symbol_rate_max = 11700000,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
@ -2635,8 +2654,9 @@ static int probe(struct cxd_state *state)
status = readregsx(state, 0x00, 0xFD, &ChipID, 1);
if (status)
return status;
printk("ChipID = %02X\n", ChipID);
state->repi2cerr = 1;
//pr_info("cxd2843: ChipID = %02X\n", ChipID);
switch (ChipID) {
case 0xa4:
state->type = CXD2843;
@ -2671,7 +2691,6 @@ struct dvb_frontend *cxd2843_attach(struct i2c_adapter *i2c,
{
struct cxd_state *state = NULL;
pr_info("attach\n");
state = kzalloc(sizeof(struct cxd_state), GFP_KERNEL);
if (!state)
return NULL;
@ -2686,8 +2705,8 @@ struct dvb_frontend *cxd2843_attach(struct i2c_adapter *i2c,
kfree(state);
return NULL;
}
EXPORT_SYMBOL(cxd2843_attach);
EXPORT_SYMBOL_GPL(cxd2843_attach);
MODULE_DESCRIPTION("CXD2843/37/38 driver");
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

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

View File

@ -30,7 +30,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include "dvb_frontend.h"
#include <media/dvb_frontend.h>
#include "lnbh25.h"
struct lnbh25 {
@ -106,6 +106,7 @@ static int lnbh25_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
return 0;
}
#if 0
static int lnbh25_set_tone(struct dvb_frontend *fe,
enum fe_sec_tone_mode tone)
{
@ -113,6 +114,7 @@ static int lnbh25_set_tone(struct dvb_frontend *fe,
return 0;
}
#endif
static int lnbh25_init(struct lnbh25 *lnbh)
{
@ -150,8 +152,8 @@ struct dvb_frontend *lnbh25_attach(struct dvb_frontend *fe,
return fe;
}
EXPORT_SYMBOL(lnbh25_attach);
EXPORT_SYMBOL_GPL(lnbh25_attach);
MODULE_DESCRIPTION("LNBH25");
MODULE_AUTHOR("Ralph Metzler");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

@ -32,7 +32,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include "dvb_frontend.h"
#include <media/dvb_frontend.h>
#include "lnbp21.h"
#include "lnbh24.h"
@ -178,7 +178,7 @@ struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
return lnbx2x_attach(fe, i2c, override_set, override_clear,
i2c_addr, LNBH24_TTX);
}
EXPORT_SYMBOL(lnbh24_attach);
EXPORT_SYMBOL_GPL(lnbh24_attach);
struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, u8 override_set,
@ -187,7 +187,7 @@ struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
return lnbx2x_attach(fe, i2c, override_set, override_clear,
0x08, LNBP21_ISEL);
}
EXPORT_SYMBOL(lnbp21_attach);
EXPORT_SYMBOL_GPL(lnbp21_attach);
MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24");
MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin");

View File

@ -39,9 +39,11 @@
#include <linux/mutex.h>
#include <linux/vmalloc.h>
#include <asm/div64.h>
#if (KERNEL_VERSION(6, 12, 0) > LINUX_VERSION_CODE)
#include <asm/unaligned.h>
#endif
#include "dvb_frontend.h"
#include <media/dvb_frontend.h>
#include "mxl5xx.h"
#include "mxl5xx_regs.h"
#include "mxl5xx_defs.h"
@ -98,26 +100,6 @@ struct mxl {
unsigned long tune_time;
};
static void le32_to_cpusn(u32 *data, u32 size)
{
u32 i;
for (i = 0; i < size; data++, i += 4)
le32_to_cpus(data);
}
static void flip_data_in_dword(u32 size, u8 *d)
{
u32 i;
u8 t;
for (i = 0; i < size; i += 4) {
t = d[i + 3]; d[i + 3] = d[i]; d[i] = t;
t = d[i + 2]; d[i + 2] = d[i + 1]; d[i + 1] = t;
}
}
static void convert_endian(u8 flag, u32 size, u8 *d)
{
u32 i;
@ -249,6 +231,7 @@ static int write_register(struct mxl *state, u32 reg, u32 val)
return stat;
}
#if 0
static int write_register_block(struct mxl *state, u32 reg,
u32 size, u8 *data)
{
@ -272,6 +255,7 @@ static int write_register_block(struct mxl *state, u32 reg,
mutex_unlock(&state->base->i2c_lock);
return stat;
}
#endif
static int write_firmware_block(struct mxl *state,
u32 reg, u32 size, u8 *regDataPtr)
@ -375,17 +359,6 @@ static int update_by_mnemonic(struct mxl *state,
return stat;
}
static void extract_from_mnemonic(u32 regAddr, u8 lsbPos, u8 width,
u32 *toAddr, u8 *toLsbPos, u8 *toWidth)
{
if (toAddr)
*toAddr = regAddr;
if (toLsbPos)
*toLsbPos = lsbPos;
if (toWidth)
*toWidth = width;
}
static int firmware_is_alive(struct mxl *state)
{
u32 hb0, hb1;
@ -395,8 +368,10 @@ static int firmware_is_alive(struct mxl *state)
msleep(20);
if (read_register(state, HYDRA_HEAR_BEAT, &hb1))
return 0;
if (hb1 == hb0)
if (hb1 == hb0) {
pr_warn("mxl5xx: Hydra FW not running!\n");
return 0;
}
return 1;
}
@ -419,7 +394,7 @@ static void release(struct dvb_frontend *fe)
kfree(state);
}
static int get_algo(struct dvb_frontend *fe)
static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{
return DVBFE_ALGO_HW;
}
@ -470,9 +445,9 @@ static int CfgDemodAbortTune(struct mxl *state)
&cmdBuff[0]);
}
#if 0
static int reset_fec_counter(struct mxl *state)
{
MXL_HYDRA_DEMOD_ABORT_TUNE_T abortTuneCmd;
u32 demodIndex = (u32) state->demod;
u8 cmdSize = sizeof(u32);
u8 cmdBuff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN];
@ -482,6 +457,7 @@ static int reset_fec_counter(struct mxl *state)
return send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE,
&cmdBuff[0]);
}
#endif
static int send_master_cmd(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd)
@ -686,9 +662,15 @@ 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:
p->block_error.len = 1;
p->block_error.stat[0].scale = FE_SCALE_COUNTER;
p->block_error.stat[0].uvalue = reg[1];
p->block_count.len = 1;
p->block_count.stat[0].scale = FE_SCALE_COUNTER;
p->block_count.stat[0].uvalue = reg[2];
break;
default:
break;
@ -806,6 +788,7 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
default:
break;
}
fallthrough;
case SYS_DVBS:
switch ((MXL_HYDRA_MODULATION_E)
regData[DMD_MODULATION_SCHEME_ADDR]) {
@ -842,21 +825,25 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
static int set_input(struct dvb_frontend *fe, int input)
{
struct mxl *state = fe->demodulator_priv;
#ifndef KERNEL_DVB_CORE
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
#endif
state->tuner = p->input = input;
state->tuner = input;
#ifndef KERNEL_DVB_CORE
p->input = input;
#endif
return 0;
}
static struct dvb_frontend_ops mxl_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
.info = {
.name = "MXL5XX",
.frequency_min = 300000,
.frequency_max = 2350000,
.frequency_stepsize = 0,
.frequency_tolerance = 0,
.frequency_min_hz = 300000000,
.frequency_max_hz = 2350000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 0,
.symbol_rate_min = 1000000,
.symbol_rate_max = 45000000,
.caps = FE_CAN_INVERSION_AUTO |
@ -875,7 +862,10 @@ static struct dvb_frontend_ops mxl_ops = {
.read_signal_strength = read_signal_strength,
.read_ucblocks = read_ucblocks,
.get_frontend = get_frontend,
#ifndef KERNEL_DVB_CORE
.set_input = set_input,
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
#endif
.diseqc_send_master_cmd = send_master_cmd,
};
@ -1118,8 +1108,6 @@ static int firmware_download(struct mxl *state, u8 *mbin, u32 mbin_len)
if (!firmware_is_alive(state))
return -1;
pr_info("mxl5xx: Hydra FW alive. Hail!\n");
/* sometimes register values are wrong shortly
after first heart beats */
msleep(50);
@ -1437,6 +1425,7 @@ static int config_ts(struct mxl *state, MXL_HYDRA_DEMOD_ID_E demodId,
{XPT_NCO_COUNT_MIN4}, {XPT_NCO_COUNT_MIN5},
{XPT_NCO_COUNT_MIN6}, {XPT_NCO_COUNT_MIN7} };
#if 0
MXL_REG_FIELD_T mxl561_xpt_ts_sync[MXL_HYDRA_DEMOD_ID_6] = {
{PAD_MUX_DIGIO_25_PINMUX_SEL}, {PAD_MUX_DIGIO_20_PINMUX_SEL},
{PAD_MUX_DIGIO_17_PINMUX_SEL}, {PAD_MUX_DIGIO_11_PINMUX_SEL},
@ -1445,6 +1434,7 @@ static int config_ts(struct mxl *state, MXL_HYDRA_DEMOD_ID_E demodId,
{PAD_MUX_DIGIO_26_PINMUX_SEL}, {PAD_MUX_DIGIO_19_PINMUX_SEL},
{PAD_MUX_DIGIO_18_PINMUX_SEL}, {PAD_MUX_DIGIO_10_PINMUX_SEL},
{PAD_MUX_DIGIO_09_PINMUX_SEL}, {PAD_MUX_DIGIO_02_PINMUX_SEL}};
#endif
demodId = state->base->ts_map[demodId];
@ -1609,6 +1599,7 @@ static int config_mux(struct mxl *state)
return 0;
}
#if 0
static int config_dis(struct mxl *state, u32 id)
{
MXL_HYDRA_DISEQC_ID_E diseqcId = id;
@ -1630,6 +1621,7 @@ static int config_dis(struct mxl *state, u32 id)
return send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE,
&cmdBuff[0]);
}
#endif
static int load_fw(struct mxl *state, struct mxl5xx_cfg *cfg)
{
@ -1890,7 +1882,8 @@ static int probe(struct mxl *state, struct mxl5xx_cfg *cfg)
struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c,
struct mxl5xx_cfg *cfg,
u32 demod, u32 tuner)
u32 demod, u32 tuner,
int (**fn_set_input)(struct dvb_frontend *, int))
{
struct mxl *state;
struct mxl_base *base;
@ -1930,9 +1923,12 @@ struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c,
list_add(&base->mxllist, &mxllist);
}
state->fe.ops = mxl_ops;
#ifndef KERNEL_DVB_CORE
state->fe.ops.xbar[1] = demod;
state->fe.demodulator_priv = state;
state->fe.dtv_property_cache.input = tuner;
#endif
state->fe.demodulator_priv = state;
*fn_set_input = set_input;
list_add(&state->mxl, &base->mxls);
return &state->fe;
@ -1945,4 +1941,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

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

View File

@ -2338,7 +2338,7 @@ error:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(stv0367ter_attach);
EXPORT_SYMBOL_GPL(stv0367ter_attach);
static int stv0367cab_gate_ctrl(struct dvb_frontend *fe, int enable)
{
@ -3462,7 +3462,7 @@ error:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(stv0367cab_attach);
EXPORT_SYMBOL_GPL(stv0367cab_attach);
MODULE_PARM_DESC(debug, "Set debug");
MODULE_PARM_DESC(i2c_debug, "Set i2c debug");

View File

@ -31,7 +31,7 @@
#include <linux/version.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
#include <media/dvb_frontend.h>
#include "stv0367dd.h"
#include "stv0367dd_regs.h"
@ -1570,7 +1570,6 @@ static int ofdm_lock(struct stv_state *state)
if (!(OFDM_Status & 0x40))
return -1;
//printk("lock 1\n");
readreg(state, R367_OFDM_SYR_STAT,&SYR_STAT);
FFTMode = (SYR_STAT & 0x0C) >> 2;
@ -1609,9 +1608,9 @@ static int ofdm_lock(struct stv_state *state)
writereg(state, R367_TSGENERAL,tmp2 & ~0x01);
}
msleep(FECTimeOut);
if( (OFDM_Status & 0x98) != 0x98 )
if( (OFDM_Status & 0x98) != 0x98 ) {
;//return -1;
//printk("lock 2\n");
}
{
u8 Guard = (SYR_STAT & 0x03);
@ -2074,9 +2073,9 @@ static struct dvb_frontend_ops common_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT },
.info = {
.name = "STV0367 DVB-C DVB-T",
.frequency_stepsize = 166667, /* DVB-T only */
.frequency_min = 47000000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */
.frequency_stepsize_hz = 166667, /* DVB-T only */
.frequency_min_hz = 47000000, /* DVB-T: 47125000 */
.frequency_max_hz = 865000000, /* DVB-C: 862000000 */
.symbol_rate_min = 870000,
.symbol_rate_max = 11700000,
.caps = /* DVB-C */
@ -2152,9 +2151,9 @@ error:
MODULE_DESCRIPTION("STV0367DD driver");
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
EXPORT_SYMBOL(stv0367_attach);
EXPORT_SYMBOL_GPL(stv0367_attach);

View File

@ -28,7 +28,7 @@
#include <linux/mutex.h>
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
#include <media/dvb_frontend.h>
#include "stv6110x.h" /* for demodulator internal modes */
@ -3644,7 +3644,6 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
{
u16 val;
u32 ber;
stv090x_read_cnr(fe, &val);
stv090x_read_signal_strength(fe, &val);
@ -3657,7 +3656,7 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
static int stv090x_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct stv090x_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
//struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 reg, h, m, l;
enum fe_status status;
@ -3836,7 +3835,7 @@ static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
u32 reg_0, reg_1, reg, i;
s32 val_0, val_1, val = 0;
u8 lock_f;
s32 cnr_db;
s32 cnr_db = 0;
s32 div;
u32 last;
@ -5075,7 +5074,7 @@ static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir,
static int stv090x_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{
struct stv090x_state *state = fe->demodulator_priv;
u8 tmp;
//u8 tmp;
u32 reg = 0;
if (state->rec_mode == 2) {
@ -5143,10 +5142,10 @@ static struct dvb_frontend_ops stv090x_ops = {
#ifdef USE_API3
.type = FE_QPSK,
#endif
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 0,
.frequency_tolerance = 0,
.frequency_min_hz = 950000000,
.frequency_max_hz = 2150000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 0,
.symbol_rate_min = 1000000,
.symbol_rate_max = 45000000,
.caps = FE_CAN_INVERSION_AUTO |
@ -5255,7 +5254,7 @@ error:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(stv090x_attach);
EXPORT_SYMBOL_GPL(stv090x_attach);
MODULE_PARM_DESC(verbose, "Set Verbosity level");
MODULE_AUTHOR("Manu Abraham");
MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend");

View File

@ -22,7 +22,7 @@
#ifndef __STV090x_PRIV_H
#define __STV090x_PRIV_H
#include "dvb_frontend.h"
#include <media/dvb_frontend.h>
#define FE_ERROR 0
#define FE_NOTICE 1

View File

@ -31,7 +31,7 @@
#include <linux/version.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
#include <media/dvb_frontend.h>
#include "stv0910.h"
#include "stv0910_regs.h"
@ -43,7 +43,7 @@
static LIST_HEAD(stvlist);
enum receive_mode { RCVMODE_NONE, RCVMODE_DVBS, RCVMODE_DVBS2, RCVMODE_AUTO };
enum ScanMode { ColdStart, BlindScan };
enum dvbs2_fec_type { DVBS2_64K, DVBS2_16K };
enum dvbs2_modcod {
@ -114,9 +114,11 @@ struct stv {
u32 first_time_lock;
u8 demod;
u32 symbol_rate;
enum ScanMode TuneMode;
enum fe_code_rate puncture_rate;
enum fe_stv0910_modcod modcod;
u8 pls;
enum dvbs2_fec_type fec_type;
u32 pilots;
enum fe_stv0910_roll_off fe_roll_off;
@ -149,10 +151,12 @@ static int write_reg(struct stv *state, u16 reg, u8 val)
return (i2c_transfer(state->base->i2c, &msg, 1) == 1) ? 0 : -1;
}
#if 0
static int write_reg_off(struct stv *state, u16 reg, u8 val)
{
return write_reg(state, reg + state->regoff, val);
}
#endif
static inline int i2c_read_regs16(struct i2c_adapter *adapter, u8 adr,
u16 reg, u8 *val, int len)
@ -205,17 +209,35 @@ static int write_field(struct stv *state, u32 field, u8 val)
return write_reg(state, field >> 16, new);
}
static int read_field(struct stv *state, u32 field, u8 *val)
{
int status;
u8 shift, mask;
status = read_reg(state, field >> 16, val);
if (status)
return status;
mask = field & 0xff;
shift = (field >> 12) & 0xf;
*val = (*val & mask) >> shift;
return status;
}
#define set_field(_reg, _val) \
write_field(state, state->nr ? FSTV0910_P2_##_reg : \
FSTV0910_P1_##_reg, _val)
#define get_field(_reg, _val) \
read_field(state, state->nr ? FSTV0910_P2_##_reg : \
FSTV0910_P1_##_reg, _val)
#define set_reg(_reg, _val) \
write_reg(state, state->nr ? RSTV0910_P2_##_reg : \
RSTV0910_P1_##_reg, _val)
#define get_reg(_reg, _val) \
read_reg(state, state->nr ? RSTV0910_P2_##_reg : \
RTV0910_P1_##_reg, _val)
RSTV0910_P1_##_reg, _val)
static const struct slookup s1_sn_lookup[] = {
{ 0, 9242 }, /* C/N= 0dB */
@ -487,6 +509,7 @@ static int get_signal_parameters(struct stv *state)
if (state->receive_mode == RCVMODE_DVBS2) {
read_reg(state, RSTV0910_P2_DMDMODCOD + state->regoff, &tmp);
state->pls = tmp & 0x7f;
state->modcod = (enum fe_stv0910_modcod)((tmp & 0x7c) >> 2);
state->pilots = (tmp & 0x01) != 0;
state->fec_type = (enum dvbs2_fec_type)((tmp & 0x02) >> 1);
@ -649,8 +672,8 @@ static int get_ber_s(struct stv *state, u32 *ber_numerator,
return -1;
if ((regs[0] & 0x80) == 0) {
state->last_ber_denominator = 1 << ((state->ber_scale * 2) +
10 + 3);
state->last_ber_denominator = 1ULL << ((state->ber_scale * 2) +
10 + 3);
state->last_ber_numerator = ((u32)(regs[0] & 0x7f) << 16) |
((u32)regs[1] << 8) | regs[2];
if (state->last_ber_numerator < 256 && state->ber_scale < 6) {
@ -1093,8 +1116,10 @@ static int start(struct stv *state, struct dtv_frontend_properties *p)
write_reg(state, RSTV0910_P2_CFRINIT0 + state->regoff, 0);
write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x1F);
/* Trigger acq */
write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x15);
write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff,
state->TuneMode == BlindScan ? 0x00 : 0x15);
state->demod_lock_time += TUNING_DELAY;
state->started = 1;
@ -1107,8 +1132,9 @@ static int init_diseqc(struct stv *state)
u16 offs = state->nr ? 0x40 : 0; /* Address offset */
u8 freq = ((state->base->mclk + 11000 * 32) / (22000 * 32));
/* Disable receiver */
write_reg(state, RSTV0910_P1_DISRXCFG + offs, 0x00);
write_reg(state, RSTV0910_P1_DISRXCFG + offs, 0x05);
//write_reg(state, RSTV0910_P1_DISRXF220 + offs, 0x69); 2b?
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0xBA); /* Reset = 1 */
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); /* Reset = 0 */
write_reg(state, RSTV0910_P1_DISTXF22 + offs, freq);
@ -1169,14 +1195,14 @@ static int probe(struct stv *state)
write_reg(state, RSTV0910_P1_TSCFGH, state->tscfgh | 0x01);
write_reg(state, RSTV0910_P1_TSCFGH, state->tscfgh);
write_reg(state, RSTV0910_P1_TSCFGM, 0xC0); /* Manual speed */
write_reg(state, RSTV0910_P1_TSCFGL, 0x20);
write_reg(state, RSTV0910_P1_TSCFGL, 0x60);
write_reg(state, RSTV0910_P1_TSSPEED, state->tsspeed);
write_reg(state, RSTV0910_P2_TSCFGH, state->tscfgh | 0x01);
write_reg(state, RSTV0910_P2_TSCFGH, state->tscfgh);
write_reg(state, RSTV0910_P2_TSCFGM, 0xC0); /* Manual speed */
write_reg(state, RSTV0910_P2_TSCFGL, 0x20);
write_reg(state, RSTV0910_P2_TSCFGL, 0x60);
write_reg(state, RSTV0910_P2_TSSPEED, state->tsspeed);
@ -1245,11 +1271,17 @@ static int set_parameters(struct dvb_frontend *fe)
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
stop(state);
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe);
if (fe->ops.tuner_ops.get_if_frequency)
fe->ops.tuner_ops.get_if_frequency(fe, &IF);
state->TuneMode = p->symbol_rate & 1 ? BlindScan : ColdStart;
p->symbol_rate &= ~(0x1);
state->symbol_rate = p->symbol_rate;
if (state->TuneMode == BlindScan)
p->symbol_rate = max((u32)(p->symbol_rate + p->symbol_rate/4),
(u32)70000000);
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe);
stat = start(state, p);
return stat;
}
@ -1298,11 +1330,12 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
FEC_3_4, FEC_4_5, FEC_5_6, FEC_8_9,
FEC_9_10
};
enum fe_rolloff ro2ro[3] = {
enum fe_rolloff ro2ro[4] = {
ROLLOFF_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_15,
};
read_reg(state, RSTV0910_P2_DMDMODCOD + state->regoff, &tmp);
mc = ((tmp & 0x7c) >> 2);
p->transmission_mode = tmp & 0x7f;
p->pilot = (tmp & 0x01) ? PILOT_ON : PILOT_OFF;
p->modulation = modcod2mod[mc];
p->fec_inner = modcod2fec[mc];
@ -1329,6 +1362,7 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
p->fec_inner = FEC_NONE;
break;
}
p->modulation = QPSK;
p->rolloff = ROLLOFF_35;
}
if (state->receive_mode != RCVMODE_NONE) {
@ -1569,7 +1603,7 @@ static int tune(struct dvb_frontend *fe, bool re_tune,
return 0;
}
static int get_algo(struct dvb_frontend *fe)
static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{
return DVBFE_ALGO_HW;
}
@ -1605,26 +1639,88 @@ static int wait_dis(struct stv *state, u8 flag, u8 val)
return -1;
}
static int clear_slave(struct dvb_frontend *fe)
{
struct stv *state = fe->demodulator_priv;
u8 n, d, done;
get_field(RXEND, &done);
get_reg(DISRXBYTES, &n);
//printk("clear: done = %u, %u fifo bytes\n", done, n);
for (get_reg(DISRXBYTES, &n); n; n--)
get_reg(DISRXFIFO, &d);
return 0;
}
static int send_master_cmd(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd)
{
struct stv *state = fe->demodulator_priv;
u16 offs = state->nr ? 0x40 : 0;
int i;
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E);
clear_slave(fe);
set_field(DISRX_ON, 0);
set_reg(DISTXCFG, 0x3e);
for (i = 0; i < cmd->msg_len; i++) {
wait_dis(state, 0x40, 0x00);
write_reg(state, RSTV0910_P1_DISTXFIFO + offs, cmd->msg[i]);
set_reg(DISTXFIFO, cmd->msg[i]);
}
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A);
set_reg(DISTXCFG, 0x3a);
wait_dis(state, 0x20, 0x20);
set_field(DISRX_ON, 1);
return 0;
}
static int recv_slave_reply(struct dvb_frontend *fe,
struct dvb_diseqc_slave_reply *reply)
{
struct stv *state = fe->demodulator_priv;
int i, to, flag = 0, max = sizeof(reply->msg);
u8 done, val, n = 0;
#if 0
get_reg(DISRXBYTES, &val);
get_field(RXEND, &done);
printk("slave: done = %u, %u fifo bytes\n", done, val);
#endif
to = reply->timeout;
if (to < 0) {
to = 100;
flag = 1;
} else if (to > 5000)
to = 100;
reply->msg_len = 0;
for (i = 0; i < to; i += 10) {
get_reg(DISRXBYTES, &val);
if (flag && val)
break;
get_field(RXEND, &done);
if (val >= max || done)
break;
msleep(10);
}
get_reg(DISRXBYTES, &val);
//printk("done = %u, %u fifo bytes, i=%u\n", done, val, i);
if (i == to && !val)
return -EIO;
if (done && !val)
return -EIO;
for (i = 100; i; i--) {
get_field(RXEND, &done);
for (get_reg(DISRXBYTES, &n); n; n--) {
if (reply->msg_len == max)
return 0;
get_reg(DISRXFIFO, &reply->msg[reply->msg_len++]);
}
if (!n || done)
break;
msleep(10);
}
if (!i)
return -EIO;
return 0;
}
@ -1632,19 +1728,18 @@ static int send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst)
{
#if 0
struct stv *state = fe->demodulator_priv;
u16 offs = state->nr ? 0x40 : 0;
u8 value;
if (burst == SEC_MINI_A) {
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3F);
set_reg(DISTXCFG, 0x3f);
value = 0x00;
} else {
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E);
value = 0xFF;
set_reg(DISTXCFG, 0x3e);
value = 0xff;
}
wait_dis(state, 0x40, 0x00);
write_reg(state, RSTV0910_P1_DISTXFIFO + offs, value);
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A);
set_reg(DISTXFIFO, value);
set_reg(DISTXCFG, 0x3a);
wait_dis(state, 0x20, 0x20);
#endif
return 0;
@ -1791,10 +1886,10 @@ static struct dvb_frontend_ops stv0910_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
.info = {
.name = "STV0910",
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 0,
.frequency_tolerance = 0,
.frequency_min_hz = 950000000,
.frequency_max_hz = 2150000000,
.frequency_stepsize_hz = 0,
.frequency_tolerance_hz = 0,
.symbol_rate_min = 100000,
.symbol_rate_max = 70000000,
.caps = FE_CAN_INVERSION_AUTO |
@ -1848,6 +1943,8 @@ struct dvb_frontend *stv0910_attach(struct i2c_adapter *i2c,
state->tsgeneral = (cfg->parallel == 2) ? 0x02 : 0x00;
state->i2crpt = 0x0A | ((cfg->rptlvl & 0x07) << 4);
state->tsspeed = cfg->parallel ? 0x10 : 0x28;
if (cfg->tsspeed)
state->tsspeed = cfg->tsspeed;
state->nr = nr;
state->regoff = state->nr ? 0 : 0x200;
state->search_range = 16000000;
@ -1892,4 +1989,4 @@ EXPORT_SYMBOL_GPL(stv0910_attach);
MODULE_DESCRIPTION("STV0910 DVB-S/S2 demodulator driver");
MODULE_AUTHOR("Ralph und Marcus Metzler, Manfred Voelkel");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

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

View File

@ -26,7 +26,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include "dvb_frontend.h"
#include <media/dvb_frontend.h>
#include "stv6110x_reg.h"
#include "stv6110x.h"
@ -345,10 +345,10 @@ static void stv6110x_release(struct dvb_frontend *fe)
static const struct dvb_tuner_ops stv6110x_ops = {
.info = {
.name = "STV6110(A) Silicon Tuner",
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_step = 0,
.name = "STV6110(A) Silicon Tuner",
.frequency_min_hz = 950000000,
.frequency_max_hz = 2150000000,
.frequency_step_hz = 0,
},
.release = stv6110x_release
};
@ -407,7 +407,7 @@ const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
printk(KERN_INFO "%s: Attaching STV6110x\n", __func__);
return stv6110x->devctl;
}
EXPORT_SYMBOL(stv6110x_attach);
EXPORT_SYMBOL_GPL(stv6110x_attach);
MODULE_AUTHOR("Manu Abraham");
MODULE_DESCRIPTION("STV6110x Silicon tuner");

View File

@ -31,7 +31,8 @@
#include <linux/version.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
#include <media/dvb_frontend.h>
#include "stv6111.h"
static inline u32 MulDiv32(u32 a, u32 b, u32 c)
{
@ -100,12 +101,12 @@ static int read_reg(struct stv *state, u8 reg, u8 *val)
return i2c_read(state->i2c, state->adr, &reg, 1, val, 1);
}
#if 0
static int read_regs(struct stv *state, u8 reg, u8 *val, int len)
{
return i2c_read(state->i2c, state->adr, &reg, 1, val, len);
}
#if 0
static void dump_regs(struct stv *state)
{
u8 d[11], *c = &state->reg[0];
@ -335,7 +336,9 @@ static int set_params(struct dvb_frontend *fe)
static int get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
*frequency = 0;
struct stv *state = fe->tuner_priv;
*frequency = state->Frequency;
return 0;
}
@ -704,9 +707,9 @@ static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
static struct dvb_tuner_ops tuner_ops = {
.info = {
.name = "STV6111",
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_step = 0
.frequency_min_hz = 950000000,
.frequency_max_hz = 2150000000,
.frequency_step_hz = 0
},
.init = init,
.sleep = sleep,
@ -751,7 +754,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

@ -32,7 +32,8 @@
#include <linux/version.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
#include <media/dvb_frontend.h>
#include "tda18212dd.h"
#ifndef CHK_ERROR
#define CHK_ERROR(s) if ((status = s) < 0) break
@ -447,18 +448,13 @@ static int attach_init(struct tda_state *state)
if (!state->m_isMaster)
state->m_bLTEnable = false;
/*pr_info("tda18212dd: ChipID %04x %s\n", state->m_ID,
state->m_isMaster ? "master" : "slave");*/
if (state->m_ID != 18212)
return -1;
stat = read_reg(state, POWER_STATE_1 , &PowerState);
if (stat < 0)
return stat;
/*pr_info("tda18212dd: PowerState %02x\n", PowerState);*/
if (state->m_isMaster) {
if (PowerState & 0x02) {
/* msleep for XTAL Calibration
@ -539,7 +535,6 @@ static int PowerMeasurement(struct tda_state *state, u8 *pPowerLevel)
if (*pPowerLevel > 110)
*pPowerLevel = 110;
} while (0);
/* pr_info("PL %d\n", *pPowerLevel); */
return status;
}
@ -806,7 +801,6 @@ static int set_params(struct dvb_frontend *fe)
bw = (p->bandwidth_hz + 999999) / 1000000;
state->m_Frequency = p->frequency;
/*pr_info("tuner bw=%u freq=%u\n", bw, state->m_Frequency);*/
if (p->delivery_system == SYS_DVBT ||
p->delivery_system == SYS_DVBT2 ||
p->delivery_system == SYS_ISDBT ||
@ -889,9 +883,9 @@ static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
static struct dvb_tuner_ops tuner_ops = {
.info = {
.name = "NXP TDA18212",
.frequency_min = 47125000,
.frequency_max = 865000000,
.frequency_step = 62500
.frequency_min_hz = 47125000,
.frequency_max_hz = 865000000,
.frequency_step_hz = 62500
},
.init = init,
.sleep = sleep,
@ -933,7 +927,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

@ -32,7 +32,8 @@
#include <linux/version.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
#include <media/dvb_frontend.h>
#include "tda18271c2dd.h"
struct SStandardParam {
s32 m_IFFrequency;
@ -1183,6 +1184,7 @@ static int set_params(struct dvb_frontend *fe,
switch (delsys) {
case SYS_DVBT:
/* fallthrough */
case SYS_DVBT2:
switch (bw) {
case 6000000:
@ -1197,7 +1199,9 @@ static int set_params(struct dvb_frontend *fe,
default:
return -EINVAL;
}
break;
case SYS_DVBC_ANNEX_A:
/* fallthrough */
case SYS_DVBC_ANNEX_C:
if (bw <= 6000000)
Standard = HF_DVBC_6MHZ;
@ -1292,9 +1296,9 @@ static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
static struct dvb_tuner_ops tuner_ops = {
.info = {
.name = "NXP TDA18271C2D",
.frequency_min = 47125000,
.frequency_max = 865000000,
.frequency_step = 62500
.frequency_min_hz = 47125000,
.frequency_max_hz = 865000000,
.frequency_step_hz = 62500
},
.init = init,
.sleep = sleep,
@ -1326,4 +1330,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

@ -1,6 +1,10 @@
#ifndef _TDA18271C2DD_H_
#define _TDA18271C2DD_H_
#if defined(CONFIG_DVB_TDA18271C2DD) || \
#include <linux/types.h>
#include <linux/i2c.h>
#if defined(CONFIG_DVB_TDA18271C2DD) || \
(defined(CONFIG_DVB_TDA18271C2DD_MODULE) \
&& defined(MODULE))
struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,

31
include/dd_compat.h Normal file
View File

@ -0,0 +1,31 @@
#include <linux/version.h>
#if (KERNEL_VERSION(3, 8, 0) <= LINUX_VERSION_CODE)
#define __devexit
#define __devinit
#define __devinitconst
#endif
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#ifndef fallthrough
#if __has_attribute(__fallthrough__)
# define fallthrough __attribute__((__fallthrough__))
#else
# define fallthrough do {} while (0) /* fallthrough */
#endif
#endif
#ifdef KERNEL_DVB_CORE
#define DVB_DEVICE_CI 0
#define DVB_DEVICE_NS 6
#define DVB_DEVICE_NSD 7
#define DVB_DEVICE_MOD 8
#define APSK_128 21
#define APSK_256 22
#define APSK_256_L 23
#endif

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