diff options
author | Johannes Stezenbach <js@linuxtv.org> | 2005-05-17 00:54:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-05-17 10:59:24 -0400 |
commit | 2add87a95068d6457d4e5824d0417d39007665a4 (patch) | |
tree | f2aa0373421b0bd78ce900a41fa5a72b853e66de | |
parent | 1ec359729960f7896db8f642454e603d22519d20 (diff) |
[PATCH] dvb: b2c2/flexcop driver refactoring part 2: add modular Flexcop driver
b2c2/flexcop driver refactoring to support PCI and USB based cards part 2: add
modular Flexcop driver
Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Johannes Stezenbach <js@linuxtv.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | Documentation/dvb/README.flexcop | 279 | ||||
-rw-r--r-- | drivers/media/dvb/Kconfig | 2 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/Kconfig | 37 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/Makefile | 11 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-common.h | 161 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-dma.c | 149 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-eeprom.c | 157 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 403 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-hw-filter.c | 198 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-i2c.c | 204 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-misc.c | 66 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-pci.c | 365 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-reg.h | 700 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-sram.c | 403 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-usb.c | 530 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-usb.h | 116 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop.c | 288 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop.h | 30 |
18 files changed, 4098 insertions, 1 deletions
diff --git a/Documentation/dvb/README.flexcop b/Documentation/dvb/README.flexcop new file mode 100644 index 000000000000..9ec735714e43 --- /dev/null +++ b/Documentation/dvb/README.flexcop | |||
@@ -0,0 +1,279 @@ | |||
1 | This README escorted the skystar2-driver rewriting procedure. It describes the | ||
2 | state of the new flexcop-driver set and some internals are written down here | ||
3 | too. | ||
4 | |||
5 | How to do something in here? | ||
6 | ============================ | ||
7 | |||
8 | make -f Makefile.t | ||
9 | make -C ../build-2.6 | ||
10 | ./in.sh # load the drivers | ||
11 | ./rm.sh # unload the drivers | ||
12 | |||
13 | Please read this file, if you want to contribute. | ||
14 | |||
15 | This document hopefully describes things about the flexcop and its | ||
16 | device-offsprings. Goal is to write a easy-to-write and easy-to-read set of | ||
17 | drivers based on the skystar2.c and other information. | ||
18 | |||
19 | This directory is temporary. It is used for rewriting the skystar2.c and to | ||
20 | create shared code, which then can be used by the usb box as well. | ||
21 | |||
22 | Remark: flexcop-pci.c was a copy of skystar2.c, but every line has been | ||
23 | touched and rewritten. | ||
24 | |||
25 | General coding processing | ||
26 | ========================= | ||
27 | |||
28 | We should proceed as follows (as long as no one complains): | ||
29 | |||
30 | 0) Think before start writing code! | ||
31 | |||
32 | 1) rewriting the skystar2.c with the help of the flexcop register descriptions | ||
33 | and splitting up the files to a pci-bus-part and a flexcop-part. | ||
34 | The new driver will be called b2c2-flexcop-pci.ko/b2c2-flexcop-usb.ko for the | ||
35 | device-specific part and b2c2-flexcop.ko for the common flexcop-functions. | ||
36 | |||
37 | 2) Search for errors in the leftover of flexcop-pci.c (compare with pluto2.c | ||
38 | and other pci drivers) | ||
39 | |||
40 | 3) make some beautification (see 'Improvements when rewriting (refactoring) is | ||
41 | done') | ||
42 | |||
43 | 4) Testing the new driver and maybe substitute the skystar2.c with it, to reach | ||
44 | a wider tester audience. | ||
45 | |||
46 | 5) creating an usb-bus-part using the already written flexcop code for the pci | ||
47 | card. | ||
48 | |||
49 | Idea: create a kernel-object for the flexcop and export all important | ||
50 | functions. This option saves kernel-memory, but maybe a lot of functions have | ||
51 | to be exported to kernel namespace. | ||
52 | |||
53 | |||
54 | Current situation | ||
55 | ================= | ||
56 | |||
57 | 0) Done :) | ||
58 | 1) Done (some minor issues left) | ||
59 | 2) Done | ||
60 | 3) Not ready yet, more information is necessary | ||
61 | 4) next to be done (see the table below) | ||
62 | 5) USB driver is working (yes, there are some minor issues) | ||
63 | |||
64 | What seems to be ready? | ||
65 | ----------------------- | ||
66 | |||
67 | 1) Rewriting | ||
68 | 1a) i2c is cut off from the flexcop-pci.c and seems to work | ||
69 | 1b) moved tuner and demod stuff from flexcop-pci.c to flexcop-tuner-fe.c | ||
70 | 1c) moved lnb and diseqc stuff from flexcop-pci.c to flexcop-tuner-fe.c | ||
71 | 1e) eeprom (reading MAC address) | ||
72 | 1d) sram (no dynamic sll size detection (commented out) (using default as JJ told me)) | ||
73 | 1f) misc. register accesses for reading parameters (e.g. resetting, revision) | ||
74 | 1g) pid/mac filter (flexcop-hw-filter.c) | ||
75 | 1i) dvb-stuff initialization in flexcop.c (done) | ||
76 | 1h) dma stuff (now just using the size-irq, instead of all-together, to be done) | ||
77 | 1j) remove flexcop initialization from flexcop-pci.c completely (done) | ||
78 | 1l) use a well working dma IRQ method (done, see 'Known bugs and problems and TODO') | ||
79 | 1k) cleanup flexcop-files (remove unused EXPORT_SYMBOLs, make static from | ||
80 | non-static where possible, moved code to proper places) | ||
81 | |||
82 | 2) Search for errors in the leftover of flexcop-pci.c (partially done) | ||
83 | 5a) add MAC address reading | ||
84 | |||
85 | What to do in the near future? | ||
86 | -------------------------------------- | ||
87 | (no special order here) | ||
88 | |||
89 | |||
90 | 5) USB driver | ||
91 | 5b) optimize isoc-transfer (submitting/killing isoc URBs when transfer is starting) | ||
92 | 5c) feeding of ISOC data to the software demux (format of the isochronous data | ||
93 | and speed optimization, no real error) | ||
94 | |||
95 | Testing changes | ||
96 | --------------- | ||
97 | |||
98 | O = item is working | ||
99 | P = item is partially working | ||
100 | X = item is not working | ||
101 | N = item does not apply here | ||
102 | <empty field> = item need to be examined | ||
103 | |||
104 | | PCI | USB | ||
105 | item | mt352 | nxt2002 | stv0299 | mt312 | mt352 | nxt2002 | stv0299 | mt312 | ||
106 | -------+-------+---------+---------+-------+-------+---------+---------+------- | ||
107 | 1a) | O | | | | N | N | N | N | ||
108 | 1b) | O | | | | | | O | | ||
109 | 1c) | N | N | | | N | N | O | | ||
110 | 1d) | O | O | ||
111 | 1e) | O | O | ||
112 | 1f) | P | ||
113 | 1g) | O | ||
114 | 1h) | P | | ||
115 | 1i) | O | N | ||
116 | 1j) | O | N | ||
117 | 1l) | O | N | ||
118 | 2) | O | N | ||
119 | 5a) | N | O | ||
120 | 5b)* | N | | ||
121 | 5c)* | N | | ||
122 | |||
123 | * - not done yet | ||
124 | |||
125 | Known bugs and problems and TODO | ||
126 | -------------------------------- | ||
127 | |||
128 | 1g/h/l) when pid filtering is enabled on the pci card | ||
129 | |||
130 | DMA usage currently: | ||
131 | The DMA is splitted in 2 equal-sized subbuffers. The Flexcop writes to first | ||
132 | address and triggers an IRQ when it's full and starts writing to the second | ||
133 | address. When the second address is full, the IRQ is triggered again, and | ||
134 | the flexcop writes to first address again, and so on. | ||
135 | The buffersize of each address is currently 640*188 bytes. | ||
136 | |||
137 | Problem is, when using hw-pid-filtering and doing some low-bandwidth | ||
138 | operation (like scanning) the buffers won't be filled enough to trigger | ||
139 | the IRQ. That's why: | ||
140 | |||
141 | When PID filtering is activated, the timer IRQ is used. Every 1.97 ms the IRQ | ||
142 | is triggered. Is the current write address of DMA1 different to the one | ||
143 | during the last IRQ, then the data is passed to the demuxer. | ||
144 | |||
145 | There is an additional DMA-IRQ-method: packet count IRQ. This isn't | ||
146 | implemented correctly yet. | ||
147 | |||
148 | The solution is to disable HW PID filtering, but I don't know how the DVB | ||
149 | API software demux behaves on slow systems with 45MBit/s TS. | ||
150 | |||
151 | Solved bugs :) | ||
152 | -------------- | ||
153 | 1g) pid-filtering (somehow pid index 4 and 5 (EMM_PID and ECM_PID) aren't | ||
154 | working) | ||
155 | SOLUTION: also index 0 was affected, because net_translation is done for | ||
156 | these indexes by default | ||
157 | |||
158 | 5b) isochronous transfer does only work in the first attempt (for the Sky2PC USB, | ||
159 | Air2PC is working) | ||
160 | SOLUTION: the flexcop was going asleep and never really woke up again (don't | ||
161 | know if this need fixes, see flexcop-fe-tuner.c:flexcop_sleep) | ||
162 | |||
163 | Improvements when rewriting (refactoring) is done | ||
164 | ================================================= | ||
165 | |||
166 | - split sleeping of the flexcop (misc_204.ACPI3_sig = 1;) from lnb_control | ||
167 | (enable sleeping for other demods than dvb-s) | ||
168 | - add support for CableStar (stv0297 Microtune 203x/ALPS) | ||
169 | |||
170 | Debugging | ||
171 | --------- | ||
172 | - add verbose debugging to skystar2.c (dump the reg_dw_data) and compare it | ||
173 | with this flexcop, this is important, because i2c is now using the | ||
174 | flexcop_ibi_value union from flexcop-reg.h (do you have a better idea for | ||
175 | that, please tell us so). | ||
176 | |||
177 | Everything which is identical in the following table, can be put into a common | ||
178 | flexcop-module. | ||
179 | |||
180 | PCI USB | ||
181 | ------------------------------------------------------------------------------- | ||
182 | Different: | ||
183 | Register access: accessing IO memory USB control message | ||
184 | I2C bus: I2C bus of the FC USB control message | ||
185 | Data transfer: DMA isochronous transfer | ||
186 | EEPROM transfer: through i2c bus not clear yet | ||
187 | |||
188 | Identical: | ||
189 | Streaming: accessing registers | ||
190 | PID Filtering: accessing registers | ||
191 | Sram destinations: accessing registers | ||
192 | Tuner/Demod: I2C bus | ||
193 | DVB-stuff: can be written for common use | ||
194 | |||
195 | Restrictions: | ||
196 | ============ | ||
197 | |||
198 | We need to create a bus-specific-struct and a flexcop-struct. | ||
199 | |||
200 | bus-specific-struct: | ||
201 | |||
202 | struct flexcop_pci | ||
203 | ... | ||
204 | |||
205 | struct flexcop_usb | ||
206 | ... | ||
207 | |||
208 | |||
209 | struct flexcop_device { | ||
210 | void *bus_specific; /* container for bus-specific struct */ | ||
211 | ... | ||
212 | } | ||
213 | |||
214 | PCI i2c can read/write max 4 bytes at a time, USB can more | ||
215 | |||
216 | Functions | ||
217 | ========= | ||
218 | |||
219 | Syntax | ||
220 | ------ | ||
221 | |||
222 | - Flexcop functions will be called "flexcop(_[a-z0-9]+)+" and exported as such | ||
223 | if needed. | ||
224 | - Flexcop-device functions will be called "flexcop_device(_[a-z0-9]+)+" and | ||
225 | exported as such if needed. | ||
226 | - Both will be compiled to b2c2-flexcop.ko and their source can be found in the | ||
227 | flexcop*.[hc] | ||
228 | |||
229 | Callbacks and exports | ||
230 | --------------------- | ||
231 | |||
232 | Bus-specific functions will be given as callbacks (function pointers) to the | ||
233 | flexcop-module. (within the flexcop_device-struct) | ||
234 | |||
235 | Initialization process | ||
236 | ====================== | ||
237 | |||
238 | b2c2-flexcop.ko is loaded | ||
239 | b2c2-flexcop-<bus>.ko is loaded | ||
240 | |||
241 | suppose a device is found: | ||
242 | malloc flexcop and the bus-specific variables (via flexcop_device_malloc) | ||
243 | fill the bus-specific variable | ||
244 | fill the flexcop variable (especially the bus-specific callbacks) | ||
245 | bus-specific initialization | ||
246 | - ... | ||
247 | do the common initialization (via flexcop_device_initialize) | ||
248 | - reset the card | ||
249 | - determine flexcop type (II, IIB, III) | ||
250 | - hw_filters (bus dependent) | ||
251 | - 0x204 | ||
252 | - set sram size | ||
253 | - create the dvb-stuff | ||
254 | - create i2c stuff | ||
255 | - frontend-initialization | ||
256 | done | ||
257 | bus specific: | ||
258 | - media_destination (this and the following 3 are bus specific) | ||
259 | - cai_dest | ||
260 | - cao_dest | ||
261 | - net_destination | ||
262 | |||
263 | Bugs fixed while rewriting the driver | ||
264 | ===================================== | ||
265 | |||
266 | - EEPROM access (to read the MAC address) was fixed to death some time last | ||
267 | year. (fixed here and in skystar2.c) (Bjarne, this was the piece of code | ||
268 | (fix-chipaddr) we were wondering about) | ||
269 | |||
270 | |||
271 | Acknowledgements (just for the rewriting part) | ||
272 | ================ | ||
273 | |||
274 | Bjarne Steinsbo thought a lot in the first place of the pci part for this code | ||
275 | sharing idea. | ||
276 | |||
277 | Andreas Oberritter for providing a recent PCI initialization template (pluto2.c). | ||
278 | |||
279 | comments, critics and ideas to linux-dvb@linuxtv.org or patrick.boettcher@desy.de | ||
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 883ec08490f4..4983e1b1bb1d 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig | |||
@@ -33,7 +33,7 @@ source "drivers/media/dvb/dibusb/Kconfig" | |||
33 | source "drivers/media/dvb/cinergyT2/Kconfig" | 33 | source "drivers/media/dvb/cinergyT2/Kconfig" |
34 | 34 | ||
35 | comment "Supported FlexCopII (B2C2) Adapters" | 35 | comment "Supported FlexCopII (B2C2) Adapters" |
36 | depends on DVB_CORE && PCI | 36 | depends on DVB_CORE && (PCI || USB) |
37 | source "drivers/media/dvb/b2c2/Kconfig" | 37 | source "drivers/media/dvb/b2c2/Kconfig" |
38 | 38 | ||
39 | comment "Supported BT878 Adapters" | 39 | comment "Supported BT878 Adapters" |
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index f1f6187b7c1e..99bd675df955 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig | |||
@@ -1,3 +1,40 @@ | |||
1 | config DVB_B2C2_FLEXCOP | ||
2 | tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters" | ||
3 | depends on DVB_CORE | ||
4 | select DVB_STV0299 | ||
5 | select DVB_MT352 | ||
6 | select DVB_MT312 | ||
7 | select DVB_NXT2002 | ||
8 | select DVB_STV0297 | ||
9 | help | ||
10 | Support for the digital TV receiver chip made by B2C2 Inc. included in | ||
11 | Technisats PCI cards and USB boxes. | ||
12 | |||
13 | Say Y if you own such a device and want to use it. | ||
14 | |||
15 | config DVB_B2C2_FLEXCOP_PCI | ||
16 | tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI" | ||
17 | depends on DVB_B2C2_FLEXCOP && PCI | ||
18 | help | ||
19 | Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2. | ||
20 | |||
21 | Say Y if you own such a device and want to use it. | ||
22 | |||
23 | config DVB_B2C2_FLEXCOP_USB | ||
24 | tristate "Technisat/B2C2 Air/Sky/Cable2PC USB" | ||
25 | depends on DVB_B2C2_FLEXCOP && USB | ||
26 | help | ||
27 | Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2, | ||
28 | |||
29 | Say Y if you own such a device and want to use it. | ||
30 | |||
31 | config DVB_B2C2_FLEXCOP_DEBUG | ||
32 | bool "Enable debug for the B2C2 FlexCop drivers" | ||
33 | depends on DVB_B2C2_FLEXCOP | ||
34 | help | ||
35 | Say Y if you want to enable the module option to control debug messages | ||
36 | of all B2C2 FlexCop drivers. | ||
37 | |||
1 | config DVB_B2C2_SKYSTAR | 38 | config DVB_B2C2_SKYSTAR |
2 | tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI" | 39 | tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI" |
3 | depends on DVB_CORE && PCI | 40 | depends on DVB_CORE && PCI |
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile index f9cdc6f052d7..7703812af34f 100644 --- a/drivers/media/dvb/b2c2/Makefile +++ b/drivers/media/dvb/b2c2/Makefile | |||
@@ -1,3 +1,14 @@ | |||
1 | b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \ | ||
2 | flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o \ | ||
3 | flexcop-dma.o | ||
4 | obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o | ||
5 | |||
6 | b2c2-flexcop-pci-objs = flexcop-pci.o | ||
7 | obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o | ||
8 | |||
9 | b2c2-flexcop-usb-objs = flexcop-usb.o | ||
10 | obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o | ||
11 | |||
1 | obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o | 12 | obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o |
2 | 13 | ||
3 | EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ | 14 | EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ |
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h new file mode 100644 index 000000000000..82b7f8fa7b9c --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-common.h | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop-common.h - common header file for device-specific source files also. | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | #ifndef __FLEXCOP_COMMON_H__ | ||
9 | #define __FLEXCOP_COMMON_H__ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/pci.h> | ||
13 | |||
14 | #include "flexcop-reg.h" | ||
15 | |||
16 | #include "dmxdev.h" | ||
17 | #include "dvb_demux.h" | ||
18 | #include "dvb_filter.h" | ||
19 | #include "dvb_net.h" | ||
20 | #include "dvb_frontend.h" | ||
21 | |||
22 | #define FC_MAX_FEED 256 | ||
23 | |||
24 | #ifndef FC_LOG_PREFIX | ||
25 | #warning please define a log prefix for your file, using a default one | ||
26 | #define FC_LOG_PREFIX "b2c2-undef" | ||
27 | #endif | ||
28 | |||
29 | /* Steal from usb.h */ | ||
30 | #undef err | ||
31 | #define err(format, arg...) printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg) | ||
32 | #undef info | ||
33 | #define info(format, arg...) printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg) | ||
34 | #undef warn | ||
35 | #define warn(format, arg...) printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg) | ||
36 | |||
37 | struct flexcop_dma { | ||
38 | struct pci_dev *pdev; | ||
39 | |||
40 | u8 *cpu_addr0; | ||
41 | dma_addr_t dma_addr0; | ||
42 | u8 *cpu_addr1; | ||
43 | dma_addr_t dma_addr1; | ||
44 | u32 size; /* size of each address in bytes */ | ||
45 | }; | ||
46 | |||
47 | /* Control structure for data definitions that are common to | ||
48 | * the B2C2-based PCI and USB devices. | ||
49 | */ | ||
50 | struct flexcop_device { | ||
51 | /* general */ | ||
52 | struct device *dev; /* for firmware_class */ | ||
53 | |||
54 | #define FC_STATE_DVB_INIT 0x01 | ||
55 | #define FC_STATE_I2C_INIT 0x02 | ||
56 | #define FC_STATE_FE_INIT 0x04 | ||
57 | int init_state; | ||
58 | |||
59 | /* device information */ | ||
60 | u8 mac_address[6]; | ||
61 | int has_32_hw_pid_filter; | ||
62 | flexcop_revision_t rev; | ||
63 | flexcop_device_type_t dev_type; | ||
64 | flexcop_bus_t bus_type; | ||
65 | |||
66 | /* dvb stuff */ | ||
67 | struct dvb_adapter dvb_adapter; | ||
68 | struct dvb_frontend *fe; | ||
69 | struct dvb_net dvbnet; | ||
70 | struct dvb_demux demux; | ||
71 | struct dmxdev dmxdev; | ||
72 | struct dmx_frontend hw_frontend; | ||
73 | struct dmx_frontend mem_frontend; | ||
74 | int (*fe_sleep) (struct dvb_frontend *); | ||
75 | |||
76 | struct i2c_adapter i2c_adap; | ||
77 | struct semaphore i2c_sem; | ||
78 | |||
79 | /* options and status */ | ||
80 | int feedcount; | ||
81 | int pid_filtering; | ||
82 | |||
83 | /* bus specific callbacks */ | ||
84 | flexcop_ibi_value (*read_ibi_reg) (struct flexcop_device *, flexcop_ibi_register); | ||
85 | int (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value); | ||
86 | |||
87 | |||
88 | int (*i2c_request) (struct flexcop_device*, flexcop_access_op_t, flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len); | ||
89 | int (*stream_control) (struct flexcop_device*, int); | ||
90 | |||
91 | int (*get_mac_addr) (struct flexcop_device *fc, int extended); | ||
92 | |||
93 | void *bus_specific; | ||
94 | }; | ||
95 | |||
96 | /* exported prototypes */ | ||
97 | |||
98 | /* from flexcop.c */ | ||
99 | void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len); | ||
100 | void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no); | ||
101 | |||
102 | struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len); | ||
103 | void flexcop_device_kfree(struct flexcop_device*); | ||
104 | |||
105 | int flexcop_device_initialize(struct flexcop_device*); | ||
106 | void flexcop_device_exit(struct flexcop_device *fc); | ||
107 | |||
108 | /* from flexcop-dma.c */ | ||
109 | int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size); | ||
110 | void flexcop_dma_free(struct flexcop_dma *dma); | ||
111 | |||
112 | int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); | ||
113 | int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); | ||
114 | int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); | ||
115 | int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index); | ||
116 | int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles); | ||
117 | int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets); | ||
118 | |||
119 | /* from flexcop-eeprom.c */ | ||
120 | /* the PCI part uses this call to get the MAC address, the USB part has its own */ | ||
121 | int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended); | ||
122 | |||
123 | /* from flexcop-i2c.c */ | ||
124 | /* the PCI part uses this a i2c_request callback, whereas the usb part has its own | ||
125 | * one. We have it in flexcop-i2c.c, because it is going via the actual | ||
126 | * I2C-channel of the flexcop. | ||
127 | */ | ||
128 | int flexcop_i2c_request(struct flexcop_device*, flexcop_access_op_t, | ||
129 | flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len); | ||
130 | |||
131 | /* from flexcop-sram.c */ | ||
132 | int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target); | ||
133 | void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s); | ||
134 | void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill); | ||
135 | |||
136 | /* global prototypes for the flexcop-chip */ | ||
137 | /* from flexcop-fe-tuner.c */ | ||
138 | int flexcop_frontend_init(struct flexcop_device *card); | ||
139 | void flexcop_frontend_exit(struct flexcop_device *fc); | ||
140 | |||
141 | /* from flexcop-i2c.c */ | ||
142 | int flexcop_i2c_init(struct flexcop_device *fc); | ||
143 | void flexcop_i2c_exit(struct flexcop_device *fc); | ||
144 | |||
145 | /* from flexcop-sram.c */ | ||
146 | int flexcop_sram_init(struct flexcop_device *fc); | ||
147 | |||
148 | /* from flexcop-misc.c */ | ||
149 | void flexcop_determine_revision(struct flexcop_device *fc); | ||
150 | void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix); | ||
151 | |||
152 | /* from flexcop-hw-filter.c */ | ||
153 | int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff); | ||
154 | void flexcop_hw_filter_init(struct flexcop_device *fc); | ||
155 | |||
156 | void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff); | ||
157 | |||
158 | void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]); | ||
159 | void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff); | ||
160 | |||
161 | #endif | ||
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c new file mode 100644 index 000000000000..8d2706075360 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-dma.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop-dma.c - methods for configuring and controlling the DMA of the FlexCop. | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | #include "flexcop.h" | ||
9 | |||
10 | int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size) | ||
11 | { | ||
12 | u8 *tcpu; | ||
13 | dma_addr_t tdma; | ||
14 | |||
15 | if (size % 2) { | ||
16 | err("dma buffersize has to be even."); | ||
17 | return -EINVAL; | ||
18 | } | ||
19 | |||
20 | if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) { | ||
21 | dma->pdev = pdev; | ||
22 | dma->cpu_addr0 = tcpu; | ||
23 | dma->dma_addr0 = tdma; | ||
24 | dma->cpu_addr1 = tcpu + size/2; | ||
25 | dma->dma_addr1 = tdma + size/2; | ||
26 | dma->size = size/2; | ||
27 | return 0; | ||
28 | } | ||
29 | return -ENOMEM; | ||
30 | } | ||
31 | EXPORT_SYMBOL(flexcop_dma_allocate); | ||
32 | |||
33 | void flexcop_dma_free(struct flexcop_dma *dma) | ||
34 | { | ||
35 | pci_free_consistent(dma->pdev, dma->size*2,dma->cpu_addr0, dma->dma_addr0); | ||
36 | memset(dma,0,sizeof(struct flexcop_dma)); | ||
37 | } | ||
38 | EXPORT_SYMBOL(flexcop_dma_free); | ||
39 | |||
40 | int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) | ||
41 | { | ||
42 | flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); | ||
43 | |||
44 | if (no & FC_DMA_1) | ||
45 | v.ctrl_208.DMA1_Timer_Enable_sig = onoff; | ||
46 | |||
47 | if (no & FC_DMA_2) | ||
48 | v.ctrl_208.DMA2_Timer_Enable_sig = onoff; | ||
49 | |||
50 | fc->write_ibi_reg(fc,ctrl_208,v); | ||
51 | return 0; | ||
52 | } | ||
53 | EXPORT_SYMBOL(flexcop_dma_control_timer_irq); | ||
54 | |||
55 | int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) | ||
56 | { | ||
57 | flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); | ||
58 | |||
59 | if (no & FC_DMA_1) | ||
60 | v.ctrl_208.DMA1_IRQ_Enable_sig = onoff; | ||
61 | |||
62 | if (no & FC_DMA_2) | ||
63 | v.ctrl_208.DMA2_IRQ_Enable_sig = onoff; | ||
64 | |||
65 | fc->write_ibi_reg(fc,ctrl_208,v); | ||
66 | return 0; | ||
67 | } | ||
68 | EXPORT_SYMBOL(flexcop_dma_control_size_irq); | ||
69 | |||
70 | int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) | ||
71 | { | ||
72 | flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); | ||
73 | |||
74 | if (no & FC_DMA_1) | ||
75 | v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff; | ||
76 | |||
77 | if (no & FC_DMA_2) | ||
78 | v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff; | ||
79 | |||
80 | fc->write_ibi_reg(fc,ctrl_208,v); | ||
81 | return 0; | ||
82 | } | ||
83 | EXPORT_SYMBOL(flexcop_dma_control_packet_irq); | ||
84 | |||
85 | int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index) | ||
86 | { | ||
87 | |||
88 | flexcop_ibi_value v0x0,v0x4,v0xc; | ||
89 | v0x0.raw = v0x4.raw = v0xc.raw = 0; | ||
90 | |||
91 | v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; | ||
92 | v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; | ||
93 | v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; | ||
94 | |||
95 | if (index & FC_DMA_SUBADDR_0) | ||
96 | v0x0.dma_0x0.dma_0start = 1; | ||
97 | |||
98 | if (index & FC_DMA_SUBADDR_1) | ||
99 | v0xc.dma_0xc.dma_1start = 1; | ||
100 | |||
101 | if (dma_idx & FC_DMA_1) { | ||
102 | fc->write_ibi_reg(fc,dma1_000,v0x0); | ||
103 | fc->write_ibi_reg(fc,dma1_004,v0x4); | ||
104 | fc->write_ibi_reg(fc,dma1_00c,v0xc); | ||
105 | } else { /* (dma_idx & FC_DMA_2) */ | ||
106 | fc->write_ibi_reg(fc,dma2_010,v0x0); | ||
107 | fc->write_ibi_reg(fc,dma2_014,v0x4); | ||
108 | fc->write_ibi_reg(fc,dma2_01c,v0xc); | ||
109 | } | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | EXPORT_SYMBOL(flexcop_dma_config); | ||
114 | |||
115 | static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff) | ||
116 | { | ||
117 | flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; | ||
118 | flexcop_ibi_value v = fc->read_ibi_reg(fc,r); | ||
119 | v.dma_0xc.remap_enable = onoff; | ||
120 | fc->write_ibi_reg(fc,r,v); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | /* 1 cycles = 1.97 msec */ | ||
125 | int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles) | ||
126 | { | ||
127 | flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; | ||
128 | flexcop_ibi_value v = fc->read_ibi_reg(fc,r); | ||
129 | |||
130 | flexcop_dma_remap(fc,dma_idx,0); | ||
131 | |||
132 | v.dma_0x4_write.dmatimer = cycles >> 1; | ||
133 | fc->write_ibi_reg(fc,r,v); | ||
134 | return 0; | ||
135 | } | ||
136 | EXPORT_SYMBOL(flexcop_dma_config_timer); | ||
137 | |||
138 | int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets) | ||
139 | { | ||
140 | flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; | ||
141 | flexcop_ibi_value v = fc->read_ibi_reg(fc,r); | ||
142 | |||
143 | flexcop_dma_remap(fc,dma_idx,1); | ||
144 | |||
145 | v.dma_0x4_remap.DMA_maxpackets = packets; | ||
146 | fc->write_ibi_reg(fc,r,v); | ||
147 | return 0; | ||
148 | } | ||
149 | EXPORT_SYMBOL(flexcop_dma_config_packet_count); | ||
diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c new file mode 100644 index 000000000000..4dbedd819734 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-eeprom.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading is used) | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | #include "flexcop.h" | ||
9 | |||
10 | #if 0 | ||
11 | /*EEPROM (Skystar2 has one "24LC08B" chip on board) */ | ||
12 | static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len) | ||
13 | { | ||
14 | return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len); | ||
15 | } | ||
16 | |||
17 | static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries) | ||
18 | { | ||
19 | int i; | ||
20 | |||
21 | for (i = 0; i < retries; i++) { | ||
22 | if (eeprom_write(adapter, addr, wbuf, len) == len) { | ||
23 | if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1) | ||
24 | return 1; | ||
25 | } | ||
26 | } | ||
27 | |||
28 | return 0; | ||
29 | } | ||
30 | |||
31 | /* These functions could be used to unlock SkyStar2 cards. */ | ||
32 | |||
33 | static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len) | ||
34 | { | ||
35 | u8 rbuf[20]; | ||
36 | u8 wbuf[20]; | ||
37 | |||
38 | if (len != 16) | ||
39 | return 0; | ||
40 | |||
41 | memcpy(wbuf, key, len); | ||
42 | |||
43 | wbuf[16] = 0; | ||
44 | wbuf[17] = 0; | ||
45 | wbuf[18] = 0; | ||
46 | wbuf[19] = calc_lrc(wbuf, 19); | ||
47 | |||
48 | return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4); | ||
49 | } | ||
50 | |||
51 | static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len) | ||
52 | { | ||
53 | u8 buf[20]; | ||
54 | |||
55 | if (len != 16) | ||
56 | return 0; | ||
57 | |||
58 | if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0) | ||
59 | return 0; | ||
60 | |||
61 | memcpy(key, buf, len); | ||
62 | |||
63 | return 1; | ||
64 | } | ||
65 | |||
66 | static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac) | ||
67 | { | ||
68 | u8 tmp[8]; | ||
69 | |||
70 | if (type != 0) { | ||
71 | tmp[0] = mac[0]; | ||
72 | tmp[1] = mac[1]; | ||
73 | tmp[2] = mac[2]; | ||
74 | tmp[3] = mac[5]; | ||
75 | tmp[4] = mac[6]; | ||
76 | tmp[5] = mac[7]; | ||
77 | |||
78 | } else { | ||
79 | |||
80 | tmp[0] = mac[0]; | ||
81 | tmp[1] = mac[1]; | ||
82 | tmp[2] = mac[2]; | ||
83 | tmp[3] = mac[3]; | ||
84 | tmp[4] = mac[4]; | ||
85 | tmp[5] = mac[5]; | ||
86 | } | ||
87 | |||
88 | tmp[6] = 0; | ||
89 | tmp[7] = calc_lrc(tmp, 7); | ||
90 | |||
91 | if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8) | ||
92 | return 1; | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int flexcop_eeprom_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len) | ||
98 | { | ||
99 | return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len); | ||
100 | } | ||
101 | |||
102 | #endif | ||
103 | |||
104 | static u8 calc_lrc(u8 *buf, int len) | ||
105 | { | ||
106 | int i; | ||
107 | u8 sum = 0; | ||
108 | for (i = 0; i < len; i++) | ||
109 | sum = sum ^ buf[i]; | ||
110 | return sum; | ||
111 | } | ||
112 | |||
113 | static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries) | ||
114 | { | ||
115 | int i,ret = 0; | ||
116 | u8 chipaddr = 0x50 | ((addr >> 8) & 3); | ||
117 | for (i = 0; i < retries; i++) | ||
118 | if ((ret = fc->i2c_request(fc,op,FC_I2C_PORT_EEPROM,chipaddr,addr & 0xff,buf,len)) == 0) | ||
119 | break; | ||
120 | return ret; | ||
121 | } | ||
122 | |||
123 | static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries) | ||
124 | { | ||
125 | int ret = flexcop_eeprom_request(fc,FC_READ,addr,buf,len,retries); | ||
126 | if (ret == 0) | ||
127 | if (calc_lrc(buf, len - 1) != buf[len - 1]) | ||
128 | ret = -EINVAL; | ||
129 | return ret; | ||
130 | } | ||
131 | |||
132 | /* TODO how is it handled in USB */ | ||
133 | |||
134 | /* JJ's comment about extended == 1: it is not presently used anywhere but was | ||
135 | * added to the low-level functions for possible support of EUI64 | ||
136 | */ | ||
137 | int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended) | ||
138 | { | ||
139 | u8 buf[8]; | ||
140 | int ret = 0; | ||
141 | |||
142 | memset(fc->mac_address,0,6); | ||
143 | |||
144 | if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) { | ||
145 | if (extended != 0) { | ||
146 | err("TODO: extended (EUI64) MAC addresses aren't completely supported yet"); | ||
147 | ret = -EINVAL; | ||
148 | /* memcpy(fc->mac_address,buf,3); | ||
149 | mac[3] = 0xfe; | ||
150 | mac[4] = 0xff; | ||
151 | memcpy(&fc->mac_address[3],&buf[5],3); */ | ||
152 | } else | ||
153 | memcpy(fc->mac_address,buf,6); | ||
154 | } | ||
155 | return ret; | ||
156 | } | ||
157 | EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr); | ||
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c new file mode 100644 index 000000000000..b3dd16fb5bbd --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC. | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | #include "flexcop.h" | ||
9 | |||
10 | #include "stv0299.h" | ||
11 | #include "mt352.h" | ||
12 | #include "nxt2002.h" | ||
13 | #include "stv0297.h" | ||
14 | #include "mt312.h" | ||
15 | |||
16 | /* lnb control */ | ||
17 | |||
18 | static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | ||
19 | { | ||
20 | struct flexcop_device *fc = fe->dvb->priv; | ||
21 | flexcop_ibi_value v; | ||
22 | deb_tuner("polarity/voltage = %u\n", voltage); | ||
23 | |||
24 | v = fc->read_ibi_reg(fc, misc_204); | ||
25 | switch (voltage) { | ||
26 | case SEC_VOLTAGE_OFF: | ||
27 | v.misc_204.ACPI1_sig = 1; | ||
28 | break; | ||
29 | case SEC_VOLTAGE_13: | ||
30 | v.misc_204.ACPI1_sig = 0; | ||
31 | v.misc_204.LNB_L_H_sig = 0; | ||
32 | break; | ||
33 | case SEC_VOLTAGE_18: | ||
34 | v.misc_204.ACPI1_sig = 0; | ||
35 | v.misc_204.LNB_L_H_sig = 1; | ||
36 | break; | ||
37 | default: | ||
38 | err("unknown SEC_VOLTAGE value"); | ||
39 | return -EINVAL; | ||
40 | } | ||
41 | return fc->write_ibi_reg(fc, misc_204, v); | ||
42 | } | ||
43 | |||
44 | static int flexcop_sleep(struct dvb_frontend* fe) | ||
45 | { | ||
46 | struct flexcop_device *fc = fe->dvb->priv; | ||
47 | /* flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */ | ||
48 | |||
49 | if (fc->fe_sleep) | ||
50 | return fc->fe_sleep(fe); | ||
51 | |||
52 | /* v.misc_204.ACPI3_sig = 1; | ||
53 | fc->write_ibi_reg(fc,misc_204,v);*/ | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) | ||
59 | { | ||
60 | /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ | ||
61 | struct flexcop_device *fc = fe->dvb->priv; | ||
62 | flexcop_ibi_value v; | ||
63 | u16 ax; | ||
64 | v.raw = 0; | ||
65 | |||
66 | deb_tuner("tone = %u\n",tone); | ||
67 | |||
68 | switch (tone) { | ||
69 | case SEC_TONE_ON: | ||
70 | ax = 0x01ff; | ||
71 | break; | ||
72 | case SEC_TONE_OFF: | ||
73 | ax = 0; | ||
74 | break; | ||
75 | default: | ||
76 | err("unknown SEC_TONE value"); | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | |||
80 | v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */ | ||
81 | |||
82 | v.lnb_switch_freq_200.LNB_CTLHighCount_sig = | ||
83 | v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax; | ||
84 | |||
85 | return fc->write_ibi_reg(fc,lnb_switch_freq_200,v); | ||
86 | } | ||
87 | |||
88 | static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data) | ||
89 | { | ||
90 | flexcop_set_tone(fe, SEC_TONE_ON); | ||
91 | udelay(data ? 500 : 1000); | ||
92 | flexcop_set_tone(fe, SEC_TONE_OFF); | ||
93 | udelay(data ? 1000 : 500); | ||
94 | } | ||
95 | |||
96 | static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data) | ||
97 | { | ||
98 | int i, par = 1, d; | ||
99 | |||
100 | for (i = 7; i >= 0; i--) { | ||
101 | d = (data >> i) & 1; | ||
102 | par ^= d; | ||
103 | flexcop_diseqc_send_bit(fe, d); | ||
104 | } | ||
105 | |||
106 | flexcop_diseqc_send_bit(fe, par); | ||
107 | } | ||
108 | |||
109 | static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst) | ||
110 | { | ||
111 | int i; | ||
112 | |||
113 | flexcop_set_tone(fe, SEC_TONE_OFF); | ||
114 | mdelay(16); | ||
115 | |||
116 | for (i = 0; i < len; i++) | ||
117 | flexcop_diseqc_send_byte(fe,msg[i]); | ||
118 | |||
119 | mdelay(16); | ||
120 | |||
121 | if (burst != -1) { | ||
122 | if (burst) | ||
123 | flexcop_diseqc_send_byte(fe, 0xff); | ||
124 | else { | ||
125 | flexcop_set_tone(fe, SEC_TONE_ON); | ||
126 | udelay(12500); | ||
127 | flexcop_set_tone(fe, SEC_TONE_OFF); | ||
128 | } | ||
129 | msleep(20); | ||
130 | } | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) | ||
135 | { | ||
136 | return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0); | ||
137 | } | ||
138 | |||
139 | static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) | ||
140 | { | ||
141 | return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd); | ||
142 | } | ||
143 | |||
144 | /* dvb-s stv0299 */ | ||
145 | static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) | ||
146 | { | ||
147 | u8 aclk = 0; | ||
148 | u8 bclk = 0; | ||
149 | |||
150 | if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } | ||
151 | else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } | ||
152 | else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } | ||
153 | else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } | ||
154 | else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } | ||
155 | else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } | ||
156 | |||
157 | stv0299_writereg (fe, 0x13, aclk); | ||
158 | stv0299_writereg (fe, 0x14, bclk); | ||
159 | stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); | ||
160 | stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); | ||
161 | stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) | ||
167 | { | ||
168 | u8 buf[4]; | ||
169 | u32 div; | ||
170 | struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; | ||
171 | struct flexcop_device *fc = fe->dvb->priv; | ||
172 | |||
173 | div = params->frequency / 125; | ||
174 | |||
175 | buf[0] = (div >> 8) & 0x7f; | ||
176 | buf[1] = div & 0xff; | ||
177 | buf[2] = 0x84; /* 0xC4 */ | ||
178 | buf[3] = 0x08; | ||
179 | |||
180 | if (params->frequency < 1500000) buf[3] |= 0x10; | ||
181 | |||
182 | if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) | ||
183 | return -EIO; | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static u8 samsung_tbmu24112_inittab[] = { | ||
188 | 0x01, 0x15, | ||
189 | 0x02, 0x30, | ||
190 | 0x03, 0x00, | ||
191 | 0x04, 0x7D, | ||
192 | 0x05, 0x35, | ||
193 | 0x06, 0x02, | ||
194 | 0x07, 0x00, | ||
195 | 0x08, 0xC3, | ||
196 | 0x0C, 0x00, | ||
197 | 0x0D, 0x81, | ||
198 | 0x0E, 0x23, | ||
199 | 0x0F, 0x12, | ||
200 | 0x10, 0x7E, | ||
201 | 0x11, 0x84, | ||
202 | 0x12, 0xB9, | ||
203 | 0x13, 0x88, | ||
204 | 0x14, 0x89, | ||
205 | 0x15, 0xC9, | ||
206 | 0x16, 0x00, | ||
207 | 0x17, 0x5C, | ||
208 | 0x18, 0x00, | ||
209 | 0x19, 0x00, | ||
210 | 0x1A, 0x00, | ||
211 | 0x1C, 0x00, | ||
212 | 0x1D, 0x00, | ||
213 | 0x1E, 0x00, | ||
214 | 0x1F, 0x3A, | ||
215 | 0x20, 0x2E, | ||
216 | 0x21, 0x80, | ||
217 | 0x22, 0xFF, | ||
218 | 0x23, 0xC1, | ||
219 | 0x28, 0x00, | ||
220 | 0x29, 0x1E, | ||
221 | 0x2A, 0x14, | ||
222 | 0x2B, 0x0F, | ||
223 | 0x2C, 0x09, | ||
224 | 0x2D, 0x05, | ||
225 | 0x31, 0x1F, | ||
226 | 0x32, 0x19, | ||
227 | 0x33, 0xFE, | ||
228 | 0x34, 0x93, | ||
229 | 0xff, 0xff, | ||
230 | }; | ||
231 | |||
232 | static struct stv0299_config samsung_tbmu24112_config = { | ||
233 | .demod_address = 0x68, | ||
234 | .inittab = samsung_tbmu24112_inittab, | ||
235 | .mclk = 88000000UL, | ||
236 | .invert = 0, | ||
237 | .enhanced_tuning = 0, | ||
238 | .skip_reinit = 0, | ||
239 | .lock_output = STV0229_LOCKOUTPUT_LK, | ||
240 | .volt13_op0_op1 = STV0299_VOLT13_OP1, | ||
241 | .min_delay_ms = 100, | ||
242 | .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, | ||
243 | .pll_set = samsung_tbmu24112_pll_set, | ||
244 | }; | ||
245 | |||
246 | /* dvb-t mt352 */ | ||
247 | static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) | ||
248 | { | ||
249 | static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d }; | ||
250 | static u8 mt352_reset [] = { 0x50, 0x80 }; | ||
251 | static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; | ||
252 | static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; | ||
253 | static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; | ||
254 | |||
255 | mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); | ||
256 | udelay(2000); | ||
257 | mt352_write(fe, mt352_reset, sizeof(mt352_reset)); | ||
258 | mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); | ||
259 | |||
260 | mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); | ||
261 | mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) | ||
267 | { | ||
268 | u32 div; | ||
269 | unsigned char bs = 0; | ||
270 | |||
271 | #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ | ||
272 | div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; | ||
273 | |||
274 | if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; | ||
275 | if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; | ||
276 | if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; | ||
277 | |||
278 | pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */ | ||
279 | pllbuf[1] = div >> 8; | ||
280 | pllbuf[2] = div & 0xff; | ||
281 | pllbuf[3] = 0xcc; | ||
282 | pllbuf[4] = bs; | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static struct mt352_config samsung_tdtc9251dh0_config = { | ||
288 | |||
289 | .demod_address = 0x0f, | ||
290 | .demod_init = samsung_tdtc9251dh0_demod_init, | ||
291 | .pll_set = samsung_tdtc9251dh0_pll_set, | ||
292 | }; | ||
293 | |||
294 | static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) | ||
295 | { | ||
296 | struct flexcop_device *fc = fe->dvb->priv; | ||
297 | return request_firmware(fw, name, fc->dev); | ||
298 | } | ||
299 | |||
300 | static struct nxt2002_config samsung_tbmv_config = { | ||
301 | .demod_address = 0x0a, | ||
302 | .request_firmware = nxt2002_request_firmware, | ||
303 | }; | ||
304 | |||
305 | static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) | ||
306 | { | ||
307 | u8 buf[4]; | ||
308 | u32 div; | ||
309 | struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; | ||
310 | struct flexcop_device *fc = fe->dvb->priv; | ||
311 | |||
312 | div = (params->frequency + (125/2)) / 125; | ||
313 | |||
314 | buf[0] = (div >> 8) & 0x7f; | ||
315 | buf[1] = (div >> 0) & 0xff; | ||
316 | buf[2] = 0x84 | ((div >> 10) & 0x60); | ||
317 | buf[3] = 0x80; | ||
318 | |||
319 | if (params->frequency < 1550000) | ||
320 | buf[3] |= 0x02; | ||
321 | |||
322 | if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) | ||
323 | return -EIO; | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static struct mt312_config skystar23_samsung_tbdu18132_config = { | ||
328 | |||
329 | .demod_address = 0x0e, | ||
330 | .pll_set = skystar23_samsung_tbdu18132_pll_set, | ||
331 | }; | ||
332 | |||
333 | static struct stv0297_config alps_tdee4_stv0297_config = { | ||
334 | .demod_address = 0x1c, | ||
335 | // .invert = 1, | ||
336 | // .pll_set = alps_tdee4_stv0297_pll_set, | ||
337 | }; | ||
338 | |||
339 | /* try to figure out the frontend, each card/box can have on of the following list */ | ||
340 | int flexcop_frontend_init(struct flexcop_device *fc) | ||
341 | { | ||
342 | /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */ | ||
343 | if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) { | ||
344 | fc->fe->ops->set_voltage = flexcop_set_voltage; | ||
345 | |||
346 | fc->fe_sleep = fc->fe->ops->sleep; | ||
347 | fc->fe->ops->sleep = flexcop_sleep; | ||
348 | |||
349 | fc->dev_type = FC_SKY; | ||
350 | info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address); | ||
351 | } else | ||
352 | /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */ | ||
353 | if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) { | ||
354 | fc->dev_type = FC_AIR_DVB; | ||
355 | info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address); | ||
356 | } else | ||
357 | /* try the air atsc (nxt2002) */ | ||
358 | if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) { | ||
359 | fc->dev_type = FC_AIR_ATSC; | ||
360 | info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address); | ||
361 | } else | ||
362 | /* try the cable dvb (stv0297) */ | ||
363 | if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) { | ||
364 | fc->dev_type = FC_CABLE; | ||
365 | info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address); | ||
366 | } else | ||
367 | /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ | ||
368 | if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) { | ||
369 | fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; | ||
370 | fc->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst; | ||
371 | fc->fe->ops->set_tone = flexcop_set_tone; | ||
372 | fc->fe->ops->set_voltage = flexcop_set_voltage; | ||
373 | |||
374 | fc->fe_sleep = fc->fe->ops->sleep; | ||
375 | fc->fe->ops->sleep = flexcop_sleep; | ||
376 | |||
377 | fc->dev_type = FC_SKY_OLD; | ||
378 | info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address); | ||
379 | } | ||
380 | |||
381 | if (fc->fe == NULL) { | ||
382 | err("no frontend driver found for this B2C2/FlexCop adapter"); | ||
383 | return -ENODEV; | ||
384 | } else { | ||
385 | if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { | ||
386 | err("frontend registration failed!"); | ||
387 | if (fc->fe->ops->release != NULL) | ||
388 | fc->fe->ops->release(fc->fe); | ||
389 | fc->fe = NULL; | ||
390 | return -EINVAL; | ||
391 | } | ||
392 | } | ||
393 | fc->init_state |= FC_STATE_FE_INIT; | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | void flexcop_frontend_exit(struct flexcop_device *fc) | ||
398 | { | ||
399 | if (fc->init_state & FC_STATE_FE_INIT) | ||
400 | dvb_unregister_frontend(fc->fe); | ||
401 | |||
402 | fc->init_state &= ~FC_STATE_FE_INIT; | ||
403 | } | ||
diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c new file mode 100644 index 000000000000..db983d704ff7 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c | |||
@@ -0,0 +1,198 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop-hw-filter.c - pid and mac address filtering and corresponding control functions. | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | #include "flexcop.h" | ||
9 | |||
10 | static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff) | ||
11 | { | ||
12 | flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff); | ||
13 | } | ||
14 | |||
15 | void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) | ||
16 | { | ||
17 | flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff); | ||
18 | } | ||
19 | |||
20 | void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) | ||
21 | { | ||
22 | flexcop_set_ibi_value(ctrl_208,Null_filter_sig,onoff); | ||
23 | } | ||
24 | |||
25 | void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]) | ||
26 | { | ||
27 | flexcop_ibi_value v418,v41c; | ||
28 | v41c = fc->read_ibi_reg(fc,mac_address_41c); | ||
29 | |||
30 | v418.mac_address_418.MAC1 = mac[0]; | ||
31 | v418.mac_address_418.MAC2 = mac[1]; | ||
32 | v418.mac_address_418.MAC3 = mac[2]; | ||
33 | v418.mac_address_418.MAC6 = mac[3]; | ||
34 | v41c.mac_address_41c.MAC7 = mac[4]; | ||
35 | v41c.mac_address_41c.MAC8 = mac[5]; | ||
36 | |||
37 | fc->write_ibi_reg(fc,mac_address_418,v418); | ||
38 | fc->write_ibi_reg(fc,mac_address_41c,v41c); | ||
39 | } | ||
40 | |||
41 | void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff) | ||
42 | { | ||
43 | flexcop_set_ibi_value(ctrl_208,MAC_filter_Mode_sig,onoff); | ||
44 | } | ||
45 | |||
46 | static void flexcop_pid_group_filter(struct flexcop_device *fc, u16 pid, u16 mask) | ||
47 | { | ||
48 | /* index_reg_310.extra_index_reg need to 0 or 7 to work */ | ||
49 | flexcop_ibi_value v30c; | ||
50 | v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid; | ||
51 | v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask; | ||
52 | fc->write_ibi_reg(fc,pid_filter_30c,v30c); | ||
53 | } | ||
54 | |||
55 | static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff) | ||
56 | { | ||
57 | flexcop_set_ibi_value(ctrl_208,Mask_filter_sig,onoff); | ||
58 | } | ||
59 | |||
60 | /* this fancy define reduces the code size of the quite similar PID controlling of | ||
61 | * the first 6 PIDs | ||
62 | */ | ||
63 | |||
64 | #define pid_ctrl(vregname,field,enablefield,trans_field,transval) \ | ||
65 | flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \ | ||
66 | v208 = fc->read_ibi_reg(fc, ctrl_208); \ | ||
67 | \ | ||
68 | vpid.vregname.field = onoff ? pid : 0x1fff; \ | ||
69 | vpid.vregname.trans_field = transval; \ | ||
70 | v208.ctrl_208.enablefield = onoff; \ | ||
71 | \ | ||
72 | fc->write_ibi_reg(fc,vregname,vpid); \ | ||
73 | fc->write_ibi_reg(fc,ctrl_208,v208); | ||
74 | |||
75 | static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) | ||
76 | { | ||
77 | pid_ctrl(pid_filter_300,Stream1_PID,Stream1_filter_sig,Stream1_trans,0); | ||
78 | } | ||
79 | |||
80 | static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) | ||
81 | { | ||
82 | pid_ctrl(pid_filter_300,Stream2_PID,Stream2_filter_sig,Stream2_trans,0); | ||
83 | } | ||
84 | |||
85 | static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) | ||
86 | { | ||
87 | pid_ctrl(pid_filter_304,PCR_PID,PCR_filter_sig,PCR_trans,0); | ||
88 | } | ||
89 | |||
90 | static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) | ||
91 | { | ||
92 | pid_ctrl(pid_filter_304,PMT_PID,PMT_filter_sig,PMT_trans,0); | ||
93 | } | ||
94 | |||
95 | static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) | ||
96 | { | ||
97 | pid_ctrl(pid_filter_308,EMM_PID,EMM_filter_sig,EMM_trans,0); | ||
98 | } | ||
99 | |||
100 | static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) | ||
101 | { | ||
102 | pid_ctrl(pid_filter_308,ECM_PID,ECM_filter_sig,ECM_trans,0); | ||
103 | } | ||
104 | |||
105 | static void flexcop_pid_control(struct flexcop_device *fc, int index, u16 pid,int onoff) | ||
106 | { | ||
107 | deb_ts("setting pid: %5d %04x at index %d '%s'\n",pid,pid,index,onoff ? "on" : "off"); | ||
108 | |||
109 | /* We could use bit magic here to reduce source code size. | ||
110 | * I decided against it, but to use the real register names */ | ||
111 | switch (index) { | ||
112 | case 0: flexcop_pid_Stream1_PID_ctrl(fc,pid,onoff); break; | ||
113 | case 1: flexcop_pid_Stream2_PID_ctrl(fc,pid,onoff); break; | ||
114 | case 2: flexcop_pid_PCR_PID_ctrl(fc,pid,onoff); break; | ||
115 | case 3: flexcop_pid_PMT_PID_ctrl(fc,pid,onoff); break; | ||
116 | case 4: flexcop_pid_EMM_PID_ctrl(fc,pid,onoff); break; | ||
117 | case 5: flexcop_pid_ECM_PID_ctrl(fc,pid,onoff); break; | ||
118 | default: | ||
119 | if (fc->has_32_hw_pid_filter && index < 38) { | ||
120 | flexcop_ibi_value vpid,vid; | ||
121 | |||
122 | /* set the index */ | ||
123 | vid = fc->read_ibi_reg(fc,index_reg_310); | ||
124 | vid.index_reg_310.index_reg = index - 6; | ||
125 | fc->write_ibi_reg(fc,index_reg_310, vid); | ||
126 | |||
127 | vpid = fc->read_ibi_reg(fc,pid_n_reg_314); | ||
128 | vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff; | ||
129 | vpid.pid_n_reg_314.PID_enable_bit = onoff; | ||
130 | fc->write_ibi_reg(fc,pid_n_reg_314, vpid); | ||
131 | } | ||
132 | break; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff) | ||
137 | { | ||
138 | int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32; | ||
139 | |||
140 | fc->feedcount += (onoff ? 1 : -1); | ||
141 | |||
142 | /* when doing hw pid filtering, set the pid */ | ||
143 | if (fc->pid_filtering) | ||
144 | flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff); | ||
145 | |||
146 | /* if it was the first feed request */ | ||
147 | if (fc->feedcount == onoff && onoff) { | ||
148 | if (!fc->pid_filtering) { | ||
149 | deb_ts("enabling full TS transfer\n"); | ||
150 | flexcop_pid_group_filter(fc, 0,0); | ||
151 | flexcop_pid_group_filter_ctrl(fc,1); | ||
152 | } | ||
153 | |||
154 | if (fc->stream_control) | ||
155 | fc->stream_control(fc,1); | ||
156 | flexcop_rcv_data_ctrl(fc,1); | ||
157 | |||
158 | /* if there is no more feed left to feed */ | ||
159 | } else if (fc->feedcount == onoff && !onoff) { | ||
160 | if (!fc->pid_filtering) { | ||
161 | deb_ts("disabling full TS transfer\n"); | ||
162 | flexcop_pid_group_filter(fc, 0x1fe0,0); | ||
163 | flexcop_pid_group_filter_ctrl(fc,0); | ||
164 | } | ||
165 | |||
166 | flexcop_rcv_data_ctrl(fc,0); | ||
167 | if (fc->stream_control) | ||
168 | fc->stream_control(fc,0); | ||
169 | } | ||
170 | |||
171 | /* if pid_filtering is on and more pids than the hw-filter can provide are | ||
172 | * requested enable the whole bandwidth. | ||
173 | */ | ||
174 | if (fc->pid_filtering && fc->feedcount > max_pid_filter) { | ||
175 | flexcop_pid_group_filter(fc, 0,0); | ||
176 | flexcop_pid_group_filter_ctrl(fc,1); | ||
177 | } else if (fc->pid_filtering && fc->feedcount <= max_pid_filter) { | ||
178 | flexcop_pid_group_filter(fc, 0x1fe0,0); | ||
179 | flexcop_pid_group_filter_ctrl(fc,0); | ||
180 | } | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | void flexcop_hw_filter_init(struct flexcop_device *fc) | ||
186 | { | ||
187 | int i; | ||
188 | flexcop_ibi_value v; | ||
189 | for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++) | ||
190 | flexcop_pid_control(fc,i,0x1fff,0); | ||
191 | |||
192 | flexcop_pid_group_filter(fc, 0x1fe0,0); | ||
193 | |||
194 | v = fc->read_ibi_reg(fc,pid_filter_308); | ||
195 | v.pid_filter_308.EMM_filter_4 = 1; | ||
196 | v.pid_filter_308.EMM_filter_6 = 0; | ||
197 | fc->write_ibi_reg(fc,pid_filter_308,v); | ||
198 | } | ||
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c new file mode 100644 index 000000000000..736251f393c2 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | #include "flexcop.h" | ||
9 | |||
10 | #define FC_MAX_I2C_RETRIES 100000 | ||
11 | |||
12 | static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100, int max_ack_errors) | ||
13 | { | ||
14 | int i,ack_errors = 0; | ||
15 | flexcop_ibi_value r; | ||
16 | |||
17 | r100->tw_sm_c_100.working_start = 1; | ||
18 | deb_i2c("r100 before: %08x\n",r100->raw); | ||
19 | |||
20 | fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero); | ||
21 | fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */ | ||
22 | |||
23 | for (i = 0; i < FC_MAX_I2C_RETRIES; i++) { | ||
24 | r = fc->read_ibi_reg(fc, tw_sm_c_100); | ||
25 | |||
26 | if (!r.tw_sm_c_100.no_base_addr_ack_error) { | ||
27 | if (r.tw_sm_c_100.st_done) { /* && !r.tw_sm_c_100.working_start */ | ||
28 | *r100 = r; | ||
29 | deb_i2c("i2c success\n"); | ||
30 | return 0; | ||
31 | } | ||
32 | } else { | ||
33 | deb_i2c("suffering from an i2c ack_error\n"); | ||
34 | if (++ack_errors >= max_ack_errors) | ||
35 | break; | ||
36 | |||
37 | fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero); | ||
38 | fc->write_ibi_reg(fc, tw_sm_c_100, *r100); | ||
39 | } | ||
40 | } | ||
41 | deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n",i); | ||
42 | return -EREMOTEIO; | ||
43 | } | ||
44 | |||
45 | static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf) | ||
46 | { | ||
47 | flexcop_ibi_value r104; | ||
48 | int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */ | ||
49 | ret; | ||
50 | |||
51 | if ((ret = flexcop_i2c_operation(fc,&r100,30)) != 0) | ||
52 | return ret; | ||
53 | |||
54 | r104 = fc->read_ibi_reg(fc,tw_sm_c_104); | ||
55 | |||
56 | deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw); | ||
57 | |||
58 | /* there is at least one byte, otherwise we wouldn't be here */ | ||
59 | buf[0] = r100.tw_sm_c_100.data1_reg; | ||
60 | |||
61 | if (len > 0) buf[1] = r104.tw_sm_c_104.data2_reg; | ||
62 | if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg; | ||
63 | if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg; | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf) | ||
69 | { | ||
70 | flexcop_ibi_value r104; | ||
71 | int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */ | ||
72 | r104.raw = 0; | ||
73 | |||
74 | /* there is at least one byte, otherwise we wouldn't be here */ | ||
75 | r100.tw_sm_c_100.data1_reg = buf[0]; | ||
76 | |||
77 | r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0; | ||
78 | r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0; | ||
79 | r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0; | ||
80 | |||
81 | deb_i2c("write: r100: %08x, r104: %08x\n",r100.raw,r104.raw); | ||
82 | |||
83 | /* write the additional i2c data before doing the actual i2c operation */ | ||
84 | fc->write_ibi_reg(fc,tw_sm_c_104,r104); | ||
85 | |||
86 | return flexcop_i2c_operation(fc,&r100,30); | ||
87 | } | ||
88 | |||
89 | /* master xfer callback for demodulator */ | ||
90 | static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) | ||
91 | { | ||
92 | struct flexcop_device *fc = i2c_get_adapdata(i2c_adap); | ||
93 | int i, ret = 0; | ||
94 | |||
95 | if (down_interruptible(&fc->i2c_sem)) | ||
96 | return -ERESTARTSYS; | ||
97 | |||
98 | /* reading */ | ||
99 | if (num == 2 && | ||
100 | msgs[0].flags == 0 && | ||
101 | msgs[1].flags == I2C_M_RD && | ||
102 | msgs[0].buf != NULL && | ||
103 | msgs[1].buf != NULL) { | ||
104 | |||
105 | ret = fc->i2c_request(fc, FC_READ, FC_I2C_PORT_DEMOD, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len); | ||
106 | |||
107 | } else for (i = 0; i < num; i++) { /* writing command */ | ||
108 | if (msgs[i].flags != 0 || msgs[i].buf == NULL || msgs[i].len < 2) { | ||
109 | ret = -EINVAL; | ||
110 | break; | ||
111 | } | ||
112 | |||
113 | ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_DEMOD, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1); | ||
114 | } | ||
115 | |||
116 | if (ret < 0) | ||
117 | err("i2c master_xfer failed"); | ||
118 | else | ||
119 | ret = num; | ||
120 | |||
121 | up(&fc->i2c_sem); | ||
122 | |||
123 | return ret; | ||
124 | } | ||
125 | |||
126 | int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | ||
127 | flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len) | ||
128 | { | ||
129 | int ret; | ||
130 | u16 bytes_to_transfer; | ||
131 | flexcop_ibi_value r100; | ||
132 | |||
133 | deb_i2c("op = %d\n",op); | ||
134 | r100.raw = 0; | ||
135 | r100.tw_sm_c_100.chipaddr = chipaddr; | ||
136 | r100.tw_sm_c_100.twoWS_rw = op; | ||
137 | r100.tw_sm_c_100.twoWS_port_reg = port; | ||
138 | |||
139 | while (len != 0) { | ||
140 | bytes_to_transfer = len > 4 ? 4 : len; | ||
141 | |||
142 | r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1; | ||
143 | r100.tw_sm_c_100.baseaddr = addr; | ||
144 | |||
145 | if (op == FC_READ) | ||
146 | ret = flexcop_i2c_read4(fc, r100, buf); | ||
147 | else | ||
148 | ret = flexcop_i2c_write4(fc,r100, buf); | ||
149 | |||
150 | if (ret < 0) | ||
151 | return ret; | ||
152 | |||
153 | buf += bytes_to_transfer; | ||
154 | addr += bytes_to_transfer; | ||
155 | len -= bytes_to_transfer; | ||
156 | }; | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | /* exported for PCI i2c */ | ||
161 | EXPORT_SYMBOL(flexcop_i2c_request); | ||
162 | |||
163 | static u32 flexcop_i2c_func(struct i2c_adapter *adapter) | ||
164 | { | ||
165 | return I2C_FUNC_I2C; | ||
166 | } | ||
167 | |||
168 | static struct i2c_algorithm flexcop_algo = { | ||
169 | .name = "FlexCop I2C algorithm", | ||
170 | .id = I2C_ALGO_BIT, | ||
171 | .master_xfer = flexcop_master_xfer, | ||
172 | .functionality = flexcop_i2c_func, | ||
173 | }; | ||
174 | |||
175 | int flexcop_i2c_init(struct flexcop_device *fc) | ||
176 | { | ||
177 | int ret; | ||
178 | |||
179 | sema_init(&fc->i2c_sem,1); | ||
180 | |||
181 | memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter)); | ||
182 | strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE); | ||
183 | |||
184 | i2c_set_adapdata(&fc->i2c_adap,fc); | ||
185 | |||
186 | fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL; | ||
187 | fc->i2c_adap.algo = &flexcop_algo; | ||
188 | fc->i2c_adap.algo_data = NULL; | ||
189 | fc->i2c_adap.id = I2C_ALGO_BIT; | ||
190 | |||
191 | if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0) | ||
192 | return ret; | ||
193 | |||
194 | fc->init_state |= FC_STATE_I2C_INIT; | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | void flexcop_i2c_exit(struct flexcop_device *fc) | ||
199 | { | ||
200 | if (fc->init_state & FC_STATE_I2C_INIT) | ||
201 | i2c_del_adapter(&fc->i2c_adap); | ||
202 | |||
203 | fc->init_state &= ~FC_STATE_I2C_INIT; | ||
204 | } | ||
diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c new file mode 100644 index 000000000000..19e06da46774 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-misc.c | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop-misc.c - miscellaneous functions. | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | #include "flexcop.h" | ||
9 | |||
10 | void flexcop_determine_revision(struct flexcop_device *fc) | ||
11 | { | ||
12 | flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); | ||
13 | |||
14 | switch (v.misc_204.Rev_N_sig_revision_hi) { | ||
15 | case 0x2: | ||
16 | deb_info("found a FlexCopII.\n"); | ||
17 | fc->rev = FLEXCOP_II; | ||
18 | break; | ||
19 | case 0x3: | ||
20 | deb_info("found a FlexCopIIb.\n"); | ||
21 | fc->rev = FLEXCOP_IIB; | ||
22 | break; | ||
23 | case 0x0: | ||
24 | deb_info("found a FlexCopIII.\n"); | ||
25 | fc->rev = FLEXCOP_III; | ||
26 | break; | ||
27 | default: | ||
28 | err("unkown FlexCop Revision: %x. Please report the linux-dvb@linuxtv.org.",v.misc_204.Rev_N_sig_revision_hi); | ||
29 | break; | ||
30 | } | ||
31 | |||
32 | if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps)) | ||
33 | deb_info("this FlexCop has the additional 32 hardware pid filter.\n"); | ||
34 | else | ||
35 | deb_info("this FlexCop has only the 6 basic main hardware pid filter.\n"); | ||
36 | /* bus parts have to decide if hw pid filtering is used or not. */ | ||
37 | } | ||
38 | |||
39 | const char *flexcop_revision_names[] = { | ||
40 | "Unkown chip", | ||
41 | "FlexCopII", | ||
42 | "FlexCopIIb", | ||
43 | "FlexCopIII", | ||
44 | }; | ||
45 | |||
46 | const char *flexcop_device_names[] = { | ||
47 | "Unkown device", | ||
48 | "AirStar 2 DVB-T", | ||
49 | "AirStar 2 ATSC", | ||
50 | "SkyStar 2 DVB-S", | ||
51 | "SkyStar 2 DVB-S (old version)", | ||
52 | "CableStar 2 DVB-C", | ||
53 | }; | ||
54 | |||
55 | const char *flexcop_bus_names[] = { | ||
56 | "USB", | ||
57 | "PCI", | ||
58 | }; | ||
59 | |||
60 | void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const | ||
61 | char *suffix) | ||
62 | { | ||
63 | info("%s '%s' at the '%s' bus controlled by a '%s' %s",prefix, | ||
64 | flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type], | ||
65 | flexcop_revision_names[fc->rev],suffix); | ||
66 | } | ||
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c new file mode 100644 index 000000000000..693af41f3370 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-pci.c | |||
@@ -0,0 +1,365 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop-pci.c - covers the PCI part including DMA transfers. | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | |||
9 | #define FC_LOG_PREFIX "flexcop-pci" | ||
10 | #include "flexcop-common.h" | ||
11 | |||
12 | static int enable_pid_filtering = 0; | ||
13 | module_param(enable_pid_filtering, int, 0444); | ||
14 | MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1"); | ||
15 | |||
16 | #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG | ||
17 | #define dprintk(level,args...) \ | ||
18 | do { if ((debug & level)) printk(args); } while (0) | ||
19 | #define DEBSTATUS "" | ||
20 | #else | ||
21 | #define dprintk(level,args...) | ||
22 | #define DEBSTATUS " (debugging is not enabled)" | ||
23 | #endif | ||
24 | |||
25 | #define deb_info(args...) dprintk(0x01,args) | ||
26 | #define deb_reg(args...) dprintk(0x02,args) | ||
27 | #define deb_ts(args...) dprintk(0x04,args) | ||
28 | #define deb_irq(args...) dprintk(0x08,args) | ||
29 | |||
30 | static int debug = 0; | ||
31 | module_param(debug, int, 0644); | ||
32 | MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS); | ||
33 | |||
34 | #define DRIVER_VERSION "0.1" | ||
35 | #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" | ||
36 | #define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>" | ||
37 | |||
38 | struct flexcop_pci { | ||
39 | struct pci_dev *pdev; | ||
40 | |||
41 | #define FC_PCI_INIT 0x01 | ||
42 | #define FC_PCI_DMA_INIT 0x02 | ||
43 | int init_state; | ||
44 | |||
45 | void __iomem *io_mem; | ||
46 | u32 irq; | ||
47 | /* buffersize (at least for DMA1, need to be % 188 == 0, | ||
48 | * this is logic is required */ | ||
49 | #define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188) | ||
50 | #define FC_DEFAULT_DMA2_BUFSIZE (10 * 188) | ||
51 | struct flexcop_dma dma[2]; | ||
52 | |||
53 | int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ | ||
54 | u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */ | ||
55 | |||
56 | struct flexcop_device *fc_dev; | ||
57 | }; | ||
58 | |||
59 | static int lastwreg,lastwval,lastrreg,lastrval; | ||
60 | |||
61 | static flexcop_ibi_value flexcop_pci_read_ibi_reg (struct flexcop_device *fc, flexcop_ibi_register r) | ||
62 | { | ||
63 | struct flexcop_pci *fc_pci = fc->bus_specific; | ||
64 | flexcop_ibi_value v; | ||
65 | v.raw = readl(fc_pci->io_mem + r); | ||
66 | |||
67 | if (lastrreg != r || lastrval != v.raw) { | ||
68 | lastrreg = r; lastrval = v.raw; | ||
69 | deb_reg("new rd: %3x: %08x\n",r,v.raw); | ||
70 | } | ||
71 | |||
72 | return v; | ||
73 | } | ||
74 | |||
75 | static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register r, flexcop_ibi_value v) | ||
76 | { | ||
77 | struct flexcop_pci *fc_pci = fc->bus_specific; | ||
78 | |||
79 | if (lastwreg != r || lastwval != v.raw) { | ||
80 | lastwreg = r; lastwval = v.raw; | ||
81 | deb_reg("new wr: %3x: %08x\n",r,v.raw); | ||
82 | } | ||
83 | |||
84 | writel(v.raw, fc_pci->io_mem + r); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | /* When PID filtering is turned on, we use the timer IRQ, because small amounts | ||
89 | * of data need to be passed to the user space instantly as well. When PID | ||
90 | * filtering is turned off, we use the page-change-IRQ */ | ||
91 | static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
92 | { | ||
93 | struct flexcop_pci *fc_pci = dev_id; | ||
94 | struct flexcop_device *fc = fc_pci->fc_dev; | ||
95 | flexcop_ibi_value v = fc->read_ibi_reg(fc,irq_20c); | ||
96 | |||
97 | deb_irq("irq: %08x cur_addr: %08x (%d), our addrs. 1: %08x 2: %08x; 0x000: " | ||
98 | "%08x, 0x00c: %08x\n",v.raw, | ||
99 | fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2, | ||
100 | fc_pci->active_dma1_addr, | ||
101 | fc_pci->dma[0].dma_addr0,fc_pci->dma[0].dma_addr1, | ||
102 | fc->read_ibi_reg(fc,dma1_000).raw, | ||
103 | fc->read_ibi_reg(fc,dma1_00c).raw); | ||
104 | |||
105 | if (v.irq_20c.DMA1_IRQ_Status == 1) { | ||
106 | if (fc_pci->active_dma1_addr == 0) | ||
107 | flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188); | ||
108 | else | ||
109 | flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr1,fc_pci->dma[0].size / 188); | ||
110 | |||
111 | deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr); | ||
112 | fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr; | ||
113 | } else if (v.irq_20c.DMA1_Timer_Status == 1) { | ||
114 | /* for the timer IRQ we only can use buffer dmx feeding, because we don't have | ||
115 | * complete TS packets when reading from the DMA memory */ | ||
116 | dma_addr_t cur_addr = | ||
117 | fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; | ||
118 | u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; | ||
119 | |||
120 | /* buffer end was reached, restarted from the beginning | ||
121 | * pass the data from last_cur_pos to the buffer end to the demux | ||
122 | */ | ||
123 | if (cur_pos < fc_pci->last_dma1_cur_pos) { | ||
124 | flexcop_pass_dmx_data(fc_pci->fc_dev, | ||
125 | fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos, | ||
126 | (fc_pci->dma[0].size*2 - 1) - fc_pci->last_dma1_cur_pos); | ||
127 | fc_pci->last_dma1_cur_pos = 0; | ||
128 | } | ||
129 | |||
130 | if (cur_pos > fc_pci->last_dma1_cur_pos) { | ||
131 | flexcop_pass_dmx_data(fc_pci->fc_dev, | ||
132 | fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos, | ||
133 | cur_pos - fc_pci->last_dma1_cur_pos); | ||
134 | } | ||
135 | |||
136 | fc_pci->last_dma1_cur_pos = cur_pos; | ||
137 | } | ||
138 | |||
139 | /* packet count would be ideal for hw filtering, but it isn't working. Either | ||
140 | * the data book is wrong, or I'm unable to read it correctly */ | ||
141 | |||
142 | /* if (v.irq_20c.DMA1_Size_IRQ_Status == 1) { packet counter */ | ||
143 | |||
144 | return IRQ_HANDLED; | ||
145 | } | ||
146 | |||
147 | static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff) | ||
148 | { | ||
149 | struct flexcop_pci *fc_pci = fc->bus_specific; | ||
150 | if (onoff) { | ||
151 | flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1); | ||
152 | flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1); | ||
153 | flexcop_dma_config_timer(fc,FC_DMA_1,1); | ||
154 | |||
155 | if (fc_pci->fc_dev->pid_filtering) { | ||
156 | fc_pci->last_dma1_cur_pos = 0; | ||
157 | flexcop_dma_control_timer_irq(fc,FC_DMA_1,1); | ||
158 | } else { | ||
159 | fc_pci->active_dma1_addr = 0; | ||
160 | flexcop_dma_control_size_irq(fc,FC_DMA_1,1); | ||
161 | } | ||
162 | |||
163 | /* flexcop_dma_config_packet_count(fc,FC_DMA_1,0xc0); | ||
164 | flexcop_dma_control_packet_irq(fc,FC_DMA_1,1); */ | ||
165 | |||
166 | deb_irq("irqs enabled\n"); | ||
167 | } else { | ||
168 | if (fc_pci->fc_dev->pid_filtering) | ||
169 | flexcop_dma_control_timer_irq(fc,FC_DMA_1,0); | ||
170 | else | ||
171 | flexcop_dma_control_size_irq(fc,FC_DMA_1,0); | ||
172 | |||
173 | // flexcop_dma_control_packet_irq(fc,FC_DMA_1,0); | ||
174 | deb_irq("irqs disabled\n"); | ||
175 | } | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci) | ||
181 | { | ||
182 | int ret; | ||
183 | if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0) | ||
184 | return ret; | ||
185 | |||
186 | if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) | ||
187 | goto dma1_free; | ||
188 | |||
189 | flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1); | ||
190 | flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2); | ||
191 | |||
192 | fc_pci->init_state |= FC_PCI_DMA_INIT; | ||
193 | goto success; | ||
194 | dma1_free: | ||
195 | flexcop_dma_free(&fc_pci->dma[0]); | ||
196 | |||
197 | success: | ||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci) | ||
202 | { | ||
203 | if (fc_pci->init_state & FC_PCI_DMA_INIT) { | ||
204 | flexcop_dma_free(&fc_pci->dma[0]); | ||
205 | flexcop_dma_free(&fc_pci->dma[1]); | ||
206 | } | ||
207 | fc_pci->init_state &= ~FC_PCI_DMA_INIT; | ||
208 | } | ||
209 | |||
210 | static int flexcop_pci_init(struct flexcop_pci *fc_pci) | ||
211 | { | ||
212 | int ret; | ||
213 | u8 card_rev; | ||
214 | |||
215 | pci_read_config_byte(fc_pci->pdev, PCI_CLASS_REVISION, &card_rev); | ||
216 | info("card revision %x", card_rev); | ||
217 | |||
218 | if ((ret = pci_enable_device(fc_pci->pdev)) != 0) | ||
219 | return ret; | ||
220 | |||
221 | pci_set_master(fc_pci->pdev); | ||
222 | |||
223 | /* enable interrupts */ | ||
224 | // pci_write_config_dword(pdev, 0x6c, 0x8000); | ||
225 | |||
226 | if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0) | ||
227 | goto err_pci_disable_device; | ||
228 | |||
229 | fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800); | ||
230 | |||
231 | if (!fc_pci->io_mem) { | ||
232 | err("cannot map io memory\n"); | ||
233 | ret = -EIO; | ||
234 | goto err_pci_release_regions; | ||
235 | } | ||
236 | |||
237 | pci_set_drvdata(fc_pci->pdev, fc_pci); | ||
238 | |||
239 | if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_irq, | ||
240 | SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0) | ||
241 | goto err_pci_iounmap; | ||
242 | |||
243 | fc_pci->init_state |= FC_PCI_INIT; | ||
244 | goto success; | ||
245 | |||
246 | err_pci_iounmap: | ||
247 | pci_iounmap(fc_pci->pdev, fc_pci->io_mem); | ||
248 | pci_set_drvdata(fc_pci->pdev, NULL); | ||
249 | err_pci_release_regions: | ||
250 | pci_release_regions(fc_pci->pdev); | ||
251 | err_pci_disable_device: | ||
252 | pci_disable_device(fc_pci->pdev); | ||
253 | |||
254 | success: | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | static void flexcop_pci_exit(struct flexcop_pci *fc_pci) | ||
259 | { | ||
260 | if (fc_pci->init_state & FC_PCI_INIT) { | ||
261 | free_irq(fc_pci->pdev->irq, fc_pci); | ||
262 | pci_iounmap(fc_pci->pdev, fc_pci->io_mem); | ||
263 | pci_set_drvdata(fc_pci->pdev, NULL); | ||
264 | pci_release_regions(fc_pci->pdev); | ||
265 | pci_disable_device(fc_pci->pdev); | ||
266 | } | ||
267 | fc_pci->init_state &= ~FC_PCI_INIT; | ||
268 | } | ||
269 | |||
270 | |||
271 | static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
272 | { | ||
273 | struct flexcop_device *fc; | ||
274 | struct flexcop_pci *fc_pci; | ||
275 | int ret = -ENOMEM; | ||
276 | |||
277 | if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_pci))) == NULL) { | ||
278 | err("out of memory\n"); | ||
279 | return -ENOMEM; | ||
280 | } | ||
281 | |||
282 | /* general flexcop init */ | ||
283 | fc_pci = fc->bus_specific; | ||
284 | fc_pci->fc_dev = fc; | ||
285 | |||
286 | fc->read_ibi_reg = flexcop_pci_read_ibi_reg; | ||
287 | fc->write_ibi_reg = flexcop_pci_write_ibi_reg; | ||
288 | fc->i2c_request = flexcop_i2c_request; | ||
289 | fc->get_mac_addr = flexcop_eeprom_check_mac_addr; | ||
290 | |||
291 | fc->stream_control = flexcop_pci_stream_control; | ||
292 | |||
293 | fc->pid_filtering = enable_pid_filtering; | ||
294 | fc->bus_type = FC_PCI; | ||
295 | |||
296 | fc->dev = &pdev->dev; | ||
297 | |||
298 | /* bus specific part */ | ||
299 | fc_pci->pdev = pdev; | ||
300 | if ((ret = flexcop_pci_init(fc_pci)) != 0) | ||
301 | goto err_kfree; | ||
302 | |||
303 | /* init flexcop */ | ||
304 | if ((ret = flexcop_device_initialize(fc)) != 0) | ||
305 | goto err_pci_exit; | ||
306 | |||
307 | /* init dma */ | ||
308 | if ((ret = flexcop_pci_dma_init(fc_pci)) != 0) | ||
309 | goto err_fc_exit; | ||
310 | |||
311 | goto success; | ||
312 | err_fc_exit: | ||
313 | flexcop_device_exit(fc); | ||
314 | err_pci_exit: | ||
315 | flexcop_pci_exit(fc_pci); | ||
316 | err_kfree: | ||
317 | flexcop_device_kfree(fc); | ||
318 | success: | ||
319 | return ret; | ||
320 | } | ||
321 | |||
322 | /* in theory every _exit function should be called exactly two times, | ||
323 | * here and in the bail-out-part of the _init-function | ||
324 | */ | ||
325 | static void flexcop_pci_remove(struct pci_dev *pdev) | ||
326 | { | ||
327 | struct flexcop_pci *fc_pci = pci_get_drvdata(pdev); | ||
328 | |||
329 | flexcop_pci_dma_exit(fc_pci); | ||
330 | flexcop_device_exit(fc_pci->fc_dev); | ||
331 | flexcop_pci_exit(fc_pci); | ||
332 | flexcop_device_kfree(fc_pci->fc_dev); | ||
333 | } | ||
334 | |||
335 | static struct pci_device_id flexcop_pci_tbl[] = { | ||
336 | { PCI_DEVICE(0x13d0, 0x2103) }, | ||
337 | /* { PCI_DEVICE(0x13d0, 0x2200) }, PCI FlexCopIII ? */ | ||
338 | { }, | ||
339 | }; | ||
340 | |||
341 | MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl); | ||
342 | |||
343 | static struct pci_driver flexcop_pci_driver = { | ||
344 | .name = "Technisat/B2C2 FlexCop II/IIb/III PCI", | ||
345 | .id_table = flexcop_pci_tbl, | ||
346 | .probe = flexcop_pci_probe, | ||
347 | .remove = flexcop_pci_remove, | ||
348 | }; | ||
349 | |||
350 | static int __init flexcop_pci_module_init(void) | ||
351 | { | ||
352 | return pci_register_driver(&flexcop_pci_driver); | ||
353 | } | ||
354 | |||
355 | static void __exit flexcop_pci_module_exit(void) | ||
356 | { | ||
357 | pci_unregister_driver(&flexcop_pci_driver); | ||
358 | } | ||
359 | |||
360 | module_init(flexcop_pci_module_init); | ||
361 | module_exit(flexcop_pci_module_exit); | ||
362 | |||
363 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
364 | MODULE_DESCRIPTION(DRIVER_NAME); | ||
365 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h new file mode 100644 index 000000000000..41835c5280ae --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-reg.h | |||
@@ -0,0 +1,700 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | #ifndef __FLEXCOP_REG_H__ | ||
9 | #define __FLEXCOP_REG_H__ | ||
10 | |||
11 | |||
12 | typedef enum { | ||
13 | FLEXCOP_UNK = 0, | ||
14 | FLEXCOP_II, | ||
15 | FLEXCOP_IIB, | ||
16 | FLEXCOP_III, | ||
17 | } flexcop_revision_t; | ||
18 | |||
19 | extern const char *flexcop_revision_names[]; | ||
20 | |||
21 | typedef enum { | ||
22 | FC_UNK = 0, | ||
23 | FC_AIR_DVB, | ||
24 | FC_AIR_ATSC, | ||
25 | FC_SKY, | ||
26 | FC_SKY_OLD, | ||
27 | FC_CABLE, | ||
28 | } flexcop_device_type_t; | ||
29 | |||
30 | typedef enum { | ||
31 | FC_USB = 0, | ||
32 | FC_PCI, | ||
33 | } flexcop_bus_t; | ||
34 | |||
35 | extern const char *flexcop_device_names[]; | ||
36 | |||
37 | /* FlexCop IBI Registers */ | ||
38 | |||
39 | /* flexcop_ibi_reg - a huge union representing the register structure */ | ||
40 | typedef union { | ||
41 | u32 raw; | ||
42 | |||
43 | /* DMA 0x000 to 0x01c | ||
44 | * DMA1 0x000 to 0x00c | ||
45 | * DMA2 0x010 to 0x01c | ||
46 | */ | ||
47 | struct { | ||
48 | u32 dma_0start : 1; /* set: data will be delivered to dma1_address0 */ | ||
49 | u32 dma_0No_update : 1; /* set: dma1_cur_address will be updated, unset: no update */ | ||
50 | u32 dma_address0 :30; /* physical/virtual host memory address0 DMA */ | ||
51 | } dma_0x0; | ||
52 | |||
53 | struct { | ||
54 | u32 DMA_maxpackets : 8; /* (remapped) PCI DMA1 Packet Count Interrupt. This variable | ||
55 | is able to be read and written while bit(1) of register | ||
56 | 0x00c (remap_enable) is set. This variable represents | ||
57 | the number of packets that will be transmitted to the PCI | ||
58 | host using PCI DMA1 before an interrupt to the PCI is | ||
59 | asserted. This functionality may be enabled using bit(20) | ||
60 | of register 0x208. N=0 disables the IRQ. */ | ||
61 | u32 dma_addr_size :24; /* size of memory buffer in DWORDs (bytesize / 4) for DMA */ | ||
62 | } dma_0x4_remap; | ||
63 | |||
64 | struct { | ||
65 | u32 dma1timer : 7; /* reading PCI DMA1 timer ... when remap_enable is 0 */ | ||
66 | u32 unused : 1; | ||
67 | u32 dma_addr_size :24; | ||
68 | } dma_0x4_read; | ||
69 | |||
70 | struct { | ||
71 | u32 unused : 1; | ||
72 | u32 dmatimer : 7; /* writing PCI DMA1 timer ... when remap_enable is 0 */ | ||
73 | u32 dma_addr_size :24; | ||
74 | } dma_0x4_write; | ||
75 | |||
76 | struct { | ||
77 | u32 unused : 2; | ||
78 | u32 dma_cur_addr :30; /* current physical host memory address pointer for DMA */ | ||
79 | } dma_0x8; | ||
80 | |||
81 | struct { | ||
82 | u32 dma_1start : 1; /* set: data will be delivered to dma_address1, when dma_address0 is full */ | ||
83 | u32 remap_enable : 1; /* remap enable for 0x0x4(7:0) */ | ||
84 | u32 dma_address1 :30; /* Physical/virtual address 1 on DMA */ | ||
85 | } dma_0xc; | ||
86 | |||
87 | /* Two-wire Serial Master and Clock 0x100-0x110 */ | ||
88 | struct { | ||
89 | // u32 slave_transmitter : 1; /* ???*/ | ||
90 | u32 chipaddr : 7; /* two-line serial address of the target slave */ | ||
91 | u32 reserved1 : 1; | ||
92 | u32 baseaddr : 8; /* address of the location of the read/write operation */ | ||
93 | u32 data1_reg : 8; /* first byte in two-line serial read/write operation */ | ||
94 | u32 working_start : 1; /* when doing a write operation this indicator is 0 when ready | ||
95 | * set to 1 when doing a write operation */ | ||
96 | u32 twoWS_rw : 1; /* read/write indicator (1 = read, 0 write) */ | ||
97 | u32 total_bytes : 2; /* number of data bytes in each two-line serial transaction (0 = 1 byte, 11 = 4byte)*/ | ||
98 | u32 twoWS_port_reg : 2; /* port selection: 01 - Front End/Demod, 10 - EEPROM, 11 - Tuner */ | ||
99 | u32 no_base_addr_ack_error : 1; /* writing: write-req: frame is produced w/o baseaddr, read-req: read-cycles w/o | ||
100 | * preceding address assignment write frame | ||
101 | * ACK_ERROR = 1 when no ACK from slave in the last transaction */ | ||
102 | u32 st_done : 1; /* indicator for transaction is done */ | ||
103 | } tw_sm_c_100; | ||
104 | |||
105 | struct { | ||
106 | u32 data2_reg : 8; /* 2nd data byte */ | ||
107 | u32 data3_reg : 8; /* 3rd data byte */ | ||
108 | u32 data4_reg : 8; /* 4th data byte */ | ||
109 | u32 exlicit_stops : 1; /* when set, transactions are produced w/o trailing STOP flag, then send isolated STOP flags */ | ||
110 | u32 force_stop : 1; /* isolated stop flag */ | ||
111 | u32 unused : 6; | ||
112 | } tw_sm_c_104; | ||
113 | |||
114 | /* Clock. The register allows the FCIII to convert an incoming Master clock | ||
115 | * (MCLK) signal into a lower frequency clock through the use of a LowCounter | ||
116 | * (TLO) and a High- Counter (THI). The time counts for THI and TLO are | ||
117 | * measured in MCLK; each count represents 4 MCLK input clock cycles. | ||
118 | * | ||
119 | * The default output for port #1 is set for Front End Demod communication. (0x108) | ||
120 | * The default output for port #2 is set for EEPROM communication. (0x10c) | ||
121 | * The default output for port #3 is set for Tuner communication. (0x110) | ||
122 | */ | ||
123 | struct { | ||
124 | u32 thi1 : 6; /* Thi for port #1 (def: 100110b; 38) */ | ||
125 | u32 reserved1 : 2; | ||
126 | u32 tlo1 : 5; /* Tlo for port #1 (def: 11100b; 28) */ | ||
127 | u32 reserved2 :19; | ||
128 | } tw_sm_c_108; | ||
129 | |||
130 | struct { | ||
131 | u32 thi1 : 6; /* Thi for port #2 (def: 111001b; 57) */ | ||
132 | u32 reserved1 : 2; | ||
133 | u32 tlo1 : 5; /* Tlo for port #2 (def: 11100b; 28) */ | ||
134 | u32 reserved2 :19; | ||
135 | } tw_sm_c_10c; | ||
136 | |||
137 | struct { | ||
138 | u32 thi1 : 6; /* Thi for port #3 (def: 111001b; 57) */ | ||
139 | u32 reserved1 : 2; | ||
140 | u32 tlo1 : 5; /* Tlo for port #3 (def: 11100b; 28) */ | ||
141 | u32 reserved2 :19; | ||
142 | } tw_sm_c_110; | ||
143 | |||
144 | /* LNB Switch Frequency 0x200 | ||
145 | * Clock that creates the LNB switch tone. The default is set to have a fixed | ||
146 | * low output (not oscillating) to the LNB_CTL line. | ||
147 | */ | ||
148 | struct { | ||
149 | u32 LNB_CTLHighCount_sig :15; /* It is the number of pre-scaled clock cycles that will be low. */ | ||
150 | u32 LNB_CTLLowCount_sig :15; /* For example, to obtain a 22KHz output given a 45 Mhz Master | ||
151 | Clock signal (MCLK), set PreScalar=01 and LowCounter value to 0x1ff. */ | ||
152 | u32 LNB_CTLPrescaler_sig : 2; /* pre-scaler divides MCLK: 00 (no division), 01 by 2, 10 by 4, 11 by 12 */ | ||
153 | } lnb_switch_freq_200; | ||
154 | |||
155 | /* ACPI, Peripheral Reset, LNB Polarity | ||
156 | * ACPI power conservation mode, LNB polarity selection (low or high voltage), | ||
157 | * and peripheral reset. | ||
158 | */ | ||
159 | struct { | ||
160 | u32 ACPI1_sig : 1; /* turn of the power of tuner and LNB, not implemented in FCIII */ | ||
161 | u32 ACPI3_sig : 1; /* turn of power of the complete satelite receiver board (except FCIII) */ | ||
162 | u32 LNB_L_H_sig : 1; /* low or high voltage for LNB. (0 = low, 1 = high) */ | ||
163 | u32 Per_reset_sig : 1; /* misc. init reset (default: 1), to reset set to low and back to high */ | ||
164 | u32 reserved :20; | ||
165 | u32 Rev_N_sig_revision_hi : 4;/* 0xc in case of FCIII */ | ||
166 | u32 Rev_N_sig_reserved1 : 2; | ||
167 | u32 Rev_N_sig_caps : 1; /* if 1, FCIII has 32 PID- and MAC-filters and is capable of IP multicast */ | ||
168 | u32 Rev_N_sig_reserved2 : 1; | ||
169 | } misc_204; | ||
170 | |||
171 | /* Control and Status 0x208 to 0x21c */ | ||
172 | /* Gross enable and disable control */ | ||
173 | struct { | ||
174 | u32 Stream1_filter_sig : 1; /* Stream1 PID filtering */ | ||
175 | u32 Stream2_filter_sig : 1; /* Stream2 PID filtering */ | ||
176 | u32 PCR_filter_sig : 1; /* PCR PID filter */ | ||
177 | u32 PMT_filter_sig : 1; /* PMT PID filter */ | ||
178 | |||
179 | u32 EMM_filter_sig : 1; /* EMM PID filter */ | ||
180 | u32 ECM_filter_sig : 1; /* ECM PID filter */ | ||
181 | u32 Null_filter_sig : 1; /* Filters null packets, PID=0x1fff. */ | ||
182 | u32 Mask_filter_sig : 1; /* mask PID filter */ | ||
183 | |||
184 | u32 WAN_Enable_sig : 1; /* WAN output line through V8 memory space is activated. */ | ||
185 | u32 WAN_CA_Enable_sig : 1; /* not in FCIII */ | ||
186 | u32 CA_Enable_sig : 1; /* not in FCIII */ | ||
187 | u32 SMC_Enable_sig : 1; /* CI stream data (CAI) goes directly to the smart card intf (opposed IBI 0x600 or SC-cmd buf). */ | ||
188 | |||
189 | u32 Per_CA_Enable_sig : 1; /* not in FCIII */ | ||
190 | u32 Multi2_Enable_sig : 1; /* ? */ | ||
191 | u32 MAC_filter_Mode_sig : 1; /* (MAC_filter_enable) Globally enables MAC filters for Net PID filteres. */ | ||
192 | u32 Rcv_Data_sig : 1; /* PID filtering module enable. When this bit is a one, the PID filter will | ||
193 | examine and process packets according to all other (individual) PID | ||
194 | filtering controls. If it a zero, no packet processing of any kind will | ||
195 | take place. All data from the tuner will be thrown away. */ | ||
196 | |||
197 | u32 DMA1_IRQ_Enable_sig : 1; /* When set, a DWORD counter is enabled on PCI DMA1 that asserts the PCI | ||
198 | * interrupt after the specified count for filling the buffer. */ | ||
199 | u32 DMA1_Timer_Enable_sig : 1; /* When set, a timer is enabled on PCI DMA1 that asserts the PCI interrupt | ||
200 | after a specified amount of time. */ | ||
201 | u32 DMA2_IRQ_Enable_sig : 1; /* same as DMA1_IRQ_Enable_sig but for DMA2 */ | ||
202 | u32 DMA2_Timer_Enable_sig : 1; /* same as DMA1_Timer_Enable_sig but for DMA2 */ | ||
203 | |||
204 | u32 DMA1_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA1 that asserts the PCI interrupt. */ | ||
205 | u32 DMA2_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA2 that asserts the PCI interrupt. */ | ||
206 | u32 Mailbox_from_V8_Enable_sig: 1; /* When set, writes to the mailbox register produce an interrupt to the | ||
207 | PCI host to indicate that mailbox data is available. */ | ||
208 | |||
209 | u32 unused : 9; | ||
210 | } ctrl_208; | ||
211 | |||
212 | /* General status. When a PCI interrupt occurs, this register is read to | ||
213 | * discover the reason for the interrupt. | ||
214 | */ | ||
215 | struct { | ||
216 | u32 DMA1_IRQ_Status : 1; /* When set(1) the DMA1 counter had generated an IRQ. Read Only. */ | ||
217 | u32 DMA1_Timer_Status : 1; /* When set(1) the DMA1 timer had generated an IRQ. Read Only. */ | ||
218 | u32 DMA2_IRQ_Status : 1; /* When set(1) the DMA2 counter had generated an IRQ. Read Only. */ | ||
219 | u32 DMA2_Timer_Status : 1; /* When set(1) the DMA2 timer had generated an IRQ. Read Only. */ | ||
220 | u32 DMA1_Size_IRQ_Status : 1; /* (Read only). This register is read after an interrupt to */ | ||
221 | u32 DMA2_Size_IRQ_Status : 1; /* find out why we had an IRQ. Reading this register will clear this bit. Packet count*/ | ||
222 | u32 Mailbox_from_V8_Status_sig: 1; /* Same as above. Reading this register will clear this bit. */ | ||
223 | u32 Data_receiver_error : 1; /* 1 indicate an error in the receiver Front End (Tuner module) */ | ||
224 | u32 Continuity_error_flag : 1; /* 1 indicates a continuity error in the TS stream. */ | ||
225 | u32 LLC_SNAP_FLAG_set : 1; /* 1 indicates that the LCC_SNAP_FLAG was set. */ | ||
226 | u32 Transport_Error : 1; /* When set indicates that an unexpected packet was received. */ | ||
227 | u32 reserved :21; | ||
228 | } irq_20c; | ||
229 | |||
230 | |||
231 | /* Software reset register */ | ||
232 | struct { | ||
233 | u32 reset_blocks : 8; /* Enabled when Block_reset_enable = 0xB2 and 0x208 bits 15:8 = 0x00. | ||
234 | Each bit location represents a 0x100 block of registers. Writing | ||
235 | a one in a bit location resets that block of registers and the logic | ||
236 | that it controls. */ | ||
237 | u32 Block_reset_enable : 8; /* This variable is set to 0xB2 when the register is written. */ | ||
238 | u32 Special_controls :16; /* Asserts Reset_V8 => 0xC258; Turns on pci encryption => 0xC25A; | ||
239 | Turns off pci encryption => 0xC259 Note: pci_encryption default | ||
240 | at power-up is ON. */ | ||
241 | } sw_reset_210; | ||
242 | |||
243 | struct { | ||
244 | u32 vuart_oe_sig : 1; /* When clear, the V8 processor has sole control of the serial UART | ||
245 | (RS-232 Smart Card interface). When set, the IBI interface | ||
246 | defined by register 0x600 controls the serial UART. */ | ||
247 | u32 v2WS_oe_sig : 1; /* When clear, the V8 processor has direct control of the Two-line | ||
248 | Serial Master EEPROM target. When set, the Two-line Serial Master | ||
249 | EEPROM target interface is controlled by IBI register 0x100. */ | ||
250 | u32 halt_V8_sig : 1; /* When set, contiguous wait states are applied to the V8-space | ||
251 | bus masters. Once this signal is cleared, normal V8-space | ||
252 | operations resume. */ | ||
253 | u32 section_pkg_enable_sig: 1; /* When set, this signal enables the front end translation circuitry | ||
254 | to process section packed transport streams. */ | ||
255 | u32 s2p_sel_sig : 1; /* Serial to parallel conversion. When set, polarized transport data | ||
256 | within the FlexCop3 front end circuitry is converted from a serial | ||
257 | stream into parallel data before downstream processing otherwise | ||
258 | interprets the data. */ | ||
259 | u32 unused1 : 3; | ||
260 | u32 polarity_PS_CLK_sig: 1; /* This signal is used to invert the input polarity of the tranport | ||
261 | stream CLOCK signal before any processing occurs on the transport | ||
262 | stream within FlexCop3. */ | ||
263 | u32 polarity_PS_VALID_sig: 1; /* This signal is used to invert the input polarity of the tranport | ||
264 | stream VALID signal before any processing occurs on the transport | ||
265 | stream within FlexCop3. */ | ||
266 | u32 polarity_PS_SYNC_sig: 1; /* This signal is used to invert the input polarity of the tranport | ||
267 | stream SYNC signal before any processing occurs on the transport | ||
268 | stream within FlexCop3. */ | ||
269 | u32 polarity_PS_ERR_sig: 1; /* This signal is used to invert the input polarity of the tranport | ||
270 | stream ERROR signal before any processing occurs on the transport | ||
271 | stream within FlexCop3. */ | ||
272 | u32 unused2 :20; | ||
273 | } misc_214; | ||
274 | |||
275 | /* Mailbox from V8 to host */ | ||
276 | struct { | ||
277 | u32 Mailbox_from_V8 :32; /* When this register is written by either the V8 processor or by an | ||
278 | end host, an interrupt is generated to the PCI host to indicate | ||
279 | that mailbox data is available. Reading register 20c will clear | ||
280 | the IRQ. */ | ||
281 | } mbox_v8_to_host_218; | ||
282 | |||
283 | /* Mailbox from host to v8 Mailbox_to_V8 | ||
284 | * Mailbox_to_V8 mailbox storage register | ||
285 | * used to send messages from PCI to V8. Writing to this register will send an | ||
286 | * IRQ to the V8. Then it can read the data from here. Reading this register | ||
287 | * will clear the IRQ. If the V8 is halted and bit 31 of this register is set, | ||
288 | * then this register is used instead as a direct interface to access the | ||
289 | * V8space memory. | ||
290 | */ | ||
291 | struct { | ||
292 | u32 sysramaccess_data : 8; /* Data byte written or read from the specified address in V8 SysRAM. */ | ||
293 | u32 sysramaccess_addr :15; /* 15 bit address used to access V8 Sys-RAM. */ | ||
294 | u32 unused : 7; | ||
295 | u32 sysramaccess_write: 1; /* Write flag used to latch data into the V8 SysRAM. */ | ||
296 | u32 sysramaccess_busmuster: 1; /* Setting this bit when the V8 is halted at 0x214 Bit(2) allows | ||
297 | this IBI register interface to directly drive the V8-space memory. */ | ||
298 | } mbox_host_to_v8_21c; | ||
299 | |||
300 | |||
301 | /* PIDs, Translation Bit, SMC Filter Select 0x300 to 0x31c */ | ||
302 | struct { | ||
303 | u32 Stream1_PID :13; /* Primary use is receiving Net data, so these 13 bits normally | ||
304 | hold the PID value for the desired network stream. */ | ||
305 | u32 Stream1_trans : 1; /* When set, Net translation will take place for Net data ferried in TS packets. */ | ||
306 | u32 MAC_Multicast_filter : 1; /* When clear, multicast MAC filtering is not allowed for Stream1 and PID_n filters. */ | ||
307 | u32 debug_flag_pid_saved : 1; | ||
308 | u32 Stream2_PID :13; /* 13 bits for Stream 2 PID filter value. General use. */ | ||
309 | u32 Stream2_trans : 1; /* When set Tables/CAI translation will take place for the data ferried in | ||
310 | Stream2_PID TS packets. */ | ||
311 | u32 debug_flag_write_status00 : 1; | ||
312 | u32 debug_fifo_problem : 1; | ||
313 | } pid_filter_300; | ||
314 | |||
315 | struct { | ||
316 | u32 PCR_PID :13; /* PCR stream PID filter value. Primary use is Program Clock Reference stream filtering. */ | ||
317 | u32 PCR_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ | ||
318 | u32 debug_overrun3 : 1; | ||
319 | u32 debug_overrun2 : 1; | ||
320 | u32 PMT_PID :13; /* stream PID filter value. Primary use is Program Management Table segment filtering. */ | ||
321 | u32 PMT_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ | ||
322 | u32 reserved : 2; | ||
323 | } pid_filter_304; | ||
324 | |||
325 | struct { | ||
326 | u32 EMM_PID :13; /* EMM PID filter value. Primary use is Entitlement Management Messaging for | ||
327 | conditional access-related data. */ | ||
328 | u32 EMM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ | ||
329 | u32 EMM_filter_4 : 1; /* When set will pass only EMM data possessing the same ID code as the | ||
330 | first four bytes (32 bits) of the end-user s 6-byte Smart Card ID number Select */ | ||
331 | u32 EMM_filter_6 : 1; /* When set will pass only EMM data possessing the same 6-byte code as the end-users | ||
332 | complete 6-byte Smart Card ID number. */ | ||
333 | u32 ECM_PID :13; /* ECM PID filter value. Primary use is Entitlement Control Messaging for conditional | ||
334 | access-related data. */ | ||
335 | u32 ECM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ | ||
336 | u32 reserved : 2; | ||
337 | } pid_filter_308; | ||
338 | |||
339 | struct { | ||
340 | u32 Group_PID :13; /* PID value for group filtering. */ | ||
341 | u32 Group_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ | ||
342 | u32 unused1 : 2; | ||
343 | u32 Group_mask :13; /* Mask value used in logical "and" equation that defines group filtering */ | ||
344 | u32 unused2 : 3; | ||
345 | } pid_filter_30c_ext_ind_0_7; | ||
346 | |||
347 | struct { | ||
348 | u32 net_master_read :17; | ||
349 | u32 unused :15; | ||
350 | } pid_filter_30c_ext_ind_1; | ||
351 | |||
352 | struct { | ||
353 | u32 net_master_write :17; | ||
354 | u32 unused :15; | ||
355 | } pid_filter_30c_ext_ind_2; | ||
356 | |||
357 | struct { | ||
358 | u32 next_net_master_write :17; | ||
359 | u32 unused :15; | ||
360 | } pid_filter_30c_ext_ind_3; | ||
361 | |||
362 | struct { | ||
363 | u32 unused1 : 1; | ||
364 | u32 state_write :10; | ||
365 | u32 reserved1 : 6; /* default: 000100 */ | ||
366 | u32 stack_read :10; | ||
367 | u32 reserved2 : 5; /* default: 00100 */ | ||
368 | } pid_filter_30c_ext_ind_4; | ||
369 | |||
370 | struct { | ||
371 | u32 stack_cnt :10; | ||
372 | u32 unused :22; | ||
373 | } pid_filter_30c_ext_ind_5; | ||
374 | |||
375 | struct { | ||
376 | u32 pid_fsm_save_reg0 : 2; | ||
377 | u32 pid_fsm_save_reg1 : 2; | ||
378 | u32 pid_fsm_save_reg2 : 2; | ||
379 | u32 pid_fsm_save_reg3 : 2; | ||
380 | u32 pid_fsm_save_reg4 : 2; | ||
381 | u32 pid_fsm_save_reg300 : 2; | ||
382 | u32 write_status1 : 2; | ||
383 | u32 write_status4 : 2; | ||
384 | u32 data_size_reg :12; | ||
385 | u32 unused : 4; | ||
386 | } pid_filter_30c_ext_ind_6; | ||
387 | |||
388 | struct { | ||
389 | u32 index_reg : 5; /* (Index pointer) Points at an internal PIDn register. A binary code | ||
390 | representing one of 32 internal PIDn registers as well as its | ||
391 | corresponding internal MAC_lown register. */ | ||
392 | u32 extra_index_reg : 3; /* This vector is used to select between sets of debug signals routed to register 0x30c. */ | ||
393 | u32 AB_select : 1; /* Used in conjunction with 0x31c. read/write to the MAC_highA or MAC_highB register | ||
394 | 0=MAC_highB register, 1=MAC_highA */ | ||
395 | u32 pass_alltables : 1; /* 1=Net packets are not filtered against the Network Table ID found in register 0x400. | ||
396 | All types of networks (DVB, ATSC, ISDB) are passed. */ | ||
397 | u32 unused :22; | ||
398 | } index_reg_310; | ||
399 | |||
400 | struct { | ||
401 | u32 PID :13; /* PID value */ | ||
402 | u32 PID_trans : 1; /* translation will take place for packets filtered */ | ||
403 | u32 PID_enable_bit : 1; /* When set this PID filter is enabled */ | ||
404 | u32 reserved :17; | ||
405 | } pid_n_reg_314; | ||
406 | |||
407 | struct { | ||
408 | u32 A4_byte : 8; | ||
409 | u32 A5_byte : 8; | ||
410 | u32 A6_byte : 8; | ||
411 | u32 Enable_bit : 1; /* enabled (1) or disabled (1) */ | ||
412 | u32 HighAB_bit : 1; /* use MAC_highA (1) or MAC_highB (0) as MSB */ | ||
413 | u32 reserved : 6; | ||
414 | } mac_low_reg_318; | ||
415 | |||
416 | struct { | ||
417 | u32 A1_byte : 8; | ||
418 | u32 A2_byte : 8; | ||
419 | u32 A3_byte : 8; | ||
420 | u32 reserved : 8; | ||
421 | } mac_high_reg_31c; | ||
422 | |||
423 | /* Table, SMCID,MACDestination Filters 0x400 to 0x41c */ | ||
424 | struct { | ||
425 | u32 reserved :16; | ||
426 | #define fc_data_Tag_ID_DVB 0x3e | ||
427 | #define fc_data_Tag_ID_ATSC 0x3f | ||
428 | #define fc_data_Tag_ID_IDSB 0x8b | ||
429 | u32 data_Tag_ID :16; | ||
430 | } data_tag_400; | ||
431 | |||
432 | struct { | ||
433 | u32 Card_IDbyte6 : 8; | ||
434 | u32 Card_IDbyte5 : 8; | ||
435 | u32 Card_IDbyte4 : 8; | ||
436 | u32 Card_IDbyte3 : 8; | ||
437 | } card_id_408; | ||
438 | |||
439 | struct { | ||
440 | u32 Card_IDbyte2 : 8; | ||
441 | u32 Card_IDbyte1 : 8; | ||
442 | } card_id_40c; | ||
443 | |||
444 | /* holding the unique mac address of the receiver which houses the FlexCopIII */ | ||
445 | struct { | ||
446 | u32 MAC1 : 8; | ||
447 | u32 MAC2 : 8; | ||
448 | u32 MAC3 : 8; | ||
449 | u32 MAC6 : 8; | ||
450 | } mac_address_418; | ||
451 | |||
452 | struct { | ||
453 | u32 MAC7 : 8; | ||
454 | u32 MAC8 : 8; | ||
455 | u32 reserved : 16; | ||
456 | } mac_address_41c; | ||
457 | |||
458 | struct { | ||
459 | u32 transmitter_data_byte : 8; | ||
460 | u32 ReceiveDataReady : 1; | ||
461 | u32 ReceiveByteFrameError: 1; | ||
462 | u32 txbuffempty : 1; | ||
463 | u32 reserved :21; | ||
464 | } ci_600; | ||
465 | |||
466 | struct { | ||
467 | u32 pi_d : 8; | ||
468 | u32 pi_ha :20; | ||
469 | u32 pi_rw : 1; | ||
470 | u32 pi_component_reg : 3; | ||
471 | } pi_604; | ||
472 | |||
473 | struct { | ||
474 | u32 serialReset : 1; | ||
475 | u32 oncecycle_read : 1; | ||
476 | u32 Timer_Read_req : 1; | ||
477 | u32 Timer_Load_req : 1; | ||
478 | u32 timer_data : 7; | ||
479 | u32 unused : 1; /* ??? not mentioned in data book */ | ||
480 | u32 Timer_addr : 5; | ||
481 | u32 reserved : 3; | ||
482 | u32 pcmcia_a_mod_pwr_n : 1; | ||
483 | u32 pcmcia_b_mod_pwr_n : 1; | ||
484 | u32 config_Done_stat : 1; | ||
485 | u32 config_Init_stat : 1; | ||
486 | u32 config_Prog_n : 1; | ||
487 | u32 config_wr_n : 1; | ||
488 | u32 config_cs_n : 1; | ||
489 | u32 config_cclk : 1; | ||
490 | u32 pi_CiMax_IRQ_n : 1; | ||
491 | u32 pi_timeout_status : 1; | ||
492 | u32 pi_wait_n : 1; | ||
493 | u32 pi_busy_n : 1; | ||
494 | } pi_608; | ||
495 | |||
496 | struct { | ||
497 | u32 PID :13; | ||
498 | u32 key_enable : 1; | ||
499 | #define fc_key_code_default 0x1 | ||
500 | #define fc_key_code_even 0x2 | ||
501 | #define fc_key_code_odd 0x3 | ||
502 | u32 key_code : 2; | ||
503 | u32 key_array_col : 3; | ||
504 | u32 key_array_row : 5; | ||
505 | u32 dvb_en : 1; /* 0=TS bypasses the Descrambler */ | ||
506 | u32 rw_flag : 1; | ||
507 | u32 reserved : 6; | ||
508 | } dvb_reg_60c; | ||
509 | |||
510 | /* SRAM and Output Destination 0x700 to 0x714 */ | ||
511 | struct { | ||
512 | u32 sram_addr :15; | ||
513 | u32 sram_rw : 1; /* 0=write, 1=read */ | ||
514 | u32 sram_data : 8; | ||
515 | u32 sc_xfer_bit : 1; | ||
516 | u32 reserved1 : 3; | ||
517 | u32 oe_pin_reg : 1; | ||
518 | u32 ce_pin_reg : 1; | ||
519 | u32 reserved2 : 1; | ||
520 | u32 start_sram_ibi : 1; | ||
521 | } sram_ctrl_reg_700; | ||
522 | |||
523 | struct { | ||
524 | u32 net_addr_read :16; | ||
525 | u32 net_addr_write :16; | ||
526 | } net_buf_reg_704; | ||
527 | |||
528 | struct { | ||
529 | u32 cai_read :11; | ||
530 | u32 reserved1 : 5; | ||
531 | u32 cai_write :11; | ||
532 | u32 reserved2 : 6; | ||
533 | u32 cai_cnt : 4; | ||
534 | } cai_buf_reg_708; | ||
535 | |||
536 | struct { | ||
537 | u32 cao_read :11; | ||
538 | u32 reserved1 : 5; | ||
539 | u32 cap_write :11; | ||
540 | u32 reserved2 : 6; | ||
541 | u32 cao_cnt : 4; | ||
542 | } cao_buf_reg_70c; | ||
543 | |||
544 | struct { | ||
545 | u32 media_read :11; | ||
546 | u32 reserved1 : 5; | ||
547 | u32 media_write :11; | ||
548 | u32 reserved2 : 6; | ||
549 | u32 media_cnt : 4; | ||
550 | } media_buf_reg_710; | ||
551 | |||
552 | struct { | ||
553 | u32 NET_Dest : 2; | ||
554 | u32 CAI_Dest : 2; | ||
555 | u32 CAO_Dest : 2; | ||
556 | u32 MEDIA_Dest : 2; | ||
557 | u32 net_ovflow_error : 1; | ||
558 | u32 media_ovflow_error : 1; | ||
559 | u32 cai_ovflow_error : 1; | ||
560 | u32 cao_ovflow_error : 1; | ||
561 | u32 ctrl_usb_wan : 1; | ||
562 | u32 ctrl_sramdma : 1; | ||
563 | u32 ctrl_maximumfill : 1; | ||
564 | u32 reserved :17; | ||
565 | } sram_dest_reg_714; | ||
566 | |||
567 | struct { | ||
568 | u32 net_cnt :12; | ||
569 | u32 reserved1 : 4; | ||
570 | u32 net_addr_read : 1; | ||
571 | u32 reserved2 : 3; | ||
572 | u32 net_addr_write : 1; | ||
573 | u32 reserved3 :11; | ||
574 | } net_buf_reg_718; | ||
575 | |||
576 | struct { | ||
577 | u32 wan_speed_sig : 2; | ||
578 | u32 reserved1 : 6; | ||
579 | u32 wan_wait_state : 8; | ||
580 | u32 sram_chip : 2; | ||
581 | u32 sram_memmap : 2; | ||
582 | u32 reserved2 : 4; | ||
583 | u32 wan_pkt_frame : 4; | ||
584 | u32 reserved3 : 4; | ||
585 | } wan_ctrl_reg_71c; | ||
586 | } flexcop_ibi_value; | ||
587 | |||
588 | extern flexcop_ibi_value ibi_zero; | ||
589 | |||
590 | typedef enum { | ||
591 | FC_I2C_PORT_DEMOD = 1, | ||
592 | FC_I2C_PORT_EEPROM = 2, | ||
593 | FC_I2C_PORT_TUNER = 3, | ||
594 | } flexcop_i2c_port_t; | ||
595 | |||
596 | typedef enum { | ||
597 | FC_WRITE = 0, | ||
598 | FC_READ = 1, | ||
599 | } flexcop_access_op_t; | ||
600 | |||
601 | typedef enum { | ||
602 | FC_SRAM_DEST_NET = 1, | ||
603 | FC_SRAM_DEST_CAI = 2, | ||
604 | FC_SRAM_DEST_CAO = 4, | ||
605 | FC_SRAM_DEST_MEDIA = 8 | ||
606 | } flexcop_sram_dest_t; | ||
607 | |||
608 | typedef enum { | ||
609 | FC_SRAM_DEST_TARGET_WAN_USB = 0, | ||
610 | FC_SRAM_DEST_TARGET_DMA1 = 1, | ||
611 | FC_SRAM_DEST_TARGET_DMA2 = 2, | ||
612 | FC_SRAM_DEST_TARGET_FC3_CA = 3 | ||
613 | } flexcop_sram_dest_target_t; | ||
614 | |||
615 | typedef enum { | ||
616 | FC_SRAM_2_32KB = 0, /* 64KB */ | ||
617 | FC_SRAM_1_32KB = 1, /* 32KB - default fow FCII */ | ||
618 | FC_SRAM_1_128KB = 2, /* 128KB */ | ||
619 | FC_SRAM_1_48KB = 3, /* 48KB - default for FCIII */ | ||
620 | } flexcop_sram_type_t; | ||
621 | |||
622 | typedef enum { | ||
623 | FC_WAN_SPEED_4MBITS = 0, | ||
624 | FC_WAN_SPEED_8MBITS = 1, | ||
625 | FC_WAN_SPEED_12MBITS = 2, | ||
626 | FC_WAN_SPEED_16MBITS = 3, | ||
627 | } flexcop_wan_speed_t; | ||
628 | |||
629 | typedef enum { | ||
630 | FC_DMA_1 = 1, | ||
631 | FC_DMA_2 = 2, | ||
632 | } flexcop_dma_index_t; | ||
633 | |||
634 | typedef enum { | ||
635 | FC_DMA_SUBADDR_0 = 1, | ||
636 | FC_DMA_SUBADDR_1 = 2, | ||
637 | } flexcop_dma_addr_index_t; | ||
638 | |||
639 | /* names of the particular registers */ | ||
640 | typedef enum { | ||
641 | dma1_000 = 0x000, | ||
642 | dma1_004 = 0x004, | ||
643 | dma1_008 = 0x008, | ||
644 | dma1_00c = 0x00c, | ||
645 | dma2_010 = 0x010, | ||
646 | dma2_014 = 0x014, | ||
647 | dma2_018 = 0x018, | ||
648 | dma2_01c = 0x01c, | ||
649 | |||
650 | tw_sm_c_100 = 0x100, | ||
651 | tw_sm_c_104 = 0x104, | ||
652 | tw_sm_c_108 = 0x108, | ||
653 | tw_sm_c_10c = 0x10c, | ||
654 | tw_sm_c_110 = 0x110, | ||
655 | |||
656 | lnb_switch_freq_200 = 0x200, | ||
657 | misc_204 = 0x204, | ||
658 | ctrl_208 = 0x208, | ||
659 | irq_20c = 0x20c, | ||
660 | sw_reset_210 = 0x210, | ||
661 | misc_214 = 0x214, | ||
662 | mbox_v8_to_host_218 = 0x218, | ||
663 | mbox_host_to_v8_21c = 0x21c, | ||
664 | |||
665 | pid_filter_300 = 0x300, | ||
666 | pid_filter_304 = 0x304, | ||
667 | pid_filter_308 = 0x308, | ||
668 | pid_filter_30c = 0x30c, | ||
669 | index_reg_310 = 0x310, | ||
670 | pid_n_reg_314 = 0x314, | ||
671 | mac_low_reg_318 = 0x318, | ||
672 | mac_high_reg_31c = 0x31c, | ||
673 | |||
674 | data_tag_400 = 0x400, | ||
675 | card_id_408 = 0x408, | ||
676 | card_id_40c = 0x40c, | ||
677 | mac_address_418 = 0x418, | ||
678 | mac_address_41c = 0x41c, | ||
679 | |||
680 | ci_600 = 0x600, | ||
681 | pi_604 = 0x604, | ||
682 | pi_608 = 0x608, | ||
683 | dvb_reg_60c = 0x60c, | ||
684 | |||
685 | sram_ctrl_reg_700 = 0x700, | ||
686 | net_buf_reg_704 = 0x704, | ||
687 | cai_buf_reg_708 = 0x708, | ||
688 | cao_buf_reg_70c = 0x70c, | ||
689 | media_buf_reg_710 = 0x710, | ||
690 | sram_dest_reg_714 = 0x714, | ||
691 | net_buf_reg_718 = 0x718, | ||
692 | wan_ctrl_reg_71c = 0x71c, | ||
693 | } flexcop_ibi_register; | ||
694 | |||
695 | #define flexcop_set_ibi_value(reg,attr,val) \ | ||
696 | flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \ | ||
697 | v.reg.attr = val; \ | ||
698 | fc->write_ibi_reg(fc,reg,v); \ | ||
699 | |||
700 | #endif | ||
diff --git a/drivers/media/dvb/b2c2/flexcop-sram.c b/drivers/media/dvb/b2c2/flexcop-sram.c new file mode 100644 index 000000000000..01570ec80962 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-sram.c | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop-sram.c - functions for controlling the SRAM. | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | #include "flexcop.h" | ||
9 | |||
10 | static void flexcop_sram_set_chip (struct flexcop_device *fc, flexcop_sram_type_t type) | ||
11 | { | ||
12 | flexcop_set_ibi_value(wan_ctrl_reg_71c,sram_chip,type); | ||
13 | } | ||
14 | |||
15 | int flexcop_sram_init(struct flexcop_device *fc) | ||
16 | { | ||
17 | switch (fc->rev) { | ||
18 | case FLEXCOP_II: | ||
19 | case FLEXCOP_IIB: | ||
20 | flexcop_sram_set_chip(fc,FC_SRAM_1_32KB); | ||
21 | break; | ||
22 | case FLEXCOP_III: | ||
23 | flexcop_sram_set_chip(fc,FC_SRAM_1_48KB); | ||
24 | break; | ||
25 | default: | ||
26 | return -EINVAL; | ||
27 | } | ||
28 | return 0; | ||
29 | } | ||
30 | |||
31 | int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target) | ||
32 | { | ||
33 | flexcop_ibi_value v; | ||
34 | |||
35 | v = fc->read_ibi_reg(fc,sram_dest_reg_714); | ||
36 | |||
37 | if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) { | ||
38 | err("SRAM destination target to available on FlexCopII(b)\n"); | ||
39 | return -EINVAL; | ||
40 | } | ||
41 | |||
42 | deb_sram("sram dest: %x target: %x\n",dest, target); | ||
43 | |||
44 | if (dest & FC_SRAM_DEST_NET) | ||
45 | v.sram_dest_reg_714.NET_Dest = target; | ||
46 | if (dest & FC_SRAM_DEST_CAI) | ||
47 | v.sram_dest_reg_714.CAI_Dest = target; | ||
48 | if (dest & FC_SRAM_DEST_CAO) | ||
49 | v.sram_dest_reg_714.CAO_Dest = target; | ||
50 | if (dest & FC_SRAM_DEST_MEDIA) | ||
51 | v.sram_dest_reg_714.MEDIA_Dest = target; | ||
52 | |||
53 | fc->write_ibi_reg(fc,sram_dest_reg_714,v); | ||
54 | udelay(1000); /* TODO delay really necessary */ | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | EXPORT_SYMBOL(flexcop_sram_set_dest); | ||
59 | |||
60 | void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s) | ||
61 | { | ||
62 | flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s); | ||
63 | } | ||
64 | EXPORT_SYMBOL(flexcop_wan_set_speed); | ||
65 | |||
66 | void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill) | ||
67 | { | ||
68 | flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); | ||
69 | v.sram_dest_reg_714.ctrl_usb_wan = usb_wan; | ||
70 | v.sram_dest_reg_714.ctrl_sramdma = sramdma; | ||
71 | v.sram_dest_reg_714.ctrl_maximumfill = maximumfill; | ||
72 | fc->write_ibi_reg(fc,sram_dest_reg_714,v); | ||
73 | } | ||
74 | EXPORT_SYMBOL(flexcop_sram_ctrl); | ||
75 | |||
76 | #if 0 | ||
77 | static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) | ||
78 | { | ||
79 | int i, retries; | ||
80 | u32 command; | ||
81 | |||
82 | for (i = 0; i < len; i++) { | ||
83 | command = bank | addr | 0x04000000 | (*buf << 0x10); | ||
84 | |||
85 | retries = 2; | ||
86 | |||
87 | while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { | ||
88 | mdelay(1); | ||
89 | retries--; | ||
90 | }; | ||
91 | |||
92 | if (retries == 0) | ||
93 | printk("%s: SRAM timeout\n", __FUNCTION__); | ||
94 | |||
95 | write_reg_dw(adapter, 0x700, command); | ||
96 | |||
97 | buf++; | ||
98 | addr++; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) | ||
103 | { | ||
104 | int i, retries; | ||
105 | u32 command, value; | ||
106 | |||
107 | for (i = 0; i < len; i++) { | ||
108 | command = bank | addr | 0x04008000; | ||
109 | |||
110 | retries = 10000; | ||
111 | |||
112 | while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { | ||
113 | mdelay(1); | ||
114 | retries--; | ||
115 | }; | ||
116 | |||
117 | if (retries == 0) | ||
118 | printk("%s: SRAM timeout\n", __FUNCTION__); | ||
119 | |||
120 | write_reg_dw(adapter, 0x700, command); | ||
121 | |||
122 | retries = 10000; | ||
123 | |||
124 | while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { | ||
125 | mdelay(1); | ||
126 | retries--; | ||
127 | }; | ||
128 | |||
129 | if (retries == 0) | ||
130 | printk("%s: SRAM timeout\n", __FUNCTION__); | ||
131 | |||
132 | value = read_reg_dw(adapter, 0x700) >> 0x10; | ||
133 | |||
134 | *buf = (value & 0xff); | ||
135 | |||
136 | addr++; | ||
137 | buf++; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) | ||
142 | { | ||
143 | u32 bank; | ||
144 | |||
145 | bank = 0; | ||
146 | |||
147 | if (adapter->dw_sram_type == 0x20000) { | ||
148 | bank = (addr & 0x18000) << 0x0d; | ||
149 | } | ||
150 | |||
151 | if (adapter->dw_sram_type == 0x00000) { | ||
152 | if ((addr >> 0x0f) == 0) | ||
153 | bank = 0x20000000; | ||
154 | else | ||
155 | bank = 0x10000000; | ||
156 | } | ||
157 | |||
158 | flex_sram_write(adapter, bank, addr & 0x7fff, buf, len); | ||
159 | } | ||
160 | |||
161 | static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) | ||
162 | { | ||
163 | u32 bank; | ||
164 | |||
165 | bank = 0; | ||
166 | |||
167 | if (adapter->dw_sram_type == 0x20000) { | ||
168 | bank = (addr & 0x18000) << 0x0d; | ||
169 | } | ||
170 | |||
171 | if (adapter->dw_sram_type == 0x00000) { | ||
172 | if ((addr >> 0x0f) == 0) | ||
173 | bank = 0x20000000; | ||
174 | else | ||
175 | bank = 0x10000000; | ||
176 | } | ||
177 | |||
178 | flex_sram_read(adapter, bank, addr & 0x7fff, buf, len); | ||
179 | } | ||
180 | |||
181 | static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len) | ||
182 | { | ||
183 | u32 length; | ||
184 | |||
185 | while (len != 0) { | ||
186 | length = len; | ||
187 | |||
188 | // check if the address range belongs to the same | ||
189 | // 32K memory chip. If not, the data is read from | ||
190 | // one chip at a time. | ||
191 | if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { | ||
192 | length = (((addr >> 0x0f) + 1) << 0x0f) - addr; | ||
193 | } | ||
194 | |||
195 | sram_read_chunk(adapter, addr, buf, length); | ||
196 | |||
197 | addr = addr + length; | ||
198 | buf = buf + length; | ||
199 | len = len - length; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len) | ||
204 | { | ||
205 | u32 length; | ||
206 | |||
207 | while (len != 0) { | ||
208 | length = len; | ||
209 | |||
210 | // check if the address range belongs to the same | ||
211 | // 32K memory chip. If not, the data is written to | ||
212 | // one chip at a time. | ||
213 | if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { | ||
214 | length = (((addr >> 0x0f) + 1) << 0x0f) - addr; | ||
215 | } | ||
216 | |||
217 | sram_write_chunk(adapter, addr, buf, length); | ||
218 | |||
219 | addr = addr + length; | ||
220 | buf = buf + length; | ||
221 | len = len - length; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static void sram_set_size(struct adapter *adapter, u32 mask) | ||
226 | { | ||
227 | write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c)))); | ||
228 | } | ||
229 | |||
230 | static void sram_init(struct adapter *adapter) | ||
231 | { | ||
232 | u32 tmp; | ||
233 | |||
234 | tmp = read_reg_dw(adapter, 0x71c); | ||
235 | |||
236 | write_reg_dw(adapter, 0x71c, 1); | ||
237 | |||
238 | if (read_reg_dw(adapter, 0x71c) != 0) { | ||
239 | write_reg_dw(adapter, 0x71c, tmp); | ||
240 | |||
241 | adapter->dw_sram_type = tmp & 0x30000; | ||
242 | |||
243 | ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type); | ||
244 | |||
245 | } else { | ||
246 | |||
247 | adapter->dw_sram_type = 0x10000; | ||
248 | |||
249 | ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type); | ||
250 | } | ||
251 | |||
252 | /* return value is never used? */ | ||
253 | /* return adapter->dw_sram_type; */ | ||
254 | } | ||
255 | |||
256 | static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr) | ||
257 | { | ||
258 | u8 tmp1, tmp2; | ||
259 | |||
260 | dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr); | ||
261 | |||
262 | sram_set_size(adapter, mask); | ||
263 | sram_init(adapter); | ||
264 | |||
265 | tmp2 = 0xa5; | ||
266 | tmp1 = 0x4f; | ||
267 | |||
268 | sram_write(adapter, addr, &tmp2, 1); | ||
269 | sram_write(adapter, addr + 4, &tmp1, 1); | ||
270 | |||
271 | tmp2 = 0; | ||
272 | |||
273 | mdelay(20); | ||
274 | |||
275 | sram_read(adapter, addr, &tmp2, 1); | ||
276 | sram_read(adapter, addr, &tmp2, 1); | ||
277 | |||
278 | dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2); | ||
279 | |||
280 | if (tmp2 != 0xa5) | ||
281 | return 0; | ||
282 | |||
283 | tmp2 = 0x5a; | ||
284 | tmp1 = 0xf4; | ||
285 | |||
286 | sram_write(adapter, addr, &tmp2, 1); | ||
287 | sram_write(adapter, addr + 4, &tmp1, 1); | ||
288 | |||
289 | tmp2 = 0; | ||
290 | |||
291 | mdelay(20); | ||
292 | |||
293 | sram_read(adapter, addr, &tmp2, 1); | ||
294 | sram_read(adapter, addr, &tmp2, 1); | ||
295 | |||
296 | dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2); | ||
297 | |||
298 | if (tmp2 != 0x5a) | ||
299 | return 0; | ||
300 | |||
301 | return 1; | ||
302 | } | ||
303 | |||
304 | static u32 sram_length(struct adapter *adapter) | ||
305 | { | ||
306 | if (adapter->dw_sram_type == 0x10000) | ||
307 | return 32768; // 32K | ||
308 | if (adapter->dw_sram_type == 0x00000) | ||
309 | return 65536; // 64K | ||
310 | if (adapter->dw_sram_type == 0x20000) | ||
311 | return 131072; // 128K | ||
312 | |||
313 | return 32768; // 32K | ||
314 | } | ||
315 | |||
316 | /* FlexcopII can work with 32K, 64K or 128K of external SRAM memory. | ||
317 | - for 128K there are 4x32K chips at bank 0,1,2,3. | ||
318 | - for 64K there are 2x32K chips at bank 1,2. | ||
319 | - for 32K there is one 32K chip at bank 0. | ||
320 | |||
321 | FlexCop works only with one bank at a time. The bank is selected | ||
322 | by bits 28-29 of the 0x700 register. | ||
323 | |||
324 | bank 0 covers addresses 0x00000-0x07fff | ||
325 | bank 1 covers addresses 0x08000-0x0ffff | ||
326 | bank 2 covers addresses 0x10000-0x17fff | ||
327 | bank 3 covers addresses 0x18000-0x1ffff | ||
328 | */ | ||
329 | |||
330 | static int flexcop_sram_detect(struct flexcop_device *fc) | ||
331 | { | ||
332 | flexcop_ibi_value r208,r71c_0,vr71c_1; | ||
333 | |||
334 | r208 = fc->read_ibi_reg(fc, ctrl_208); | ||
335 | fc->write_ibi_reg(fc, ctrl_208, ibi_zero); | ||
336 | |||
337 | r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c); | ||
338 | |||
339 | write_reg_dw(adapter, 0x71c, 1); | ||
340 | |||
341 | tmp3 = read_reg_dw(adapter, 0x71c); | ||
342 | |||
343 | dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3); | ||
344 | |||
345 | write_reg_dw(adapter, 0x71c, tmp2); | ||
346 | |||
347 | // check for internal SRAM ??? | ||
348 | tmp3--; | ||
349 | if (tmp3 != 0) { | ||
350 | sram_set_size(adapter, 0x10000); | ||
351 | sram_init(adapter); | ||
352 | write_reg_dw(adapter, 0x208, tmp); | ||
353 | |||
354 | dprintk("%s: sram size = 32K\n", __FUNCTION__); | ||
355 | |||
356 | return 32; | ||
357 | } | ||
358 | |||
359 | if (sram_test_location(adapter, 0x20000, 0x18000) != 0) { | ||
360 | sram_set_size(adapter, 0x20000); | ||
361 | sram_init(adapter); | ||
362 | write_reg_dw(adapter, 0x208, tmp); | ||
363 | |||
364 | dprintk("%s: sram size = 128K\n", __FUNCTION__); | ||
365 | |||
366 | return 128; | ||
367 | } | ||
368 | |||
369 | if (sram_test_location(adapter, 0x00000, 0x10000) != 0) { | ||
370 | sram_set_size(adapter, 0x00000); | ||
371 | sram_init(adapter); | ||
372 | write_reg_dw(adapter, 0x208, tmp); | ||
373 | |||
374 | dprintk("%s: sram size = 64K\n", __FUNCTION__); | ||
375 | |||
376 | return 64; | ||
377 | } | ||
378 | |||
379 | if (sram_test_location(adapter, 0x10000, 0x00000) != 0) { | ||
380 | sram_set_size(adapter, 0x10000); | ||
381 | sram_init(adapter); | ||
382 | write_reg_dw(adapter, 0x208, tmp); | ||
383 | |||
384 | dprintk("%s: sram size = 32K\n", __FUNCTION__); | ||
385 | |||
386 | return 32; | ||
387 | } | ||
388 | |||
389 | sram_set_size(adapter, 0x10000); | ||
390 | sram_init(adapter); | ||
391 | write_reg_dw(adapter, 0x208, tmp); | ||
392 | |||
393 | dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__); | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | static void sll_detect_sram_size(struct adapter *adapter) | ||
399 | { | ||
400 | sram_detect_for_flex2(adapter); | ||
401 | } | ||
402 | |||
403 | #endif | ||
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c new file mode 100644 index 000000000000..5fa68febf3a6 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-usb.c | |||
@@ -0,0 +1,530 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop-usb.c - covers the USB part. | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | |||
9 | #define FC_LOG_PREFIX "flexcop_usb" | ||
10 | #include "flexcop-usb.h" | ||
11 | #include "flexcop-common.h" | ||
12 | |||
13 | /* Version information */ | ||
14 | #define DRIVER_VERSION "0.1" | ||
15 | #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver" | ||
16 | #define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>" | ||
17 | |||
18 | /* debug */ | ||
19 | #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG | ||
20 | #define dprintk(level,args...) \ | ||
21 | do { if ((debug & level)) { printk(args); } } while (0) | ||
22 | #define debug_dump(b,l,method) {\ | ||
23 | int i; \ | ||
24 | for (i = 0; i < l; i++) method("%02x ", b[i]); \ | ||
25 | method("\n");\ | ||
26 | } | ||
27 | |||
28 | #define DEBSTATUS "" | ||
29 | #else | ||
30 | #define dprintk(level,args...) | ||
31 | #define debug_dump(b,l,method) | ||
32 | #define DEBSTATUS " (debugging is not enabled)" | ||
33 | #endif | ||
34 | |||
35 | static int debug; | ||
36 | module_param(debug, int, 0644); | ||
37 | MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS); | ||
38 | #undef DEBSTATUS | ||
39 | |||
40 | #define deb_info(args...) dprintk(0x01,args) | ||
41 | #define deb_ts(args...) dprintk(0x02,args) | ||
42 | #define deb_ctrl(args...) dprintk(0x04,args) | ||
43 | #define deb_i2c(args...) dprintk(0x08,args) | ||
44 | #define deb_v8(args...) dprintk(0x10,args) | ||
45 | |||
46 | /* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits | ||
47 | * in the IBI address, to make the V8 code simpler. | ||
48 | * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used) | ||
49 | * in general: 0000 0HHH 000L LL00 | ||
50 | * IBI ADDRESS FORMAT: RHHH BLLL | ||
51 | * | ||
52 | * where R is the read(1)/write(0) bit, B is the busy bit | ||
53 | * and HHH and LLL are the two sets of three bits from the PCI address. | ||
54 | */ | ||
55 | #define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70)) | ||
56 | #define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4)) | ||
57 | |||
58 | /* | ||
59 | * DKT 020228 | ||
60 | * - forget about this VENDOR_BUFFER_SIZE, read and write register | ||
61 | * deal with DWORD or 4 bytes, that should be should from now on | ||
62 | * - from now on, we don't support anything older than firm 1.00 | ||
63 | * I eliminated the write register as a 2 trip of writing hi word and lo word | ||
64 | * and force this to write only 4 bytes at a time. | ||
65 | * NOTE: this should work with all the firmware from 1.00 and newer | ||
66 | */ | ||
67 | static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read) | ||
68 | { | ||
69 | struct flexcop_usb *fc_usb = fc->bus_specific; | ||
70 | u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG; | ||
71 | u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR; | ||
72 | u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | (read ? 0x80 : 0); | ||
73 | |||
74 | int len = usb_control_msg(fc_usb->udev, | ||
75 | read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT, | ||
76 | request, | ||
77 | request_type, /* 0xc0 read or 0x40 write*/ | ||
78 | wAddress, | ||
79 | 0, | ||
80 | val, | ||
81 | sizeof(u32), | ||
82 | B2C2_WAIT_FOR_OPERATION_RDW * HZ); | ||
83 | |||
84 | if (len != sizeof(u32)) { | ||
85 | err("error while %s dword from %d (%d).",read ? "reading" : "writing", | ||
86 | wAddress,wRegOffsPCI); | ||
87 | return -EIO; | ||
88 | } | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * DKT 010817 - add support for V8 memory read/write and flash update | ||
94 | */ | ||
95 | static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb, | ||
96 | flexcop_usb_request_t req, u8 page, u16 wAddress, | ||
97 | u8 *pbBuffer,u32 buflen) | ||
98 | { | ||
99 | // u8 dwRequestType; | ||
100 | u8 request_type = USB_TYPE_VENDOR; | ||
101 | u16 wIndex; | ||
102 | int nWaitTime,pipe,len; | ||
103 | |||
104 | wIndex = page << 8; | ||
105 | |||
106 | switch (req) { | ||
107 | case B2C2_USB_READ_V8_MEM: | ||
108 | nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ; | ||
109 | request_type |= USB_DIR_IN; | ||
110 | // dwRequestType = (u8) RTYPE_READ_V8_MEMORY; | ||
111 | pipe = B2C2_USB_CTRL_PIPE_IN; | ||
112 | break; | ||
113 | case B2C2_USB_WRITE_V8_MEM: | ||
114 | wIndex |= pbBuffer[0]; | ||
115 | request_type |= USB_DIR_OUT; | ||
116 | nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE; | ||
117 | // dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY; | ||
118 | pipe = B2C2_USB_CTRL_PIPE_OUT; | ||
119 | break; | ||
120 | case B2C2_USB_FLASH_BLOCK: | ||
121 | request_type |= USB_DIR_OUT; | ||
122 | nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH; | ||
123 | // dwRequestType = (u8) RTYPE_WRITE_V8_FLASH; | ||
124 | pipe = B2C2_USB_CTRL_PIPE_OUT; | ||
125 | break; | ||
126 | default: | ||
127 | deb_info("unsupported request for v8_mem_req %x.\n",req); | ||
128 | return -EINVAL; | ||
129 | } | ||
130 | deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n",request_type,req, | ||
131 | wAddress,wIndex,buflen); | ||
132 | |||
133 | len = usb_control_msg(fc_usb->udev,pipe, | ||
134 | req, | ||
135 | request_type, | ||
136 | wAddress, | ||
137 | wIndex, | ||
138 | pbBuffer, | ||
139 | buflen, | ||
140 | nWaitTime * HZ); | ||
141 | |||
142 | debug_dump(pbBuffer,len,deb_v8); | ||
143 | |||
144 | return len == buflen ? 0 : -EIO; | ||
145 | } | ||
146 | |||
147 | #define bytes_left_to_read_on_page(paddr,buflen) \ | ||
148 | ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \ | ||
149 | ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK))) | ||
150 | |||
151 | static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,flexcop_usb_request_t req, | ||
152 | flexcop_usb_mem_page_t page_start, u32 addr, int extended, u8 *buf, u32 len) | ||
153 | { | ||
154 | int i,ret = 0; | ||
155 | u16 wMax; | ||
156 | u32 pagechunk = 0; | ||
157 | |||
158 | switch(req) { | ||
159 | case B2C2_USB_READ_V8_MEM: wMax = USB_MEM_READ_MAX; break; | ||
160 | case B2C2_USB_WRITE_V8_MEM: wMax = USB_MEM_WRITE_MAX; break; | ||
161 | case B2C2_USB_FLASH_BLOCK: wMax = USB_FLASH_MAX; break; | ||
162 | default: | ||
163 | return -EINVAL; | ||
164 | break; | ||
165 | } | ||
166 | for (i = 0; i < len;) { | ||
167 | pagechunk = wMax < bytes_left_to_read_on_page(addr,len) ? wMax : bytes_left_to_read_on_page(addr,len); | ||
168 | deb_info("%x\n",(addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended)); | ||
169 | if ((ret = flexcop_usb_v8_memory_req(fc_usb,req, | ||
170 | page_start + (addr / V8_MEMORY_PAGE_SIZE), /* actual page */ | ||
171 | (addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended), | ||
172 | &buf[i],pagechunk)) < 0) | ||
173 | return ret; | ||
174 | |||
175 | addr += pagechunk; | ||
176 | len -= pagechunk; | ||
177 | } | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended) | ||
182 | { | ||
183 | return flexcop_usb_memory_req(fc->bus_specific,B2C2_USB_READ_V8_MEM,V8_MEMORY_PAGE_FLASH,0x1f010,1,fc->mac_address,6); | ||
184 | } | ||
185 | |||
186 | #if 0 | ||
187 | static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set, | ||
188 | flexcop_usb_utility_function_t func, u8 extra, u16 wIndex, | ||
189 | u16 buflen, u8 *pvBuffer) | ||
190 | { | ||
191 | u16 wValue; | ||
192 | u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR; | ||
193 | // u8 dwRequestType = (u8) RTYPE_GENERIC, | ||
194 | int nWaitTime = 2, | ||
195 | pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, | ||
196 | len; | ||
197 | |||
198 | wValue = (func << 8) | extra; | ||
199 | |||
200 | len = usb_control_msg(fc_usb->udev,pipe, | ||
201 | B2C2_USB_UTILITY, | ||
202 | request_type, | ||
203 | wValue, | ||
204 | wIndex, | ||
205 | pvBuffer, | ||
206 | buflen, | ||
207 | nWaitTime * HZ); | ||
208 | return len == buflen ? 0 : -EIO; | ||
209 | } | ||
210 | #endif | ||
211 | |||
212 | /* usb i2c stuff */ | ||
213 | static int flexcop_usb_i2c_req(struct flexcop_usb *fc_usb, | ||
214 | flexcop_usb_request_t req, flexcop_usb_i2c_function_t func, | ||
215 | flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u8 buflen) | ||
216 | { | ||
217 | u16 wValue, wIndex; | ||
218 | int nWaitTime,pipe,len; | ||
219 | // u8 dwRequestType; | ||
220 | u8 request_type = USB_TYPE_VENDOR; | ||
221 | |||
222 | switch (func) { | ||
223 | case USB_FUNC_I2C_WRITE: | ||
224 | case USB_FUNC_I2C_MULTIWRITE: | ||
225 | case USB_FUNC_I2C_REPEATWRITE: | ||
226 | /* DKT 020208 - add this to support special case of DiSEqC */ | ||
227 | case USB_FUNC_I2C_CHECKWRITE: | ||
228 | pipe = B2C2_USB_CTRL_PIPE_OUT; | ||
229 | nWaitTime = 2; | ||
230 | // dwRequestType = (u8) RTYPE_GENERIC; | ||
231 | request_type |= USB_DIR_OUT; | ||
232 | break; | ||
233 | case USB_FUNC_I2C_READ: | ||
234 | case USB_FUNC_I2C_REPEATREAD: | ||
235 | pipe = B2C2_USB_CTRL_PIPE_IN; | ||
236 | nWaitTime = 2; | ||
237 | // dwRequestType = (u8) RTYPE_GENERIC; | ||
238 | request_type |= USB_DIR_IN; | ||
239 | break; | ||
240 | default: | ||
241 | deb_info("unsupported function for i2c_req %x\n",func); | ||
242 | return -EINVAL; | ||
243 | } | ||
244 | wValue = (func << 8 ) | (port << 4); | ||
245 | wIndex = (chipaddr << 8 ) | addr; | ||
246 | |||
247 | deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req, | ||
248 | ((wValue && 0xff) << 8),wValue >> 8,((wIndex && 0xff) << 8),wIndex >> 8); | ||
249 | |||
250 | len = usb_control_msg(fc_usb->udev,pipe, | ||
251 | req, | ||
252 | request_type, | ||
253 | wValue, | ||
254 | wIndex, | ||
255 | buf, | ||
256 | buflen, | ||
257 | nWaitTime * HZ); | ||
258 | |||
259 | return len == buflen ? 0 : -EREMOTEIO; | ||
260 | } | ||
261 | |||
262 | /* actual bus specific access functions, make sure prototype are/will be equal to pci */ | ||
263 | static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg) | ||
264 | { | ||
265 | flexcop_ibi_value val; | ||
266 | val.raw = 0; | ||
267 | flexcop_usb_readwrite_dw(fc,reg, &val.raw, 1); | ||
268 | return val; | ||
269 | } | ||
270 | |||
271 | static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg, flexcop_ibi_value val) | ||
272 | { | ||
273 | return flexcop_usb_readwrite_dw(fc,reg, &val.raw, 0); | ||
274 | } | ||
275 | |||
276 | static int flexcop_usb_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | ||
277 | flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len) | ||
278 | { | ||
279 | if (op == FC_READ) | ||
280 | return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_READ,port,chipaddr,addr,buf,len); | ||
281 | else | ||
282 | return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_WRITE,port,chipaddr,addr,buf,len); | ||
283 | } | ||
284 | |||
285 | static void flexcop_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs) | ||
286 | { | ||
287 | struct flexcop_usb *fc_usb = urb->context; | ||
288 | int i; | ||
289 | |||
290 | if (urb->actual_length > 0) | ||
291 | deb_ts("urb completed, bufsize: %d actlen; %d\n",urb->transfer_buffer_length, urb->actual_length); | ||
292 | |||
293 | for (i = 0; i < urb->number_of_packets; i++) { | ||
294 | if (urb->iso_frame_desc[i].status < 0) { | ||
295 | err("iso frame descriptor %d has an error: %d\n",i,urb->iso_frame_desc[i].status); | ||
296 | } else | ||
297 | if (urb->iso_frame_desc[i].actual_length > 0) { | ||
298 | deb_ts("passed %d bytes to the demux\n",urb->iso_frame_desc[i].actual_length); | ||
299 | |||
300 | flexcop_pass_dmx_data(fc_usb->fc_dev, | ||
301 | urb->transfer_buffer + urb->iso_frame_desc[i].offset, | ||
302 | urb->iso_frame_desc[i].actual_length); | ||
303 | } | ||
304 | urb->iso_frame_desc[i].status = 0; | ||
305 | urb->iso_frame_desc[i].actual_length = 0; | ||
306 | } | ||
307 | |||
308 | usb_submit_urb(urb,GFP_ATOMIC); | ||
309 | } | ||
310 | |||
311 | static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff) | ||
312 | { | ||
313 | /* submit/kill iso packets */ | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb) | ||
318 | { | ||
319 | int i; | ||
320 | for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) | ||
321 | if (fc_usb->iso_urb[i] != NULL) { | ||
322 | deb_ts("unlinking/killing urb no. %d\n",i); | ||
323 | usb_kill_urb(fc_usb->iso_urb[i]); | ||
324 | usb_free_urb(fc_usb->iso_urb[i]); | ||
325 | } | ||
326 | |||
327 | if (fc_usb->iso_buffer != NULL) | ||
328 | pci_free_consistent(NULL,fc_usb->buffer_size, fc_usb->iso_buffer, fc_usb->dma_addr); | ||
329 | } | ||
330 | |||
331 | static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) | ||
332 | { | ||
333 | u16 frame_size = fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize; | ||
334 | int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret; | ||
335 | int buffer_offset = 0; | ||
336 | |||
337 | deb_ts("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n", | ||
338 | B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize); | ||
339 | |||
340 | fc_usb->iso_buffer = pci_alloc_consistent(NULL,bufsize,&fc_usb->dma_addr); | ||
341 | if (fc_usb->iso_buffer == NULL) | ||
342 | return -ENOMEM; | ||
343 | memset(fc_usb->iso_buffer, 0, bufsize); | ||
344 | fc_usb->buffer_size = bufsize; | ||
345 | |||
346 | /* creating iso urbs */ | ||
347 | for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) | ||
348 | if (!(fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) { | ||
349 | ret = -ENOMEM; | ||
350 | goto urb_error; | ||
351 | } | ||
352 | /* initialising and submitting iso urbs */ | ||
353 | for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { | ||
354 | int frame_offset = 0; | ||
355 | struct urb *urb = fc_usb->iso_urb[i]; | ||
356 | deb_ts("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset); | ||
357 | |||
358 | urb->dev = fc_usb->udev; | ||
359 | urb->context = fc_usb; | ||
360 | urb->complete = flexcop_usb_urb_complete; | ||
361 | urb->pipe = B2C2_USB_DATA_PIPE; | ||
362 | urb->transfer_flags = URB_ISO_ASAP; | ||
363 | urb->interval = 1; | ||
364 | urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO; | ||
365 | urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO; | ||
366 | urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset; | ||
367 | |||
368 | buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO; | ||
369 | for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) { | ||
370 | deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset); | ||
371 | urb->iso_frame_desc[j].offset = frame_offset; | ||
372 | urb->iso_frame_desc[j].length = frame_size; | ||
373 | frame_offset += frame_size; | ||
374 | } | ||
375 | |||
376 | if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) { | ||
377 | err("submitting urb %d failed with %d.",i,ret); | ||
378 | goto urb_error; | ||
379 | } | ||
380 | deb_ts("submitted urb no. %d.\n",i); | ||
381 | } | ||
382 | |||
383 | /* SRAM */ | ||
384 | |||
385 | flexcop_sram_set_dest(fc_usb->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET | | ||
386 | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_WAN_USB); | ||
387 | flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS); | ||
388 | flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1); | ||
389 | |||
390 | ret = 0; | ||
391 | goto success; | ||
392 | urb_error: | ||
393 | flexcop_usb_transfer_exit(fc_usb); | ||
394 | success: | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | static int flexcop_usb_init(struct flexcop_usb *fc_usb) | ||
399 | { | ||
400 | /* use the alternate setting with the larges buffer */ | ||
401 | usb_set_interface(fc_usb->udev,0,1); | ||
402 | switch (fc_usb->udev->speed) { | ||
403 | case USB_SPEED_LOW: | ||
404 | err("cannot handle USB speed because it is to sLOW."); | ||
405 | return -ENODEV; | ||
406 | break; | ||
407 | case USB_SPEED_FULL: | ||
408 | info("running at FULL speed."); | ||
409 | break; | ||
410 | case USB_SPEED_HIGH: | ||
411 | info("running at HIGH speed."); | ||
412 | break; | ||
413 | case USB_SPEED_UNKNOWN: /* fall through */ | ||
414 | default: | ||
415 | err("cannot handle USB speed because it is unkown."); | ||
416 | return -ENODEV; | ||
417 | } | ||
418 | usb_set_intfdata(fc_usb->uintf, fc_usb); | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static void flexcop_usb_exit(struct flexcop_usb *fc_usb) | ||
423 | { | ||
424 | usb_set_intfdata(fc_usb->uintf, NULL); | ||
425 | } | ||
426 | |||
427 | static int flexcop_usb_probe(struct usb_interface *intf, | ||
428 | const struct usb_device_id *id) | ||
429 | { | ||
430 | struct usb_device *udev = interface_to_usbdev(intf); | ||
431 | struct flexcop_usb *fc_usb = NULL; | ||
432 | struct flexcop_device *fc = NULL; | ||
433 | int ret; | ||
434 | |||
435 | if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { | ||
436 | err("out of memory\n"); | ||
437 | return -ENOMEM; | ||
438 | } | ||
439 | |||
440 | /* general flexcop init */ | ||
441 | fc_usb = fc->bus_specific; | ||
442 | fc_usb->fc_dev = fc; | ||
443 | |||
444 | fc->read_ibi_reg = flexcop_usb_read_ibi_reg; | ||
445 | fc->write_ibi_reg = flexcop_usb_write_ibi_reg; | ||
446 | fc->i2c_request = flexcop_usb_i2c_request; | ||
447 | fc->get_mac_addr = flexcop_usb_get_mac_addr; | ||
448 | |||
449 | fc->stream_control = flexcop_usb_stream_control; | ||
450 | |||
451 | fc->pid_filtering = 1; | ||
452 | fc->bus_type = FC_USB; | ||
453 | |||
454 | fc->dev = &udev->dev; | ||
455 | |||
456 | /* bus specific part */ | ||
457 | fc_usb->udev = udev; | ||
458 | fc_usb->uintf = intf; | ||
459 | if ((ret = flexcop_usb_init(fc_usb)) != 0) | ||
460 | goto err_kfree; | ||
461 | |||
462 | /* init flexcop */ | ||
463 | if ((ret = flexcop_device_initialize(fc)) != 0) | ||
464 | goto err_usb_exit; | ||
465 | |||
466 | /* xfer init */ | ||
467 | if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0) | ||
468 | goto err_fc_exit; | ||
469 | |||
470 | info("%s successfully initialized and connected.",DRIVER_NAME); | ||
471 | ret = 0; | ||
472 | goto success; | ||
473 | err_fc_exit: | ||
474 | flexcop_device_exit(fc); | ||
475 | err_usb_exit: | ||
476 | flexcop_usb_exit(fc_usb); | ||
477 | err_kfree: | ||
478 | flexcop_device_kfree(fc); | ||
479 | success: | ||
480 | return ret; | ||
481 | } | ||
482 | |||
483 | static void flexcop_usb_disconnect(struct usb_interface *intf) | ||
484 | { | ||
485 | struct flexcop_usb *fc_usb = usb_get_intfdata(intf); | ||
486 | flexcop_usb_transfer_exit(fc_usb); | ||
487 | flexcop_device_exit(fc_usb->fc_dev); | ||
488 | flexcop_usb_exit(fc_usb); | ||
489 | flexcop_device_kfree(fc_usb->fc_dev); | ||
490 | info("%s successfully deinitialized and disconnected.",DRIVER_NAME); | ||
491 | } | ||
492 | |||
493 | static struct usb_device_id flexcop_usb_table [] = { | ||
494 | { USB_DEVICE(0x0af7, 0x0101) }, | ||
495 | { } | ||
496 | }; | ||
497 | |||
498 | /* usb specific object needed to register this driver with the usb subsystem */ | ||
499 | static struct usb_driver flexcop_usb_driver = { | ||
500 | .owner = THIS_MODULE, | ||
501 | .name = "Technisat/B2C2 FlexCop II/IIb/III USB", | ||
502 | .probe = flexcop_usb_probe, | ||
503 | .disconnect = flexcop_usb_disconnect, | ||
504 | .id_table = flexcop_usb_table, | ||
505 | }; | ||
506 | |||
507 | /* module stuff */ | ||
508 | static int __init flexcop_usb_module_init(void) | ||
509 | { | ||
510 | int result; | ||
511 | if ((result = usb_register(&flexcop_usb_driver))) { | ||
512 | err("usb_register failed. (%d)",result); | ||
513 | return result; | ||
514 | } | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | static void __exit flexcop_usb_module_exit(void) | ||
520 | { | ||
521 | /* deregister this driver from the USB subsystem */ | ||
522 | usb_deregister(&flexcop_usb_driver); | ||
523 | } | ||
524 | |||
525 | module_init(flexcop_usb_module_init); | ||
526 | module_exit(flexcop_usb_module_exit); | ||
527 | |||
528 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
529 | MODULE_DESCRIPTION(DRIVER_NAME); | ||
530 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.h b/drivers/media/dvb/b2c2/flexcop-usb.h new file mode 100644 index 000000000000..bfcec25ff2d9 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-usb.h | |||
@@ -0,0 +1,116 @@ | |||
1 | #ifndef __FLEXCOP_USB_H_INCLUDED__ | ||
2 | #define __FLEXCOP_USB_H_INCLUDED__ | ||
3 | |||
4 | #include <linux/usb.h> | ||
5 | |||
6 | /* transfer parameters */ | ||
7 | #define B2C2_USB_FRAMES_PER_ISO 4 | ||
8 | #define B2C2_USB_NUM_ISO_URB 4 | ||
9 | |||
10 | #define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev,0) | ||
11 | #define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev,0) | ||
12 | #define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev,0x81) | ||
13 | |||
14 | struct flexcop_usb { | ||
15 | struct usb_device *udev; | ||
16 | struct usb_interface *uintf; | ||
17 | |||
18 | u8 *iso_buffer; | ||
19 | int buffer_size; | ||
20 | dma_addr_t dma_addr; | ||
21 | struct urb *iso_urb[B2C2_USB_NUM_ISO_URB]; | ||
22 | |||
23 | struct flexcop_device *fc_dev; | ||
24 | }; | ||
25 | |||
26 | #if 0 | ||
27 | /* request types TODO What is its use?*/ | ||
28 | typedef enum { | ||
29 | |||
30 | /* something is wrong with this part | ||
31 | RTYPE_READ_DW = (1 << 6), | ||
32 | RTYPE_WRITE_DW_1 = (3 << 6), | ||
33 | RTYPE_READ_V8_MEMORY = (6 << 6), | ||
34 | RTYPE_WRITE_V8_MEMORY = (7 << 6), | ||
35 | RTYPE_WRITE_V8_FLASH = (8 << 6), | ||
36 | RTYPE_GENERIC = (9 << 6), | ||
37 | */ | ||
38 | } flexcop_usb_request_type_t; | ||
39 | #endif | ||
40 | |||
41 | /* request */ | ||
42 | typedef enum { | ||
43 | B2C2_USB_WRITE_V8_MEM = 0x04, | ||
44 | B2C2_USB_READ_V8_MEM = 0x05, | ||
45 | B2C2_USB_READ_REG = 0x08, | ||
46 | B2C2_USB_WRITE_REG = 0x0A, | ||
47 | /* B2C2_USB_WRITEREGLO = 0x0A, */ | ||
48 | B2C2_USB_WRITEREGHI = 0x0B, | ||
49 | B2C2_USB_FLASH_BLOCK = 0x10, | ||
50 | B2C2_USB_I2C_REQUEST = 0x11, | ||
51 | B2C2_USB_UTILITY = 0x12, | ||
52 | } flexcop_usb_request_t; | ||
53 | |||
54 | /* function definition for I2C_REQUEST */ | ||
55 | typedef enum { | ||
56 | USB_FUNC_I2C_WRITE = 0x01, | ||
57 | USB_FUNC_I2C_MULTIWRITE = 0x02, | ||
58 | USB_FUNC_I2C_READ = 0x03, | ||
59 | USB_FUNC_I2C_REPEATWRITE = 0x04, | ||
60 | USB_FUNC_GET_DESCRIPTOR = 0x05, | ||
61 | USB_FUNC_I2C_REPEATREAD = 0x06, | ||
62 | /* DKT 020208 - add this to support special case of DiSEqC */ | ||
63 | USB_FUNC_I2C_CHECKWRITE = 0x07, | ||
64 | USB_FUNC_I2C_CHECKRESULT = 0x08, | ||
65 | } flexcop_usb_i2c_function_t; | ||
66 | |||
67 | /* | ||
68 | * function definition for UTILITY request 0x12 | ||
69 | * DKT 020304 - new utility function | ||
70 | */ | ||
71 | typedef enum { | ||
72 | UTILITY_SET_FILTER = 0x01, | ||
73 | UTILITY_DATA_ENABLE = 0x02, | ||
74 | UTILITY_FLEX_MULTIWRITE = 0x03, | ||
75 | UTILITY_SET_BUFFER_SIZE = 0x04, | ||
76 | UTILITY_FLEX_OPERATOR = 0x05, | ||
77 | UTILITY_FLEX_RESET300_START = 0x06, | ||
78 | UTILITY_FLEX_RESET300_STOP = 0x07, | ||
79 | UTILITY_FLEX_RESET300 = 0x08, | ||
80 | UTILITY_SET_ISO_SIZE = 0x09, | ||
81 | UTILITY_DATA_RESET = 0x0A, | ||
82 | UTILITY_GET_DATA_STATUS = 0x10, | ||
83 | UTILITY_GET_V8_REG = 0x11, | ||
84 | /* DKT 020326 - add function for v1.14 */ | ||
85 | UTILITY_SRAM_WRITE = 0x12, | ||
86 | UTILITY_SRAM_READ = 0x13, | ||
87 | UTILITY_SRAM_TESTFILL = 0x14, | ||
88 | UTILITY_SRAM_TESTSET = 0x15, | ||
89 | UTILITY_SRAM_TESTVERIFY = 0x16, | ||
90 | } flexcop_usb_utility_function_t; | ||
91 | |||
92 | #define B2C2_WAIT_FOR_OPERATION_RW 1*HZ /* 1 s */ | ||
93 | #define B2C2_WAIT_FOR_OPERATION_RDW 3*HZ /* 3 s */ | ||
94 | #define B2C2_WAIT_FOR_OPERATION_WDW 1*HZ /* 1 s */ | ||
95 | |||
96 | #define B2C2_WAIT_FOR_OPERATION_V8READ 3*HZ /* 3 s */ | ||
97 | #define B2C2_WAIT_FOR_OPERATION_V8WRITE 3*HZ /* 3 s */ | ||
98 | #define B2C2_WAIT_FOR_OPERATION_V8FLASH 3*HZ /* 3 s */ | ||
99 | |||
100 | typedef enum { | ||
101 | V8_MEMORY_PAGE_DVB_CI = 0x20, | ||
102 | V8_MEMORY_PAGE_DVB_DS = 0x40, | ||
103 | V8_MEMORY_PAGE_MULTI2 = 0x60, | ||
104 | V8_MEMORY_PAGE_FLASH = 0x80 | ||
105 | } flexcop_usb_mem_page_t; | ||
106 | |||
107 | #define V8_MEMORY_EXTENDED (1 << 15) | ||
108 | |||
109 | #define USB_MEM_READ_MAX 32 | ||
110 | #define USB_MEM_WRITE_MAX 1 | ||
111 | #define USB_FLASH_MAX 8 | ||
112 | |||
113 | #define V8_MEMORY_PAGE_SIZE 0x8000 // 32K | ||
114 | #define V8_MEMORY_PAGE_MASK 0x7FFF | ||
115 | |||
116 | #endif | ||
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c new file mode 100644 index 000000000000..1998267207fb --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * flexcop.c - driver for digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * Copyright (C) 2004-5 Patrick Boettcher <patrick.boettcher@desy.de> | ||
5 | * | ||
6 | * based on the skystar2-driver | ||
7 | * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc | ||
8 | * | ||
9 | * Acknowledgements: | ||
10 | * John Jurrius from BBTI, Inc. for extensive support with | ||
11 | * code examples and data books | ||
12 | * | ||
13 | * Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting) | ||
14 | * | ||
15 | * Contributions to the skystar2-driver have been done by | ||
16 | * Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes) | ||
17 | * Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code) | ||
18 | * Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac filtering) | ||
19 | * | ||
20 | * | ||
21 | * This program is free software; you can redistribute it and/or | ||
22 | * modify it under the terms of the GNU Lesser General Public License | ||
23 | * as published by the Free Software Foundation; either version 2.1 | ||
24 | * of the License, or (at your option) any later version. | ||
25 | * | ||
26 | * This program is distributed in the hope that it will be useful, | ||
27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
29 | * GNU General Public License for more details. | ||
30 | * | ||
31 | * You should have received a copy of the GNU Lesser General Public License | ||
32 | * along with this program; if not, write to the Free Software | ||
33 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
34 | */ | ||
35 | |||
36 | #include "flexcop.h" | ||
37 | |||
38 | #define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip" | ||
39 | #define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de" | ||
40 | |||
41 | #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG | ||
42 | #define DEBSTATUS "" | ||
43 | #else | ||
44 | #define DEBSTATUS " (debugging is not enabled)" | ||
45 | #endif | ||
46 | |||
47 | int b2c2_flexcop_debug; | ||
48 | module_param_named(debug, b2c2_flexcop_debug, int, 0644); | ||
49 | MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram (|-able))." DEBSTATUS); | ||
50 | #undef DEBSTATUS | ||
51 | |||
52 | /* global zero for ibi values */ | ||
53 | flexcop_ibi_value ibi_zero; | ||
54 | |||
55 | static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
56 | { | ||
57 | struct flexcop_device *fc = dvbdmxfeed->demux->priv; | ||
58 | return flexcop_pid_feed_control(fc,dvbdmxfeed,1); | ||
59 | } | ||
60 | |||
61 | static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
62 | { | ||
63 | struct flexcop_device *fc = dvbdmxfeed->demux->priv; | ||
64 | return flexcop_pid_feed_control(fc,dvbdmxfeed,0); | ||
65 | } | ||
66 | |||
67 | static int flexcop_dvb_init(struct flexcop_device *fc) | ||
68 | { | ||
69 | int ret; | ||
70 | if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",THIS_MODULE)) < 0) { | ||
71 | err("error registering DVB adapter"); | ||
72 | return ret; | ||
73 | } | ||
74 | fc->dvb_adapter.priv = fc; | ||
75 | |||
76 | fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); | ||
77 | fc->demux.priv = fc; | ||
78 | |||
79 | fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED; | ||
80 | |||
81 | fc->demux.start_feed = flexcop_dvb_start_feed; | ||
82 | fc->demux.stop_feed = flexcop_dvb_stop_feed; | ||
83 | fc->demux.write_to_decoder = NULL; | ||
84 | |||
85 | if ((ret = dvb_dmx_init(&fc->demux)) < 0) { | ||
86 | err("dvb_dmx failed: error %d",ret); | ||
87 | goto err_dmx; | ||
88 | } | ||
89 | |||
90 | fc->hw_frontend.source = DMX_FRONTEND_0; | ||
91 | |||
92 | fc->dmxdev.filternum = fc->demux.feednum; | ||
93 | fc->dmxdev.demux = &fc->demux.dmx; | ||
94 | fc->dmxdev.capabilities = 0; | ||
95 | if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) { | ||
96 | err("dvb_dmxdev_init failed: error %d",ret); | ||
97 | goto err_dmx_dev; | ||
98 | } | ||
99 | |||
100 | if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { | ||
101 | err("adding hw_frontend to dmx failed: error %d",ret); | ||
102 | goto err_dmx_add_hw_frontend; | ||
103 | } | ||
104 | |||
105 | fc->mem_frontend.source = DMX_MEMORY_FE; | ||
106 | if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) { | ||
107 | err("adding mem_frontend to dmx failed: error %d",ret); | ||
108 | goto err_dmx_add_mem_frontend; | ||
109 | } | ||
110 | |||
111 | if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { | ||
112 | err("connect frontend failed: error %d",ret); | ||
113 | goto err_connect_frontend; | ||
114 | } | ||
115 | |||
116 | dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx); | ||
117 | |||
118 | fc->init_state |= FC_STATE_DVB_INIT; | ||
119 | goto success; | ||
120 | |||
121 | err_connect_frontend: | ||
122 | fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend); | ||
123 | err_dmx_add_mem_frontend: | ||
124 | fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend); | ||
125 | err_dmx_add_hw_frontend: | ||
126 | dvb_dmxdev_release(&fc->dmxdev); | ||
127 | err_dmx_dev: | ||
128 | dvb_dmx_release(&fc->demux); | ||
129 | err_dmx: | ||
130 | dvb_unregister_adapter(&fc->dvb_adapter); | ||
131 | return ret; | ||
132 | |||
133 | success: | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static void flexcop_dvb_exit(struct flexcop_device *fc) | ||
138 | { | ||
139 | if (fc->init_state & FC_STATE_DVB_INIT) { | ||
140 | dvb_net_release(&fc->dvbnet); | ||
141 | |||
142 | fc->demux.dmx.close(&fc->demux.dmx); | ||
143 | fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend); | ||
144 | fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend); | ||
145 | dvb_dmxdev_release(&fc->dmxdev); | ||
146 | dvb_dmx_release(&fc->demux); | ||
147 | dvb_unregister_adapter(&fc->dvb_adapter); | ||
148 | |||
149 | deb_info("deinitialized dvb stuff\n"); | ||
150 | } | ||
151 | fc->init_state &= ~FC_STATE_DVB_INIT; | ||
152 | } | ||
153 | |||
154 | /* these methods are necessary to achieve the long-term-goal of hiding the | ||
155 | * struct flexcop_device from the bus-parts */ | ||
156 | void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len) | ||
157 | { | ||
158 | dvb_dmx_swfilter(&fc->demux, buf, len); | ||
159 | } | ||
160 | EXPORT_SYMBOL(flexcop_pass_dmx_data); | ||
161 | |||
162 | void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no) | ||
163 | { | ||
164 | dvb_dmx_swfilter_packets(&fc->demux, buf, no); | ||
165 | } | ||
166 | EXPORT_SYMBOL(flexcop_pass_dmx_packets); | ||
167 | |||
168 | static void flexcop_reset(struct flexcop_device *fc) | ||
169 | { | ||
170 | flexcop_ibi_value v210,v204; | ||
171 | |||
172 | /* reset the flexcop itself */ | ||
173 | fc->write_ibi_reg(fc,ctrl_208,ibi_zero); | ||
174 | |||
175 | v210.raw = 0; | ||
176 | v210.sw_reset_210.reset_blocks = 0xff; | ||
177 | v210.sw_reset_210.Block_reset_enable = 0xb2; | ||
178 | fc->write_ibi_reg(fc,sw_reset_210,v210); | ||
179 | |||
180 | /* reset the periphical devices */ | ||
181 | |||
182 | v204 = fc->read_ibi_reg(fc,misc_204); | ||
183 | v204.misc_204.Per_reset_sig = 0; | ||
184 | fc->write_ibi_reg(fc,misc_204,v204); | ||
185 | v204.misc_204.Per_reset_sig = 1; | ||
186 | fc->write_ibi_reg(fc,misc_204,v204); | ||
187 | |||
188 | /* v208.raw = 0; | ||
189 | v208.ctrl_208.Null_filter_sig = 1; | ||
190 | fc->write_ibi_reg(fc,ctrl_208,v208);*/ | ||
191 | } | ||
192 | |||
193 | struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) | ||
194 | { | ||
195 | void *bus; | ||
196 | struct flexcop_device *fc = kmalloc(sizeof(struct flexcop_device), GFP_KERNEL); | ||
197 | if (!fc) { | ||
198 | err("no memory"); | ||
199 | return NULL; | ||
200 | } | ||
201 | memset(fc, 0, sizeof(struct flexcop_device)); | ||
202 | |||
203 | bus = kmalloc(bus_specific_len, GFP_KERNEL); | ||
204 | if (!bus) { | ||
205 | err("no memory"); | ||
206 | kfree(fc); | ||
207 | return NULL; | ||
208 | } | ||
209 | memset(bus, 0, bus_specific_len); | ||
210 | |||
211 | fc->bus_specific = bus; | ||
212 | |||
213 | return fc; | ||
214 | } | ||
215 | EXPORT_SYMBOL(flexcop_device_kmalloc); | ||
216 | |||
217 | void flexcop_device_kfree(struct flexcop_device *fc) | ||
218 | { | ||
219 | kfree(fc->bus_specific); | ||
220 | kfree(fc); | ||
221 | } | ||
222 | EXPORT_SYMBOL(flexcop_device_kfree); | ||
223 | |||
224 | int flexcop_device_initialize(struct flexcop_device *fc) | ||
225 | { | ||
226 | int ret; | ||
227 | ibi_zero.raw = 0; | ||
228 | |||
229 | flexcop_reset(fc); | ||
230 | flexcop_determine_revision(fc); | ||
231 | flexcop_sram_init(fc); | ||
232 | flexcop_hw_filter_init(fc); | ||
233 | |||
234 | flexcop_smc_ctrl(fc, 0); | ||
235 | |||
236 | if (fc->get_mac_addr(fc, 0) == 0) { | ||
237 | u8 *b = fc->mac_address; | ||
238 | info("MAC address = %02x:%02x:%02x:%02x:%02x:%02x", b[0],b[1],b[2],b[3],b[4],b[5]); | ||
239 | flexcop_set_mac_filter(fc,fc->mac_address); | ||
240 | flexcop_mac_filter_ctrl(fc,1); | ||
241 | } else | ||
242 | warn("reading of MAC address failed.\n"); | ||
243 | |||
244 | if ((ret = flexcop_dvb_init(fc))) | ||
245 | goto error; | ||
246 | |||
247 | if ((ret = flexcop_i2c_init(fc))) | ||
248 | goto error; | ||
249 | |||
250 | if ((ret = flexcop_frontend_init(fc))) | ||
251 | goto error; | ||
252 | |||
253 | flexcop_device_name(fc,"initialization of","complete"); | ||
254 | |||
255 | ret = 0; | ||
256 | goto success; | ||
257 | error: | ||
258 | flexcop_device_exit(fc); | ||
259 | success: | ||
260 | return ret; | ||
261 | } | ||
262 | EXPORT_SYMBOL(flexcop_device_initialize); | ||
263 | |||
264 | void flexcop_device_exit(struct flexcop_device *fc) | ||
265 | { | ||
266 | flexcop_frontend_exit(fc); | ||
267 | flexcop_i2c_exit(fc); | ||
268 | flexcop_dvb_exit(fc); | ||
269 | } | ||
270 | EXPORT_SYMBOL(flexcop_device_exit); | ||
271 | |||
272 | static int flexcop_module_init(void) | ||
273 | { | ||
274 | info(DRIVER_NAME " loaded successfully"); | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static void flexcop_module_cleanup(void) | ||
279 | { | ||
280 | info(DRIVER_NAME " unloaded successfully"); | ||
281 | } | ||
282 | |||
283 | module_init(flexcop_module_init); | ||
284 | module_exit(flexcop_module_cleanup); | ||
285 | |||
286 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
287 | MODULE_DESCRIPTION(DRIVER_NAME); | ||
288 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h new file mode 100644 index 000000000000..caa343a97bdc --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III | ||
3 | * | ||
4 | * flexcop.h - private header file for all flexcop-chip-source files. | ||
5 | * | ||
6 | * see flexcop.c for copyright information. | ||
7 | */ | ||
8 | #ifndef __FLEXCOP_H__ | ||
9 | #define __FLEXCOP_H___ | ||
10 | |||
11 | #define FC_LOG_PREFIX "b2c2-flexcop" | ||
12 | #include "flexcop-common.h" | ||
13 | |||
14 | extern int b2c2_flexcop_debug; | ||
15 | |||
16 | /* debug */ | ||
17 | #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG | ||
18 | #define dprintk(level,args...) \ | ||
19 | do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0) | ||
20 | #else | ||
21 | #define dprintk(level,args...) | ||
22 | #endif | ||
23 | |||
24 | #define deb_info(args...) dprintk(0x01,args) | ||
25 | #define deb_tuner(args...) dprintk(0x02,args) | ||
26 | #define deb_i2c(args...) dprintk(0x04,args) | ||
27 | #define deb_ts(args...) dprintk(0x08,args) | ||
28 | #define deb_sram(args...) dprintk(0x10,args) | ||
29 | |||
30 | #endif | ||