diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-06-14 15:35:57 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-13 22:30:06 -0400 |
commit | 25aee3debe0464f6c680173041fa3de30ec9ff54 (patch) | |
tree | e2b14f952a0831399f9cbb444cfb9c7980b6485b /drivers/media/pci/bt8xx | |
parent | 786baecfe78f8e25547c628b48a60fc8e5636056 (diff) |
[media] Rename media/dvb as media/pci
The remaining dvb drivers are pci, so rename them to match the
bus.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/pci/bt8xx')
-rw-r--r-- | drivers/media/pci/bt8xx/Kconfig | 22 | ||||
-rw-r--r-- | drivers/media/pci/bt8xx/Makefile | 6 | ||||
-rw-r--r-- | drivers/media/pci/bt8xx/bt878.c | 609 | ||||
-rw-r--r-- | drivers/media/pci/bt8xx/bt878.h | 159 | ||||
-rw-r--r-- | drivers/media/pci/bt8xx/dst.c | 1873 | ||||
-rw-r--r-- | drivers/media/pci/bt8xx/dst_ca.c | 726 | ||||
-rw-r--r-- | drivers/media/pci/bt8xx/dst_ca.h | 58 | ||||
-rw-r--r-- | drivers/media/pci/bt8xx/dst_common.h | 182 | ||||
-rw-r--r-- | drivers/media/pci/bt8xx/dst_priv.h | 35 | ||||
-rw-r--r-- | drivers/media/pci/bt8xx/dvb-bt8xx.c | 975 | ||||
-rw-r--r-- | drivers/media/pci/bt8xx/dvb-bt8xx.h | 63 |
11 files changed, 4708 insertions, 0 deletions
diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig new file mode 100644 index 000000000000..8668e634c7ec --- /dev/null +++ b/drivers/media/pci/bt8xx/Kconfig | |||
@@ -0,0 +1,22 @@ | |||
1 | config DVB_BT8XX | ||
2 | tristate "BT8xx based PCI cards" | ||
3 | depends on DVB_CORE && PCI && I2C && VIDEO_BT848 | ||
4 | select DVB_MT352 if !DVB_FE_CUSTOMISE | ||
5 | select DVB_SP887X if !DVB_FE_CUSTOMISE | ||
6 | select DVB_NXT6000 if !DVB_FE_CUSTOMISE | ||
7 | select DVB_CX24110 if !DVB_FE_CUSTOMISE | ||
8 | select DVB_OR51211 if !DVB_FE_CUSTOMISE | ||
9 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE | ||
10 | select DVB_ZL10353 if !DVB_FE_CUSTOMISE | ||
11 | select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE | ||
12 | help | ||
13 | Support for PCI cards based on the Bt8xx PCI bridge. Examples are | ||
14 | the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, | ||
15 | the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and | ||
16 | some AVerMedia cards. | ||
17 | |||
18 | Since these cards have no MPEG decoder onboard, they transmit | ||
19 | only compressed MPEG data over the PCI bus, so you need | ||
20 | an external software decoder to watch TV on your computer. | ||
21 | |||
22 | Say Y if you own such a device and want to use it. | ||
diff --git a/drivers/media/pci/bt8xx/Makefile b/drivers/media/pci/bt8xx/Makefile new file mode 100644 index 000000000000..36591ae505f4 --- /dev/null +++ b/drivers/media/pci/bt8xx/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o | ||
2 | |||
3 | ccflags-y += -Idrivers/media/dvb-core | ||
4 | ccflags-y += -Idrivers/media/dvb-frontends | ||
5 | ccflags-y += -Idrivers/media/video/bt8xx | ||
6 | ccflags-y += -Idrivers/media/common/tuners | ||
diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c new file mode 100644 index 000000000000..b34fa95185e4 --- /dev/null +++ b/drivers/media/pci/bt8xx/bt878.c | |||
@@ -0,0 +1,609 @@ | |||
1 | /* | ||
2 | * bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card | ||
3 | * | ||
4 | * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> | ||
5 | * | ||
6 | * large parts based on the bttv driver | ||
7 | * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de) | ||
8 | * & Marcus Metzler (mocm@metzlerbros.de) | ||
9 | * (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | |||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | |||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
26 | * Or, point your browser to http://www.gnu.org/copyleft/gpl.html | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/pci.h> | ||
33 | #include <asm/io.h> | ||
34 | #include <linux/ioport.h> | ||
35 | #include <asm/pgtable.h> | ||
36 | #include <asm/page.h> | ||
37 | #include <linux/types.h> | ||
38 | #include <linux/interrupt.h> | ||
39 | #include <linux/kmod.h> | ||
40 | #include <linux/vmalloc.h> | ||
41 | #include <linux/init.h> | ||
42 | |||
43 | #include "dmxdev.h" | ||
44 | #include "dvbdev.h" | ||
45 | #include "bt878.h" | ||
46 | #include "dst_priv.h" | ||
47 | |||
48 | |||
49 | /**************************************/ | ||
50 | /* Miscellaneous utility definitions */ | ||
51 | /**************************************/ | ||
52 | |||
53 | static unsigned int bt878_verbose = 1; | ||
54 | static unsigned int bt878_debug; | ||
55 | |||
56 | module_param_named(verbose, bt878_verbose, int, 0444); | ||
57 | MODULE_PARM_DESC(verbose, | ||
58 | "verbose startup messages, default is 1 (yes)"); | ||
59 | module_param_named(debug, bt878_debug, int, 0644); | ||
60 | MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off)."); | ||
61 | |||
62 | int bt878_num; | ||
63 | struct bt878 bt878[BT878_MAX]; | ||
64 | |||
65 | EXPORT_SYMBOL(bt878_num); | ||
66 | EXPORT_SYMBOL(bt878); | ||
67 | |||
68 | #define btwrite(dat,adr) bmtwrite((dat), (bt->bt878_mem+(adr))) | ||
69 | #define btread(adr) bmtread(bt->bt878_mem+(adr)) | ||
70 | |||
71 | #define btand(dat,adr) btwrite((dat) & btread(adr), adr) | ||
72 | #define btor(dat,adr) btwrite((dat) | btread(adr), adr) | ||
73 | #define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) | ||
74 | |||
75 | #if defined(dprintk) | ||
76 | #undef dprintk | ||
77 | #endif | ||
78 | #define dprintk(fmt, arg...) \ | ||
79 | do { \ | ||
80 | if (bt878_debug) \ | ||
81 | printk(KERN_DEBUG fmt, ##arg); \ | ||
82 | } while (0) | ||
83 | |||
84 | static void bt878_mem_free(struct bt878 *bt) | ||
85 | { | ||
86 | if (bt->buf_cpu) { | ||
87 | pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu, | ||
88 | bt->buf_dma); | ||
89 | bt->buf_cpu = NULL; | ||
90 | } | ||
91 | |||
92 | if (bt->risc_cpu) { | ||
93 | pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu, | ||
94 | bt->risc_dma); | ||
95 | bt->risc_cpu = NULL; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | static int bt878_mem_alloc(struct bt878 *bt) | ||
100 | { | ||
101 | if (!bt->buf_cpu) { | ||
102 | bt->buf_size = 128 * 1024; | ||
103 | |||
104 | bt->buf_cpu = | ||
105 | pci_alloc_consistent(bt->dev, bt->buf_size, | ||
106 | &bt->buf_dma); | ||
107 | |||
108 | if (!bt->buf_cpu) | ||
109 | return -ENOMEM; | ||
110 | |||
111 | memset(bt->buf_cpu, 0, bt->buf_size); | ||
112 | } | ||
113 | |||
114 | if (!bt->risc_cpu) { | ||
115 | bt->risc_size = PAGE_SIZE; | ||
116 | bt->risc_cpu = | ||
117 | pci_alloc_consistent(bt->dev, bt->risc_size, | ||
118 | &bt->risc_dma); | ||
119 | |||
120 | if (!bt->risc_cpu) { | ||
121 | bt878_mem_free(bt); | ||
122 | return -ENOMEM; | ||
123 | } | ||
124 | |||
125 | memset(bt->risc_cpu, 0, bt->risc_size); | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | /* RISC instructions */ | ||
132 | #define RISC_WRITE (0x01 << 28) | ||
133 | #define RISC_JUMP (0x07 << 28) | ||
134 | #define RISC_SYNC (0x08 << 28) | ||
135 | |||
136 | /* RISC bits */ | ||
137 | #define RISC_WR_SOL (1 << 27) | ||
138 | #define RISC_WR_EOL (1 << 26) | ||
139 | #define RISC_IRQ (1 << 24) | ||
140 | #define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16)) | ||
141 | #define RISC_SYNC_RESYNC (1 << 15) | ||
142 | #define RISC_SYNC_FM1 0x06 | ||
143 | #define RISC_SYNC_VRO 0x0C | ||
144 | |||
145 | #define RISC_FLUSH() bt->risc_pos = 0 | ||
146 | #define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr) | ||
147 | |||
148 | static int bt878_make_risc(struct bt878 *bt) | ||
149 | { | ||
150 | bt->block_bytes = bt->buf_size >> 4; | ||
151 | bt->block_count = 1 << 4; | ||
152 | bt->line_bytes = bt->block_bytes; | ||
153 | bt->line_count = bt->block_count; | ||
154 | |||
155 | while (bt->line_bytes > 4095) { | ||
156 | bt->line_bytes >>= 1; | ||
157 | bt->line_count <<= 1; | ||
158 | } | ||
159 | |||
160 | if (bt->line_count > 255) { | ||
161 | printk(KERN_ERR "bt878: buffer size error!\n"); | ||
162 | return -EINVAL; | ||
163 | } | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | |||
168 | static void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin) | ||
169 | { | ||
170 | u32 buf_pos = 0; | ||
171 | u32 line; | ||
172 | |||
173 | RISC_FLUSH(); | ||
174 | RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin); | ||
175 | RISC_INSTR(0); | ||
176 | |||
177 | dprintk("bt878: risc len lines %u, bytes per line %u\n", | ||
178 | bt->line_count, bt->line_bytes); | ||
179 | for (line = 0; line < bt->line_count; line++) { | ||
180 | // At the beginning of every block we issue an IRQ with previous (finished) block number set | ||
181 | if (!(buf_pos % bt->block_bytes)) | ||
182 | RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | | ||
183 | RISC_IRQ | | ||
184 | RISC_STATUS(((buf_pos / | ||
185 | bt->block_bytes) + | ||
186 | (bt->block_count - | ||
187 | 1)) % | ||
188 | bt->block_count) | bt-> | ||
189 | line_bytes); | ||
190 | else | ||
191 | RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | | ||
192 | bt->line_bytes); | ||
193 | RISC_INSTR(bt->buf_dma + buf_pos); | ||
194 | buf_pos += bt->line_bytes; | ||
195 | } | ||
196 | |||
197 | RISC_INSTR(RISC_SYNC | op_sync_orin | RISC_SYNC_VRO); | ||
198 | RISC_INSTR(0); | ||
199 | |||
200 | RISC_INSTR(RISC_JUMP); | ||
201 | RISC_INSTR(bt->risc_dma); | ||
202 | |||
203 | btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN); | ||
204 | } | ||
205 | |||
206 | /*****************************/ | ||
207 | /* Start/Stop grabbing funcs */ | ||
208 | /*****************************/ | ||
209 | |||
210 | void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, | ||
211 | u32 irq_err_ignore) | ||
212 | { | ||
213 | u32 int_mask; | ||
214 | |||
215 | dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n", controlreg); | ||
216 | /* complete the writing of the risc dma program now we have | ||
217 | * the card specifics | ||
218 | */ | ||
219 | bt878_risc_program(bt, op_sync_orin); | ||
220 | controlreg &= ~0x1f; | ||
221 | controlreg |= 0x1b; | ||
222 | |||
223 | btwrite(bt->risc_dma, BT878_ARISC_START); | ||
224 | |||
225 | /* original int mask had : | ||
226 | * 6 2 8 4 0 | ||
227 | * 1111 1111 1000 0000 0000 | ||
228 | * SCERR|OCERR|PABORT|RIPERR|FDSR|FTRGT|FBUS|RISCI | ||
229 | * Hacked for DST to: | ||
230 | * SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI | ||
231 | */ | ||
232 | int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT | | ||
233 | BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT | | ||
234 | BT878_AFBUS | BT878_ARISCI; | ||
235 | |||
236 | |||
237 | /* ignore pesky bits */ | ||
238 | int_mask &= ~irq_err_ignore; | ||
239 | |||
240 | btwrite(int_mask, BT878_AINT_MASK); | ||
241 | btwrite(controlreg, BT878_AGPIO_DMA_CTL); | ||
242 | } | ||
243 | |||
244 | void bt878_stop(struct bt878 *bt) | ||
245 | { | ||
246 | u32 stat; | ||
247 | int i = 0; | ||
248 | |||
249 | dprintk("bt878 debug: bt878_stop\n"); | ||
250 | |||
251 | btwrite(0, BT878_AINT_MASK); | ||
252 | btand(~0x13, BT878_AGPIO_DMA_CTL); | ||
253 | |||
254 | do { | ||
255 | stat = btread(BT878_AINT_STAT); | ||
256 | if (!(stat & BT878_ARISC_EN)) | ||
257 | break; | ||
258 | i++; | ||
259 | } while (i < 500); | ||
260 | |||
261 | dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n", | ||
262 | bt->nr, i, stat); | ||
263 | } | ||
264 | |||
265 | EXPORT_SYMBOL(bt878_start); | ||
266 | EXPORT_SYMBOL(bt878_stop); | ||
267 | |||
268 | /*****************************/ | ||
269 | /* Interrupt service routine */ | ||
270 | /*****************************/ | ||
271 | |||
272 | static irqreturn_t bt878_irq(int irq, void *dev_id) | ||
273 | { | ||
274 | u32 stat, astat, mask; | ||
275 | int count; | ||
276 | struct bt878 *bt; | ||
277 | |||
278 | bt = (struct bt878 *) dev_id; | ||
279 | |||
280 | count = 0; | ||
281 | while (1) { | ||
282 | stat = btread(BT878_AINT_STAT); | ||
283 | mask = btread(BT878_AINT_MASK); | ||
284 | if (!(astat = (stat & mask))) | ||
285 | return IRQ_NONE; /* this interrupt is not for me */ | ||
286 | /* dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */ | ||
287 | btwrite(astat, BT878_AINT_STAT); /* try to clear interrupt condition */ | ||
288 | |||
289 | |||
290 | if (astat & (BT878_ASCERR | BT878_AOCERR)) { | ||
291 | if (bt878_verbose) { | ||
292 | printk(KERN_INFO | ||
293 | "bt878(%d): irq%s%s risc_pc=%08x\n", | ||
294 | bt->nr, | ||
295 | (astat & BT878_ASCERR) ? " SCERR" : | ||
296 | "", | ||
297 | (astat & BT878_AOCERR) ? " OCERR" : | ||
298 | "", btread(BT878_ARISC_PC)); | ||
299 | } | ||
300 | } | ||
301 | if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) { | ||
302 | if (bt878_verbose) { | ||
303 | printk(KERN_INFO | ||
304 | "bt878(%d): irq%s%s%s risc_pc=%08x\n", | ||
305 | bt->nr, | ||
306 | (astat & BT878_APABORT) ? " PABORT" : | ||
307 | "", | ||
308 | (astat & BT878_ARIPERR) ? " RIPERR" : | ||
309 | "", | ||
310 | (astat & BT878_APPERR) ? " PPERR" : | ||
311 | "", btread(BT878_ARISC_PC)); | ||
312 | } | ||
313 | } | ||
314 | if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) { | ||
315 | if (bt878_verbose) { | ||
316 | printk(KERN_INFO | ||
317 | "bt878(%d): irq%s%s%s risc_pc=%08x\n", | ||
318 | bt->nr, | ||
319 | (astat & BT878_AFDSR) ? " FDSR" : "", | ||
320 | (astat & BT878_AFTRGT) ? " FTRGT" : | ||
321 | "", | ||
322 | (astat & BT878_AFBUS) ? " FBUS" : "", | ||
323 | btread(BT878_ARISC_PC)); | ||
324 | } | ||
325 | } | ||
326 | if (astat & BT878_ARISCI) { | ||
327 | bt->finished_block = (stat & BT878_ARISCS) >> 28; | ||
328 | tasklet_schedule(&bt->tasklet); | ||
329 | break; | ||
330 | } | ||
331 | count++; | ||
332 | if (count > 20) { | ||
333 | btwrite(0, BT878_AINT_MASK); | ||
334 | printk(KERN_ERR | ||
335 | "bt878(%d): IRQ lockup, cleared int mask\n", | ||
336 | bt->nr); | ||
337 | break; | ||
338 | } | ||
339 | } | ||
340 | return IRQ_HANDLED; | ||
341 | } | ||
342 | |||
343 | int | ||
344 | bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp) | ||
345 | { | ||
346 | int retval; | ||
347 | |||
348 | retval = 0; | ||
349 | if (mutex_lock_interruptible(&bt->gpio_lock)) | ||
350 | return -ERESTARTSYS; | ||
351 | /* special gpio signal */ | ||
352 | switch (cmd) { | ||
353 | case DST_IG_ENABLE: | ||
354 | // dprintk("dvb_bt8xx: dst enable mask 0x%02x enb 0x%02x \n", mp->dstg.enb.mask, mp->dstg.enb.enable); | ||
355 | retval = bttv_gpio_enable(bt->bttv_nr, | ||
356 | mp->enb.mask, | ||
357 | mp->enb.enable); | ||
358 | break; | ||
359 | case DST_IG_WRITE: | ||
360 | // dprintk("dvb_bt8xx: dst write gpio mask 0x%02x out 0x%02x\n", mp->dstg.outp.mask, mp->dstg.outp.highvals); | ||
361 | retval = bttv_write_gpio(bt->bttv_nr, | ||
362 | mp->outp.mask, | ||
363 | mp->outp.highvals); | ||
364 | |||
365 | break; | ||
366 | case DST_IG_READ: | ||
367 | /* read */ | ||
368 | retval = bttv_read_gpio(bt->bttv_nr, &mp->rd.value); | ||
369 | // dprintk("dvb_bt8xx: dst read gpio 0x%02x\n", (unsigned)mp->dstg.rd.value); | ||
370 | break; | ||
371 | case DST_IG_TS: | ||
372 | /* Set packet size */ | ||
373 | bt->TS_Size = mp->psize; | ||
374 | break; | ||
375 | |||
376 | default: | ||
377 | retval = -EINVAL; | ||
378 | break; | ||
379 | } | ||
380 | mutex_unlock(&bt->gpio_lock); | ||
381 | return retval; | ||
382 | } | ||
383 | |||
384 | EXPORT_SYMBOL(bt878_device_control); | ||
385 | |||
386 | #define BROOKTREE_878_DEVICE(vend, dev, name) \ | ||
387 | { \ | ||
388 | .vendor = PCI_VENDOR_ID_BROOKTREE, \ | ||
389 | .device = PCI_DEVICE_ID_BROOKTREE_878, \ | ||
390 | .subvendor = (vend), .subdevice = (dev), \ | ||
391 | .driver_data = (unsigned long) name \ | ||
392 | } | ||
393 | |||
394 | static struct pci_device_id bt878_pci_tbl[] __devinitdata = { | ||
395 | BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"), | ||
396 | BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"), | ||
397 | BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"), | ||
398 | BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"), | ||
399 | BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"), | ||
400 | BROOKTREE_878_DEVICE(0x270f, 0xfc00, | ||
401 | "ChainTech digitop DST-1000 DVB-S"), | ||
402 | BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"), | ||
403 | BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"), | ||
404 | BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"), | ||
405 | BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"), | ||
406 | BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"), | ||
407 | BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"), | ||
408 | { } | ||
409 | }; | ||
410 | |||
411 | MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); | ||
412 | |||
413 | static const char * __devinit card_name(const struct pci_device_id *id) | ||
414 | { | ||
415 | return id->driver_data ? (const char *)id->driver_data : "Unknown"; | ||
416 | } | ||
417 | |||
418 | /***********************/ | ||
419 | /* PCI device handling */ | ||
420 | /***********************/ | ||
421 | |||
422 | static int __devinit bt878_probe(struct pci_dev *dev, | ||
423 | const struct pci_device_id *pci_id) | ||
424 | { | ||
425 | int result = 0; | ||
426 | unsigned char lat; | ||
427 | struct bt878 *bt; | ||
428 | #if defined(__powerpc__) | ||
429 | unsigned int cmd; | ||
430 | #endif | ||
431 | unsigned int cardid; | ||
432 | |||
433 | printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", | ||
434 | bt878_num); | ||
435 | if (bt878_num >= BT878_MAX) { | ||
436 | printk(KERN_ERR "bt878: Too many devices inserted\n"); | ||
437 | result = -ENOMEM; | ||
438 | goto fail0; | ||
439 | } | ||
440 | if (pci_enable_device(dev)) | ||
441 | return -EIO; | ||
442 | |||
443 | cardid = dev->subsystem_device << 16; | ||
444 | cardid |= dev->subsystem_vendor; | ||
445 | |||
446 | printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n", | ||
447 | __func__, cardid, card_name(pci_id)); | ||
448 | |||
449 | bt = &bt878[bt878_num]; | ||
450 | bt->dev = dev; | ||
451 | bt->nr = bt878_num; | ||
452 | bt->shutdown = 0; | ||
453 | |||
454 | bt->id = dev->device; | ||
455 | bt->irq = dev->irq; | ||
456 | bt->bt878_adr = pci_resource_start(dev, 0); | ||
457 | if (!request_mem_region(pci_resource_start(dev, 0), | ||
458 | pci_resource_len(dev, 0), "bt878")) { | ||
459 | result = -EBUSY; | ||
460 | goto fail0; | ||
461 | } | ||
462 | |||
463 | bt->revision = dev->revision; | ||
464 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); | ||
465 | |||
466 | |||
467 | printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ", | ||
468 | bt878_num, bt->id, bt->revision, dev->bus->number, | ||
469 | PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); | ||
470 | printk("irq: %d, latency: %d, memory: 0x%lx\n", | ||
471 | bt->irq, lat, bt->bt878_adr); | ||
472 | |||
473 | |||
474 | #if defined(__powerpc__) | ||
475 | /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ | ||
476 | /* response on cards with no firmware is not enabled by OF */ | ||
477 | pci_read_config_dword(dev, PCI_COMMAND, &cmd); | ||
478 | cmd = (cmd | PCI_COMMAND_MEMORY); | ||
479 | pci_write_config_dword(dev, PCI_COMMAND, cmd); | ||
480 | #endif | ||
481 | |||
482 | #ifdef __sparc__ | ||
483 | bt->bt878_mem = (unsigned char *) bt->bt878_adr; | ||
484 | #else | ||
485 | bt->bt878_mem = ioremap(bt->bt878_adr, 0x1000); | ||
486 | #endif | ||
487 | |||
488 | /* clear interrupt mask */ | ||
489 | btwrite(0, BT848_INT_MASK); | ||
490 | |||
491 | result = request_irq(bt->irq, bt878_irq, | ||
492 | IRQF_SHARED | IRQF_DISABLED, "bt878", | ||
493 | (void *) bt); | ||
494 | if (result == -EINVAL) { | ||
495 | printk(KERN_ERR "bt878(%d): Bad irq number or handler\n", | ||
496 | bt878_num); | ||
497 | goto fail1; | ||
498 | } | ||
499 | if (result == -EBUSY) { | ||
500 | printk(KERN_ERR | ||
501 | "bt878(%d): IRQ %d busy, change your PnP config in BIOS\n", | ||
502 | bt878_num, bt->irq); | ||
503 | goto fail1; | ||
504 | } | ||
505 | if (result < 0) | ||
506 | goto fail1; | ||
507 | |||
508 | pci_set_master(dev); | ||
509 | pci_set_drvdata(dev, bt); | ||
510 | |||
511 | if ((result = bt878_mem_alloc(bt))) { | ||
512 | printk(KERN_ERR "bt878: failed to allocate memory!\n"); | ||
513 | goto fail2; | ||
514 | } | ||
515 | |||
516 | bt878_make_risc(bt); | ||
517 | btwrite(0, BT878_AINT_MASK); | ||
518 | bt878_num++; | ||
519 | |||
520 | return 0; | ||
521 | |||
522 | fail2: | ||
523 | free_irq(bt->irq, bt); | ||
524 | fail1: | ||
525 | release_mem_region(pci_resource_start(bt->dev, 0), | ||
526 | pci_resource_len(bt->dev, 0)); | ||
527 | fail0: | ||
528 | pci_disable_device(dev); | ||
529 | return result; | ||
530 | } | ||
531 | |||
532 | static void __devexit bt878_remove(struct pci_dev *pci_dev) | ||
533 | { | ||
534 | u8 command; | ||
535 | struct bt878 *bt = pci_get_drvdata(pci_dev); | ||
536 | |||
537 | if (bt878_verbose) | ||
538 | printk(KERN_INFO "bt878(%d): unloading\n", bt->nr); | ||
539 | |||
540 | /* turn off all capturing, DMA and IRQs */ | ||
541 | btand(~0x13, BT878_AGPIO_DMA_CTL); | ||
542 | |||
543 | /* first disable interrupts before unmapping the memory! */ | ||
544 | btwrite(0, BT878_AINT_MASK); | ||
545 | btwrite(~0U, BT878_AINT_STAT); | ||
546 | |||
547 | /* disable PCI bus-mastering */ | ||
548 | pci_read_config_byte(bt->dev, PCI_COMMAND, &command); | ||
549 | /* Should this be &=~ ?? */ | ||
550 | command &= ~PCI_COMMAND_MASTER; | ||
551 | pci_write_config_byte(bt->dev, PCI_COMMAND, command); | ||
552 | |||
553 | free_irq(bt->irq, bt); | ||
554 | printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem); | ||
555 | if (bt->bt878_mem) | ||
556 | iounmap(bt->bt878_mem); | ||
557 | |||
558 | release_mem_region(pci_resource_start(bt->dev, 0), | ||
559 | pci_resource_len(bt->dev, 0)); | ||
560 | /* wake up any waiting processes | ||
561 | because shutdown flag is set, no new processes (in this queue) | ||
562 | are expected | ||
563 | */ | ||
564 | bt->shutdown = 1; | ||
565 | bt878_mem_free(bt); | ||
566 | |||
567 | pci_set_drvdata(pci_dev, NULL); | ||
568 | pci_disable_device(pci_dev); | ||
569 | return; | ||
570 | } | ||
571 | |||
572 | static struct pci_driver bt878_pci_driver = { | ||
573 | .name = "bt878", | ||
574 | .id_table = bt878_pci_tbl, | ||
575 | .probe = bt878_probe, | ||
576 | .remove = __devexit_p(bt878_remove), | ||
577 | }; | ||
578 | |||
579 | /*******************************/ | ||
580 | /* Module management functions */ | ||
581 | /*******************************/ | ||
582 | |||
583 | static int __init bt878_init_module(void) | ||
584 | { | ||
585 | bt878_num = 0; | ||
586 | |||
587 | printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n", | ||
588 | (BT878_VERSION_CODE >> 16) & 0xff, | ||
589 | (BT878_VERSION_CODE >> 8) & 0xff, | ||
590 | BT878_VERSION_CODE & 0xff); | ||
591 | |||
592 | return pci_register_driver(&bt878_pci_driver); | ||
593 | } | ||
594 | |||
595 | static void __exit bt878_cleanup_module(void) | ||
596 | { | ||
597 | pci_unregister_driver(&bt878_pci_driver); | ||
598 | } | ||
599 | |||
600 | module_init(bt878_init_module); | ||
601 | module_exit(bt878_cleanup_module); | ||
602 | |||
603 | MODULE_LICENSE("GPL"); | ||
604 | |||
605 | /* | ||
606 | * Local variables: | ||
607 | * c-basic-offset: 8 | ||
608 | * End: | ||
609 | */ | ||
diff --git a/drivers/media/pci/bt8xx/bt878.h b/drivers/media/pci/bt8xx/bt878.h new file mode 100644 index 000000000000..d19b59299d78 --- /dev/null +++ b/drivers/media/pci/bt8xx/bt878.h | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | bt878.h - Bt878 audio module (register offsets) | ||
3 | |||
4 | Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef _BT878_H_ | ||
22 | #define _BT878_H_ | ||
23 | |||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/mutex.h> | ||
29 | |||
30 | #include "bt848.h" | ||
31 | #include "bttv.h" | ||
32 | |||
33 | #define BT878_VERSION_CODE 0x000000 | ||
34 | |||
35 | #define BT878_AINT_STAT 0x100 | ||
36 | #define BT878_ARISCS (0xf<<28) | ||
37 | #define BT878_ARISC_EN (1<<27) | ||
38 | #define BT878_ASCERR (1<<19) | ||
39 | #define BT878_AOCERR (1<<18) | ||
40 | #define BT878_APABORT (1<<17) | ||
41 | #define BT878_ARIPERR (1<<16) | ||
42 | #define BT878_APPERR (1<<15) | ||
43 | #define BT878_AFDSR (1<<14) | ||
44 | #define BT878_AFTRGT (1<<13) | ||
45 | #define BT878_AFBUS (1<<12) | ||
46 | #define BT878_ARISCI (1<<11) | ||
47 | #define BT878_AOFLOW (1<<3) | ||
48 | |||
49 | #define BT878_AINT_MASK 0x104 | ||
50 | |||
51 | #define BT878_AGPIO_DMA_CTL 0x10c | ||
52 | #define BT878_A_GAIN (0xf<<28) | ||
53 | #define BT878_A_G2X (1<<27) | ||
54 | #define BT878_A_PWRDN (1<<26) | ||
55 | #define BT878_A_SEL (3<<24) | ||
56 | #define BT878_DA_SCE (1<<23) | ||
57 | #define BT878_DA_LRI (1<<22) | ||
58 | #define BT878_DA_MLB (1<<21) | ||
59 | #define BT878_DA_LRD (0x1f<<16) | ||
60 | #define BT878_DA_DPM (1<<15) | ||
61 | #define BT878_DA_SBR (1<<14) | ||
62 | #define BT878_DA_ES2 (1<<13) | ||
63 | #define BT878_DA_LMT (1<<12) | ||
64 | #define BT878_DA_SDR (0xf<<8) | ||
65 | #define BT878_DA_IOM (3<<6) | ||
66 | #define BT878_DA_APP (1<<5) | ||
67 | #define BT878_ACAP_EN (1<<4) | ||
68 | #define BT878_PKTP (3<<2) | ||
69 | #define BT878_RISC_EN (1<<1) | ||
70 | #define BT878_FIFO_EN 1 | ||
71 | |||
72 | #define BT878_APACK_LEN 0x110 | ||
73 | #define BT878_AFP_LEN (0xff<<16) | ||
74 | #define BT878_ALP_LEN 0xfff | ||
75 | |||
76 | #define BT878_ARISC_START 0x114 | ||
77 | |||
78 | #define BT878_ARISC_PC 0x120 | ||
79 | |||
80 | /* BT878 FUNCTION 0 REGISTERS */ | ||
81 | #define BT878_GPIO_DMA_CTL 0x10c | ||
82 | |||
83 | /* Interrupt register */ | ||
84 | #define BT878_INT_STAT 0x100 | ||
85 | #define BT878_INT_MASK 0x104 | ||
86 | #define BT878_I2CRACK (1<<25) | ||
87 | #define BT878_I2CDONE (1<<8) | ||
88 | |||
89 | #define BT878_MAX 4 | ||
90 | |||
91 | #define BT878_RISC_SYNC_MASK (1 << 15) | ||
92 | |||
93 | |||
94 | #define BTTV_BOARD_UNKNOWN 0x00 | ||
95 | #define BTTV_BOARD_PINNACLESAT 0x5e | ||
96 | #define BTTV_BOARD_NEBULA_DIGITV 0x68 | ||
97 | #define BTTV_BOARD_PC_HDTV 0x70 | ||
98 | #define BTTV_BOARD_TWINHAN_DST 0x71 | ||
99 | #define BTTV_BOARD_AVDVBT_771 0x7b | ||
100 | #define BTTV_BOARD_AVDVBT_761 0x7c | ||
101 | #define BTTV_BOARD_DVICO_DVBT_LITE 0x80 | ||
102 | #define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 | ||
103 | |||
104 | extern int bt878_num; | ||
105 | |||
106 | struct bt878 { | ||
107 | struct mutex gpio_lock; | ||
108 | unsigned int nr; | ||
109 | unsigned int bttv_nr; | ||
110 | struct i2c_adapter *adapter; | ||
111 | struct pci_dev *dev; | ||
112 | unsigned int id; | ||
113 | unsigned int TS_Size; | ||
114 | unsigned char revision; | ||
115 | unsigned int irq; | ||
116 | unsigned long bt878_adr; | ||
117 | volatile void __iomem *bt878_mem; /* function 1 */ | ||
118 | |||
119 | volatile u32 finished_block; | ||
120 | volatile u32 last_block; | ||
121 | u32 block_count; | ||
122 | u32 block_bytes; | ||
123 | u32 line_bytes; | ||
124 | u32 line_count; | ||
125 | |||
126 | u32 buf_size; | ||
127 | u8 *buf_cpu; | ||
128 | dma_addr_t buf_dma; | ||
129 | |||
130 | u32 risc_size; | ||
131 | __le32 *risc_cpu; | ||
132 | dma_addr_t risc_dma; | ||
133 | u32 risc_pos; | ||
134 | |||
135 | struct tasklet_struct tasklet; | ||
136 | int shutdown; | ||
137 | }; | ||
138 | |||
139 | extern struct bt878 bt878[BT878_MAX]; | ||
140 | |||
141 | void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, | ||
142 | u32 irq_err_ignore); | ||
143 | void bt878_stop(struct bt878 *bt); | ||
144 | |||
145 | #if defined(__powerpc__) /* big-endian */ | ||
146 | static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) | ||
147 | { | ||
148 | st_le32(addr, val); | ||
149 | eieio(); | ||
150 | } | ||
151 | |||
152 | #define bmtwrite(dat,adr) io_st_le32((adr),(dat)) | ||
153 | #define bmtread(adr) ld_le32((adr)) | ||
154 | #else | ||
155 | #define bmtwrite(dat,adr) writel((dat), (adr)) | ||
156 | #define bmtread(adr) readl(adr) | ||
157 | #endif | ||
158 | |||
159 | #endif | ||
diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c new file mode 100644 index 000000000000..430b3eb11815 --- /dev/null +++ b/drivers/media/pci/bt8xx/dst.c | |||
@@ -0,0 +1,1873 @@ | |||
1 | /* | ||
2 | Frontend/Card driver for TwinHan DST Frontend | ||
3 | Copyright (C) 2003 Jamie Honan | ||
4 | Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/vmalloc.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <asm/div64.h> | ||
29 | #include "dvb_frontend.h" | ||
30 | #include "dst_priv.h" | ||
31 | #include "dst_common.h" | ||
32 | |||
33 | static unsigned int verbose = 1; | ||
34 | module_param(verbose, int, 0644); | ||
35 | MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); | ||
36 | |||
37 | static unsigned int dst_addons; | ||
38 | module_param(dst_addons, int, 0644); | ||
39 | MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)"); | ||
40 | |||
41 | static unsigned int dst_algo; | ||
42 | module_param(dst_algo, int, 0644); | ||
43 | MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)"); | ||
44 | |||
45 | #define HAS_LOCK 1 | ||
46 | #define ATTEMPT_TUNE 2 | ||
47 | #define HAS_POWER 4 | ||
48 | |||
49 | #define DST_ERROR 0 | ||
50 | #define DST_NOTICE 1 | ||
51 | #define DST_INFO 2 | ||
52 | #define DST_DEBUG 3 | ||
53 | |||
54 | #define dprintk(x, y, z, format, arg...) do { \ | ||
55 | if (z) { \ | ||
56 | if ((x > DST_ERROR) && (x > y)) \ | ||
57 | printk(KERN_ERR "dst(%d) %s: " format "\n", \ | ||
58 | state->bt->nr, __func__ , ##arg); \ | ||
59 | else if ((x > DST_NOTICE) && (x > y)) \ | ||
60 | printk(KERN_NOTICE "dst(%d) %s: " format "\n", \ | ||
61 | state->bt->nr, __func__ , ##arg); \ | ||
62 | else if ((x > DST_INFO) && (x > y)) \ | ||
63 | printk(KERN_INFO "dst(%d) %s: " format "\n", \ | ||
64 | state->bt->nr, __func__ , ##arg); \ | ||
65 | else if ((x > DST_DEBUG) && (x > y)) \ | ||
66 | printk(KERN_DEBUG "dst(%d) %s: " format "\n", \ | ||
67 | state->bt->nr, __func__ , ##arg); \ | ||
68 | } else { \ | ||
69 | if (x > y) \ | ||
70 | printk(format, ##arg); \ | ||
71 | } \ | ||
72 | } while(0) | ||
73 | |||
74 | static int dst_command(struct dst_state *state, u8 *data, u8 len); | ||
75 | |||
76 | static void dst_packsize(struct dst_state *state, int psize) | ||
77 | { | ||
78 | union dst_gpio_packet bits; | ||
79 | |||
80 | bits.psize = psize; | ||
81 | bt878_device_control(state->bt, DST_IG_TS, &bits); | ||
82 | } | ||
83 | |||
84 | static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, | ||
85 | u32 outhigh, int delay) | ||
86 | { | ||
87 | union dst_gpio_packet enb; | ||
88 | union dst_gpio_packet bits; | ||
89 | int err; | ||
90 | |||
91 | enb.enb.mask = mask; | ||
92 | enb.enb.enable = enbb; | ||
93 | |||
94 | dprintk(verbose, DST_INFO, 1, "mask=[%04x], enbb=[%04x], outhigh=[%04x]", mask, enbb, outhigh); | ||
95 | if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { | ||
96 | dprintk(verbose, DST_INFO, 1, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)", err, mask, enbb); | ||
97 | return -EREMOTEIO; | ||
98 | } | ||
99 | udelay(1000); | ||
100 | /* because complete disabling means no output, no need to do output packet */ | ||
101 | if (enbb == 0) | ||
102 | return 0; | ||
103 | if (delay) | ||
104 | msleep(10); | ||
105 | bits.outp.mask = enbb; | ||
106 | bits.outp.highvals = outhigh; | ||
107 | if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { | ||
108 | dprintk(verbose, DST_INFO, 1, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)", err, enbb, outhigh); | ||
109 | return -EREMOTEIO; | ||
110 | } | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int dst_gpio_inb(struct dst_state *state, u8 *result) | ||
116 | { | ||
117 | union dst_gpio_packet rd_packet; | ||
118 | int err; | ||
119 | |||
120 | *result = 0; | ||
121 | if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { | ||
122 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err); | ||
123 | return -EREMOTEIO; | ||
124 | } | ||
125 | *result = (u8) rd_packet.rd.value; | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | int rdc_reset_state(struct dst_state *state) | ||
131 | { | ||
132 | dprintk(verbose, DST_INFO, 1, "Resetting state machine"); | ||
133 | if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) { | ||
134 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); | ||
135 | return -1; | ||
136 | } | ||
137 | msleep(10); | ||
138 | if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) { | ||
139 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); | ||
140 | msleep(10); | ||
141 | return -1; | ||
142 | } | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | EXPORT_SYMBOL(rdc_reset_state); | ||
147 | |||
148 | static int rdc_8820_reset(struct dst_state *state) | ||
149 | { | ||
150 | dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); | ||
151 | if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { | ||
152 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); | ||
153 | return -1; | ||
154 | } | ||
155 | udelay(1000); | ||
156 | if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { | ||
157 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); | ||
158 | return -1; | ||
159 | } | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static int dst_pio_enable(struct dst_state *state) | ||
165 | { | ||
166 | if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { | ||
167 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); | ||
168 | return -1; | ||
169 | } | ||
170 | udelay(1000); | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | int dst_pio_disable(struct dst_state *state) | ||
176 | { | ||
177 | if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) { | ||
178 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); | ||
179 | return -1; | ||
180 | } | ||
181 | if (state->type_flags & DST_TYPE_HAS_FW_1) | ||
182 | udelay(1000); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | EXPORT_SYMBOL(dst_pio_disable); | ||
187 | |||
188 | int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) | ||
189 | { | ||
190 | u8 reply; | ||
191 | int i; | ||
192 | |||
193 | for (i = 0; i < 200; i++) { | ||
194 | if (dst_gpio_inb(state, &reply) < 0) { | ||
195 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb ERROR !"); | ||
196 | return -1; | ||
197 | } | ||
198 | if ((reply & RDC_8820_PIO_0_ENABLE) == 0) { | ||
199 | dprintk(verbose, DST_INFO, 1, "dst wait ready after %d", i); | ||
200 | return 1; | ||
201 | } | ||
202 | msleep(10); | ||
203 | } | ||
204 | dprintk(verbose, DST_NOTICE, 1, "dst wait NOT ready after %d", i); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | EXPORT_SYMBOL(dst_wait_dst_ready); | ||
209 | |||
210 | int dst_error_recovery(struct dst_state *state) | ||
211 | { | ||
212 | dprintk(verbose, DST_NOTICE, 1, "Trying to return from previous errors."); | ||
213 | dst_pio_disable(state); | ||
214 | msleep(10); | ||
215 | dst_pio_enable(state); | ||
216 | msleep(10); | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | EXPORT_SYMBOL(dst_error_recovery); | ||
221 | |||
222 | int dst_error_bailout(struct dst_state *state) | ||
223 | { | ||
224 | dprintk(verbose, DST_INFO, 1, "Trying to bailout from previous error."); | ||
225 | rdc_8820_reset(state); | ||
226 | dst_pio_disable(state); | ||
227 | msleep(10); | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | EXPORT_SYMBOL(dst_error_bailout); | ||
232 | |||
233 | int dst_comm_init(struct dst_state *state) | ||
234 | { | ||
235 | dprintk(verbose, DST_INFO, 1, "Initializing DST."); | ||
236 | if ((dst_pio_enable(state)) < 0) { | ||
237 | dprintk(verbose, DST_ERROR, 1, "PIO Enable Failed"); | ||
238 | return -1; | ||
239 | } | ||
240 | if ((rdc_reset_state(state)) < 0) { | ||
241 | dprintk(verbose, DST_ERROR, 1, "RDC 8820 State RESET Failed."); | ||
242 | return -1; | ||
243 | } | ||
244 | if (state->type_flags & DST_TYPE_HAS_FW_1) | ||
245 | msleep(100); | ||
246 | else | ||
247 | msleep(5); | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | EXPORT_SYMBOL(dst_comm_init); | ||
252 | |||
253 | int write_dst(struct dst_state *state, u8 *data, u8 len) | ||
254 | { | ||
255 | struct i2c_msg msg = { | ||
256 | .addr = state->config->demod_address, | ||
257 | .flags = 0, | ||
258 | .buf = data, | ||
259 | .len = len | ||
260 | }; | ||
261 | |||
262 | int err; | ||
263 | u8 cnt, i; | ||
264 | |||
265 | dprintk(verbose, DST_NOTICE, 0, "writing [ "); | ||
266 | for (i = 0; i < len; i++) | ||
267 | dprintk(verbose, DST_NOTICE, 0, "%02x ", data[i]); | ||
268 | dprintk(verbose, DST_NOTICE, 0, "]\n"); | ||
269 | |||
270 | for (cnt = 0; cnt < 2; cnt++) { | ||
271 | if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { | ||
272 | dprintk(verbose, DST_INFO, 1, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, data[0]); | ||
273 | dst_error_recovery(state); | ||
274 | continue; | ||
275 | } else | ||
276 | break; | ||
277 | } | ||
278 | if (cnt >= 2) { | ||
279 | dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); | ||
280 | dst_error_bailout(state); | ||
281 | |||
282 | return -1; | ||
283 | } | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | EXPORT_SYMBOL(write_dst); | ||
288 | |||
289 | int read_dst(struct dst_state *state, u8 *ret, u8 len) | ||
290 | { | ||
291 | struct i2c_msg msg = { | ||
292 | .addr = state->config->demod_address, | ||
293 | .flags = I2C_M_RD, | ||
294 | .buf = ret, | ||
295 | .len = len | ||
296 | }; | ||
297 | |||
298 | int err; | ||
299 | int cnt; | ||
300 | |||
301 | for (cnt = 0; cnt < 2; cnt++) { | ||
302 | if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { | ||
303 | dprintk(verbose, DST_INFO, 1, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, ret[0]); | ||
304 | dst_error_recovery(state); | ||
305 | continue; | ||
306 | } else | ||
307 | break; | ||
308 | } | ||
309 | if (cnt >= 2) { | ||
310 | dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); | ||
311 | dst_error_bailout(state); | ||
312 | |||
313 | return -1; | ||
314 | } | ||
315 | dprintk(verbose, DST_DEBUG, 1, "reply is 0x%x", ret[0]); | ||
316 | for (err = 1; err < len; err++) | ||
317 | dprintk(verbose, DST_DEBUG, 0, " 0x%x", ret[err]); | ||
318 | if (err > 1) | ||
319 | dprintk(verbose, DST_DEBUG, 0, "\n"); | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | EXPORT_SYMBOL(read_dst); | ||
324 | |||
325 | static int dst_set_polarization(struct dst_state *state) | ||
326 | { | ||
327 | switch (state->voltage) { | ||
328 | case SEC_VOLTAGE_13: /* Vertical */ | ||
329 | dprintk(verbose, DST_INFO, 1, "Polarization=[Vertical]"); | ||
330 | state->tx_tuna[8] &= ~0x40; | ||
331 | break; | ||
332 | case SEC_VOLTAGE_18: /* Horizontal */ | ||
333 | dprintk(verbose, DST_INFO, 1, "Polarization=[Horizontal]"); | ||
334 | state->tx_tuna[8] |= 0x40; | ||
335 | break; | ||
336 | case SEC_VOLTAGE_OFF: | ||
337 | break; | ||
338 | } | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int dst_set_freq(struct dst_state *state, u32 freq) | ||
344 | { | ||
345 | state->frequency = freq; | ||
346 | dprintk(verbose, DST_INFO, 1, "set Frequency %u", freq); | ||
347 | |||
348 | if (state->dst_type == DST_TYPE_IS_SAT) { | ||
349 | freq = freq / 1000; | ||
350 | if (freq < 950 || freq > 2150) | ||
351 | return -EINVAL; | ||
352 | state->tx_tuna[2] = (freq >> 8); | ||
353 | state->tx_tuna[3] = (u8) freq; | ||
354 | state->tx_tuna[4] = 0x01; | ||
355 | state->tx_tuna[8] &= ~0x04; | ||
356 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { | ||
357 | if (freq < 1531) | ||
358 | state->tx_tuna[8] |= 0x04; | ||
359 | } | ||
360 | } else if (state->dst_type == DST_TYPE_IS_TERR) { | ||
361 | freq = freq / 1000; | ||
362 | if (freq < 137000 || freq > 858000) | ||
363 | return -EINVAL; | ||
364 | state->tx_tuna[2] = (freq >> 16) & 0xff; | ||
365 | state->tx_tuna[3] = (freq >> 8) & 0xff; | ||
366 | state->tx_tuna[4] = (u8) freq; | ||
367 | } else if (state->dst_type == DST_TYPE_IS_CABLE) { | ||
368 | freq = freq / 1000; | ||
369 | state->tx_tuna[2] = (freq >> 16) & 0xff; | ||
370 | state->tx_tuna[3] = (freq >> 8) & 0xff; | ||
371 | state->tx_tuna[4] = (u8) freq; | ||
372 | } else if (state->dst_type == DST_TYPE_IS_ATSC) { | ||
373 | freq = freq / 1000; | ||
374 | if (freq < 51000 || freq > 858000) | ||
375 | return -EINVAL; | ||
376 | state->tx_tuna[2] = (freq >> 16) & 0xff; | ||
377 | state->tx_tuna[3] = (freq >> 8) & 0xff; | ||
378 | state->tx_tuna[4] = (u8) freq; | ||
379 | state->tx_tuna[5] = 0x00; /* ATSC */ | ||
380 | state->tx_tuna[6] = 0x00; | ||
381 | if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG) | ||
382 | state->tx_tuna[7] = 0x00; /* Digital */ | ||
383 | } else | ||
384 | return -EINVAL; | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth) | ||
390 | { | ||
391 | state->bandwidth = bandwidth; | ||
392 | |||
393 | if (state->dst_type != DST_TYPE_IS_TERR) | ||
394 | return -EOPNOTSUPP; | ||
395 | |||
396 | switch (bandwidth) { | ||
397 | case 6000000: | ||
398 | if (state->dst_hw_cap & DST_TYPE_HAS_CA) | ||
399 | state->tx_tuna[7] = 0x06; | ||
400 | else { | ||
401 | state->tx_tuna[6] = 0x06; | ||
402 | state->tx_tuna[7] = 0x00; | ||
403 | } | ||
404 | break; | ||
405 | case 7000000: | ||
406 | if (state->dst_hw_cap & DST_TYPE_HAS_CA) | ||
407 | state->tx_tuna[7] = 0x07; | ||
408 | else { | ||
409 | state->tx_tuna[6] = 0x07; | ||
410 | state->tx_tuna[7] = 0x00; | ||
411 | } | ||
412 | break; | ||
413 | case 8000000: | ||
414 | if (state->dst_hw_cap & DST_TYPE_HAS_CA) | ||
415 | state->tx_tuna[7] = 0x08; | ||
416 | else { | ||
417 | state->tx_tuna[6] = 0x08; | ||
418 | state->tx_tuna[7] = 0x00; | ||
419 | } | ||
420 | break; | ||
421 | default: | ||
422 | return -EINVAL; | ||
423 | } | ||
424 | |||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion) | ||
429 | { | ||
430 | state->inversion = inversion; | ||
431 | switch (inversion) { | ||
432 | case INVERSION_OFF: /* Inversion = Normal */ | ||
433 | state->tx_tuna[8] &= ~0x80; | ||
434 | break; | ||
435 | case INVERSION_ON: | ||
436 | state->tx_tuna[8] |= 0x80; | ||
437 | break; | ||
438 | default: | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec) | ||
446 | { | ||
447 | state->fec = fec; | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static fe_code_rate_t dst_get_fec(struct dst_state *state) | ||
452 | { | ||
453 | return state->fec; | ||
454 | } | ||
455 | |||
456 | static int dst_set_symbolrate(struct dst_state *state, u32 srate) | ||
457 | { | ||
458 | u32 symcalc; | ||
459 | u64 sval; | ||
460 | |||
461 | state->symbol_rate = srate; | ||
462 | if (state->dst_type == DST_TYPE_IS_TERR) { | ||
463 | return -EOPNOTSUPP; | ||
464 | } | ||
465 | dprintk(verbose, DST_INFO, 1, "set symrate %u", srate); | ||
466 | srate /= 1000; | ||
467 | if (state->dst_type == DST_TYPE_IS_SAT) { | ||
468 | if (state->type_flags & DST_TYPE_HAS_SYMDIV) { | ||
469 | sval = srate; | ||
470 | sval <<= 20; | ||
471 | do_div(sval, 88000); | ||
472 | symcalc = (u32) sval; | ||
473 | dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc); | ||
474 | state->tx_tuna[5] = (u8) (symcalc >> 12); | ||
475 | state->tx_tuna[6] = (u8) (symcalc >> 4); | ||
476 | state->tx_tuna[7] = (u8) (symcalc << 4); | ||
477 | } else { | ||
478 | state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f; | ||
479 | state->tx_tuna[6] = (u8) (srate >> 8); | ||
480 | state->tx_tuna[7] = (u8) srate; | ||
481 | } | ||
482 | state->tx_tuna[8] &= ~0x20; | ||
483 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { | ||
484 | if (srate > 8000) | ||
485 | state->tx_tuna[8] |= 0x20; | ||
486 | } | ||
487 | } else if (state->dst_type == DST_TYPE_IS_CABLE) { | ||
488 | dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name); | ||
489 | if (!strncmp(state->fw_name, "DCTNEW", 6)) { | ||
490 | state->tx_tuna[5] = (u8) (srate >> 8); | ||
491 | state->tx_tuna[6] = (u8) srate; | ||
492 | state->tx_tuna[7] = 0x00; | ||
493 | } else if (!strncmp(state->fw_name, "DCT-CI", 6)) { | ||
494 | state->tx_tuna[5] = 0x00; | ||
495 | state->tx_tuna[6] = (u8) (srate >> 8); | ||
496 | state->tx_tuna[7] = (u8) srate; | ||
497 | } | ||
498 | } | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) | ||
503 | { | ||
504 | if (state->dst_type != DST_TYPE_IS_CABLE) | ||
505 | return -EOPNOTSUPP; | ||
506 | |||
507 | state->modulation = modulation; | ||
508 | switch (modulation) { | ||
509 | case QAM_16: | ||
510 | state->tx_tuna[8] = 0x10; | ||
511 | break; | ||
512 | case QAM_32: | ||
513 | state->tx_tuna[8] = 0x20; | ||
514 | break; | ||
515 | case QAM_64: | ||
516 | state->tx_tuna[8] = 0x40; | ||
517 | break; | ||
518 | case QAM_128: | ||
519 | state->tx_tuna[8] = 0x80; | ||
520 | break; | ||
521 | case QAM_256: | ||
522 | if (!strncmp(state->fw_name, "DCTNEW", 6)) | ||
523 | state->tx_tuna[8] = 0xff; | ||
524 | else if (!strncmp(state->fw_name, "DCT-CI", 6)) | ||
525 | state->tx_tuna[8] = 0x00; | ||
526 | break; | ||
527 | case QPSK: | ||
528 | case QAM_AUTO: | ||
529 | case VSB_8: | ||
530 | case VSB_16: | ||
531 | default: | ||
532 | return -EINVAL; | ||
533 | |||
534 | } | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | static fe_modulation_t dst_get_modulation(struct dst_state *state) | ||
540 | { | ||
541 | return state->modulation; | ||
542 | } | ||
543 | |||
544 | |||
545 | u8 dst_check_sum(u8 *buf, u32 len) | ||
546 | { | ||
547 | u32 i; | ||
548 | u8 val = 0; | ||
549 | if (!len) | ||
550 | return 0; | ||
551 | for (i = 0; i < len; i++) { | ||
552 | val += buf[i]; | ||
553 | } | ||
554 | return ((~val) + 1); | ||
555 | } | ||
556 | EXPORT_SYMBOL(dst_check_sum); | ||
557 | |||
558 | static void dst_type_flags_print(struct dst_state *state) | ||
559 | { | ||
560 | u32 type_flags = state->type_flags; | ||
561 | |||
562 | dprintk(verbose, DST_ERROR, 0, "DST type flags :"); | ||
563 | if (type_flags & DST_TYPE_HAS_TS188) | ||
564 | dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188); | ||
565 | if (type_flags & DST_TYPE_HAS_NEWTUNE_2) | ||
566 | dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2); | ||
567 | if (type_flags & DST_TYPE_HAS_TS204) | ||
568 | dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204); | ||
569 | if (type_flags & DST_TYPE_HAS_VLF) | ||
570 | dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF); | ||
571 | if (type_flags & DST_TYPE_HAS_SYMDIV) | ||
572 | dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV); | ||
573 | if (type_flags & DST_TYPE_HAS_FW_1) | ||
574 | dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); | ||
575 | if (type_flags & DST_TYPE_HAS_FW_2) | ||
576 | dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); | ||
577 | if (type_flags & DST_TYPE_HAS_FW_3) | ||
578 | dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); | ||
579 | dprintk(verbose, DST_ERROR, 0, "\n"); | ||
580 | } | ||
581 | |||
582 | |||
583 | static int dst_type_print(struct dst_state *state, u8 type) | ||
584 | { | ||
585 | char *otype; | ||
586 | switch (type) { | ||
587 | case DST_TYPE_IS_SAT: | ||
588 | otype = "satellite"; | ||
589 | break; | ||
590 | |||
591 | case DST_TYPE_IS_TERR: | ||
592 | otype = "terrestrial"; | ||
593 | break; | ||
594 | |||
595 | case DST_TYPE_IS_CABLE: | ||
596 | otype = "cable"; | ||
597 | break; | ||
598 | |||
599 | case DST_TYPE_IS_ATSC: | ||
600 | otype = "atsc"; | ||
601 | break; | ||
602 | |||
603 | default: | ||
604 | dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type); | ||
605 | return -EINVAL; | ||
606 | } | ||
607 | dprintk(verbose, DST_INFO, 1, "DST type: %s", otype); | ||
608 | |||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static struct tuner_types tuner_list[] = { | ||
613 | { | ||
614 | .tuner_type = TUNER_TYPE_L64724, | ||
615 | .tuner_name = "L 64724", | ||
616 | .board_name = "UNKNOWN", | ||
617 | .fw_name = "UNKNOWN" | ||
618 | }, | ||
619 | |||
620 | { | ||
621 | .tuner_type = TUNER_TYPE_STV0299, | ||
622 | .tuner_name = "STV 0299", | ||
623 | .board_name = "VP1020", | ||
624 | .fw_name = "DST-MOT" | ||
625 | }, | ||
626 | |||
627 | { | ||
628 | .tuner_type = TUNER_TYPE_STV0299, | ||
629 | .tuner_name = "STV 0299", | ||
630 | .board_name = "VP1020", | ||
631 | .fw_name = "DST-03T" | ||
632 | }, | ||
633 | |||
634 | { | ||
635 | .tuner_type = TUNER_TYPE_MB86A15, | ||
636 | .tuner_name = "MB 86A15", | ||
637 | .board_name = "VP1022", | ||
638 | .fw_name = "DST-03T" | ||
639 | }, | ||
640 | |||
641 | { | ||
642 | .tuner_type = TUNER_TYPE_MB86A15, | ||
643 | .tuner_name = "MB 86A15", | ||
644 | .board_name = "VP1025", | ||
645 | .fw_name = "DST-03T" | ||
646 | }, | ||
647 | |||
648 | { | ||
649 | .tuner_type = TUNER_TYPE_STV0299, | ||
650 | .tuner_name = "STV 0299", | ||
651 | .board_name = "VP1030", | ||
652 | .fw_name = "DST-CI" | ||
653 | }, | ||
654 | |||
655 | { | ||
656 | .tuner_type = TUNER_TYPE_STV0299, | ||
657 | .tuner_name = "STV 0299", | ||
658 | .board_name = "VP1030", | ||
659 | .fw_name = "DSTMCI" | ||
660 | }, | ||
661 | |||
662 | { | ||
663 | .tuner_type = TUNER_TYPE_UNKNOWN, | ||
664 | .tuner_name = "UNKNOWN", | ||
665 | .board_name = "VP2021", | ||
666 | .fw_name = "DCTNEW" | ||
667 | }, | ||
668 | |||
669 | { | ||
670 | .tuner_type = TUNER_TYPE_UNKNOWN, | ||
671 | .tuner_name = "UNKNOWN", | ||
672 | .board_name = "VP2030", | ||
673 | .fw_name = "DCT-CI" | ||
674 | }, | ||
675 | |||
676 | { | ||
677 | .tuner_type = TUNER_TYPE_UNKNOWN, | ||
678 | .tuner_name = "UNKNOWN", | ||
679 | .board_name = "VP2031", | ||
680 | .fw_name = "DCT-CI" | ||
681 | }, | ||
682 | |||
683 | { | ||
684 | .tuner_type = TUNER_TYPE_UNKNOWN, | ||
685 | .tuner_name = "UNKNOWN", | ||
686 | .board_name = "VP2040", | ||
687 | .fw_name = "DCT-CI" | ||
688 | }, | ||
689 | |||
690 | { | ||
691 | .tuner_type = TUNER_TYPE_UNKNOWN, | ||
692 | .tuner_name = "UNKNOWN", | ||
693 | .board_name = "VP3020", | ||
694 | .fw_name = "DTTFTA" | ||
695 | }, | ||
696 | |||
697 | { | ||
698 | .tuner_type = TUNER_TYPE_UNKNOWN, | ||
699 | .tuner_name = "UNKNOWN", | ||
700 | .board_name = "VP3021", | ||
701 | .fw_name = "DTTFTA" | ||
702 | }, | ||
703 | |||
704 | { | ||
705 | .tuner_type = TUNER_TYPE_TDA10046, | ||
706 | .tuner_name = "TDA10046", | ||
707 | .board_name = "VP3040", | ||
708 | .fw_name = "DTT-CI" | ||
709 | }, | ||
710 | |||
711 | { | ||
712 | .tuner_type = TUNER_TYPE_UNKNOWN, | ||
713 | .tuner_name = "UNKNOWN", | ||
714 | .board_name = "VP3051", | ||
715 | .fw_name = "DTTNXT" | ||
716 | }, | ||
717 | |||
718 | { | ||
719 | .tuner_type = TUNER_TYPE_NXT200x, | ||
720 | .tuner_name = "NXT200x", | ||
721 | .board_name = "VP3220", | ||
722 | .fw_name = "ATSCDI" | ||
723 | }, | ||
724 | |||
725 | { | ||
726 | .tuner_type = TUNER_TYPE_NXT200x, | ||
727 | .tuner_name = "NXT200x", | ||
728 | .board_name = "VP3250", | ||
729 | .fw_name = "ATSCAD" | ||
730 | }, | ||
731 | }; | ||
732 | |||
733 | /* | ||
734 | Known cards list | ||
735 | Satellite | ||
736 | ------------------- | ||
737 | 200103A | ||
738 | VP-1020 DST-MOT LG(old), TS=188 | ||
739 | |||
740 | VP-1020 DST-03T LG(new), TS=204 | ||
741 | VP-1022 DST-03T LG(new), TS=204 | ||
742 | VP-1025 DST-03T LG(new), TS=204 | ||
743 | |||
744 | VP-1030 DSTMCI, LG(new), TS=188 | ||
745 | VP-1032 DSTMCI, LG(new), TS=188 | ||
746 | |||
747 | Cable | ||
748 | ------------------- | ||
749 | VP-2030 DCT-CI, Samsung, TS=204 | ||
750 | VP-2021 DCT-CI, Unknown, TS=204 | ||
751 | VP-2031 DCT-CI, Philips, TS=188 | ||
752 | VP-2040 DCT-CI, Philips, TS=188, with CA daughter board | ||
753 | VP-2040 DCT-CI, Philips, TS=204, without CA daughter board | ||
754 | |||
755 | Terrestrial | ||
756 | ------------------- | ||
757 | VP-3050 DTTNXT TS=188 | ||
758 | VP-3040 DTT-CI, Philips, TS=188 | ||
759 | VP-3040 DTT-CI, Philips, TS=204 | ||
760 | |||
761 | ATSC | ||
762 | ------------------- | ||
763 | VP-3220 ATSCDI, TS=188 | ||
764 | VP-3250 ATSCAD, TS=188 | ||
765 | |||
766 | */ | ||
767 | |||
768 | static struct dst_types dst_tlist[] = { | ||
769 | { | ||
770 | .device_id = "200103A", | ||
771 | .offset = 0, | ||
772 | .dst_type = DST_TYPE_IS_SAT, | ||
773 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS, | ||
774 | .dst_feature = 0, | ||
775 | .tuner_type = 0 | ||
776 | }, /* obsolete */ | ||
777 | |||
778 | { | ||
779 | .device_id = "DST-020", | ||
780 | .offset = 0, | ||
781 | .dst_type = DST_TYPE_IS_SAT, | ||
782 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, | ||
783 | .dst_feature = 0, | ||
784 | .tuner_type = 0 | ||
785 | }, /* obsolete */ | ||
786 | |||
787 | { | ||
788 | .device_id = "DST-030", | ||
789 | .offset = 0, | ||
790 | .dst_type = DST_TYPE_IS_SAT, | ||
791 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, | ||
792 | .dst_feature = 0, | ||
793 | .tuner_type = 0 | ||
794 | }, /* obsolete */ | ||
795 | |||
796 | { | ||
797 | .device_id = "DST-03T", | ||
798 | .offset = 0, | ||
799 | .dst_type = DST_TYPE_IS_SAT, | ||
800 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, | ||
801 | .dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5 | ||
802 | | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO, | ||
803 | .tuner_type = TUNER_TYPE_MULTI | ||
804 | }, | ||
805 | |||
806 | { | ||
807 | .device_id = "DST-MOT", | ||
808 | .offset = 0, | ||
809 | .dst_type = DST_TYPE_IS_SAT, | ||
810 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, | ||
811 | .dst_feature = 0, | ||
812 | .tuner_type = 0 | ||
813 | }, /* obsolete */ | ||
814 | |||
815 | { | ||
816 | .device_id = "DST-CI", | ||
817 | .offset = 1, | ||
818 | .dst_type = DST_TYPE_IS_SAT, | ||
819 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1, | ||
820 | .dst_feature = DST_TYPE_HAS_CA, | ||
821 | .tuner_type = 0 | ||
822 | }, /* An OEM board */ | ||
823 | |||
824 | { | ||
825 | .device_id = "DSTMCI", | ||
826 | .offset = 1, | ||
827 | .dst_type = DST_TYPE_IS_SAT, | ||
828 | .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF, | ||
829 | .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | ||
830 | | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC, | ||
831 | .tuner_type = TUNER_TYPE_MULTI | ||
832 | }, | ||
833 | |||
834 | { | ||
835 | .device_id = "DSTFCI", | ||
836 | .offset = 1, | ||
837 | .dst_type = DST_TYPE_IS_SAT, | ||
838 | .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, | ||
839 | .dst_feature = 0, | ||
840 | .tuner_type = 0 | ||
841 | }, /* unknown to vendor */ | ||
842 | |||
843 | { | ||
844 | .device_id = "DCT-CI", | ||
845 | .offset = 1, | ||
846 | .dst_type = DST_TYPE_IS_CABLE, | ||
847 | .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF, | ||
848 | .dst_feature = DST_TYPE_HAS_CA, | ||
849 | .tuner_type = 0 | ||
850 | }, | ||
851 | |||
852 | { | ||
853 | .device_id = "DCTNEW", | ||
854 | .offset = 1, | ||
855 | .dst_type = DST_TYPE_IS_CABLE, | ||
856 | .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE, | ||
857 | .dst_feature = 0, | ||
858 | .tuner_type = 0 | ||
859 | }, | ||
860 | |||
861 | { | ||
862 | .device_id = "DTT-CI", | ||
863 | .offset = 1, | ||
864 | .dst_type = DST_TYPE_IS_TERR, | ||
865 | .type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF, | ||
866 | .dst_feature = DST_TYPE_HAS_CA, | ||
867 | .tuner_type = 0 | ||
868 | }, | ||
869 | |||
870 | { | ||
871 | .device_id = "DTTDIG", | ||
872 | .offset = 1, | ||
873 | .dst_type = DST_TYPE_IS_TERR, | ||
874 | .type_flags = DST_TYPE_HAS_FW_2, | ||
875 | .dst_feature = 0, | ||
876 | .tuner_type = 0 | ||
877 | }, | ||
878 | |||
879 | { | ||
880 | .device_id = "DTTNXT", | ||
881 | .offset = 1, | ||
882 | .dst_type = DST_TYPE_IS_TERR, | ||
883 | .type_flags = DST_TYPE_HAS_FW_2, | ||
884 | .dst_feature = DST_TYPE_HAS_ANALOG, | ||
885 | .tuner_type = 0 | ||
886 | }, | ||
887 | |||
888 | { | ||
889 | .device_id = "ATSCDI", | ||
890 | .offset = 1, | ||
891 | .dst_type = DST_TYPE_IS_ATSC, | ||
892 | .type_flags = DST_TYPE_HAS_FW_2, | ||
893 | .dst_feature = 0, | ||
894 | .tuner_type = 0 | ||
895 | }, | ||
896 | |||
897 | { | ||
898 | .device_id = "ATSCAD", | ||
899 | .offset = 1, | ||
900 | .dst_type = DST_TYPE_IS_ATSC, | ||
901 | .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, | ||
902 | .dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG, | ||
903 | .tuner_type = 0 | ||
904 | }, | ||
905 | |||
906 | { } | ||
907 | |||
908 | }; | ||
909 | |||
910 | static int dst_get_mac(struct dst_state *state) | ||
911 | { | ||
912 | u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
913 | get_mac[7] = dst_check_sum(get_mac, 7); | ||
914 | if (dst_command(state, get_mac, 8) < 0) { | ||
915 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | ||
916 | return -1; | ||
917 | } | ||
918 | memset(&state->mac_address, '\0', 8); | ||
919 | memcpy(&state->mac_address, &state->rxbuffer, 6); | ||
920 | dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address); | ||
921 | |||
922 | return 0; | ||
923 | } | ||
924 | |||
925 | static int dst_fw_ver(struct dst_state *state) | ||
926 | { | ||
927 | u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
928 | get_ver[7] = dst_check_sum(get_ver, 7); | ||
929 | if (dst_command(state, get_ver, 8) < 0) { | ||
930 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | ||
931 | return -1; | ||
932 | } | ||
933 | memcpy(&state->fw_version, &state->rxbuffer, 8); | ||
934 | dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x", | ||
935 | state->fw_version[0] >> 4, state->fw_version[0] & 0x0f, | ||
936 | state->fw_version[1], | ||
937 | state->fw_version[5], state->fw_version[6], | ||
938 | state->fw_version[4], state->fw_version[3], state->fw_version[2]); | ||
939 | |||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | static int dst_card_type(struct dst_state *state) | ||
944 | { | ||
945 | int j; | ||
946 | struct tuner_types *p_tuner_list = NULL; | ||
947 | |||
948 | u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
949 | get_type[7] = dst_check_sum(get_type, 7); | ||
950 | if (dst_command(state, get_type, 8) < 0) { | ||
951 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | ||
952 | return -1; | ||
953 | } | ||
954 | memset(&state->card_info, '\0', 8); | ||
955 | memcpy(&state->card_info, &state->rxbuffer, 7); | ||
956 | dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]); | ||
957 | |||
958 | for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { | ||
959 | if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) { | ||
960 | state->tuner_type = p_tuner_list->tuner_type; | ||
961 | dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]", | ||
962 | p_tuner_list->tuner_name, p_tuner_list->tuner_type); | ||
963 | } | ||
964 | } | ||
965 | |||
966 | return 0; | ||
967 | } | ||
968 | |||
969 | static int dst_get_vendor(struct dst_state *state) | ||
970 | { | ||
971 | u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
972 | get_vendor[7] = dst_check_sum(get_vendor, 7); | ||
973 | if (dst_command(state, get_vendor, 8) < 0) { | ||
974 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | ||
975 | return -1; | ||
976 | } | ||
977 | memset(&state->vendor, '\0', 8); | ||
978 | memcpy(&state->vendor, &state->rxbuffer, 7); | ||
979 | dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]); | ||
980 | |||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | static void debug_dst_buffer(struct dst_state *state) | ||
985 | { | ||
986 | int i; | ||
987 | |||
988 | if (verbose > 2) { | ||
989 | printk("%s: [", __func__); | ||
990 | for (i = 0; i < 8; i++) | ||
991 | printk(" %02x", state->rxbuffer[i]); | ||
992 | printk("]\n"); | ||
993 | } | ||
994 | } | ||
995 | |||
996 | static int dst_check_stv0299(struct dst_state *state) | ||
997 | { | ||
998 | u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
999 | |||
1000 | check_stv0299[7] = dst_check_sum(check_stv0299, 7); | ||
1001 | if (dst_command(state, check_stv0299, 8) < 0) { | ||
1002 | dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed"); | ||
1003 | return -1; | ||
1004 | } | ||
1005 | debug_dst_buffer(state); | ||
1006 | |||
1007 | if (memcmp(&check_stv0299, &state->rxbuffer, 8)) { | ||
1008 | dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM"); | ||
1009 | state->tuner_type = TUNER_TYPE_STV0299; | ||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | return -1; | ||
1014 | } | ||
1015 | |||
1016 | static int dst_check_mb86a15(struct dst_state *state) | ||
1017 | { | ||
1018 | u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
1019 | |||
1020 | check_mb86a15[7] = dst_check_sum(check_mb86a15, 7); | ||
1021 | if (dst_command(state, check_mb86a15, 8) < 0) { | ||
1022 | dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed"); | ||
1023 | return -1; | ||
1024 | } | ||
1025 | debug_dst_buffer(state); | ||
1026 | |||
1027 | if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) { | ||
1028 | dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM"); | ||
1029 | state->tuner_type = TUNER_TYPE_MB86A15; | ||
1030 | return 0; | ||
1031 | } | ||
1032 | |||
1033 | return -1; | ||
1034 | } | ||
1035 | |||
1036 | static int dst_get_tuner_info(struct dst_state *state) | ||
1037 | { | ||
1038 | u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
1039 | u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
1040 | |||
1041 | get_tuner_1[7] = dst_check_sum(get_tuner_1, 7); | ||
1042 | get_tuner_2[7] = dst_check_sum(get_tuner_2, 7); | ||
1043 | dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE"); | ||
1044 | if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { | ||
1045 | if (dst_command(state, get_tuner_1, 8) < 0) { | ||
1046 | dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported"); | ||
1047 | goto force; | ||
1048 | } | ||
1049 | } else { | ||
1050 | if (dst_command(state, get_tuner_2, 8) < 0) { | ||
1051 | dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported"); | ||
1052 | goto force; | ||
1053 | } | ||
1054 | } | ||
1055 | memcpy(&state->board_info, &state->rxbuffer, 8); | ||
1056 | if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { | ||
1057 | dprintk(verbose, DST_ERROR, 1, "DST type has TS=188"); | ||
1058 | } | ||
1059 | if (state->board_info[0] == 0xbc) { | ||
1060 | if (state->dst_type != DST_TYPE_IS_ATSC) | ||
1061 | state->type_flags |= DST_TYPE_HAS_TS188; | ||
1062 | else | ||
1063 | state->type_flags |= DST_TYPE_HAS_NEWTUNE_2; | ||
1064 | |||
1065 | if (state->board_info[1] == 0x01) { | ||
1066 | state->dst_hw_cap |= DST_TYPE_HAS_DBOARD; | ||
1067 | dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard"); | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1071 | return 0; | ||
1072 | force: | ||
1073 | if (!strncmp(state->fw_name, "DCT-CI", 6)) { | ||
1074 | state->type_flags |= DST_TYPE_HAS_TS204; | ||
1075 | dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name); | ||
1076 | } | ||
1077 | |||
1078 | return -1; | ||
1079 | } | ||
1080 | |||
1081 | static int dst_get_device_id(struct dst_state *state) | ||
1082 | { | ||
1083 | u8 reply; | ||
1084 | |||
1085 | int i, j; | ||
1086 | struct dst_types *p_dst_type = NULL; | ||
1087 | struct tuner_types *p_tuner_list = NULL; | ||
1088 | |||
1089 | u8 use_dst_type = 0; | ||
1090 | u32 use_type_flags = 0; | ||
1091 | |||
1092 | static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; | ||
1093 | |||
1094 | state->tuner_type = 0; | ||
1095 | device_type[7] = dst_check_sum(device_type, 7); | ||
1096 | |||
1097 | if (write_dst(state, device_type, FIXED_COMM)) | ||
1098 | return -1; /* Write failed */ | ||
1099 | if ((dst_pio_disable(state)) < 0) | ||
1100 | return -1; | ||
1101 | if (read_dst(state, &reply, GET_ACK)) | ||
1102 | return -1; /* Read failure */ | ||
1103 | if (reply != ACK) { | ||
1104 | dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply); | ||
1105 | return -1; /* Unack'd write */ | ||
1106 | } | ||
1107 | if (!dst_wait_dst_ready(state, DEVICE_INIT)) | ||
1108 | return -1; /* DST not ready yet */ | ||
1109 | if (read_dst(state, state->rxbuffer, FIXED_COMM)) | ||
1110 | return -1; | ||
1111 | |||
1112 | dst_pio_disable(state); | ||
1113 | if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { | ||
1114 | dprintk(verbose, DST_INFO, 1, "Checksum failure!"); | ||
1115 | return -1; /* Checksum failure */ | ||
1116 | } | ||
1117 | state->rxbuffer[7] = '\0'; | ||
1118 | |||
1119 | for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) { | ||
1120 | if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) { | ||
1121 | use_type_flags = p_dst_type->type_flags; | ||
1122 | use_dst_type = p_dst_type->dst_type; | ||
1123 | |||
1124 | /* Card capabilities */ | ||
1125 | state->dst_hw_cap = p_dst_type->dst_feature; | ||
1126 | dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id); | ||
1127 | strncpy(&state->fw_name[0], p_dst_type->device_id, 6); | ||
1128 | /* Multiple tuners */ | ||
1129 | if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) { | ||
1130 | switch (use_dst_type) { | ||
1131 | case DST_TYPE_IS_SAT: | ||
1132 | /* STV0299 check */ | ||
1133 | if (dst_check_stv0299(state) < 0) { | ||
1134 | dprintk(verbose, DST_ERROR, 1, "Unsupported"); | ||
1135 | state->tuner_type = TUNER_TYPE_MB86A15; | ||
1136 | } | ||
1137 | break; | ||
1138 | default: | ||
1139 | break; | ||
1140 | } | ||
1141 | if (dst_check_mb86a15(state) < 0) | ||
1142 | dprintk(verbose, DST_ERROR, 1, "Unsupported"); | ||
1143 | /* Single tuner */ | ||
1144 | } else { | ||
1145 | state->tuner_type = p_dst_type->tuner_type; | ||
1146 | } | ||
1147 | for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { | ||
1148 | if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) && | ||
1149 | p_tuner_list->tuner_type == state->tuner_type) { | ||
1150 | dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]", | ||
1151 | p_dst_type->device_id, p_tuner_list->tuner_name); | ||
1152 | } | ||
1153 | } | ||
1154 | break; | ||
1155 | } | ||
1156 | } | ||
1157 | |||
1158 | if (i >= ARRAY_SIZE(dst_tlist)) { | ||
1159 | dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]); | ||
1160 | dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in"); | ||
1161 | use_dst_type = DST_TYPE_IS_SAT; | ||
1162 | use_type_flags = DST_TYPE_HAS_SYMDIV; | ||
1163 | } | ||
1164 | dst_type_print(state, use_dst_type); | ||
1165 | state->type_flags = use_type_flags; | ||
1166 | state->dst_type = use_dst_type; | ||
1167 | dst_type_flags_print(state); | ||
1168 | |||
1169 | return 0; | ||
1170 | } | ||
1171 | |||
1172 | static int dst_probe(struct dst_state *state) | ||
1173 | { | ||
1174 | mutex_init(&state->dst_mutex); | ||
1175 | if (dst_addons & DST_TYPE_HAS_CA) { | ||
1176 | if ((rdc_8820_reset(state)) < 0) { | ||
1177 | dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); | ||
1178 | return -1; | ||
1179 | } | ||
1180 | msleep(4000); | ||
1181 | } else { | ||
1182 | msleep(100); | ||
1183 | } | ||
1184 | if ((dst_comm_init(state)) < 0) { | ||
1185 | dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed."); | ||
1186 | return -1; | ||
1187 | } | ||
1188 | msleep(100); | ||
1189 | if (dst_get_device_id(state) < 0) { | ||
1190 | dprintk(verbose, DST_ERROR, 1, "unknown device."); | ||
1191 | return -1; | ||
1192 | } | ||
1193 | if (dst_get_mac(state) < 0) { | ||
1194 | dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); | ||
1195 | } | ||
1196 | if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) { | ||
1197 | if (dst_get_tuner_info(state) < 0) | ||
1198 | dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command"); | ||
1199 | } | ||
1200 | if (state->type_flags & DST_TYPE_HAS_TS204) { | ||
1201 | dst_packsize(state, 204); | ||
1202 | } | ||
1203 | if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { | ||
1204 | if (dst_fw_ver(state) < 0) { | ||
1205 | dprintk(verbose, DST_INFO, 1, "FW: Unsupported command"); | ||
1206 | return 0; | ||
1207 | } | ||
1208 | if (dst_card_type(state) < 0) { | ||
1209 | dprintk(verbose, DST_INFO, 1, "Card: Unsupported command"); | ||
1210 | return 0; | ||
1211 | } | ||
1212 | if (dst_get_vendor(state) < 0) { | ||
1213 | dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command"); | ||
1214 | return 0; | ||
1215 | } | ||
1216 | } | ||
1217 | |||
1218 | return 0; | ||
1219 | } | ||
1220 | |||
1221 | static int dst_command(struct dst_state *state, u8 *data, u8 len) | ||
1222 | { | ||
1223 | u8 reply; | ||
1224 | |||
1225 | mutex_lock(&state->dst_mutex); | ||
1226 | if ((dst_comm_init(state)) < 0) { | ||
1227 | dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed."); | ||
1228 | goto error; | ||
1229 | } | ||
1230 | if (write_dst(state, data, len)) { | ||
1231 | dprintk(verbose, DST_INFO, 1, "Trying to recover.. "); | ||
1232 | if ((dst_error_recovery(state)) < 0) { | ||
1233 | dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); | ||
1234 | goto error; | ||
1235 | } | ||
1236 | goto error; | ||
1237 | } | ||
1238 | if ((dst_pio_disable(state)) < 0) { | ||
1239 | dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed."); | ||
1240 | goto error; | ||
1241 | } | ||
1242 | if (state->type_flags & DST_TYPE_HAS_FW_1) | ||
1243 | mdelay(3); | ||
1244 | if (read_dst(state, &reply, GET_ACK)) { | ||
1245 | dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); | ||
1246 | if ((dst_error_recovery(state)) < 0) { | ||
1247 | dprintk(verbose, DST_INFO, 1, "Recovery Failed."); | ||
1248 | goto error; | ||
1249 | } | ||
1250 | goto error; | ||
1251 | } | ||
1252 | if (reply != ACK) { | ||
1253 | dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply); | ||
1254 | goto error; | ||
1255 | } | ||
1256 | if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) | ||
1257 | goto error; | ||
1258 | if (state->type_flags & DST_TYPE_HAS_FW_1) | ||
1259 | mdelay(3); | ||
1260 | else | ||
1261 | udelay(2000); | ||
1262 | if (!dst_wait_dst_ready(state, NO_DELAY)) | ||
1263 | goto error; | ||
1264 | if (read_dst(state, state->rxbuffer, FIXED_COMM)) { | ||
1265 | dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); | ||
1266 | if ((dst_error_recovery(state)) < 0) { | ||
1267 | dprintk(verbose, DST_INFO, 1, "Recovery failed."); | ||
1268 | goto error; | ||
1269 | } | ||
1270 | goto error; | ||
1271 | } | ||
1272 | if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { | ||
1273 | dprintk(verbose, DST_INFO, 1, "checksum failure"); | ||
1274 | goto error; | ||
1275 | } | ||
1276 | mutex_unlock(&state->dst_mutex); | ||
1277 | return 0; | ||
1278 | |||
1279 | error: | ||
1280 | mutex_unlock(&state->dst_mutex); | ||
1281 | return -EIO; | ||
1282 | |||
1283 | } | ||
1284 | |||
1285 | static int dst_get_signal(struct dst_state *state) | ||
1286 | { | ||
1287 | int retval; | ||
1288 | u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; | ||
1289 | //dprintk("%s: Getting Signal strength and other parameters\n", __func__); | ||
1290 | if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { | ||
1291 | state->decode_lock = state->decode_strength = state->decode_snr = 0; | ||
1292 | return 0; | ||
1293 | } | ||
1294 | if (0 == (state->diseq_flags & HAS_LOCK)) { | ||
1295 | state->decode_lock = state->decode_strength = state->decode_snr = 0; | ||
1296 | return 0; | ||
1297 | } | ||
1298 | if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) { | ||
1299 | retval = dst_command(state, get_signal, 8); | ||
1300 | if (retval < 0) | ||
1301 | return retval; | ||
1302 | if (state->dst_type == DST_TYPE_IS_SAT) { | ||
1303 | state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0; | ||
1304 | state->decode_strength = state->rxbuffer[5] << 8; | ||
1305 | state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; | ||
1306 | } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) { | ||
1307 | state->decode_lock = (state->rxbuffer[1]) ? 1 : 0; | ||
1308 | state->decode_strength = state->rxbuffer[4] << 8; | ||
1309 | state->decode_snr = state->rxbuffer[3] << 8; | ||
1310 | } else if (state->dst_type == DST_TYPE_IS_ATSC) { | ||
1311 | state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0; | ||
1312 | state->decode_strength = state->rxbuffer[4] << 8; | ||
1313 | state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; | ||
1314 | } | ||
1315 | state->cur_jiff = jiffies; | ||
1316 | } | ||
1317 | return 0; | ||
1318 | } | ||
1319 | |||
1320 | static int dst_tone_power_cmd(struct dst_state *state) | ||
1321 | { | ||
1322 | u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; | ||
1323 | |||
1324 | if (state->dst_type != DST_TYPE_IS_SAT) | ||
1325 | return -EOPNOTSUPP; | ||
1326 | paket[4] = state->tx_tuna[4]; | ||
1327 | paket[2] = state->tx_tuna[2]; | ||
1328 | paket[3] = state->tx_tuna[3]; | ||
1329 | paket[7] = dst_check_sum (paket, 7); | ||
1330 | return dst_command(state, paket, 8); | ||
1331 | } | ||
1332 | |||
1333 | static int dst_get_tuna(struct dst_state *state) | ||
1334 | { | ||
1335 | int retval; | ||
1336 | |||
1337 | if ((state->diseq_flags & ATTEMPT_TUNE) == 0) | ||
1338 | return 0; | ||
1339 | state->diseq_flags &= ~(HAS_LOCK); | ||
1340 | if (!dst_wait_dst_ready(state, NO_DELAY)) | ||
1341 | return -EIO; | ||
1342 | if ((state->type_flags & DST_TYPE_HAS_VLF) && | ||
1343 | !(state->dst_type == DST_TYPE_IS_ATSC)) | ||
1344 | |||
1345 | retval = read_dst(state, state->rx_tuna, 10); | ||
1346 | else | ||
1347 | retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); | ||
1348 | if (retval < 0) { | ||
1349 | dprintk(verbose, DST_DEBUG, 1, "read not successful"); | ||
1350 | return retval; | ||
1351 | } | ||
1352 | if ((state->type_flags & DST_TYPE_HAS_VLF) && | ||
1353 | !(state->dst_type == DST_TYPE_IS_ATSC)) { | ||
1354 | |||
1355 | if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { | ||
1356 | dprintk(verbose, DST_INFO, 1, "checksum failure ? "); | ||
1357 | return -EIO; | ||
1358 | } | ||
1359 | } else { | ||
1360 | if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { | ||
1361 | dprintk(verbose, DST_INFO, 1, "checksum failure? "); | ||
1362 | return -EIO; | ||
1363 | } | ||
1364 | } | ||
1365 | if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) | ||
1366 | return 0; | ||
1367 | if (state->dst_type == DST_TYPE_IS_SAT) { | ||
1368 | state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; | ||
1369 | } else { | ||
1370 | state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4]; | ||
1371 | } | ||
1372 | state->decode_freq = state->decode_freq * 1000; | ||
1373 | state->decode_lock = 1; | ||
1374 | state->diseq_flags |= HAS_LOCK; | ||
1375 | |||
1376 | return 1; | ||
1377 | } | ||
1378 | |||
1379 | static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); | ||
1380 | |||
1381 | static int dst_write_tuna(struct dvb_frontend *fe) | ||
1382 | { | ||
1383 | struct dst_state *state = fe->demodulator_priv; | ||
1384 | int retval; | ||
1385 | u8 reply; | ||
1386 | |||
1387 | dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags); | ||
1388 | state->decode_freq = 0; | ||
1389 | state->decode_lock = state->decode_strength = state->decode_snr = 0; | ||
1390 | if (state->dst_type == DST_TYPE_IS_SAT) { | ||
1391 | if (!(state->diseq_flags & HAS_POWER)) | ||
1392 | dst_set_voltage(fe, SEC_VOLTAGE_13); | ||
1393 | } | ||
1394 | state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); | ||
1395 | mutex_lock(&state->dst_mutex); | ||
1396 | if ((dst_comm_init(state)) < 0) { | ||
1397 | dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); | ||
1398 | goto error; | ||
1399 | } | ||
1400 | // if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { | ||
1401 | if ((state->type_flags & DST_TYPE_HAS_VLF) && | ||
1402 | (!(state->dst_type == DST_TYPE_IS_ATSC))) { | ||
1403 | |||
1404 | state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); | ||
1405 | retval = write_dst(state, &state->tx_tuna[0], 10); | ||
1406 | } else { | ||
1407 | state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); | ||
1408 | retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM); | ||
1409 | } | ||
1410 | if (retval < 0) { | ||
1411 | dst_pio_disable(state); | ||
1412 | dprintk(verbose, DST_DEBUG, 1, "write not successful"); | ||
1413 | goto werr; | ||
1414 | } | ||
1415 | if ((dst_pio_disable(state)) < 0) { | ||
1416 | dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !"); | ||
1417 | goto error; | ||
1418 | } | ||
1419 | if ((read_dst(state, &reply, GET_ACK) < 0)) { | ||
1420 | dprintk(verbose, DST_DEBUG, 1, "read verify not successful."); | ||
1421 | goto error; | ||
1422 | } | ||
1423 | if (reply != ACK) { | ||
1424 | dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply); | ||
1425 | goto error; | ||
1426 | } | ||
1427 | state->diseq_flags |= ATTEMPT_TUNE; | ||
1428 | retval = dst_get_tuna(state); | ||
1429 | werr: | ||
1430 | mutex_unlock(&state->dst_mutex); | ||
1431 | return retval; | ||
1432 | |||
1433 | error: | ||
1434 | mutex_unlock(&state->dst_mutex); | ||
1435 | return -EIO; | ||
1436 | } | ||
1437 | |||
1438 | /* | ||
1439 | * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 | ||
1440 | * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 | ||
1441 | * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 | ||
1442 | * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 | ||
1443 | * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 | ||
1444 | * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 | ||
1445 | * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 | ||
1446 | * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec | ||
1447 | * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 | ||
1448 | * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 | ||
1449 | * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 | ||
1450 | */ | ||
1451 | |||
1452 | static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) | ||
1453 | { | ||
1454 | struct dst_state *state = fe->demodulator_priv; | ||
1455 | u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; | ||
1456 | |||
1457 | if (state->dst_type != DST_TYPE_IS_SAT) | ||
1458 | return -EOPNOTSUPP; | ||
1459 | if (cmd->msg_len > 0 && cmd->msg_len < 5) | ||
1460 | memcpy(&paket[3], cmd->msg, cmd->msg_len); | ||
1461 | else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5) | ||
1462 | memcpy(&paket[2], cmd->msg, cmd->msg_len); | ||
1463 | else | ||
1464 | return -EINVAL; | ||
1465 | paket[7] = dst_check_sum(&paket[0], 7); | ||
1466 | return dst_command(state, paket, 8); | ||
1467 | } | ||
1468 | |||
1469 | static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | ||
1470 | { | ||
1471 | int need_cmd, retval = 0; | ||
1472 | struct dst_state *state = fe->demodulator_priv; | ||
1473 | |||
1474 | state->voltage = voltage; | ||
1475 | if (state->dst_type != DST_TYPE_IS_SAT) | ||
1476 | return -EOPNOTSUPP; | ||
1477 | |||
1478 | need_cmd = 0; | ||
1479 | |||
1480 | switch (voltage) { | ||
1481 | case SEC_VOLTAGE_13: | ||
1482 | case SEC_VOLTAGE_18: | ||
1483 | if ((state->diseq_flags & HAS_POWER) == 0) | ||
1484 | need_cmd = 1; | ||
1485 | state->diseq_flags |= HAS_POWER; | ||
1486 | state->tx_tuna[4] = 0x01; | ||
1487 | break; | ||
1488 | case SEC_VOLTAGE_OFF: | ||
1489 | need_cmd = 1; | ||
1490 | state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); | ||
1491 | state->tx_tuna[4] = 0x00; | ||
1492 | break; | ||
1493 | default: | ||
1494 | return -EINVAL; | ||
1495 | } | ||
1496 | |||
1497 | if (need_cmd) | ||
1498 | retval = dst_tone_power_cmd(state); | ||
1499 | |||
1500 | return retval; | ||
1501 | } | ||
1502 | |||
1503 | static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) | ||
1504 | { | ||
1505 | struct dst_state *state = fe->demodulator_priv; | ||
1506 | |||
1507 | state->tone = tone; | ||
1508 | if (state->dst_type != DST_TYPE_IS_SAT) | ||
1509 | return -EOPNOTSUPP; | ||
1510 | |||
1511 | switch (tone) { | ||
1512 | case SEC_TONE_OFF: | ||
1513 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) | ||
1514 | state->tx_tuna[2] = 0x00; | ||
1515 | else | ||
1516 | state->tx_tuna[2] = 0xff; | ||
1517 | break; | ||
1518 | |||
1519 | case SEC_TONE_ON: | ||
1520 | state->tx_tuna[2] = 0x02; | ||
1521 | break; | ||
1522 | default: | ||
1523 | return -EINVAL; | ||
1524 | } | ||
1525 | return dst_tone_power_cmd(state); | ||
1526 | } | ||
1527 | |||
1528 | static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) | ||
1529 | { | ||
1530 | struct dst_state *state = fe->demodulator_priv; | ||
1531 | |||
1532 | if (state->dst_type != DST_TYPE_IS_SAT) | ||
1533 | return -EOPNOTSUPP; | ||
1534 | state->minicmd = minicmd; | ||
1535 | switch (minicmd) { | ||
1536 | case SEC_MINI_A: | ||
1537 | state->tx_tuna[3] = 0x02; | ||
1538 | break; | ||
1539 | case SEC_MINI_B: | ||
1540 | state->tx_tuna[3] = 0xff; | ||
1541 | break; | ||
1542 | } | ||
1543 | return dst_tone_power_cmd(state); | ||
1544 | } | ||
1545 | |||
1546 | |||
1547 | static int dst_init(struct dvb_frontend *fe) | ||
1548 | { | ||
1549 | struct dst_state *state = fe->demodulator_priv; | ||
1550 | |||
1551 | static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 }; | ||
1552 | static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 }; | ||
1553 | static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | ||
1554 | static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | ||
1555 | static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | ||
1556 | static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | ||
1557 | static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | ||
1558 | |||
1559 | state->inversion = INVERSION_OFF; | ||
1560 | state->voltage = SEC_VOLTAGE_13; | ||
1561 | state->tone = SEC_TONE_OFF; | ||
1562 | state->diseq_flags = 0; | ||
1563 | state->k22 = 0x02; | ||
1564 | state->bandwidth = 7000000; | ||
1565 | state->cur_jiff = jiffies; | ||
1566 | if (state->dst_type == DST_TYPE_IS_SAT) | ||
1567 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); | ||
1568 | else if (state->dst_type == DST_TYPE_IS_TERR) | ||
1569 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); | ||
1570 | else if (state->dst_type == DST_TYPE_IS_CABLE) | ||
1571 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); | ||
1572 | else if (state->dst_type == DST_TYPE_IS_ATSC) | ||
1573 | memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner)); | ||
1574 | |||
1575 | return 0; | ||
1576 | } | ||
1577 | |||
1578 | static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
1579 | { | ||
1580 | struct dst_state *state = fe->demodulator_priv; | ||
1581 | |||
1582 | *status = 0; | ||
1583 | if (state->diseq_flags & HAS_LOCK) { | ||
1584 | // dst_get_signal(state); // don't require(?) to ask MCU | ||
1585 | if (state->decode_lock) | ||
1586 | *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; | ||
1587 | } | ||
1588 | |||
1589 | return 0; | ||
1590 | } | ||
1591 | |||
1592 | static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | ||
1593 | { | ||
1594 | struct dst_state *state = fe->demodulator_priv; | ||
1595 | |||
1596 | int retval = dst_get_signal(state); | ||
1597 | *strength = state->decode_strength; | ||
1598 | |||
1599 | return retval; | ||
1600 | } | ||
1601 | |||
1602 | static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
1603 | { | ||
1604 | struct dst_state *state = fe->demodulator_priv; | ||
1605 | |||
1606 | int retval = dst_get_signal(state); | ||
1607 | *snr = state->decode_snr; | ||
1608 | |||
1609 | return retval; | ||
1610 | } | ||
1611 | |||
1612 | static int dst_set_frontend(struct dvb_frontend *fe) | ||
1613 | { | ||
1614 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
1615 | int retval = -EINVAL; | ||
1616 | struct dst_state *state = fe->demodulator_priv; | ||
1617 | |||
1618 | if (p != NULL) { | ||
1619 | retval = dst_set_freq(state, p->frequency); | ||
1620 | if(retval != 0) | ||
1621 | return retval; | ||
1622 | dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); | ||
1623 | |||
1624 | if (state->dst_type == DST_TYPE_IS_SAT) { | ||
1625 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) | ||
1626 | dst_set_inversion(state, p->inversion); | ||
1627 | dst_set_fec(state, p->fec_inner); | ||
1628 | dst_set_symbolrate(state, p->symbol_rate); | ||
1629 | dst_set_polarization(state); | ||
1630 | dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); | ||
1631 | |||
1632 | } else if (state->dst_type == DST_TYPE_IS_TERR) | ||
1633 | dst_set_bandwidth(state, p->bandwidth_hz); | ||
1634 | else if (state->dst_type == DST_TYPE_IS_CABLE) { | ||
1635 | dst_set_fec(state, p->fec_inner); | ||
1636 | dst_set_symbolrate(state, p->symbol_rate); | ||
1637 | dst_set_modulation(state, p->modulation); | ||
1638 | } | ||
1639 | retval = dst_write_tuna(fe); | ||
1640 | } | ||
1641 | |||
1642 | return retval; | ||
1643 | } | ||
1644 | |||
1645 | static int dst_tune_frontend(struct dvb_frontend* fe, | ||
1646 | bool re_tune, | ||
1647 | unsigned int mode_flags, | ||
1648 | unsigned int *delay, | ||
1649 | fe_status_t *status) | ||
1650 | { | ||
1651 | struct dst_state *state = fe->demodulator_priv; | ||
1652 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
1653 | |||
1654 | if (re_tune) { | ||
1655 | dst_set_freq(state, p->frequency); | ||
1656 | dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); | ||
1657 | |||
1658 | if (state->dst_type == DST_TYPE_IS_SAT) { | ||
1659 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) | ||
1660 | dst_set_inversion(state, p->inversion); | ||
1661 | dst_set_fec(state, p->fec_inner); | ||
1662 | dst_set_symbolrate(state, p->symbol_rate); | ||
1663 | dst_set_polarization(state); | ||
1664 | dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); | ||
1665 | |||
1666 | } else if (state->dst_type == DST_TYPE_IS_TERR) | ||
1667 | dst_set_bandwidth(state, p->bandwidth_hz); | ||
1668 | else if (state->dst_type == DST_TYPE_IS_CABLE) { | ||
1669 | dst_set_fec(state, p->fec_inner); | ||
1670 | dst_set_symbolrate(state, p->symbol_rate); | ||
1671 | dst_set_modulation(state, p->modulation); | ||
1672 | } | ||
1673 | dst_write_tuna(fe); | ||
1674 | } | ||
1675 | |||
1676 | if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) | ||
1677 | dst_read_status(fe, status); | ||
1678 | |||
1679 | *delay = HZ/10; | ||
1680 | return 0; | ||
1681 | } | ||
1682 | |||
1683 | static int dst_get_tuning_algo(struct dvb_frontend *fe) | ||
1684 | { | ||
1685 | return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW; | ||
1686 | } | ||
1687 | |||
1688 | static int dst_get_frontend(struct dvb_frontend *fe) | ||
1689 | { | ||
1690 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
1691 | struct dst_state *state = fe->demodulator_priv; | ||
1692 | |||
1693 | p->frequency = state->decode_freq; | ||
1694 | if (state->dst_type == DST_TYPE_IS_SAT) { | ||
1695 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) | ||
1696 | p->inversion = state->inversion; | ||
1697 | p->symbol_rate = state->symbol_rate; | ||
1698 | p->fec_inner = dst_get_fec(state); | ||
1699 | } else if (state->dst_type == DST_TYPE_IS_TERR) { | ||
1700 | p->bandwidth_hz = state->bandwidth; | ||
1701 | } else if (state->dst_type == DST_TYPE_IS_CABLE) { | ||
1702 | p->symbol_rate = state->symbol_rate; | ||
1703 | p->fec_inner = dst_get_fec(state); | ||
1704 | p->modulation = dst_get_modulation(state); | ||
1705 | } | ||
1706 | |||
1707 | return 0; | ||
1708 | } | ||
1709 | |||
1710 | static void dst_release(struct dvb_frontend *fe) | ||
1711 | { | ||
1712 | struct dst_state *state = fe->demodulator_priv; | ||
1713 | if (state->dst_ca) { | ||
1714 | dvb_unregister_device(state->dst_ca); | ||
1715 | #ifdef CONFIG_MEDIA_ATTACH | ||
1716 | symbol_put(dst_ca_attach); | ||
1717 | #endif | ||
1718 | } | ||
1719 | kfree(state); | ||
1720 | } | ||
1721 | |||
1722 | static struct dvb_frontend_ops dst_dvbt_ops; | ||
1723 | static struct dvb_frontend_ops dst_dvbs_ops; | ||
1724 | static struct dvb_frontend_ops dst_dvbc_ops; | ||
1725 | static struct dvb_frontend_ops dst_atsc_ops; | ||
1726 | |||
1727 | struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) | ||
1728 | { | ||
1729 | /* check if the ASIC is there */ | ||
1730 | if (dst_probe(state) < 0) { | ||
1731 | kfree(state); | ||
1732 | return NULL; | ||
1733 | } | ||
1734 | /* determine settings based on type */ | ||
1735 | /* create dvb_frontend */ | ||
1736 | switch (state->dst_type) { | ||
1737 | case DST_TYPE_IS_TERR: | ||
1738 | memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); | ||
1739 | break; | ||
1740 | case DST_TYPE_IS_CABLE: | ||
1741 | memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); | ||
1742 | break; | ||
1743 | case DST_TYPE_IS_SAT: | ||
1744 | memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); | ||
1745 | break; | ||
1746 | case DST_TYPE_IS_ATSC: | ||
1747 | memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops)); | ||
1748 | break; | ||
1749 | default: | ||
1750 | dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); | ||
1751 | kfree(state); | ||
1752 | return NULL; | ||
1753 | } | ||
1754 | state->frontend.demodulator_priv = state; | ||
1755 | |||
1756 | return state; /* Manu (DST is a card not a frontend) */ | ||
1757 | } | ||
1758 | |||
1759 | EXPORT_SYMBOL(dst_attach); | ||
1760 | |||
1761 | static struct dvb_frontend_ops dst_dvbt_ops = { | ||
1762 | .delsys = { SYS_DVBT }, | ||
1763 | .info = { | ||
1764 | .name = "DST DVB-T", | ||
1765 | .frequency_min = 137000000, | ||
1766 | .frequency_max = 858000000, | ||
1767 | .frequency_stepsize = 166667, | ||
1768 | .caps = FE_CAN_FEC_AUTO | | ||
1769 | FE_CAN_QAM_AUTO | | ||
1770 | FE_CAN_QAM_16 | | ||
1771 | FE_CAN_QAM_32 | | ||
1772 | FE_CAN_QAM_64 | | ||
1773 | FE_CAN_QAM_128 | | ||
1774 | FE_CAN_QAM_256 | | ||
1775 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
1776 | FE_CAN_GUARD_INTERVAL_AUTO | ||
1777 | }, | ||
1778 | |||
1779 | .release = dst_release, | ||
1780 | .init = dst_init, | ||
1781 | .tune = dst_tune_frontend, | ||
1782 | .set_frontend = dst_set_frontend, | ||
1783 | .get_frontend = dst_get_frontend, | ||
1784 | .get_frontend_algo = dst_get_tuning_algo, | ||
1785 | .read_status = dst_read_status, | ||
1786 | .read_signal_strength = dst_read_signal_strength, | ||
1787 | .read_snr = dst_read_snr, | ||
1788 | }; | ||
1789 | |||
1790 | static struct dvb_frontend_ops dst_dvbs_ops = { | ||
1791 | .delsys = { SYS_DVBS }, | ||
1792 | .info = { | ||
1793 | .name = "DST DVB-S", | ||
1794 | .frequency_min = 950000, | ||
1795 | .frequency_max = 2150000, | ||
1796 | .frequency_stepsize = 1000, /* kHz for QPSK frontends */ | ||
1797 | .frequency_tolerance = 29500, | ||
1798 | .symbol_rate_min = 1000000, | ||
1799 | .symbol_rate_max = 45000000, | ||
1800 | /* . symbol_rate_tolerance = ???,*/ | ||
1801 | .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK | ||
1802 | }, | ||
1803 | |||
1804 | .release = dst_release, | ||
1805 | .init = dst_init, | ||
1806 | .tune = dst_tune_frontend, | ||
1807 | .set_frontend = dst_set_frontend, | ||
1808 | .get_frontend = dst_get_frontend, | ||
1809 | .get_frontend_algo = dst_get_tuning_algo, | ||
1810 | .read_status = dst_read_status, | ||
1811 | .read_signal_strength = dst_read_signal_strength, | ||
1812 | .read_snr = dst_read_snr, | ||
1813 | .diseqc_send_burst = dst_send_burst, | ||
1814 | .diseqc_send_master_cmd = dst_set_diseqc, | ||
1815 | .set_voltage = dst_set_voltage, | ||
1816 | .set_tone = dst_set_tone, | ||
1817 | }; | ||
1818 | |||
1819 | static struct dvb_frontend_ops dst_dvbc_ops = { | ||
1820 | .delsys = { SYS_DVBC_ANNEX_A }, | ||
1821 | .info = { | ||
1822 | .name = "DST DVB-C", | ||
1823 | .frequency_stepsize = 62500, | ||
1824 | .frequency_min = 51000000, | ||
1825 | .frequency_max = 858000000, | ||
1826 | .symbol_rate_min = 1000000, | ||
1827 | .symbol_rate_max = 45000000, | ||
1828 | .caps = FE_CAN_FEC_AUTO | | ||
1829 | FE_CAN_QAM_AUTO | | ||
1830 | FE_CAN_QAM_16 | | ||
1831 | FE_CAN_QAM_32 | | ||
1832 | FE_CAN_QAM_64 | | ||
1833 | FE_CAN_QAM_128 | | ||
1834 | FE_CAN_QAM_256 | ||
1835 | }, | ||
1836 | |||
1837 | .release = dst_release, | ||
1838 | .init = dst_init, | ||
1839 | .tune = dst_tune_frontend, | ||
1840 | .set_frontend = dst_set_frontend, | ||
1841 | .get_frontend = dst_get_frontend, | ||
1842 | .get_frontend_algo = dst_get_tuning_algo, | ||
1843 | .read_status = dst_read_status, | ||
1844 | .read_signal_strength = dst_read_signal_strength, | ||
1845 | .read_snr = dst_read_snr, | ||
1846 | }; | ||
1847 | |||
1848 | static struct dvb_frontend_ops dst_atsc_ops = { | ||
1849 | .delsys = { SYS_ATSC }, | ||
1850 | .info = { | ||
1851 | .name = "DST ATSC", | ||
1852 | .frequency_stepsize = 62500, | ||
1853 | .frequency_min = 510000000, | ||
1854 | .frequency_max = 858000000, | ||
1855 | .symbol_rate_min = 1000000, | ||
1856 | .symbol_rate_max = 45000000, | ||
1857 | .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB | ||
1858 | }, | ||
1859 | |||
1860 | .release = dst_release, | ||
1861 | .init = dst_init, | ||
1862 | .tune = dst_tune_frontend, | ||
1863 | .set_frontend = dst_set_frontend, | ||
1864 | .get_frontend = dst_get_frontend, | ||
1865 | .get_frontend_algo = dst_get_tuning_algo, | ||
1866 | .read_status = dst_read_status, | ||
1867 | .read_signal_strength = dst_read_signal_strength, | ||
1868 | .read_snr = dst_read_snr, | ||
1869 | }; | ||
1870 | |||
1871 | MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver"); | ||
1872 | MODULE_AUTHOR("Jamie Honan, Manu Abraham"); | ||
1873 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c new file mode 100644 index 000000000000..ee3884fbc9ce --- /dev/null +++ b/drivers/media/pci/bt8xx/dst_ca.c | |||
@@ -0,0 +1,726 @@ | |||
1 | /* | ||
2 | CA-driver for TwinHan DST Frontend/Card | ||
3 | |||
4 | Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/mutex.h> | ||
26 | #include <linux/string.h> | ||
27 | #include <linux/dvb/ca.h> | ||
28 | #include "dvbdev.h" | ||
29 | #include "dvb_frontend.h" | ||
30 | #include "dst_ca.h" | ||
31 | #include "dst_common.h" | ||
32 | |||
33 | #define DST_CA_ERROR 0 | ||
34 | #define DST_CA_NOTICE 1 | ||
35 | #define DST_CA_INFO 2 | ||
36 | #define DST_CA_DEBUG 3 | ||
37 | |||
38 | #define dprintk(x, y, z, format, arg...) do { \ | ||
39 | if (z) { \ | ||
40 | if ((x > DST_CA_ERROR) && (x > y)) \ | ||
41 | printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ | ||
42 | else if ((x > DST_CA_NOTICE) && (x > y)) \ | ||
43 | printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ | ||
44 | else if ((x > DST_CA_INFO) && (x > y)) \ | ||
45 | printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ | ||
46 | else if ((x > DST_CA_DEBUG) && (x > y)) \ | ||
47 | printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ | ||
48 | } else { \ | ||
49 | if (x > y) \ | ||
50 | printk(format, ## arg); \ | ||
51 | } \ | ||
52 | } while(0) | ||
53 | |||
54 | |||
55 | static DEFINE_MUTEX(dst_ca_mutex); | ||
56 | static unsigned int verbose = 5; | ||
57 | module_param(verbose, int, 0644); | ||
58 | MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); | ||
59 | |||
60 | /* Need some more work */ | ||
61 | static int ca_set_slot_descr(void) | ||
62 | { | ||
63 | /* We could make this more graceful ? */ | ||
64 | return -EOPNOTSUPP; | ||
65 | } | ||
66 | |||
67 | /* Need some more work */ | ||
68 | static int ca_set_pid(void) | ||
69 | { | ||
70 | /* We could make this more graceful ? */ | ||
71 | return -EOPNOTSUPP; | ||
72 | } | ||
73 | |||
74 | static void put_command_and_length(u8 *data, int command, int length) | ||
75 | { | ||
76 | data[0] = (command >> 16) & 0xff; | ||
77 | data[1] = (command >> 8) & 0xff; | ||
78 | data[2] = command & 0xff; | ||
79 | data[3] = length; | ||
80 | } | ||
81 | |||
82 | static void put_checksum(u8 *check_string, int length) | ||
83 | { | ||
84 | dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum."); | ||
85 | dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length); | ||
86 | check_string[length] = dst_check_sum (check_string, length); | ||
87 | dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]); | ||
88 | } | ||
89 | |||
90 | static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read) | ||
91 | { | ||
92 | u8 reply; | ||
93 | |||
94 | mutex_lock(&state->dst_mutex); | ||
95 | dst_comm_init(state); | ||
96 | msleep(65); | ||
97 | |||
98 | if (write_dst(state, data, len)) { | ||
99 | dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover"); | ||
100 | dst_error_recovery(state); | ||
101 | goto error; | ||
102 | } | ||
103 | if ((dst_pio_disable(state)) < 0) { | ||
104 | dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed."); | ||
105 | goto error; | ||
106 | } | ||
107 | if (read_dst(state, &reply, GET_ACK) < 0) { | ||
108 | dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); | ||
109 | dst_error_recovery(state); | ||
110 | goto error; | ||
111 | } | ||
112 | if (read) { | ||
113 | if (! dst_wait_dst_ready(state, LONG_DELAY)) { | ||
114 | dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready"); | ||
115 | goto error; | ||
116 | } | ||
117 | if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */ | ||
118 | dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); | ||
119 | dst_error_recovery(state); | ||
120 | goto error; | ||
121 | } | ||
122 | } | ||
123 | mutex_unlock(&state->dst_mutex); | ||
124 | return 0; | ||
125 | |||
126 | error: | ||
127 | mutex_unlock(&state->dst_mutex); | ||
128 | return -EIO; | ||
129 | } | ||
130 | |||
131 | |||
132 | static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read) | ||
133 | { | ||
134 | u8 dst_ca_comm_err = 0; | ||
135 | |||
136 | while (dst_ca_comm_err < RETRIES) { | ||
137 | dprintk(verbose, DST_CA_NOTICE, 1, " Put Command"); | ||
138 | if (dst_ci_command(state, data, ca_string, len, read)) { // If error | ||
139 | dst_error_recovery(state); | ||
140 | dst_ca_comm_err++; // work required here. | ||
141 | } else { | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | if(dst_ca_comm_err == RETRIES) | ||
147 | return -1; | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | |||
153 | |||
154 | static int ca_get_app_info(struct dst_state *state) | ||
155 | { | ||
156 | int length, str_length; | ||
157 | static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff}; | ||
158 | |||
159 | put_checksum(&command[0], command[0]); | ||
160 | if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) { | ||
161 | dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); | ||
162 | return -1; | ||
163 | } | ||
164 | dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); | ||
165 | dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================"); | ||
166 | dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]", | ||
167 | state->messages[7], (state->messages[8] << 8) | state->messages[9], | ||
168 | (state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12])); | ||
169 | dprintk(verbose, DST_CA_INFO, 1, " =================================================================================================="); | ||
170 | |||
171 | // Transform dst message to correct application_info message | ||
172 | length = state->messages[5]; | ||
173 | str_length = length - 6; | ||
174 | if (str_length < 0) { | ||
175 | str_length = 0; | ||
176 | dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering."); | ||
177 | } | ||
178 | |||
179 | // First, the command and length fields | ||
180 | put_command_and_length(&state->messages[0], CA_APP_INFO, length); | ||
181 | |||
182 | // Copy application_type, application_manufacturer and manufacturer_code | ||
183 | memcpy(&state->messages[4], &state->messages[7], 5); | ||
184 | |||
185 | // Set string length and copy string | ||
186 | state->messages[9] = str_length; | ||
187 | memcpy(&state->messages[10], &state->messages[12], str_length); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static int ca_get_ca_info(struct dst_state *state) | ||
193 | { | ||
194 | int srcPtr, dstPtr, i, num_ids; | ||
195 | static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff}; | ||
196 | const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7; | ||
197 | |||
198 | put_checksum(&slot_command[0], slot_command[0]); | ||
199 | if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) { | ||
200 | dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); | ||
201 | return -1; | ||
202 | } | ||
203 | dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); | ||
204 | |||
205 | // Print raw data | ||
206 | dprintk(verbose, DST_CA_INFO, 0, " DST data = ["); | ||
207 | for (i = 0; i < state->messages[0] + 1; i++) { | ||
208 | dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]); | ||
209 | } | ||
210 | dprintk(verbose, DST_CA_INFO, 0, "]\n"); | ||
211 | |||
212 | // Set the command and length of the output | ||
213 | num_ids = state->messages[in_num_ids_pos]; | ||
214 | if (num_ids >= 100) { | ||
215 | num_ids = 100; | ||
216 | dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering."); | ||
217 | } | ||
218 | put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2); | ||
219 | |||
220 | dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = ["); | ||
221 | srcPtr = in_system_id_pos; | ||
222 | dstPtr = out_system_id_pos; | ||
223 | for(i = 0; i < num_ids; i++) { | ||
224 | dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]); | ||
225 | // Append to output | ||
226 | state->messages[dstPtr + 0] = state->messages[srcPtr + 0]; | ||
227 | state->messages[dstPtr + 1] = state->messages[srcPtr + 1]; | ||
228 | srcPtr += 2; | ||
229 | dstPtr += 2; | ||
230 | } | ||
231 | dprintk(verbose, DST_CA_INFO, 0, "]\n"); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg) | ||
237 | { | ||
238 | int i; | ||
239 | u8 slot_cap[256]; | ||
240 | static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff}; | ||
241 | |||
242 | put_checksum(&slot_command[0], slot_command[0]); | ||
243 | if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) { | ||
244 | dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); | ||
245 | return -1; | ||
246 | } | ||
247 | dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !"); | ||
248 | |||
249 | /* Will implement the rest soon */ | ||
250 | |||
251 | dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]); | ||
252 | dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); | ||
253 | for (i = 0; i < slot_cap[0] + 1; i++) | ||
254 | dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]); | ||
255 | dprintk(verbose, DST_CA_INFO, 0, "\n"); | ||
256 | |||
257 | p_ca_caps->slot_num = 1; | ||
258 | p_ca_caps->slot_type = 1; | ||
259 | p_ca_caps->descr_num = slot_cap[7]; | ||
260 | p_ca_caps->descr_type = 1; | ||
261 | |||
262 | if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps))) | ||
263 | return -EFAULT; | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | /* Need some more work */ | ||
269 | static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) | ||
270 | { | ||
271 | return -EOPNOTSUPP; | ||
272 | } | ||
273 | |||
274 | |||
275 | static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg) | ||
276 | { | ||
277 | int i; | ||
278 | static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; | ||
279 | |||
280 | u8 *slot_info = state->messages; | ||
281 | |||
282 | put_checksum(&slot_command[0], 7); | ||
283 | if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) { | ||
284 | dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); | ||
285 | return -1; | ||
286 | } | ||
287 | dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); | ||
288 | |||
289 | /* Will implement the rest soon */ | ||
290 | |||
291 | dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]); | ||
292 | dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); | ||
293 | for (i = 0; i < 8; i++) | ||
294 | dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]); | ||
295 | dprintk(verbose, DST_CA_INFO, 0, "\n"); | ||
296 | |||
297 | if (slot_info[4] & 0x80) { | ||
298 | p_ca_slot_info->flags = CA_CI_MODULE_PRESENT; | ||
299 | p_ca_slot_info->num = 1; | ||
300 | p_ca_slot_info->type = CA_CI; | ||
301 | } else if (slot_info[4] & 0x40) { | ||
302 | p_ca_slot_info->flags = CA_CI_MODULE_READY; | ||
303 | p_ca_slot_info->num = 1; | ||
304 | p_ca_slot_info->type = CA_CI; | ||
305 | } else | ||
306 | p_ca_slot_info->flags = 0; | ||
307 | |||
308 | if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info))) | ||
309 | return -EFAULT; | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | |||
315 | static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) | ||
316 | { | ||
317 | u8 i = 0; | ||
318 | u32 command = 0; | ||
319 | |||
320 | if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) | ||
321 | return -EFAULT; | ||
322 | |||
323 | if (p_ca_message->msg) { | ||
324 | dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%*ph]", | ||
325 | 3, p_ca_message->msg); | ||
326 | |||
327 | for (i = 0; i < 3; i++) { | ||
328 | command = command | p_ca_message->msg[i]; | ||
329 | if (i < 2) | ||
330 | command = command << 8; | ||
331 | } | ||
332 | dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command); | ||
333 | |||
334 | switch (command) { | ||
335 | case CA_APP_INFO: | ||
336 | memcpy(p_ca_message->msg, state->messages, 128); | ||
337 | if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) | ||
338 | return -EFAULT; | ||
339 | break; | ||
340 | case CA_INFO: | ||
341 | memcpy(p_ca_message->msg, state->messages, 128); | ||
342 | if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) | ||
343 | return -EFAULT; | ||
344 | break; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length) | ||
352 | { | ||
353 | if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) { | ||
354 | hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ | ||
355 | hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ | ||
356 | } else { | ||
357 | if (length > 247) { | ||
358 | dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !"); | ||
359 | return -1; | ||
360 | } | ||
361 | hw_buffer->msg[0] = (length & 0xff) + 7; | ||
362 | hw_buffer->msg[1] = 0x40; | ||
363 | hw_buffer->msg[2] = 0x03; | ||
364 | hw_buffer->msg[3] = 0x00; | ||
365 | hw_buffer->msg[4] = 0x03; | ||
366 | hw_buffer->msg[5] = length & 0xff; | ||
367 | hw_buffer->msg[6] = 0x00; | ||
368 | |||
369 | /* | ||
370 | * Need to compute length for EN50221 section 8.3.2, for the time being | ||
371 | * assuming 8.3.2 is not applicable | ||
372 | */ | ||
373 | memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length); | ||
374 | } | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply) | ||
380 | { | ||
381 | if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) { | ||
382 | dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed."); | ||
383 | dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST."); | ||
384 | rdc_reset_state(state); | ||
385 | return -1; | ||
386 | } | ||
387 | dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success."); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static u32 asn_1_decode(u8 *asn_1_array) | ||
393 | { | ||
394 | u8 length_field = 0, word_count = 0, count = 0; | ||
395 | u32 length = 0; | ||
396 | |||
397 | length_field = asn_1_array[0]; | ||
398 | dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field); | ||
399 | if (length_field < 0x80) { | ||
400 | length = length_field & 0x7f; | ||
401 | dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length); | ||
402 | } else { | ||
403 | word_count = length_field & 0x7f; | ||
404 | for (count = 0; count < word_count; count++) { | ||
405 | length = length << 8; | ||
406 | length += asn_1_array[count + 1]; | ||
407 | dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length); | ||
408 | } | ||
409 | } | ||
410 | return length; | ||
411 | } | ||
412 | |||
413 | static int debug_string(u8 *msg, u32 length, u32 offset) | ||
414 | { | ||
415 | u32 i; | ||
416 | |||
417 | dprintk(verbose, DST_CA_DEBUG, 0, " String=[ "); | ||
418 | for (i = offset; i < length; i++) | ||
419 | dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]); | ||
420 | dprintk(verbose, DST_CA_DEBUG, 0, "]\n"); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | |||
426 | static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) | ||
427 | { | ||
428 | u32 length = 0; | ||
429 | u8 tag_length = 8; | ||
430 | |||
431 | length = asn_1_decode(&p_ca_message->msg[3]); | ||
432 | dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length); | ||
433 | debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */ | ||
434 | |||
435 | memset(hw_buffer->msg, '\0', length); | ||
436 | handle_dst_tag(state, p_ca_message, hw_buffer, length); | ||
437 | put_checksum(hw_buffer->msg, hw_buffer->msg[0]); | ||
438 | |||
439 | debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */ | ||
440 | write_to_8820(state, hw_buffer, (length + tag_length), reply); | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | |||
446 | /* Board supports CA PMT reply ? */ | ||
447 | static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) | ||
448 | { | ||
449 | int ca_pmt_reply_test = 0; | ||
450 | |||
451 | /* Do test board */ | ||
452 | /* Not there yet but soon */ | ||
453 | |||
454 | /* CA PMT Reply capable */ | ||
455 | if (ca_pmt_reply_test) { | ||
456 | if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) { | ||
457 | dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); | ||
458 | return -1; | ||
459 | } | ||
460 | |||
461 | /* Process CA PMT Reply */ | ||
462 | /* will implement soon */ | ||
463 | dprintk(verbose, DST_CA_ERROR, 1, " Not there yet"); | ||
464 | } | ||
465 | /* CA PMT Reply not capable */ | ||
466 | if (!ca_pmt_reply_test) { | ||
467 | if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) { | ||
468 | dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); | ||
469 | return -1; | ||
470 | } | ||
471 | dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !"); | ||
472 | /* put a dummy message */ | ||
473 | |||
474 | } | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) | ||
479 | { | ||
480 | int i = 0; | ||
481 | |||
482 | u32 command = 0; | ||
483 | struct ca_msg *hw_buffer; | ||
484 | int result = 0; | ||
485 | |||
486 | if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { | ||
487 | dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); | ||
488 | return -ENOMEM; | ||
489 | } | ||
490 | dprintk(verbose, DST_CA_DEBUG, 1, " "); | ||
491 | |||
492 | if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) { | ||
493 | result = -EFAULT; | ||
494 | goto free_mem_and_exit; | ||
495 | } | ||
496 | |||
497 | |||
498 | if (p_ca_message->msg) { | ||
499 | /* EN50221 tag */ | ||
500 | command = 0; | ||
501 | |||
502 | for (i = 0; i < 3; i++) { | ||
503 | command = command | p_ca_message->msg[i]; | ||
504 | if (i < 2) | ||
505 | command = command << 8; | ||
506 | } | ||
507 | dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command); | ||
508 | |||
509 | switch (command) { | ||
510 | case CA_PMT: | ||
511 | dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); | ||
512 | if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started | ||
513 | dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); | ||
514 | result = -1; | ||
515 | goto free_mem_and_exit; | ||
516 | } | ||
517 | dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); | ||
518 | break; | ||
519 | case CA_PMT_REPLY: | ||
520 | dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY"); | ||
521 | /* Have to handle the 2 basic types of cards here */ | ||
522 | if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { | ||
523 | dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); | ||
524 | result = -1; | ||
525 | goto free_mem_and_exit; | ||
526 | } | ||
527 | dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); | ||
528 | break; | ||
529 | case CA_APP_INFO_ENQUIRY: // only for debugging | ||
530 | dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information"); | ||
531 | |||
532 | if ((ca_get_app_info(state)) < 0) { | ||
533 | dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); | ||
534 | result = -1; | ||
535 | goto free_mem_and_exit; | ||
536 | } | ||
537 | dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); | ||
538 | break; | ||
539 | case CA_INFO_ENQUIRY: | ||
540 | dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information"); | ||
541 | |||
542 | if ((ca_get_ca_info(state)) < 0) { | ||
543 | dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !"); | ||
544 | result = -1; | ||
545 | goto free_mem_and_exit; | ||
546 | } | ||
547 | dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !"); | ||
548 | break; | ||
549 | } | ||
550 | } | ||
551 | free_mem_and_exit: | ||
552 | kfree (hw_buffer); | ||
553 | |||
554 | return result; | ||
555 | } | ||
556 | |||
557 | static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg) | ||
558 | { | ||
559 | struct dvb_device *dvbdev; | ||
560 | struct dst_state *state; | ||
561 | struct ca_slot_info *p_ca_slot_info; | ||
562 | struct ca_caps *p_ca_caps; | ||
563 | struct ca_msg *p_ca_message; | ||
564 | void __user *arg = (void __user *)ioctl_arg; | ||
565 | int result = 0; | ||
566 | |||
567 | mutex_lock(&dst_ca_mutex); | ||
568 | dvbdev = file->private_data; | ||
569 | state = (struct dst_state *)dvbdev->priv; | ||
570 | p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL); | ||
571 | p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL); | ||
572 | p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL); | ||
573 | if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) { | ||
574 | dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); | ||
575 | result = -ENOMEM; | ||
576 | goto free_mem_and_exit; | ||
577 | } | ||
578 | |||
579 | /* We have now only the standard ioctl's, the driver is upposed to handle internals. */ | ||
580 | switch (cmd) { | ||
581 | case CA_SEND_MSG: | ||
582 | dprintk(verbose, DST_CA_INFO, 1, " Sending message"); | ||
583 | if ((ca_send_message(state, p_ca_message, arg)) < 0) { | ||
584 | dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !"); | ||
585 | result = -1; | ||
586 | goto free_mem_and_exit; | ||
587 | } | ||
588 | break; | ||
589 | case CA_GET_MSG: | ||
590 | dprintk(verbose, DST_CA_INFO, 1, " Getting message"); | ||
591 | if ((ca_get_message(state, p_ca_message, arg)) < 0) { | ||
592 | dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !"); | ||
593 | result = -1; | ||
594 | goto free_mem_and_exit; | ||
595 | } | ||
596 | dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !"); | ||
597 | break; | ||
598 | case CA_RESET: | ||
599 | dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST"); | ||
600 | dst_error_bailout(state); | ||
601 | msleep(4000); | ||
602 | break; | ||
603 | case CA_GET_SLOT_INFO: | ||
604 | dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info"); | ||
605 | if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { | ||
606 | dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !"); | ||
607 | result = -1; | ||
608 | goto free_mem_and_exit; | ||
609 | } | ||
610 | dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !"); | ||
611 | break; | ||
612 | case CA_GET_CAP: | ||
613 | dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities"); | ||
614 | if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { | ||
615 | dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !"); | ||
616 | result = -1; | ||
617 | goto free_mem_and_exit; | ||
618 | } | ||
619 | dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !"); | ||
620 | break; | ||
621 | case CA_GET_DESCR_INFO: | ||
622 | dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description"); | ||
623 | if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { | ||
624 | dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !"); | ||
625 | result = -1; | ||
626 | goto free_mem_and_exit; | ||
627 | } | ||
628 | dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !"); | ||
629 | break; | ||
630 | case CA_SET_DESCR: | ||
631 | dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler"); | ||
632 | if ((ca_set_slot_descr()) < 0) { | ||
633 | dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !"); | ||
634 | result = -1; | ||
635 | goto free_mem_and_exit; | ||
636 | } | ||
637 | dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !"); | ||
638 | break; | ||
639 | case CA_SET_PID: | ||
640 | dprintk(verbose, DST_CA_INFO, 1, " Setting PID"); | ||
641 | if ((ca_set_pid()) < 0) { | ||
642 | dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !"); | ||
643 | result = -1; | ||
644 | goto free_mem_and_exit; | ||
645 | } | ||
646 | dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); | ||
647 | default: | ||
648 | result = -EOPNOTSUPP; | ||
649 | }; | ||
650 | free_mem_and_exit: | ||
651 | kfree (p_ca_message); | ||
652 | kfree (p_ca_slot_info); | ||
653 | kfree (p_ca_caps); | ||
654 | |||
655 | mutex_unlock(&dst_ca_mutex); | ||
656 | return result; | ||
657 | } | ||
658 | |||
659 | static int dst_ca_open(struct inode *inode, struct file *file) | ||
660 | { | ||
661 | dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file); | ||
662 | try_module_get(THIS_MODULE); | ||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int dst_ca_release(struct inode *inode, struct file *file) | ||
668 | { | ||
669 | dprintk(verbose, DST_CA_DEBUG, 1, " Device closed."); | ||
670 | module_put(THIS_MODULE); | ||
671 | |||
672 | return 0; | ||
673 | } | ||
674 | |||
675 | static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) | ||
676 | { | ||
677 | ssize_t bytes_read = 0; | ||
678 | |||
679 | dprintk(verbose, DST_CA_DEBUG, 1, " Device read."); | ||
680 | |||
681 | return bytes_read; | ||
682 | } | ||
683 | |||
684 | static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) | ||
685 | { | ||
686 | dprintk(verbose, DST_CA_DEBUG, 1, " Device write."); | ||
687 | |||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static const struct file_operations dst_ca_fops = { | ||
692 | .owner = THIS_MODULE, | ||
693 | .unlocked_ioctl = dst_ca_ioctl, | ||
694 | .open = dst_ca_open, | ||
695 | .release = dst_ca_release, | ||
696 | .read = dst_ca_read, | ||
697 | .write = dst_ca_write, | ||
698 | .llseek = noop_llseek, | ||
699 | }; | ||
700 | |||
701 | static struct dvb_device dvbdev_ca = { | ||
702 | .priv = NULL, | ||
703 | .users = 1, | ||
704 | .readers = 1, | ||
705 | .writers = 1, | ||
706 | .fops = &dst_ca_fops | ||
707 | }; | ||
708 | |||
709 | struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter) | ||
710 | { | ||
711 | struct dvb_device *dvbdev; | ||
712 | |||
713 | dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device"); | ||
714 | if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) { | ||
715 | dst->dst_ca = dvbdev; | ||
716 | return dst->dst_ca; | ||
717 | } | ||
718 | |||
719 | return NULL; | ||
720 | } | ||
721 | |||
722 | EXPORT_SYMBOL(dst_ca_attach); | ||
723 | |||
724 | MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver"); | ||
725 | MODULE_AUTHOR("Manu Abraham"); | ||
726 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/pci/bt8xx/dst_ca.h b/drivers/media/pci/bt8xx/dst_ca.h new file mode 100644 index 000000000000..59cd0ddd6d8e --- /dev/null +++ b/drivers/media/pci/bt8xx/dst_ca.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | CA-driver for TwinHan DST Frontend/Card | ||
3 | |||
4 | Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef _DST_CA_H_ | ||
22 | #define _DST_CA_H_ | ||
23 | |||
24 | #define RETRIES 5 | ||
25 | |||
26 | |||
27 | #define CA_APP_INFO_ENQUIRY 0x9f8020 | ||
28 | #define CA_APP_INFO 0x9f8021 | ||
29 | #define CA_ENTER_MENU 0x9f8022 | ||
30 | #define CA_INFO_ENQUIRY 0x9f8030 | ||
31 | #define CA_INFO 0x9f8031 | ||
32 | #define CA_PMT 0x9f8032 | ||
33 | #define CA_PMT_REPLY 0x9f8033 | ||
34 | |||
35 | #define CA_CLOSE_MMI 0x9f8800 | ||
36 | #define CA_DISPLAY_CONTROL 0x9f8801 | ||
37 | #define CA_DISPLAY_REPLY 0x9f8802 | ||
38 | #define CA_TEXT_LAST 0x9f8803 | ||
39 | #define CA_TEXT_MORE 0x9f8804 | ||
40 | #define CA_KEYPAD_CONTROL 0x9f8805 | ||
41 | #define CA_KEYPRESS 0x9f8806 | ||
42 | |||
43 | #define CA_ENQUIRY 0x9f8807 | ||
44 | #define CA_ANSWER 0x9f8808 | ||
45 | #define CA_MENU_LAST 0x9f8809 | ||
46 | #define CA_MENU_MORE 0x9f880a | ||
47 | #define CA_MENU_ANSWER 0x9f880b | ||
48 | #define CA_LIST_LAST 0x9f880c | ||
49 | #define CA_LIST_MORE 0x9f880d | ||
50 | |||
51 | |||
52 | struct dst_ca_private { | ||
53 | struct dst_state *dst; | ||
54 | struct dvb_device *dvbdev; | ||
55 | }; | ||
56 | |||
57 | |||
58 | #endif | ||
diff --git a/drivers/media/pci/bt8xx/dst_common.h b/drivers/media/pci/bt8xx/dst_common.h new file mode 100644 index 000000000000..d70d98f1a571 --- /dev/null +++ b/drivers/media/pci/bt8xx/dst_common.h | |||
@@ -0,0 +1,182 @@ | |||
1 | /* | ||
2 | Frontend-driver for TwinHan DST Frontend | ||
3 | |||
4 | Copyright (C) 2003 Jamie Honan | ||
5 | Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef DST_COMMON_H | ||
23 | #define DST_COMMON_H | ||
24 | |||
25 | #include <linux/dvb/frontend.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include "bt878.h" | ||
29 | |||
30 | #include "dst_ca.h" | ||
31 | |||
32 | |||
33 | #define NO_DELAY 0 | ||
34 | #define LONG_DELAY 1 | ||
35 | #define DEVICE_INIT 2 | ||
36 | |||
37 | #define DELAY 1 | ||
38 | |||
39 | #define DST_TYPE_IS_SAT 0 | ||
40 | #define DST_TYPE_IS_TERR 1 | ||
41 | #define DST_TYPE_IS_CABLE 2 | ||
42 | #define DST_TYPE_IS_ATSC 3 | ||
43 | |||
44 | #define DST_TYPE_HAS_TS188 1 | ||
45 | #define DST_TYPE_HAS_TS204 2 | ||
46 | #define DST_TYPE_HAS_SYMDIV 4 | ||
47 | #define DST_TYPE_HAS_FW_1 8 | ||
48 | #define DST_TYPE_HAS_FW_2 16 | ||
49 | #define DST_TYPE_HAS_FW_3 32 | ||
50 | #define DST_TYPE_HAS_FW_BUILD 64 | ||
51 | #define DST_TYPE_HAS_OBS_REGS 128 | ||
52 | #define DST_TYPE_HAS_INC_COUNT 256 | ||
53 | #define DST_TYPE_HAS_MULTI_FE 512 | ||
54 | #define DST_TYPE_HAS_NEWTUNE_2 1024 | ||
55 | #define DST_TYPE_HAS_DBOARD 2048 | ||
56 | #define DST_TYPE_HAS_VLF 4096 | ||
57 | |||
58 | /* Card capability list */ | ||
59 | |||
60 | #define DST_TYPE_HAS_MAC 1 | ||
61 | #define DST_TYPE_HAS_DISEQC3 2 | ||
62 | #define DST_TYPE_HAS_DISEQC4 4 | ||
63 | #define DST_TYPE_HAS_DISEQC5 8 | ||
64 | #define DST_TYPE_HAS_MOTO 16 | ||
65 | #define DST_TYPE_HAS_CA 32 | ||
66 | #define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */ | ||
67 | #define DST_TYPE_HAS_SESSION 128 | ||
68 | |||
69 | #define TUNER_TYPE_MULTI 1 | ||
70 | #define TUNER_TYPE_UNKNOWN 2 | ||
71 | /* DVB-S */ | ||
72 | #define TUNER_TYPE_L64724 4 | ||
73 | #define TUNER_TYPE_STV0299 8 | ||
74 | #define TUNER_TYPE_MB86A15 16 | ||
75 | |||
76 | /* DVB-T */ | ||
77 | #define TUNER_TYPE_TDA10046 32 | ||
78 | |||
79 | /* ATSC */ | ||
80 | #define TUNER_TYPE_NXT200x 64 | ||
81 | |||
82 | |||
83 | #define RDC_8820_PIO_0_DISABLE 0 | ||
84 | #define RDC_8820_PIO_0_ENABLE 1 | ||
85 | #define RDC_8820_INT 2 | ||
86 | #define RDC_8820_RESET 4 | ||
87 | |||
88 | /* DST Communication */ | ||
89 | #define GET_REPLY 1 | ||
90 | #define NO_REPLY 0 | ||
91 | |||
92 | #define GET_ACK 1 | ||
93 | #define FIXED_COMM 8 | ||
94 | |||
95 | #define ACK 0xff | ||
96 | |||
97 | struct dst_state { | ||
98 | |||
99 | struct i2c_adapter* i2c; | ||
100 | |||
101 | struct bt878* bt; | ||
102 | |||
103 | /* configuration settings */ | ||
104 | const struct dst_config* config; | ||
105 | |||
106 | struct dvb_frontend frontend; | ||
107 | |||
108 | /* private ASIC data */ | ||
109 | u8 tx_tuna[10]; | ||
110 | u8 rx_tuna[10]; | ||
111 | u8 rxbuffer[10]; | ||
112 | u8 diseq_flags; | ||
113 | u8 dst_type; | ||
114 | u32 type_flags; | ||
115 | u32 frequency; /* intermediate frequency in kHz for QPSK */ | ||
116 | fe_spectral_inversion_t inversion; | ||
117 | u32 symbol_rate; /* symbol rate in Symbols per second */ | ||
118 | fe_code_rate_t fec; | ||
119 | fe_sec_voltage_t voltage; | ||
120 | fe_sec_tone_mode_t tone; | ||
121 | u32 decode_freq; | ||
122 | u8 decode_lock; | ||
123 | u16 decode_strength; | ||
124 | u16 decode_snr; | ||
125 | unsigned long cur_jiff; | ||
126 | u8 k22; | ||
127 | u32 bandwidth; | ||
128 | u32 dst_hw_cap; | ||
129 | u8 dst_fw_version; | ||
130 | fe_sec_mini_cmd_t minicmd; | ||
131 | fe_modulation_t modulation; | ||
132 | u8 messages[256]; | ||
133 | u8 mac_address[8]; | ||
134 | u8 fw_version[8]; | ||
135 | u8 card_info[8]; | ||
136 | u8 vendor[8]; | ||
137 | u8 board_info[8]; | ||
138 | u32 tuner_type; | ||
139 | char *tuner_name; | ||
140 | struct mutex dst_mutex; | ||
141 | u8 fw_name[8]; | ||
142 | struct dvb_device *dst_ca; | ||
143 | }; | ||
144 | |||
145 | struct tuner_types { | ||
146 | u32 tuner_type; | ||
147 | char *tuner_name; | ||
148 | char *board_name; | ||
149 | char *fw_name; | ||
150 | }; | ||
151 | |||
152 | struct dst_types { | ||
153 | char *device_id; | ||
154 | int offset; | ||
155 | u8 dst_type; | ||
156 | u32 type_flags; | ||
157 | u32 dst_feature; | ||
158 | u32 tuner_type; | ||
159 | }; | ||
160 | |||
161 | struct dst_config | ||
162 | { | ||
163 | /* the ASIC i2c address */ | ||
164 | u8 demod_address; | ||
165 | }; | ||
166 | |||
167 | int rdc_reset_state(struct dst_state *state); | ||
168 | |||
169 | int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode); | ||
170 | int dst_pio_disable(struct dst_state *state); | ||
171 | int dst_error_recovery(struct dst_state* state); | ||
172 | int dst_error_bailout(struct dst_state *state); | ||
173 | int dst_comm_init(struct dst_state* state); | ||
174 | |||
175 | int write_dst(struct dst_state *state, u8 * data, u8 len); | ||
176 | int read_dst(struct dst_state *state, u8 * ret, u8 len); | ||
177 | u8 dst_check_sum(u8 * buf, u32 len); | ||
178 | struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter); | ||
179 | struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter); | ||
180 | |||
181 | |||
182 | #endif // DST_COMMON_H | ||
diff --git a/drivers/media/pci/bt8xx/dst_priv.h b/drivers/media/pci/bt8xx/dst_priv.h new file mode 100644 index 000000000000..3974a4c6ebe7 --- /dev/null +++ b/drivers/media/pci/bt8xx/dst_priv.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend | ||
3 | * | ||
4 | * Copyright (C) 2003 Jamie Honan | ||
5 | */ | ||
6 | |||
7 | struct dst_gpio_enable { | ||
8 | u32 mask; | ||
9 | u32 enable; | ||
10 | }; | ||
11 | |||
12 | struct dst_gpio_output { | ||
13 | u32 mask; | ||
14 | u32 highvals; | ||
15 | }; | ||
16 | |||
17 | struct dst_gpio_read { | ||
18 | unsigned long value; | ||
19 | }; | ||
20 | |||
21 | union dst_gpio_packet { | ||
22 | struct dst_gpio_enable enb; | ||
23 | struct dst_gpio_output outp; | ||
24 | struct dst_gpio_read rd; | ||
25 | int psize; | ||
26 | }; | ||
27 | |||
28 | #define DST_IG_ENABLE 0 | ||
29 | #define DST_IG_WRITE 1 | ||
30 | #define DST_IG_READ 2 | ||
31 | #define DST_IG_TS 3 | ||
32 | |||
33 | struct bt878; | ||
34 | |||
35 | int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp); | ||
diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c new file mode 100644 index 000000000000..81fab9adc1ca --- /dev/null +++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c | |||
@@ -0,0 +1,975 @@ | |||
1 | /* | ||
2 | * Bt8xx based DVB adapter driver | ||
3 | * | ||
4 | * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #define pr_fmt(fmt) "dvb_bt8xx: " fmt | ||
23 | |||
24 | #include <linux/bitops.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/i2c.h> | ||
32 | |||
33 | #include "dmxdev.h" | ||
34 | #include "dvbdev.h" | ||
35 | #include "dvb_demux.h" | ||
36 | #include "dvb_frontend.h" | ||
37 | #include "dvb-bt8xx.h" | ||
38 | #include "bt878.h" | ||
39 | |||
40 | static int debug; | ||
41 | |||
42 | module_param(debug, int, 0644); | ||
43 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
44 | |||
45 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
46 | |||
47 | #define dprintk( args... ) \ | ||
48 | do { \ | ||
49 | if (debug) printk(KERN_DEBUG args); \ | ||
50 | } while (0) | ||
51 | |||
52 | #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ | ||
53 | |||
54 | static void dvb_bt8xx_task(unsigned long data) | ||
55 | { | ||
56 | struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data; | ||
57 | |||
58 | //printk("%d ", card->bt->finished_block); | ||
59 | |||
60 | while (card->bt->last_block != card->bt->finished_block) { | ||
61 | (card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) | ||
62 | (&card->demux, | ||
63 | &card->bt->buf_cpu[card->bt->last_block * | ||
64 | card->bt->block_bytes], | ||
65 | card->bt->block_bytes); | ||
66 | card->bt->last_block = (card->bt->last_block + 1) % | ||
67 | card->bt->block_count; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
72 | { | ||
73 | struct dvb_demux*dvbdmx = dvbdmxfeed->demux; | ||
74 | struct dvb_bt8xx_card *card = dvbdmx->priv; | ||
75 | int rc; | ||
76 | |||
77 | dprintk("dvb_bt8xx: start_feed\n"); | ||
78 | |||
79 | if (!dvbdmx->dmx.frontend) | ||
80 | return -EINVAL; | ||
81 | |||
82 | mutex_lock(&card->lock); | ||
83 | card->nfeeds++; | ||
84 | rc = card->nfeeds; | ||
85 | if (card->nfeeds == 1) | ||
86 | bt878_start(card->bt, card->gpio_mode, | ||
87 | card->op_sync_orin, card->irq_err_ignore); | ||
88 | mutex_unlock(&card->lock); | ||
89 | return rc; | ||
90 | } | ||
91 | |||
92 | static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
93 | { | ||
94 | struct dvb_demux *dvbdmx = dvbdmxfeed->demux; | ||
95 | struct dvb_bt8xx_card *card = dvbdmx->priv; | ||
96 | |||
97 | dprintk("dvb_bt8xx: stop_feed\n"); | ||
98 | |||
99 | if (!dvbdmx->dmx.frontend) | ||
100 | return -EINVAL; | ||
101 | |||
102 | mutex_lock(&card->lock); | ||
103 | card->nfeeds--; | ||
104 | if (card->nfeeds == 0) | ||
105 | bt878_stop(card->bt); | ||
106 | mutex_unlock(&card->lock); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev) | ||
112 | { | ||
113 | if ((adev->subsystem_vendor == bdev->subsystem_vendor) && | ||
114 | (adev->subsystem_device == bdev->subsystem_device) && | ||
115 | (adev->bus->number == bdev->bus->number) && | ||
116 | (PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn))) | ||
117 | return 1; | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev) | ||
122 | { | ||
123 | unsigned int card_nr; | ||
124 | |||
125 | /* Hmm, n squared. Hope n is small */ | ||
126 | for (card_nr = 0; card_nr < bt878_num; card_nr++) | ||
127 | if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev)) | ||
128 | return &bt878[card_nr]; | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) | ||
133 | { | ||
134 | static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 }; | ||
135 | static u8 mt352_reset [] = { 0x50, 0x80 }; | ||
136 | static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; | ||
137 | static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 }; | ||
138 | static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 }; | ||
139 | static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; | ||
140 | |||
141 | mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); | ||
142 | udelay(2000); | ||
143 | mt352_write(fe, mt352_reset, sizeof(mt352_reset)); | ||
144 | mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); | ||
145 | |||
146 | mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); | ||
147 | mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); | ||
148 | mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend *fe, u8* pllbuf, int buf_len) | ||
154 | { | ||
155 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
156 | u32 div; | ||
157 | unsigned char bs = 0; | ||
158 | unsigned char cp = 0; | ||
159 | |||
160 | if (buf_len < 5) | ||
161 | return -EINVAL; | ||
162 | |||
163 | div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; | ||
164 | |||
165 | if (c->frequency < 542000000) | ||
166 | cp = 0xb4; | ||
167 | else if (c->frequency < 771000000) | ||
168 | cp = 0xbc; | ||
169 | else | ||
170 | cp = 0xf4; | ||
171 | |||
172 | if (c->frequency == 0) | ||
173 | bs = 0x03; | ||
174 | else if (c->frequency < 443250000) | ||
175 | bs = 0x02; | ||
176 | else | ||
177 | bs = 0x08; | ||
178 | |||
179 | pllbuf[0] = 0x60; | ||
180 | pllbuf[1] = div >> 8; | ||
181 | pllbuf[2] = div & 0xff; | ||
182 | pllbuf[3] = cp; | ||
183 | pllbuf[4] = bs; | ||
184 | |||
185 | return 5; | ||
186 | } | ||
187 | |||
188 | static struct mt352_config thomson_dtt7579_config = { | ||
189 | .demod_address = 0x0f, | ||
190 | .demod_init = thomson_dtt7579_demod_init, | ||
191 | }; | ||
192 | |||
193 | static struct zl10353_config thomson_dtt7579_zl10353_config = { | ||
194 | .demod_address = 0x0f, | ||
195 | }; | ||
196 | |||
197 | static int cx24108_tuner_set_params(struct dvb_frontend *fe) | ||
198 | { | ||
199 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
200 | u32 freq = c->frequency; | ||
201 | int i, a, n, pump; | ||
202 | u32 band, pll; | ||
203 | u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, | ||
204 | 1576000,1718000,1856000,2036000,2150000}; | ||
205 | u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, | ||
206 | 0x00102000,0x00104000,0x00108000,0x00110000, | ||
207 | 0x00120000,0x00140000}; | ||
208 | |||
209 | #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ | ||
210 | dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq); | ||
211 | |||
212 | /* This is really the bit driving the tuner chip cx24108 */ | ||
213 | |||
214 | if (freq<950000) | ||
215 | freq = 950000; /* kHz */ | ||
216 | else if (freq>2150000) | ||
217 | freq = 2150000; /* satellite IF is 950..2150MHz */ | ||
218 | |||
219 | /* decide which VCO to use for the input frequency */ | ||
220 | for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++); | ||
221 | dprintk("cx24108 debug: select vco #%d (f=%d)\n", i, freq); | ||
222 | band=bandsel[i]; | ||
223 | /* the gain values must be set by SetSymbolrate */ | ||
224 | /* compute the pll divider needed, from Conexant data sheet, | ||
225 | resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4, | ||
226 | depending on the divider bit. It is set to /4 on the 2 lowest | ||
227 | bands */ | ||
228 | n=((i<=2?2:1)*freq*10L)/(XTAL/100); | ||
229 | a=n%32; n/=32; if(a==0) n--; | ||
230 | pump=(freq<(osci[i-1]+osci[i])/2); | ||
231 | pll=0xf8000000| | ||
232 | ((pump?1:2)<<(14+11))| | ||
233 | ((n&0x1ff)<<(5+11))| | ||
234 | ((a&0x1f)<<11); | ||
235 | /* everything is shifted left 11 bits to left-align the bits in the | ||
236 | 32bit word. Output to the tuner goes MSB-aligned, after all */ | ||
237 | dprintk("cx24108 debug: pump=%d, n=%d, a=%d\n", pump, n, a); | ||
238 | cx24110_pll_write(fe,band); | ||
239 | /* set vga and vca to their widest-band settings, as a precaution. | ||
240 | SetSymbolrate might not be called to set this up */ | ||
241 | cx24110_pll_write(fe,0x500c0000); | ||
242 | cx24110_pll_write(fe,0x83f1f800); | ||
243 | cx24110_pll_write(fe,pll); | ||
244 | //writereg(client,0x56,0x7f); | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int pinnsat_tuner_init(struct dvb_frontend* fe) | ||
250 | { | ||
251 | struct dvb_bt8xx_card *card = fe->dvb->priv; | ||
252 | |||
253 | bttv_gpio_enable(card->bttv_nr, 1, 1); /* output */ | ||
254 | bttv_write_gpio(card->bttv_nr, 1, 1); /* relay on */ | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int pinnsat_tuner_sleep(struct dvb_frontend* fe) | ||
260 | { | ||
261 | struct dvb_bt8xx_card *card = fe->dvb->priv; | ||
262 | |||
263 | bttv_write_gpio(card->bttv_nr, 1, 0); /* relay off */ | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static struct cx24110_config pctvsat_config = { | ||
269 | .demod_address = 0x55, | ||
270 | }; | ||
271 | |||
272 | static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend *fe) | ||
273 | { | ||
274 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
275 | struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; | ||
276 | u8 cfg, cpump, band_select; | ||
277 | u8 data[4]; | ||
278 | u32 div; | ||
279 | struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; | ||
280 | |||
281 | div = (36000000 + c->frequency + 83333) / 166666; | ||
282 | cfg = 0x88; | ||
283 | |||
284 | if (c->frequency < 175000000) | ||
285 | cpump = 2; | ||
286 | else if (c->frequency < 390000000) | ||
287 | cpump = 1; | ||
288 | else if (c->frequency < 470000000) | ||
289 | cpump = 2; | ||
290 | else if (c->frequency < 750000000) | ||
291 | cpump = 2; | ||
292 | else | ||
293 | cpump = 3; | ||
294 | |||
295 | if (c->frequency < 175000000) | ||
296 | band_select = 0x0e; | ||
297 | else if (c->frequency < 470000000) | ||
298 | band_select = 0x05; | ||
299 | else | ||
300 | band_select = 0x03; | ||
301 | |||
302 | data[0] = (div >> 8) & 0x7f; | ||
303 | data[1] = div & 0xff; | ||
304 | data[2] = ((div >> 10) & 0x60) | cfg; | ||
305 | data[3] = (cpump << 6) | band_select; | ||
306 | |||
307 | if (fe->ops.i2c_gate_ctrl) | ||
308 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
309 | i2c_transfer(card->i2c_adapter, &msg, 1); | ||
310 | return (div * 166666 - 36000000); | ||
311 | } | ||
312 | |||
313 | static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) | ||
314 | { | ||
315 | struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; | ||
316 | |||
317 | return request_firmware(fw, name, &bt->bt->dev->dev); | ||
318 | } | ||
319 | |||
320 | static struct sp887x_config microtune_mt7202dtf_config = { | ||
321 | .demod_address = 0x70, | ||
322 | .request_firmware = microtune_mt7202dtf_request_firmware, | ||
323 | }; | ||
324 | |||
325 | static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) | ||
326 | { | ||
327 | static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; | ||
328 | static u8 mt352_reset [] = { 0x50, 0x80 }; | ||
329 | static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; | ||
330 | static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, | ||
331 | 0x00, 0xFF, 0x00, 0x40, 0x40 }; | ||
332 | static u8 mt352_av771_extra[] = { 0xB5, 0x7A }; | ||
333 | static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; | ||
334 | |||
335 | mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); | ||
336 | udelay(2000); | ||
337 | mt352_write(fe, mt352_reset, sizeof(mt352_reset)); | ||
338 | mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); | ||
339 | |||
340 | mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); | ||
341 | udelay(2000); | ||
342 | mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra)); | ||
343 | mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len) | ||
349 | { | ||
350 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
351 | u32 div; | ||
352 | unsigned char bs = 0; | ||
353 | unsigned char cp = 0; | ||
354 | |||
355 | if (buf_len < 5) return -EINVAL; | ||
356 | |||
357 | div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; | ||
358 | |||
359 | if (c->frequency < 150000000) | ||
360 | cp = 0xB4; | ||
361 | else if (c->frequency < 173000000) | ||
362 | cp = 0xBC; | ||
363 | else if (c->frequency < 250000000) | ||
364 | cp = 0xB4; | ||
365 | else if (c->frequency < 400000000) | ||
366 | cp = 0xBC; | ||
367 | else if (c->frequency < 420000000) | ||
368 | cp = 0xF4; | ||
369 | else if (c->frequency < 470000000) | ||
370 | cp = 0xFC; | ||
371 | else if (c->frequency < 600000000) | ||
372 | cp = 0xBC; | ||
373 | else if (c->frequency < 730000000) | ||
374 | cp = 0xF4; | ||
375 | else | ||
376 | cp = 0xFC; | ||
377 | |||
378 | if (c->frequency < 150000000) | ||
379 | bs = 0x01; | ||
380 | else if (c->frequency < 173000000) | ||
381 | bs = 0x01; | ||
382 | else if (c->frequency < 250000000) | ||
383 | bs = 0x02; | ||
384 | else if (c->frequency < 400000000) | ||
385 | bs = 0x02; | ||
386 | else if (c->frequency < 420000000) | ||
387 | bs = 0x02; | ||
388 | else if (c->frequency < 470000000) | ||
389 | bs = 0x02; | ||
390 | else if (c->frequency < 600000000) | ||
391 | bs = 0x08; | ||
392 | else if (c->frequency < 730000000) | ||
393 | bs = 0x08; | ||
394 | else | ||
395 | bs = 0x08; | ||
396 | |||
397 | pllbuf[0] = 0x61; | ||
398 | pllbuf[1] = div >> 8; | ||
399 | pllbuf[2] = div & 0xff; | ||
400 | pllbuf[3] = cp; | ||
401 | pllbuf[4] = bs; | ||
402 | |||
403 | return 5; | ||
404 | } | ||
405 | |||
406 | static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { | ||
407 | .demod_address = 0x0f, | ||
408 | .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, | ||
409 | }; | ||
410 | |||
411 | static struct dst_config dst_config = { | ||
412 | .demod_address = 0x55, | ||
413 | }; | ||
414 | |||
415 | static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) | ||
416 | { | ||
417 | struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; | ||
418 | |||
419 | return request_firmware(fw, name, &bt->bt->dev->dev); | ||
420 | } | ||
421 | |||
422 | static void or51211_setmode(struct dvb_frontend * fe, int mode) | ||
423 | { | ||
424 | struct dvb_bt8xx_card *bt = fe->dvb->priv; | ||
425 | bttv_write_gpio(bt->bttv_nr, 0x0002, mode); /* Reset */ | ||
426 | msleep(20); | ||
427 | } | ||
428 | |||
429 | static void or51211_reset(struct dvb_frontend * fe) | ||
430 | { | ||
431 | struct dvb_bt8xx_card *bt = fe->dvb->priv; | ||
432 | |||
433 | /* RESET DEVICE | ||
434 | * reset is controlled by GPIO-0 | ||
435 | * when set to 0 causes reset and when to 1 for normal op | ||
436 | * must remain reset for 128 clock cycles on a 50Mhz clock | ||
437 | * also PRM1 PRM2 & PRM4 are controlled by GPIO-1,GPIO-2 & GPIO-4 | ||
438 | * We assume that the reset has be held low long enough or we | ||
439 | * have been reset by a power on. When the driver is unloaded | ||
440 | * reset set to 0 so if reloaded we have been reset. | ||
441 | */ | ||
442 | /* reset & PRM1,2&4 are outputs */ | ||
443 | int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F); | ||
444 | if (ret != 0) | ||
445 | printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret); | ||
446 | bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */ | ||
447 | msleep(20); | ||
448 | /* Now set for normal operation */ | ||
449 | bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001); | ||
450 | /* wait for operation to begin */ | ||
451 | msleep(500); | ||
452 | } | ||
453 | |||
454 | static void or51211_sleep(struct dvb_frontend * fe) | ||
455 | { | ||
456 | struct dvb_bt8xx_card *bt = fe->dvb->priv; | ||
457 | bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000); | ||
458 | } | ||
459 | |||
460 | static struct or51211_config or51211_config = { | ||
461 | .demod_address = 0x15, | ||
462 | .request_firmware = or51211_request_firmware, | ||
463 | .setmode = or51211_setmode, | ||
464 | .reset = or51211_reset, | ||
465 | .sleep = or51211_sleep, | ||
466 | }; | ||
467 | |||
468 | static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend *fe) | ||
469 | { | ||
470 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
471 | struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; | ||
472 | u8 buf[4]; | ||
473 | u32 div; | ||
474 | struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) }; | ||
475 | |||
476 | div = (c->frequency + 36166667) / 166667; | ||
477 | |||
478 | buf[0] = (div >> 8) & 0x7F; | ||
479 | buf[1] = div & 0xFF; | ||
480 | buf[2] = 0x85; | ||
481 | if ((c->frequency >= 47000000) && (c->frequency < 153000000)) | ||
482 | buf[3] = 0x01; | ||
483 | else if ((c->frequency >= 153000000) && (c->frequency < 430000000)) | ||
484 | buf[3] = 0x02; | ||
485 | else if ((c->frequency >= 430000000) && (c->frequency < 824000000)) | ||
486 | buf[3] = 0x0C; | ||
487 | else if ((c->frequency >= 824000000) && (c->frequency < 863000000)) | ||
488 | buf[3] = 0x8C; | ||
489 | else | ||
490 | return -EINVAL; | ||
491 | |||
492 | if (fe->ops.i2c_gate_ctrl) | ||
493 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
494 | i2c_transfer(card->i2c_adapter, &msg, 1); | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static struct nxt6000_config vp3021_alps_tded4_config = { | ||
499 | .demod_address = 0x0a, | ||
500 | .clock_inversion = 1, | ||
501 | }; | ||
502 | |||
503 | static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) | ||
504 | { | ||
505 | static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; | ||
506 | static u8 mt352_reset [] = { 0x50, 0x80 }; | ||
507 | static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; | ||
508 | static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 }; | ||
509 | static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; | ||
510 | |||
511 | mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); | ||
512 | udelay(2000); | ||
513 | mt352_write(fe, mt352_reset, sizeof(mt352_reset)); | ||
514 | mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); | ||
515 | mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); | ||
516 | mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len) | ||
522 | { | ||
523 | u32 div; | ||
524 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
525 | |||
526 | if (buf_len < 5) | ||
527 | return -EINVAL; | ||
528 | |||
529 | div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; | ||
530 | |||
531 | pllbuf[0] = 0x61; | ||
532 | pllbuf[1] = (div >> 8) & 0x7F; | ||
533 | pllbuf[2] = div & 0xFF; | ||
534 | pllbuf[3] = 0x85; | ||
535 | |||
536 | dprintk("frequency %u, div %u\n", c->frequency, div); | ||
537 | |||
538 | if (c->frequency < 470000000) | ||
539 | pllbuf[4] = 0x02; | ||
540 | else if (c->frequency > 823000000) | ||
541 | pllbuf[4] = 0x88; | ||
542 | else | ||
543 | pllbuf[4] = 0x08; | ||
544 | |||
545 | if (c->bandwidth_hz == 8000000) | ||
546 | pllbuf[4] |= 0x04; | ||
547 | |||
548 | return 5; | ||
549 | } | ||
550 | |||
551 | static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) | ||
552 | { | ||
553 | /* | ||
554 | * Reset the frontend, must be called before trying | ||
555 | * to initialise the MT352 or mt352_attach | ||
556 | * will fail. Same goes for the nxt6000 frontend. | ||
557 | * | ||
558 | */ | ||
559 | |||
560 | int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08); | ||
561 | if (ret != 0) | ||
562 | printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret); | ||
563 | |||
564 | /* Pulse the reset line */ | ||
565 | bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ | ||
566 | bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low */ | ||
567 | msleep(100); | ||
568 | |||
569 | bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ | ||
570 | } | ||
571 | |||
572 | static struct mt352_config digitv_alps_tded4_config = { | ||
573 | .demod_address = 0x0a, | ||
574 | .demod_init = digitv_alps_tded4_demod_init, | ||
575 | }; | ||
576 | |||
577 | static struct lgdt330x_config tdvs_tua6034_config = { | ||
578 | .demod_address = 0x0e, | ||
579 | .demod_chip = LGDT3303, | ||
580 | .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ | ||
581 | }; | ||
582 | |||
583 | static void lgdt330x_reset(struct dvb_bt8xx_card *bt) | ||
584 | { | ||
585 | /* Set pin 27 of the lgdt3303 chip high to reset the frontend */ | ||
586 | |||
587 | /* Pulse the reset line */ | ||
588 | bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ | ||
589 | bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low */ | ||
590 | msleep(100); | ||
591 | |||
592 | bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ | ||
593 | msleep(100); | ||
594 | } | ||
595 | |||
596 | static void frontend_init(struct dvb_bt8xx_card *card, u32 type) | ||
597 | { | ||
598 | struct dst_state* state = NULL; | ||
599 | |||
600 | switch(type) { | ||
601 | case BTTV_BOARD_DVICO_DVBT_LITE: | ||
602 | card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter); | ||
603 | |||
604 | if (card->fe == NULL) | ||
605 | card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config, | ||
606 | card->i2c_adapter); | ||
607 | |||
608 | if (card->fe != NULL) { | ||
609 | card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs; | ||
610 | card->fe->ops.info.frequency_min = 174000000; | ||
611 | card->fe->ops.info.frequency_max = 862000000; | ||
612 | } | ||
613 | break; | ||
614 | |||
615 | case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: | ||
616 | lgdt330x_reset(card); | ||
617 | card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter); | ||
618 | if (card->fe != NULL) { | ||
619 | dvb_attach(simple_tuner_attach, card->fe, | ||
620 | card->i2c_adapter, 0x61, | ||
621 | TUNER_LG_TDVS_H06XF); | ||
622 | dprintk ("dvb_bt8xx: lgdt330x detected\n"); | ||
623 | } | ||
624 | break; | ||
625 | |||
626 | case BTTV_BOARD_NEBULA_DIGITV: | ||
627 | /* | ||
628 | * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK); | ||
629 | * this would be a cleaner solution than trying each frontend in turn. | ||
630 | */ | ||
631 | |||
632 | /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */ | ||
633 | digitv_alps_tded4_reset(card); | ||
634 | card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter); | ||
635 | if (card->fe != NULL) { | ||
636 | card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params; | ||
637 | dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); | ||
638 | break; | ||
639 | } | ||
640 | |||
641 | /* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */ | ||
642 | digitv_alps_tded4_reset(card); | ||
643 | card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter); | ||
644 | |||
645 | if (card->fe != NULL) { | ||
646 | card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs; | ||
647 | dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n"); | ||
648 | } | ||
649 | break; | ||
650 | |||
651 | case BTTV_BOARD_AVDVBT_761: | ||
652 | card->fe = dvb_attach(sp887x_attach, µtune_mt7202dtf_config, card->i2c_adapter); | ||
653 | if (card->fe) { | ||
654 | card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params; | ||
655 | } | ||
656 | break; | ||
657 | |||
658 | case BTTV_BOARD_AVDVBT_771: | ||
659 | card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter); | ||
660 | if (card->fe != NULL) { | ||
661 | card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs; | ||
662 | card->fe->ops.info.frequency_min = 174000000; | ||
663 | card->fe->ops.info.frequency_max = 862000000; | ||
664 | } | ||
665 | break; | ||
666 | |||
667 | case BTTV_BOARD_TWINHAN_DST: | ||
668 | /* DST is not a frontend driver !!! */ | ||
669 | state = kmalloc(sizeof (struct dst_state), GFP_KERNEL); | ||
670 | if (!state) { | ||
671 | pr_err("No memory\n"); | ||
672 | break; | ||
673 | } | ||
674 | /* Setup the Card */ | ||
675 | state->config = &dst_config; | ||
676 | state->i2c = card->i2c_adapter; | ||
677 | state->bt = card->bt; | ||
678 | state->dst_ca = NULL; | ||
679 | /* DST is not a frontend, attaching the ASIC */ | ||
680 | if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) { | ||
681 | pr_err("%s: Could not find a Twinhan DST\n", __func__); | ||
682 | break; | ||
683 | } | ||
684 | /* Attach other DST peripherals if any */ | ||
685 | /* Conditional Access device */ | ||
686 | card->fe = &state->frontend; | ||
687 | if (state->dst_hw_cap & DST_TYPE_HAS_CA) | ||
688 | dvb_attach(dst_ca_attach, state, &card->dvb_adapter); | ||
689 | break; | ||
690 | |||
691 | case BTTV_BOARD_PINNACLESAT: | ||
692 | card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter); | ||
693 | if (card->fe) { | ||
694 | card->fe->ops.tuner_ops.init = pinnsat_tuner_init; | ||
695 | card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep; | ||
696 | card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params; | ||
697 | } | ||
698 | break; | ||
699 | |||
700 | case BTTV_BOARD_PC_HDTV: | ||
701 | card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter); | ||
702 | if (card->fe != NULL) | ||
703 | dvb_attach(simple_tuner_attach, card->fe, | ||
704 | card->i2c_adapter, 0x61, | ||
705 | TUNER_PHILIPS_FCV1236D); | ||
706 | break; | ||
707 | } | ||
708 | |||
709 | if (card->fe == NULL) | ||
710 | pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", | ||
711 | card->bt->dev->vendor, | ||
712 | card->bt->dev->device, | ||
713 | card->bt->dev->subsystem_vendor, | ||
714 | card->bt->dev->subsystem_device); | ||
715 | else | ||
716 | if (dvb_register_frontend(&card->dvb_adapter, card->fe)) { | ||
717 | pr_err("Frontend registration failed!\n"); | ||
718 | dvb_frontend_detach(card->fe); | ||
719 | card->fe = NULL; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) | ||
724 | { | ||
725 | int result; | ||
726 | |||
727 | result = dvb_register_adapter(&card->dvb_adapter, card->card_name, | ||
728 | THIS_MODULE, &card->bt->dev->dev, | ||
729 | adapter_nr); | ||
730 | if (result < 0) { | ||
731 | pr_err("dvb_register_adapter failed (errno = %d)\n", result); | ||
732 | return result; | ||
733 | } | ||
734 | card->dvb_adapter.priv = card; | ||
735 | |||
736 | card->bt->adapter = card->i2c_adapter; | ||
737 | |||
738 | memset(&card->demux, 0, sizeof(struct dvb_demux)); | ||
739 | |||
740 | card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING; | ||
741 | |||
742 | card->demux.priv = card; | ||
743 | card->demux.filternum = 256; | ||
744 | card->demux.feednum = 256; | ||
745 | card->demux.start_feed = dvb_bt8xx_start_feed; | ||
746 | card->demux.stop_feed = dvb_bt8xx_stop_feed; | ||
747 | card->demux.write_to_decoder = NULL; | ||
748 | |||
749 | result = dvb_dmx_init(&card->demux); | ||
750 | if (result < 0) { | ||
751 | pr_err("dvb_dmx_init failed (errno = %d)\n", result); | ||
752 | goto err_unregister_adaptor; | ||
753 | } | ||
754 | |||
755 | card->dmxdev.filternum = 256; | ||
756 | card->dmxdev.demux = &card->demux.dmx; | ||
757 | card->dmxdev.capabilities = 0; | ||
758 | |||
759 | result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter); | ||
760 | if (result < 0) { | ||
761 | pr_err("dvb_dmxdev_init failed (errno = %d)\n", result); | ||
762 | goto err_dmx_release; | ||
763 | } | ||
764 | |||
765 | card->fe_hw.source = DMX_FRONTEND_0; | ||
766 | |||
767 | result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw); | ||
768 | if (result < 0) { | ||
769 | pr_err("dvb_dmx_init failed (errno = %d)\n", result); | ||
770 | goto err_dmxdev_release; | ||
771 | } | ||
772 | |||
773 | card->fe_mem.source = DMX_MEMORY_FE; | ||
774 | |||
775 | result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem); | ||
776 | if (result < 0) { | ||
777 | pr_err("dvb_dmx_init failed (errno = %d)\n", result); | ||
778 | goto err_remove_hw_frontend; | ||
779 | } | ||
780 | |||
781 | result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw); | ||
782 | if (result < 0) { | ||
783 | pr_err("dvb_dmx_init failed (errno = %d)\n", result); | ||
784 | goto err_remove_mem_frontend; | ||
785 | } | ||
786 | |||
787 | result = dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx); | ||
788 | if (result < 0) { | ||
789 | pr_err("dvb_net_init failed (errno = %d)\n", result); | ||
790 | goto err_disconnect_frontend; | ||
791 | } | ||
792 | |||
793 | tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card); | ||
794 | |||
795 | frontend_init(card, type); | ||
796 | |||
797 | return 0; | ||
798 | |||
799 | err_disconnect_frontend: | ||
800 | card->demux.dmx.disconnect_frontend(&card->demux.dmx); | ||
801 | err_remove_mem_frontend: | ||
802 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); | ||
803 | err_remove_hw_frontend: | ||
804 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); | ||
805 | err_dmxdev_release: | ||
806 | dvb_dmxdev_release(&card->dmxdev); | ||
807 | err_dmx_release: | ||
808 | dvb_dmx_release(&card->demux); | ||
809 | err_unregister_adaptor: | ||
810 | dvb_unregister_adapter(&card->dvb_adapter); | ||
811 | return result; | ||
812 | } | ||
813 | |||
814 | static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) | ||
815 | { | ||
816 | struct dvb_bt8xx_card *card; | ||
817 | struct pci_dev* bttv_pci_dev; | ||
818 | int ret; | ||
819 | |||
820 | if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL))) | ||
821 | return -ENOMEM; | ||
822 | |||
823 | mutex_init(&card->lock); | ||
824 | card->bttv_nr = sub->core->nr; | ||
825 | strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name)); | ||
826 | card->i2c_adapter = &sub->core->i2c_adap; | ||
827 | |||
828 | switch(sub->core->type) { | ||
829 | case BTTV_BOARD_PINNACLESAT: | ||
830 | card->gpio_mode = 0x0400c060; | ||
831 | /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, | ||
832 | BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ | ||
833 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
834 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
835 | break; | ||
836 | |||
837 | case BTTV_BOARD_DVICO_DVBT_LITE: | ||
838 | card->gpio_mode = 0x0400C060; | ||
839 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
840 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
841 | /* 26, 15, 14, 6, 5 | ||
842 | * A_PWRDN DA_DPM DA_SBR DA_IOM_DA | ||
843 | * DA_APP(parallel) */ | ||
844 | break; | ||
845 | |||
846 | case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: | ||
847 | card->gpio_mode = 0x0400c060; | ||
848 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
849 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
850 | break; | ||
851 | |||
852 | case BTTV_BOARD_NEBULA_DIGITV: | ||
853 | case BTTV_BOARD_AVDVBT_761: | ||
854 | card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); | ||
855 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
856 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
857 | /* A_PWRDN DA_SBR DA_APP (high speed serial) */ | ||
858 | break; | ||
859 | |||
860 | case BTTV_BOARD_AVDVBT_771: //case 0x07711461: | ||
861 | card->gpio_mode = 0x0400402B; | ||
862 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
863 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
864 | /* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/ | ||
865 | break; | ||
866 | |||
867 | case BTTV_BOARD_TWINHAN_DST: | ||
868 | card->gpio_mode = 0x2204f2c; | ||
869 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
870 | card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR | | ||
871 | BT878_APPERR | BT878_AFBUS; | ||
872 | /* 25,21,14,11,10,9,8,3,2 then | ||
873 | * 0x33 = 5,4,1,0 | ||
874 | * A_SEL=SML, DA_MLB, DA_SBR, | ||
875 | * DA_SDR=f, fifo trigger = 32 DWORDS | ||
876 | * IOM = 0 == audio A/D | ||
877 | * DPM = 0 == digital audio mode | ||
878 | * == async data parallel port | ||
879 | * then 0x33 (13 is set by start_capture) | ||
880 | * DA_APP = async data parallel port, | ||
881 | * ACAP_EN = 1, | ||
882 | * RISC+FIFO ENABLE */ | ||
883 | break; | ||
884 | |||
885 | case BTTV_BOARD_PC_HDTV: | ||
886 | card->gpio_mode = 0x0100EC7B; | ||
887 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
888 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
889 | break; | ||
890 | |||
891 | default: | ||
892 | pr_err("Unknown bttv card type: %d\n", sub->core->type); | ||
893 | kfree(card); | ||
894 | return -ENODEV; | ||
895 | } | ||
896 | |||
897 | dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name); | ||
898 | |||
899 | if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) { | ||
900 | pr_err("no pci device for card %d\n", card->bttv_nr); | ||
901 | kfree(card); | ||
902 | return -ENODEV; | ||
903 | } | ||
904 | |||
905 | if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) { | ||
906 | pr_err("unable to determine DMA core of card %d,\n", card->bttv_nr); | ||
907 | pr_err("if you have the ALSA bt87x audio driver installed, try removing it.\n"); | ||
908 | |||
909 | kfree(card); | ||
910 | return -ENODEV; | ||
911 | } | ||
912 | |||
913 | mutex_init(&card->bt->gpio_lock); | ||
914 | card->bt->bttv_nr = sub->core->nr; | ||
915 | |||
916 | if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) { | ||
917 | kfree(card); | ||
918 | return ret; | ||
919 | } | ||
920 | |||
921 | dev_set_drvdata(&sub->dev, card); | ||
922 | return 0; | ||
923 | } | ||
924 | |||
925 | static void dvb_bt8xx_remove(struct bttv_sub_device *sub) | ||
926 | { | ||
927 | struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev); | ||
928 | |||
929 | dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr); | ||
930 | |||
931 | bt878_stop(card->bt); | ||
932 | tasklet_kill(&card->bt->tasklet); | ||
933 | dvb_net_release(&card->dvbnet); | ||
934 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); | ||
935 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); | ||
936 | dvb_dmxdev_release(&card->dmxdev); | ||
937 | dvb_dmx_release(&card->demux); | ||
938 | if (card->fe) { | ||
939 | dvb_unregister_frontend(card->fe); | ||
940 | dvb_frontend_detach(card->fe); | ||
941 | } | ||
942 | dvb_unregister_adapter(&card->dvb_adapter); | ||
943 | |||
944 | kfree(card); | ||
945 | } | ||
946 | |||
947 | static struct bttv_sub_driver driver = { | ||
948 | .drv = { | ||
949 | .name = "dvb-bt8xx", | ||
950 | }, | ||
951 | .probe = dvb_bt8xx_probe, | ||
952 | .remove = dvb_bt8xx_remove, | ||
953 | /* FIXME: | ||
954 | * .shutdown = dvb_bt8xx_shutdown, | ||
955 | * .suspend = dvb_bt8xx_suspend, | ||
956 | * .resume = dvb_bt8xx_resume, | ||
957 | */ | ||
958 | }; | ||
959 | |||
960 | static int __init dvb_bt8xx_init(void) | ||
961 | { | ||
962 | return bttv_sub_register(&driver, "dvb"); | ||
963 | } | ||
964 | |||
965 | static void __exit dvb_bt8xx_exit(void) | ||
966 | { | ||
967 | bttv_sub_unregister(&driver); | ||
968 | } | ||
969 | |||
970 | module_init(dvb_bt8xx_init); | ||
971 | module_exit(dvb_bt8xx_exit); | ||
972 | |||
973 | MODULE_DESCRIPTION("Bt8xx based DVB adapter driver"); | ||
974 | MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>"); | ||
975 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.h b/drivers/media/pci/bt8xx/dvb-bt8xx.h new file mode 100644 index 000000000000..4499ed2ac0ed --- /dev/null +++ b/drivers/media/pci/bt8xx/dvb-bt8xx.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Bt8xx based DVB adapter driver | ||
3 | * | ||
4 | * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org> | ||
5 | * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> | ||
6 | * Copyright (C) 1999-2001 Ralph Metzler & Marcus Metzler for convergence integrated media GmbH | ||
7 | * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef DVB_BT8XX_H | ||
26 | #define DVB_BT8XX_H | ||
27 | |||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/mutex.h> | ||
30 | #include "dvbdev.h" | ||
31 | #include "dvb_net.h" | ||
32 | #include "bttv.h" | ||
33 | #include "mt352.h" | ||
34 | #include "sp887x.h" | ||
35 | #include "dst_common.h" | ||
36 | #include "nxt6000.h" | ||
37 | #include "cx24110.h" | ||
38 | #include "or51211.h" | ||
39 | #include "lgdt330x.h" | ||
40 | #include "zl10353.h" | ||
41 | #include "tuner-simple.h" | ||
42 | |||
43 | struct dvb_bt8xx_card { | ||
44 | struct mutex lock; | ||
45 | int nfeeds; | ||
46 | char card_name[32]; | ||
47 | struct dvb_adapter dvb_adapter; | ||
48 | struct bt878 *bt; | ||
49 | unsigned int bttv_nr; | ||
50 | struct dvb_demux demux; | ||
51 | struct dmxdev dmxdev; | ||
52 | struct dmx_frontend fe_hw; | ||
53 | struct dmx_frontend fe_mem; | ||
54 | u32 gpio_mode; | ||
55 | u32 op_sync_orin; | ||
56 | u32 irq_err_ignore; | ||
57 | struct i2c_adapter *i2c_adapter; | ||
58 | struct dvb_net dvbnet; | ||
59 | |||
60 | struct dvb_frontend* fe; | ||
61 | }; | ||
62 | |||
63 | #endif /* DVB_BT8XX_H */ | ||