1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | Frontend/Card driver for TwinHan DST Frontend |
4 | Copyright (C) 2003 Jamie Honan |
5 | Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) |
6 | |
7 | */ |
8 | |
9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
10 | |
11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> |
13 | #include <linux/init.h> |
14 | #include <linux/string.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/vmalloc.h> |
17 | #include <linux/delay.h> |
18 | #include <asm/div64.h> |
19 | #include <media/dvb_frontend.h> |
20 | #include "dst_priv.h" |
21 | #include "dst_common.h" |
22 | |
23 | static unsigned int verbose; |
24 | module_param(verbose, int, 0644); |
25 | MODULE_PARM_DESC(verbose, "verbosity level (0 to 3)" ); |
26 | |
27 | static unsigned int dst_addons; |
28 | module_param(dst_addons, int, 0644); |
29 | MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)" ); |
30 | |
31 | static unsigned int dst_algo; |
32 | module_param(dst_algo, int, 0644); |
33 | MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)" ); |
34 | |
35 | #define HAS_LOCK 1 |
36 | #define ATTEMPT_TUNE 2 |
37 | #define HAS_POWER 4 |
38 | |
39 | #define dprintk(level, fmt, arg...) do { \ |
40 | if (level >= verbose) \ |
41 | printk(KERN_DEBUG pr_fmt("%s: " fmt), \ |
42 | __func__, ##arg); \ |
43 | } while(0) |
44 | |
45 | static int dst_command(struct dst_state *state, u8 *data, u8 len); |
46 | |
47 | static void dst_packsize(struct dst_state *state, int psize) |
48 | { |
49 | union dst_gpio_packet bits; |
50 | |
51 | bits.psize = psize; |
52 | bt878_device_control(bt: state->bt, DST_IG_TS, mp: &bits); |
53 | } |
54 | |
55 | static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, |
56 | u32 outhigh, int delay) |
57 | { |
58 | union dst_gpio_packet enb; |
59 | union dst_gpio_packet bits; |
60 | int err; |
61 | |
62 | enb.enb.mask = mask; |
63 | enb.enb.enable = enbb; |
64 | |
65 | dprintk(2, "mask=[%04x], enbb=[%04x], outhigh=[%04x]\n" , |
66 | mask, enbb, outhigh); |
67 | if ((err = bt878_device_control(bt: state->bt, DST_IG_ENABLE, mp: &enb)) < 0) { |
68 | dprintk(2, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)\n" , |
69 | err, mask, enbb); |
70 | return -EREMOTEIO; |
71 | } |
72 | udelay(1000); |
73 | /* because complete disabling means no output, no need to do output packet */ |
74 | if (enbb == 0) |
75 | return 0; |
76 | if (delay) |
77 | msleep(msecs: 10); |
78 | bits.outp.mask = enbb; |
79 | bits.outp.highvals = outhigh; |
80 | if ((err = bt878_device_control(bt: state->bt, DST_IG_WRITE, mp: &bits)) < 0) { |
81 | dprintk(2, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)\n" , |
82 | err, enbb, outhigh); |
83 | return -EREMOTEIO; |
84 | } |
85 | |
86 | return 0; |
87 | } |
88 | |
89 | static int dst_gpio_inb(struct dst_state *state, u8 *result) |
90 | { |
91 | union dst_gpio_packet rd_packet; |
92 | int err; |
93 | |
94 | *result = 0; |
95 | if ((err = bt878_device_control(bt: state->bt, DST_IG_READ, mp: &rd_packet)) < 0) { |
96 | pr_err("dst_gpio_inb error (err == %i)\n" , err); |
97 | return -EREMOTEIO; |
98 | } |
99 | *result = (u8) rd_packet.rd.value; |
100 | |
101 | return 0; |
102 | } |
103 | |
104 | int rdc_reset_state(struct dst_state *state) |
105 | { |
106 | dprintk(2, "Resetting state machine\n" ); |
107 | if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, outhigh: 0, NO_DELAY) < 0) { |
108 | pr_err("dst_gpio_outb ERROR !\n" ); |
109 | return -1; |
110 | } |
111 | msleep(msecs: 10); |
112 | if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) { |
113 | pr_err("dst_gpio_outb ERROR !\n" ); |
114 | msleep(msecs: 10); |
115 | return -1; |
116 | } |
117 | |
118 | return 0; |
119 | } |
120 | EXPORT_SYMBOL(rdc_reset_state); |
121 | |
122 | static int rdc_8820_reset(struct dst_state *state) |
123 | { |
124 | dprintk(3, "Resetting DST\n" ); |
125 | if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, outhigh: 0, NO_DELAY) < 0) { |
126 | pr_err("dst_gpio_outb ERROR !\n" ); |
127 | return -1; |
128 | } |
129 | udelay(1000); |
130 | if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { |
131 | pr_err("dst_gpio_outb ERROR !\n" ); |
132 | return -1; |
133 | } |
134 | |
135 | return 0; |
136 | } |
137 | |
138 | static int dst_pio_enable(struct dst_state *state) |
139 | { |
140 | if (dst_gpio_outb(state, mask: ~0, RDC_8820_PIO_0_ENABLE, outhigh: 0, NO_DELAY) < 0) { |
141 | pr_err("dst_gpio_outb ERROR !\n" ); |
142 | return -1; |
143 | } |
144 | udelay(1000); |
145 | |
146 | return 0; |
147 | } |
148 | |
149 | int dst_pio_disable(struct dst_state *state) |
150 | { |
151 | if (dst_gpio_outb(state, mask: ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) { |
152 | pr_err("dst_gpio_outb ERROR !\n" ); |
153 | return -1; |
154 | } |
155 | if (state->type_flags & DST_TYPE_HAS_FW_1) |
156 | udelay(1000); |
157 | |
158 | return 0; |
159 | } |
160 | EXPORT_SYMBOL(dst_pio_disable); |
161 | |
162 | int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) |
163 | { |
164 | u8 reply; |
165 | int i; |
166 | |
167 | for (i = 0; i < 200; i++) { |
168 | if (dst_gpio_inb(state, result: &reply) < 0) { |
169 | pr_err("dst_gpio_inb ERROR !\n" ); |
170 | return -1; |
171 | } |
172 | if ((reply & RDC_8820_PIO_0_ENABLE) == 0) { |
173 | dprintk(2, "dst wait ready after %d\n" , i); |
174 | return 1; |
175 | } |
176 | msleep(msecs: 10); |
177 | } |
178 | dprintk(1, "dst wait NOT ready after %d\n" , i); |
179 | |
180 | return 0; |
181 | } |
182 | EXPORT_SYMBOL(dst_wait_dst_ready); |
183 | |
184 | int dst_error_recovery(struct dst_state *state) |
185 | { |
186 | dprintk(1, "Trying to return from previous errors.\n" ); |
187 | dst_pio_disable(state); |
188 | msleep(msecs: 10); |
189 | dst_pio_enable(state); |
190 | msleep(msecs: 10); |
191 | |
192 | return 0; |
193 | } |
194 | EXPORT_SYMBOL(dst_error_recovery); |
195 | |
196 | int dst_error_bailout(struct dst_state *state) |
197 | { |
198 | dprintk(2, "Trying to bailout from previous error.\n" ); |
199 | rdc_8820_reset(state); |
200 | dst_pio_disable(state); |
201 | msleep(msecs: 10); |
202 | |
203 | return 0; |
204 | } |
205 | EXPORT_SYMBOL(dst_error_bailout); |
206 | |
207 | int dst_comm_init(struct dst_state *state) |
208 | { |
209 | dprintk(2, "Initializing DST.\n" ); |
210 | if ((dst_pio_enable(state)) < 0) { |
211 | pr_err("PIO Enable Failed\n" ); |
212 | return -1; |
213 | } |
214 | if ((rdc_reset_state(state)) < 0) { |
215 | pr_err("RDC 8820 State RESET Failed.\n" ); |
216 | return -1; |
217 | } |
218 | if (state->type_flags & DST_TYPE_HAS_FW_1) |
219 | msleep(msecs: 100); |
220 | else |
221 | msleep(msecs: 5); |
222 | |
223 | return 0; |
224 | } |
225 | EXPORT_SYMBOL(dst_comm_init); |
226 | |
227 | int write_dst(struct dst_state *state, u8 *data, u8 len) |
228 | { |
229 | struct i2c_msg msg = { |
230 | .addr = state->config->demod_address, |
231 | .flags = 0, |
232 | .buf = data, |
233 | .len = len |
234 | }; |
235 | |
236 | int err; |
237 | u8 cnt; |
238 | |
239 | dprintk(1, "writing [ %*ph ]\n" , len, data); |
240 | |
241 | for (cnt = 0; cnt < 2; cnt++) { |
242 | if ((err = i2c_transfer(adap: state->i2c, msgs: &msg, num: 1)) < 0) { |
243 | dprintk(2, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n" , |
244 | err, len, data[0]); |
245 | dst_error_recovery(state); |
246 | continue; |
247 | } else |
248 | break; |
249 | } |
250 | if (cnt >= 2) { |
251 | dprintk(2, "RDC 8820 RESET\n" ); |
252 | dst_error_bailout(state); |
253 | |
254 | return -1; |
255 | } |
256 | |
257 | return 0; |
258 | } |
259 | EXPORT_SYMBOL(write_dst); |
260 | |
261 | int read_dst(struct dst_state *state, u8 *ret, u8 len) |
262 | { |
263 | struct i2c_msg msg = { |
264 | .addr = state->config->demod_address, |
265 | .flags = I2C_M_RD, |
266 | .buf = ret, |
267 | .len = len |
268 | }; |
269 | |
270 | int err; |
271 | int cnt; |
272 | |
273 | for (cnt = 0; cnt < 2; cnt++) { |
274 | if ((err = i2c_transfer(adap: state->i2c, msgs: &msg, num: 1)) < 0) { |
275 | dprintk(2, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n" , |
276 | err, len, ret[0]); |
277 | dst_error_recovery(state); |
278 | continue; |
279 | } else |
280 | break; |
281 | } |
282 | if (cnt >= 2) { |
283 | dprintk(2, "RDC 8820 RESET\n" ); |
284 | dst_error_bailout(state); |
285 | |
286 | return -1; |
287 | } |
288 | dprintk(3, "reply is %*ph\n" , len, ret); |
289 | |
290 | return 0; |
291 | } |
292 | EXPORT_SYMBOL(read_dst); |
293 | |
294 | static int dst_set_polarization(struct dst_state *state) |
295 | { |
296 | switch (state->voltage) { |
297 | case SEC_VOLTAGE_13: /* Vertical */ |
298 | dprintk(2, "Polarization=[Vertical]\n" ); |
299 | state->tx_tuna[8] &= ~0x40; |
300 | break; |
301 | case SEC_VOLTAGE_18: /* Horizontal */ |
302 | dprintk(2, "Polarization=[Horizontal]\n" ); |
303 | state->tx_tuna[8] |= 0x40; |
304 | break; |
305 | case SEC_VOLTAGE_OFF: |
306 | break; |
307 | } |
308 | |
309 | return 0; |
310 | } |
311 | |
312 | static int dst_set_freq(struct dst_state *state, u32 freq) |
313 | { |
314 | state->frequency = freq; |
315 | dprintk(2, "set Frequency %u\n" , freq); |
316 | |
317 | if (state->dst_type == DST_TYPE_IS_SAT) { |
318 | freq = freq / 1000; |
319 | if (freq < 950 || freq > 2150) |
320 | return -EINVAL; |
321 | state->tx_tuna[2] = (freq >> 8); |
322 | state->tx_tuna[3] = (u8) freq; |
323 | state->tx_tuna[4] = 0x01; |
324 | state->tx_tuna[8] &= ~0x04; |
325 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { |
326 | if (freq < 1531) |
327 | state->tx_tuna[8] |= 0x04; |
328 | } |
329 | } else if (state->dst_type == DST_TYPE_IS_TERR) { |
330 | freq = freq / 1000; |
331 | if (freq < 137000 || freq > 858000) |
332 | return -EINVAL; |
333 | state->tx_tuna[2] = (freq >> 16) & 0xff; |
334 | state->tx_tuna[3] = (freq >> 8) & 0xff; |
335 | state->tx_tuna[4] = (u8) freq; |
336 | } else if (state->dst_type == DST_TYPE_IS_CABLE) { |
337 | freq = freq / 1000; |
338 | state->tx_tuna[2] = (freq >> 16) & 0xff; |
339 | state->tx_tuna[3] = (freq >> 8) & 0xff; |
340 | state->tx_tuna[4] = (u8) freq; |
341 | } else if (state->dst_type == DST_TYPE_IS_ATSC) { |
342 | freq = freq / 1000; |
343 | if (freq < 51000 || freq > 858000) |
344 | return -EINVAL; |
345 | state->tx_tuna[2] = (freq >> 16) & 0xff; |
346 | state->tx_tuna[3] = (freq >> 8) & 0xff; |
347 | state->tx_tuna[4] = (u8) freq; |
348 | state->tx_tuna[5] = 0x00; /* ATSC */ |
349 | state->tx_tuna[6] = 0x00; |
350 | if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG) |
351 | state->tx_tuna[7] = 0x00; /* Digital */ |
352 | } else |
353 | return -EINVAL; |
354 | |
355 | return 0; |
356 | } |
357 | |
358 | static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth) |
359 | { |
360 | state->bandwidth = bandwidth; |
361 | |
362 | if (state->dst_type != DST_TYPE_IS_TERR) |
363 | return -EOPNOTSUPP; |
364 | |
365 | switch (bandwidth) { |
366 | case 6000000: |
367 | if (state->dst_hw_cap & DST_TYPE_HAS_CA) |
368 | state->tx_tuna[7] = 0x06; |
369 | else { |
370 | state->tx_tuna[6] = 0x06; |
371 | state->tx_tuna[7] = 0x00; |
372 | } |
373 | break; |
374 | case 7000000: |
375 | if (state->dst_hw_cap & DST_TYPE_HAS_CA) |
376 | state->tx_tuna[7] = 0x07; |
377 | else { |
378 | state->tx_tuna[6] = 0x07; |
379 | state->tx_tuna[7] = 0x00; |
380 | } |
381 | break; |
382 | case 8000000: |
383 | if (state->dst_hw_cap & DST_TYPE_HAS_CA) |
384 | state->tx_tuna[7] = 0x08; |
385 | else { |
386 | state->tx_tuna[6] = 0x08; |
387 | state->tx_tuna[7] = 0x00; |
388 | } |
389 | break; |
390 | default: |
391 | return -EINVAL; |
392 | } |
393 | |
394 | return 0; |
395 | } |
396 | |
397 | static int dst_set_inversion(struct dst_state *state, |
398 | enum fe_spectral_inversion inversion) |
399 | { |
400 | state->inversion = inversion; |
401 | switch (inversion) { |
402 | case INVERSION_OFF: /* Inversion = Normal */ |
403 | state->tx_tuna[8] &= ~0x80; |
404 | break; |
405 | case INVERSION_ON: |
406 | state->tx_tuna[8] |= 0x80; |
407 | break; |
408 | default: |
409 | return -EINVAL; |
410 | } |
411 | |
412 | return 0; |
413 | } |
414 | |
415 | static int dst_set_fec(struct dst_state *state, enum fe_code_rate fec) |
416 | { |
417 | state->fec = fec; |
418 | return 0; |
419 | } |
420 | |
421 | static enum fe_code_rate dst_get_fec(struct dst_state *state) |
422 | { |
423 | return state->fec; |
424 | } |
425 | |
426 | static int dst_set_symbolrate(struct dst_state *state, u32 srate) |
427 | { |
428 | u32 symcalc; |
429 | u64 sval; |
430 | |
431 | state->symbol_rate = srate; |
432 | if (state->dst_type == DST_TYPE_IS_TERR) { |
433 | return -EOPNOTSUPP; |
434 | } |
435 | dprintk(2, "set symrate %u\n" , srate); |
436 | srate /= 1000; |
437 | if (state->dst_type == DST_TYPE_IS_SAT) { |
438 | if (state->type_flags & DST_TYPE_HAS_SYMDIV) { |
439 | sval = srate; |
440 | sval <<= 20; |
441 | do_div(sval, 88000); |
442 | symcalc = (u32) sval; |
443 | dprintk(2, "set symcalc %u\n" , symcalc); |
444 | state->tx_tuna[5] = (u8) (symcalc >> 12); |
445 | state->tx_tuna[6] = (u8) (symcalc >> 4); |
446 | state->tx_tuna[7] = (u8) (symcalc << 4); |
447 | } else { |
448 | state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f; |
449 | state->tx_tuna[6] = (u8) (srate >> 8); |
450 | state->tx_tuna[7] = (u8) srate; |
451 | } |
452 | state->tx_tuna[8] &= ~0x20; |
453 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { |
454 | if (srate > 8000) |
455 | state->tx_tuna[8] |= 0x20; |
456 | } |
457 | } else if (state->dst_type == DST_TYPE_IS_CABLE) { |
458 | dprintk(3, "%s\n" , state->fw_name); |
459 | if (!strncmp(state->fw_name, "DCTNEW" , 6)) { |
460 | state->tx_tuna[5] = (u8) (srate >> 8); |
461 | state->tx_tuna[6] = (u8) srate; |
462 | state->tx_tuna[7] = 0x00; |
463 | } else if (!strncmp(state->fw_name, "DCT-CI" , 6)) { |
464 | state->tx_tuna[5] = 0x00; |
465 | state->tx_tuna[6] = (u8) (srate >> 8); |
466 | state->tx_tuna[7] = (u8) srate; |
467 | } |
468 | } |
469 | return 0; |
470 | } |
471 | |
472 | static int dst_set_modulation(struct dst_state *state, |
473 | enum fe_modulation modulation) |
474 | { |
475 | if (state->dst_type != DST_TYPE_IS_CABLE) |
476 | return -EOPNOTSUPP; |
477 | |
478 | state->modulation = modulation; |
479 | switch (modulation) { |
480 | case QAM_16: |
481 | state->tx_tuna[8] = 0x10; |
482 | break; |
483 | case QAM_32: |
484 | state->tx_tuna[8] = 0x20; |
485 | break; |
486 | case QAM_64: |
487 | state->tx_tuna[8] = 0x40; |
488 | break; |
489 | case QAM_128: |
490 | state->tx_tuna[8] = 0x80; |
491 | break; |
492 | case QAM_256: |
493 | if (!strncmp(state->fw_name, "DCTNEW" , 6)) |
494 | state->tx_tuna[8] = 0xff; |
495 | else if (!strncmp(state->fw_name, "DCT-CI" , 6)) |
496 | state->tx_tuna[8] = 0x00; |
497 | break; |
498 | case QPSK: |
499 | case QAM_AUTO: |
500 | case VSB_8: |
501 | case VSB_16: |
502 | default: |
503 | return -EINVAL; |
504 | |
505 | } |
506 | |
507 | return 0; |
508 | } |
509 | |
510 | static enum fe_modulation dst_get_modulation(struct dst_state *state) |
511 | { |
512 | return state->modulation; |
513 | } |
514 | |
515 | |
516 | u8 dst_check_sum(u8 *buf, u32 len) |
517 | { |
518 | u32 i; |
519 | u8 val = 0; |
520 | if (!len) |
521 | return 0; |
522 | for (i = 0; i < len; i++) { |
523 | val += buf[i]; |
524 | } |
525 | return ((~val) + 1); |
526 | } |
527 | EXPORT_SYMBOL(dst_check_sum); |
528 | |
529 | static void dst_type_flags_print(struct dst_state *state) |
530 | { |
531 | u32 type_flags = state->type_flags; |
532 | |
533 | pr_err("DST type flags :\n" ); |
534 | if (type_flags & DST_TYPE_HAS_TS188) |
535 | pr_err(" 0x%x newtuner\n" , DST_TYPE_HAS_TS188); |
536 | if (type_flags & DST_TYPE_HAS_NEWTUNE_2) |
537 | pr_err(" 0x%x newtuner 2\n" , DST_TYPE_HAS_NEWTUNE_2); |
538 | if (type_flags & DST_TYPE_HAS_TS204) |
539 | pr_err(" 0x%x ts204\n" , DST_TYPE_HAS_TS204); |
540 | if (type_flags & DST_TYPE_HAS_VLF) |
541 | pr_err(" 0x%x VLF\n" , DST_TYPE_HAS_VLF); |
542 | if (type_flags & DST_TYPE_HAS_SYMDIV) |
543 | pr_err(" 0x%x symdiv\n" , DST_TYPE_HAS_SYMDIV); |
544 | if (type_flags & DST_TYPE_HAS_FW_1) |
545 | pr_err(" 0x%x firmware version = 1\n" , DST_TYPE_HAS_FW_1); |
546 | if (type_flags & DST_TYPE_HAS_FW_2) |
547 | pr_err(" 0x%x firmware version = 2\n" , DST_TYPE_HAS_FW_2); |
548 | if (type_flags & DST_TYPE_HAS_FW_3) |
549 | pr_err(" 0x%x firmware version = 3\n" , DST_TYPE_HAS_FW_3); |
550 | pr_err("\n" ); |
551 | } |
552 | |
553 | |
554 | static int dst_type_print(struct dst_state *state, u8 type) |
555 | { |
556 | char *otype; |
557 | switch (type) { |
558 | case DST_TYPE_IS_SAT: |
559 | otype = "satellite" ; |
560 | break; |
561 | |
562 | case DST_TYPE_IS_TERR: |
563 | otype = "terrestrial" ; |
564 | break; |
565 | |
566 | case DST_TYPE_IS_CABLE: |
567 | otype = "cable" ; |
568 | break; |
569 | |
570 | case DST_TYPE_IS_ATSC: |
571 | otype = "atsc" ; |
572 | break; |
573 | |
574 | default: |
575 | dprintk(2, "invalid dst type %d\n" , type); |
576 | return -EINVAL; |
577 | } |
578 | dprintk(2, "DST type: %s\n" , otype); |
579 | |
580 | return 0; |
581 | } |
582 | |
583 | static struct tuner_types tuner_list[] = { |
584 | { |
585 | .tuner_type = TUNER_TYPE_L64724, |
586 | .tuner_name = "L 64724" , |
587 | .board_name = "UNKNOWN" , |
588 | .fw_name = "UNKNOWN" |
589 | }, |
590 | |
591 | { |
592 | .tuner_type = TUNER_TYPE_STV0299, |
593 | .tuner_name = "STV 0299" , |
594 | .board_name = "VP1020" , |
595 | .fw_name = "DST-MOT" |
596 | }, |
597 | |
598 | { |
599 | .tuner_type = TUNER_TYPE_STV0299, |
600 | .tuner_name = "STV 0299" , |
601 | .board_name = "VP1020" , |
602 | .fw_name = "DST-03T" |
603 | }, |
604 | |
605 | { |
606 | .tuner_type = TUNER_TYPE_MB86A15, |
607 | .tuner_name = "MB 86A15" , |
608 | .board_name = "VP1022" , |
609 | .fw_name = "DST-03T" |
610 | }, |
611 | |
612 | { |
613 | .tuner_type = TUNER_TYPE_MB86A15, |
614 | .tuner_name = "MB 86A15" , |
615 | .board_name = "VP1025" , |
616 | .fw_name = "DST-03T" |
617 | }, |
618 | |
619 | { |
620 | .tuner_type = TUNER_TYPE_STV0299, |
621 | .tuner_name = "STV 0299" , |
622 | .board_name = "VP1030" , |
623 | .fw_name = "DST-CI" |
624 | }, |
625 | |
626 | { |
627 | .tuner_type = TUNER_TYPE_STV0299, |
628 | .tuner_name = "STV 0299" , |
629 | .board_name = "VP1030" , |
630 | .fw_name = "DSTMCI" |
631 | }, |
632 | |
633 | { |
634 | .tuner_type = TUNER_TYPE_UNKNOWN, |
635 | .tuner_name = "UNKNOWN" , |
636 | .board_name = "VP2021" , |
637 | .fw_name = "DCTNEW" |
638 | }, |
639 | |
640 | { |
641 | .tuner_type = TUNER_TYPE_UNKNOWN, |
642 | .tuner_name = "UNKNOWN" , |
643 | .board_name = "VP2030" , |
644 | .fw_name = "DCT-CI" |
645 | }, |
646 | |
647 | { |
648 | .tuner_type = TUNER_TYPE_UNKNOWN, |
649 | .tuner_name = "UNKNOWN" , |
650 | .board_name = "VP2031" , |
651 | .fw_name = "DCT-CI" |
652 | }, |
653 | |
654 | { |
655 | .tuner_type = TUNER_TYPE_UNKNOWN, |
656 | .tuner_name = "UNKNOWN" , |
657 | .board_name = "VP2040" , |
658 | .fw_name = "DCT-CI" |
659 | }, |
660 | |
661 | { |
662 | .tuner_type = TUNER_TYPE_UNKNOWN, |
663 | .tuner_name = "UNKNOWN" , |
664 | .board_name = "VP3020" , |
665 | .fw_name = "DTTFTA" |
666 | }, |
667 | |
668 | { |
669 | .tuner_type = TUNER_TYPE_UNKNOWN, |
670 | .tuner_name = "UNKNOWN" , |
671 | .board_name = "VP3021" , |
672 | .fw_name = "DTTFTA" |
673 | }, |
674 | |
675 | { |
676 | .tuner_type = TUNER_TYPE_TDA10046, |
677 | .tuner_name = "TDA10046" , |
678 | .board_name = "VP3040" , |
679 | .fw_name = "DTT-CI" |
680 | }, |
681 | |
682 | { |
683 | .tuner_type = TUNER_TYPE_UNKNOWN, |
684 | .tuner_name = "UNKNOWN" , |
685 | .board_name = "VP3051" , |
686 | .fw_name = "DTTNXT" |
687 | }, |
688 | |
689 | { |
690 | .tuner_type = TUNER_TYPE_NXT200x, |
691 | .tuner_name = "NXT200x" , |
692 | .board_name = "VP3220" , |
693 | .fw_name = "ATSCDI" |
694 | }, |
695 | |
696 | { |
697 | .tuner_type = TUNER_TYPE_NXT200x, |
698 | .tuner_name = "NXT200x" , |
699 | .board_name = "VP3250" , |
700 | .fw_name = "ATSCAD" |
701 | }, |
702 | }; |
703 | |
704 | /* |
705 | Known cards list |
706 | Satellite |
707 | ------------------- |
708 | 200103A |
709 | VP-1020 DST-MOT LG(old), TS=188 |
710 | |
711 | VP-1020 DST-03T LG(new), TS=204 |
712 | VP-1022 DST-03T LG(new), TS=204 |
713 | VP-1025 DST-03T LG(new), TS=204 |
714 | |
715 | VP-1030 DSTMCI, LG(new), TS=188 |
716 | VP-1032 DSTMCI, LG(new), TS=188 |
717 | |
718 | Cable |
719 | ------------------- |
720 | VP-2030 DCT-CI, Samsung, TS=204 |
721 | VP-2021 DCT-CI, Unknown, TS=204 |
722 | VP-2031 DCT-CI, Philips, TS=188 |
723 | VP-2040 DCT-CI, Philips, TS=188, with CA daughter board |
724 | VP-2040 DCT-CI, Philips, TS=204, without CA daughter board |
725 | |
726 | Terrestrial |
727 | ------------------- |
728 | VP-3050 DTTNXT TS=188 |
729 | VP-3040 DTT-CI, Philips, TS=188 |
730 | VP-3040 DTT-CI, Philips, TS=204 |
731 | |
732 | ATSC |
733 | ------------------- |
734 | VP-3220 ATSCDI, TS=188 |
735 | VP-3250 ATSCAD, TS=188 |
736 | |
737 | */ |
738 | |
739 | static struct dst_types dst_tlist[] = { |
740 | { |
741 | .device_id = "200103A" , |
742 | .offset = 0, |
743 | .dst_type = DST_TYPE_IS_SAT, |
744 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS, |
745 | .dst_feature = 0, |
746 | .tuner_type = 0 |
747 | }, /* obsolete */ |
748 | |
749 | { |
750 | .device_id = "DST-020" , |
751 | .offset = 0, |
752 | .dst_type = DST_TYPE_IS_SAT, |
753 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, |
754 | .dst_feature = 0, |
755 | .tuner_type = 0 |
756 | }, /* obsolete */ |
757 | |
758 | { |
759 | .device_id = "DST-030" , |
760 | .offset = 0, |
761 | .dst_type = DST_TYPE_IS_SAT, |
762 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, |
763 | .dst_feature = 0, |
764 | .tuner_type = 0 |
765 | }, /* obsolete */ |
766 | |
767 | { |
768 | .device_id = "DST-03T" , |
769 | .offset = 0, |
770 | .dst_type = DST_TYPE_IS_SAT, |
771 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, |
772 | .dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5 |
773 | | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO, |
774 | .tuner_type = TUNER_TYPE_MULTI |
775 | }, |
776 | |
777 | { |
778 | .device_id = "DST-MOT" , |
779 | .offset = 0, |
780 | .dst_type = DST_TYPE_IS_SAT, |
781 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, |
782 | .dst_feature = 0, |
783 | .tuner_type = 0 |
784 | }, /* obsolete */ |
785 | |
786 | { |
787 | .device_id = "DST-CI" , |
788 | .offset = 1, |
789 | .dst_type = DST_TYPE_IS_SAT, |
790 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1, |
791 | .dst_feature = DST_TYPE_HAS_CA, |
792 | .tuner_type = 0 |
793 | }, /* An OEM board */ |
794 | |
795 | { |
796 | .device_id = "DSTMCI" , |
797 | .offset = 1, |
798 | .dst_type = DST_TYPE_IS_SAT, |
799 | .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, |
800 | .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 |
801 | | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC, |
802 | .tuner_type = TUNER_TYPE_MULTI |
803 | }, |
804 | |
805 | { |
806 | .device_id = "DSTFCI" , |
807 | .offset = 1, |
808 | .dst_type = DST_TYPE_IS_SAT, |
809 | .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, |
810 | .dst_feature = 0, |
811 | .tuner_type = 0 |
812 | }, /* unknown to vendor */ |
813 | |
814 | { |
815 | .device_id = "DCT-CI" , |
816 | .offset = 1, |
817 | .dst_type = DST_TYPE_IS_CABLE, |
818 | .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF, |
819 | .dst_feature = DST_TYPE_HAS_CA, |
820 | .tuner_type = 0 |
821 | }, |
822 | |
823 | { |
824 | .device_id = "DCTNEW" , |
825 | .offset = 1, |
826 | .dst_type = DST_TYPE_IS_CABLE, |
827 | .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE, |
828 | .dst_feature = 0, |
829 | .tuner_type = 0 |
830 | }, |
831 | |
832 | { |
833 | .device_id = "DTT-CI" , |
834 | .offset = 1, |
835 | .dst_type = DST_TYPE_IS_TERR, |
836 | .type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF, |
837 | .dst_feature = DST_TYPE_HAS_CA, |
838 | .tuner_type = 0 |
839 | }, |
840 | |
841 | { |
842 | .device_id = "DTTDIG" , |
843 | .offset = 1, |
844 | .dst_type = DST_TYPE_IS_TERR, |
845 | .type_flags = DST_TYPE_HAS_FW_2, |
846 | .dst_feature = 0, |
847 | .tuner_type = 0 |
848 | }, |
849 | |
850 | { |
851 | .device_id = "DTTNXT" , |
852 | .offset = 1, |
853 | .dst_type = DST_TYPE_IS_TERR, |
854 | .type_flags = DST_TYPE_HAS_FW_2, |
855 | .dst_feature = DST_TYPE_HAS_ANALOG, |
856 | .tuner_type = 0 |
857 | }, |
858 | |
859 | { |
860 | .device_id = "ATSCDI" , |
861 | .offset = 1, |
862 | .dst_type = DST_TYPE_IS_ATSC, |
863 | .type_flags = DST_TYPE_HAS_FW_2, |
864 | .dst_feature = 0, |
865 | .tuner_type = 0 |
866 | }, |
867 | |
868 | { |
869 | .device_id = "ATSCAD" , |
870 | .offset = 1, |
871 | .dst_type = DST_TYPE_IS_ATSC, |
872 | .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, |
873 | .dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG, |
874 | .tuner_type = 0 |
875 | }, |
876 | |
877 | { } |
878 | |
879 | }; |
880 | |
881 | static int dst_get_mac(struct dst_state *state) |
882 | { |
883 | u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
884 | get_mac[7] = dst_check_sum(get_mac, 7); |
885 | if (dst_command(state, data: get_mac, len: 8) < 0) { |
886 | dprintk(2, "Unsupported Command\n" ); |
887 | return -1; |
888 | } |
889 | memset(&state->mac_address, '\0', 8); |
890 | memcpy(&state->mac_address, &state->rxbuffer, 6); |
891 | pr_err("MAC Address=[%pM]\n" , state->mac_address); |
892 | |
893 | return 0; |
894 | } |
895 | |
896 | static int dst_fw_ver(struct dst_state *state) |
897 | { |
898 | u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
899 | get_ver[7] = dst_check_sum(get_ver, 7); |
900 | if (dst_command(state, data: get_ver, len: 8) < 0) { |
901 | dprintk(2, "Unsupported Command\n" ); |
902 | return -1; |
903 | } |
904 | memcpy(&state->fw_version, &state->rxbuffer, 8); |
905 | pr_err("Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x\n" , |
906 | state->fw_version[0] >> 4, state->fw_version[0] & 0x0f, |
907 | state->fw_version[1], |
908 | state->fw_version[5], state->fw_version[6], |
909 | state->fw_version[4], state->fw_version[3], state->fw_version[2]); |
910 | |
911 | return 0; |
912 | } |
913 | |
914 | static int dst_card_type(struct dst_state *state) |
915 | { |
916 | int j; |
917 | struct tuner_types *p_tuner_list = NULL; |
918 | |
919 | u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
920 | get_type[7] = dst_check_sum(get_type, 7); |
921 | if (dst_command(state, data: get_type, len: 8) < 0) { |
922 | dprintk(2, "Unsupported Command\n" ); |
923 | return -1; |
924 | } |
925 | memset(&state->card_info, '\0', 8); |
926 | memcpy(&state->card_info, &state->rxbuffer, 7); |
927 | pr_err("Device Model=[%s]\n" , &state->card_info[0]); |
928 | |
929 | for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { |
930 | if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) { |
931 | state->tuner_type = p_tuner_list->tuner_type; |
932 | pr_err("DST has [%s] tuner, tuner type=[%d]\n" , |
933 | p_tuner_list->tuner_name, p_tuner_list->tuner_type); |
934 | } |
935 | } |
936 | |
937 | return 0; |
938 | } |
939 | |
940 | static int dst_get_vendor(struct dst_state *state) |
941 | { |
942 | u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
943 | get_vendor[7] = dst_check_sum(get_vendor, 7); |
944 | if (dst_command(state, data: get_vendor, len: 8) < 0) { |
945 | dprintk(2, "Unsupported Command\n" ); |
946 | return -1; |
947 | } |
948 | memset(&state->vendor, '\0', 8); |
949 | memcpy(&state->vendor, &state->rxbuffer, 7); |
950 | pr_err("Vendor=[%s]\n" , &state->vendor[0]); |
951 | |
952 | return 0; |
953 | } |
954 | |
955 | static void debug_dst_buffer(struct dst_state *state) |
956 | { |
957 | dprintk(3, "%s: [ %*ph ]\n" , __func__, 8, state->rxbuffer); |
958 | } |
959 | |
960 | static int dst_check_stv0299(struct dst_state *state) |
961 | { |
962 | u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
963 | |
964 | check_stv0299[7] = dst_check_sum(check_stv0299, 7); |
965 | if (dst_command(state, data: check_stv0299, len: 8) < 0) { |
966 | pr_err("Cmd=[0x04] failed\n" ); |
967 | return -1; |
968 | } |
969 | debug_dst_buffer(state); |
970 | |
971 | if (memcmp(p: &check_stv0299, q: &state->rxbuffer, size: 8)) { |
972 | pr_err("Found a STV0299 NIM\n" ); |
973 | state->tuner_type = TUNER_TYPE_STV0299; |
974 | return 0; |
975 | } |
976 | |
977 | return -1; |
978 | } |
979 | |
980 | static int dst_check_mb86a15(struct dst_state *state) |
981 | { |
982 | u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
983 | |
984 | check_mb86a15[7] = dst_check_sum(check_mb86a15, 7); |
985 | if (dst_command(state, data: check_mb86a15, len: 8) < 0) { |
986 | pr_err("Cmd=[0x10], failed\n" ); |
987 | return -1; |
988 | } |
989 | debug_dst_buffer(state); |
990 | |
991 | if (memcmp(p: &check_mb86a15, q: &state->rxbuffer, size: 8) < 0) { |
992 | pr_err("Found a MB86A15 NIM\n" ); |
993 | state->tuner_type = TUNER_TYPE_MB86A15; |
994 | return 0; |
995 | } |
996 | |
997 | return -1; |
998 | } |
999 | |
1000 | static int dst_get_tuner_info(struct dst_state *state) |
1001 | { |
1002 | u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
1003 | u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
1004 | |
1005 | get_tuner_1[7] = dst_check_sum(get_tuner_1, 7); |
1006 | get_tuner_2[7] = dst_check_sum(get_tuner_2, 7); |
1007 | pr_err("DST TYpe = MULTI FE\n" ); |
1008 | if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { |
1009 | if (dst_command(state, data: get_tuner_1, len: 8) < 0) { |
1010 | dprintk(2, "Cmd=[0x13], Unsupported\n" ); |
1011 | goto force; |
1012 | } |
1013 | } else { |
1014 | if (dst_command(state, data: get_tuner_2, len: 8) < 0) { |
1015 | dprintk(2, "Cmd=[0xb], Unsupported\n" ); |
1016 | goto force; |
1017 | } |
1018 | } |
1019 | memcpy(&state->board_info, &state->rxbuffer, 8); |
1020 | if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { |
1021 | pr_err("DST type has TS=188\n" ); |
1022 | } |
1023 | if (state->board_info[0] == 0xbc) { |
1024 | if (state->dst_type != DST_TYPE_IS_ATSC) |
1025 | state->type_flags |= DST_TYPE_HAS_TS188; |
1026 | else |
1027 | state->type_flags |= DST_TYPE_HAS_NEWTUNE_2; |
1028 | |
1029 | if (state->board_info[1] == 0x01) { |
1030 | state->dst_hw_cap |= DST_TYPE_HAS_DBOARD; |
1031 | pr_err("DST has Daughterboard\n" ); |
1032 | } |
1033 | } |
1034 | |
1035 | return 0; |
1036 | force: |
1037 | if (!strncmp(state->fw_name, "DCT-CI" , 6)) { |
1038 | state->type_flags |= DST_TYPE_HAS_TS204; |
1039 | pr_err("Forcing [%s] to TS188\n" , state->fw_name); |
1040 | } |
1041 | |
1042 | return -1; |
1043 | } |
1044 | |
1045 | static int dst_get_device_id(struct dst_state *state) |
1046 | { |
1047 | u8 reply; |
1048 | |
1049 | int i, j; |
1050 | struct dst_types *p_dst_type = NULL; |
1051 | struct tuner_types *p_tuner_list = NULL; |
1052 | |
1053 | u8 use_dst_type = 0; |
1054 | u32 use_type_flags = 0; |
1055 | |
1056 | static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; |
1057 | |
1058 | state->tuner_type = 0; |
1059 | device_type[7] = dst_check_sum(device_type, 7); |
1060 | |
1061 | if (write_dst(state, device_type, FIXED_COMM)) |
1062 | return -1; /* Write failed */ |
1063 | if ((dst_pio_disable(state)) < 0) |
1064 | return -1; |
1065 | if (read_dst(state, &reply, GET_ACK)) |
1066 | return -1; /* Read failure */ |
1067 | if (reply != ACK) { |
1068 | dprintk(2, "Write not Acknowledged! [Reply=0x%02x]\n" , reply); |
1069 | return -1; /* Unack'd write */ |
1070 | } |
1071 | if (!dst_wait_dst_ready(state, DEVICE_INIT)) |
1072 | return -1; /* DST not ready yet */ |
1073 | if (read_dst(state, state->rxbuffer, FIXED_COMM)) |
1074 | return -1; |
1075 | |
1076 | dst_pio_disable(state); |
1077 | if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { |
1078 | dprintk(2, "Checksum failure!\n" ); |
1079 | return -1; /* Checksum failure */ |
1080 | } |
1081 | state->rxbuffer[7] = '\0'; |
1082 | |
1083 | for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) { |
1084 | if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) { |
1085 | use_type_flags = p_dst_type->type_flags; |
1086 | use_dst_type = p_dst_type->dst_type; |
1087 | |
1088 | /* Card capabilities */ |
1089 | state->dst_hw_cap = p_dst_type->dst_feature; |
1090 | pr_err("Recognise [%s]\n" , p_dst_type->device_id); |
1091 | strscpy(state->fw_name, p_dst_type->device_id, |
1092 | sizeof(state->fw_name)); |
1093 | /* Multiple tuners */ |
1094 | if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) { |
1095 | switch (use_dst_type) { |
1096 | case DST_TYPE_IS_SAT: |
1097 | /* STV0299 check */ |
1098 | if (dst_check_stv0299(state) < 0) { |
1099 | pr_err("Unsupported\n" ); |
1100 | state->tuner_type = TUNER_TYPE_MB86A15; |
1101 | } |
1102 | break; |
1103 | default: |
1104 | break; |
1105 | } |
1106 | if (dst_check_mb86a15(state) < 0) |
1107 | pr_err("Unsupported\n" ); |
1108 | /* Single tuner */ |
1109 | } else { |
1110 | state->tuner_type = p_dst_type->tuner_type; |
1111 | } |
1112 | for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { |
1113 | if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) && |
1114 | p_tuner_list->tuner_type == state->tuner_type) { |
1115 | pr_err("[%s] has a [%s]\n" , |
1116 | p_dst_type->device_id, p_tuner_list->tuner_name); |
1117 | } |
1118 | } |
1119 | break; |
1120 | } |
1121 | } |
1122 | |
1123 | if (i >= ARRAY_SIZE(dst_tlist)) { |
1124 | pr_err("Unable to recognize %s or %s\n" , &state->rxbuffer[0], &state->rxbuffer[1]); |
1125 | pr_err("please email linux-dvb@linuxtv.org with this type in" ); |
1126 | use_dst_type = DST_TYPE_IS_SAT; |
1127 | use_type_flags = DST_TYPE_HAS_SYMDIV; |
1128 | } |
1129 | dst_type_print(state, type: use_dst_type); |
1130 | state->type_flags = use_type_flags; |
1131 | state->dst_type = use_dst_type; |
1132 | dst_type_flags_print(state); |
1133 | |
1134 | return 0; |
1135 | } |
1136 | |
1137 | static int dst_probe(struct dst_state *state) |
1138 | { |
1139 | mutex_init(&state->dst_mutex); |
1140 | if (dst_addons & DST_TYPE_HAS_CA) { |
1141 | if ((rdc_8820_reset(state)) < 0) { |
1142 | pr_err("RDC 8820 RESET Failed.\n" ); |
1143 | return -1; |
1144 | } |
1145 | msleep(msecs: 4000); |
1146 | } else { |
1147 | msleep(msecs: 100); |
1148 | } |
1149 | if ((dst_comm_init(state)) < 0) { |
1150 | pr_err("DST Initialization Failed.\n" ); |
1151 | return -1; |
1152 | } |
1153 | msleep(msecs: 100); |
1154 | if (dst_get_device_id(state) < 0) { |
1155 | pr_err("unknown device.\n" ); |
1156 | return -1; |
1157 | } |
1158 | if (dst_get_mac(state) < 0) { |
1159 | dprintk(2, "MAC: Unsupported command\n" ); |
1160 | } |
1161 | if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) { |
1162 | if (dst_get_tuner_info(state) < 0) |
1163 | dprintk(2, "Tuner: Unsupported command\n" ); |
1164 | } |
1165 | if (state->type_flags & DST_TYPE_HAS_TS204) { |
1166 | dst_packsize(state, psize: 204); |
1167 | } |
1168 | if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { |
1169 | if (dst_fw_ver(state) < 0) { |
1170 | dprintk(2, "FW: Unsupported command\n" ); |
1171 | return 0; |
1172 | } |
1173 | if (dst_card_type(state) < 0) { |
1174 | dprintk(2, "Card: Unsupported command\n" ); |
1175 | return 0; |
1176 | } |
1177 | if (dst_get_vendor(state) < 0) { |
1178 | dprintk(2, "Vendor: Unsupported command\n" ); |
1179 | return 0; |
1180 | } |
1181 | } |
1182 | |
1183 | return 0; |
1184 | } |
1185 | |
1186 | static int dst_command(struct dst_state *state, u8 *data, u8 len) |
1187 | { |
1188 | u8 reply; |
1189 | |
1190 | mutex_lock(&state->dst_mutex); |
1191 | if ((dst_comm_init(state)) < 0) { |
1192 | dprintk(1, "DST Communication Initialization Failed.\n" ); |
1193 | goto error; |
1194 | } |
1195 | if (write_dst(state, data, len)) { |
1196 | dprintk(2, "Trying to recover..\n" ); |
1197 | if ((dst_error_recovery(state)) < 0) { |
1198 | pr_err("Recovery Failed.\n" ); |
1199 | goto error; |
1200 | } |
1201 | goto error; |
1202 | } |
1203 | if ((dst_pio_disable(state)) < 0) { |
1204 | pr_err("PIO Disable Failed.\n" ); |
1205 | goto error; |
1206 | } |
1207 | if (state->type_flags & DST_TYPE_HAS_FW_1) |
1208 | mdelay(3); |
1209 | if (read_dst(state, &reply, GET_ACK)) { |
1210 | dprintk(3, "Trying to recover..\n" ); |
1211 | if ((dst_error_recovery(state)) < 0) { |
1212 | dprintk(2, "Recovery Failed.\n" ); |
1213 | goto error; |
1214 | } |
1215 | goto error; |
1216 | } |
1217 | if (reply != ACK) { |
1218 | dprintk(2, "write not acknowledged 0x%02x\n" , reply); |
1219 | goto error; |
1220 | } |
1221 | if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) |
1222 | goto error; |
1223 | if (state->type_flags & DST_TYPE_HAS_FW_1) |
1224 | mdelay(3); |
1225 | else |
1226 | udelay(2000); |
1227 | if (!dst_wait_dst_ready(state, NO_DELAY)) |
1228 | goto error; |
1229 | if (read_dst(state, state->rxbuffer, FIXED_COMM)) { |
1230 | dprintk(3, "Trying to recover..\n" ); |
1231 | if ((dst_error_recovery(state)) < 0) { |
1232 | dprintk(2, "Recovery failed.\n" ); |
1233 | goto error; |
1234 | } |
1235 | goto error; |
1236 | } |
1237 | if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { |
1238 | dprintk(2, "checksum failure\n" ); |
1239 | goto error; |
1240 | } |
1241 | mutex_unlock(lock: &state->dst_mutex); |
1242 | return 0; |
1243 | |
1244 | error: |
1245 | mutex_unlock(lock: &state->dst_mutex); |
1246 | return -EIO; |
1247 | |
1248 | } |
1249 | |
1250 | static int dst_get_signal(struct dst_state *state) |
1251 | { |
1252 | int retval; |
1253 | u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; |
1254 | //dprintk("%s: Getting Signal strength and other parameters\n", __func__); |
1255 | if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { |
1256 | state->decode_lock = state->decode_strength = state->decode_snr = 0; |
1257 | return 0; |
1258 | } |
1259 | if (0 == (state->diseq_flags & HAS_LOCK)) { |
1260 | state->decode_lock = state->decode_strength = state->decode_snr = 0; |
1261 | return 0; |
1262 | } |
1263 | if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) { |
1264 | retval = dst_command(state, data: get_signal, len: 8); |
1265 | if (retval < 0) |
1266 | return retval; |
1267 | if (state->dst_type == DST_TYPE_IS_SAT) { |
1268 | state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0; |
1269 | state->decode_strength = state->rxbuffer[5] << 8; |
1270 | state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; |
1271 | } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) { |
1272 | state->decode_lock = (state->rxbuffer[1]) ? 1 : 0; |
1273 | state->decode_strength = state->rxbuffer[4] << 8; |
1274 | state->decode_snr = state->rxbuffer[3] << 8; |
1275 | } else if (state->dst_type == DST_TYPE_IS_ATSC) { |
1276 | state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0; |
1277 | state->decode_strength = state->rxbuffer[4] << 8; |
1278 | state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; |
1279 | } |
1280 | state->cur_jiff = jiffies; |
1281 | } |
1282 | return 0; |
1283 | } |
1284 | |
1285 | static int dst_tone_power_cmd(struct dst_state *state) |
1286 | { |
1287 | u8 packet[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; |
1288 | |
1289 | if (state->dst_type != DST_TYPE_IS_SAT) |
1290 | return -EOPNOTSUPP; |
1291 | packet[4] = state->tx_tuna[4]; |
1292 | packet[2] = state->tx_tuna[2]; |
1293 | packet[3] = state->tx_tuna[3]; |
1294 | packet[7] = dst_check_sum (packet, 7); |
1295 | return dst_command(state, data: packet, len: 8); |
1296 | } |
1297 | |
1298 | static int dst_get_tuna(struct dst_state *state) |
1299 | { |
1300 | int retval; |
1301 | |
1302 | if ((state->diseq_flags & ATTEMPT_TUNE) == 0) |
1303 | return 0; |
1304 | state->diseq_flags &= ~(HAS_LOCK); |
1305 | if (!dst_wait_dst_ready(state, NO_DELAY)) |
1306 | return -EIO; |
1307 | if ((state->type_flags & DST_TYPE_HAS_VLF) && |
1308 | !(state->dst_type == DST_TYPE_IS_ATSC)) |
1309 | |
1310 | retval = read_dst(state, state->rx_tuna, 10); |
1311 | else |
1312 | retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); |
1313 | if (retval < 0) { |
1314 | dprintk(3, "read not successful\n" ); |
1315 | return retval; |
1316 | } |
1317 | if ((state->type_flags & DST_TYPE_HAS_VLF) && |
1318 | !(state->dst_type == DST_TYPE_IS_ATSC)) { |
1319 | |
1320 | if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { |
1321 | dprintk(2, "checksum failure ?\n" ); |
1322 | return -EIO; |
1323 | } |
1324 | } else { |
1325 | if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { |
1326 | dprintk(2, "checksum failure?\n" ); |
1327 | return -EIO; |
1328 | } |
1329 | } |
1330 | if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) |
1331 | return 0; |
1332 | if (state->dst_type == DST_TYPE_IS_SAT) { |
1333 | state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; |
1334 | } else { |
1335 | state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4]; |
1336 | } |
1337 | state->decode_freq = state->decode_freq * 1000; |
1338 | state->decode_lock = 1; |
1339 | state->diseq_flags |= HAS_LOCK; |
1340 | |
1341 | return 1; |
1342 | } |
1343 | |
1344 | static int dst_set_voltage(struct dvb_frontend *fe, |
1345 | enum fe_sec_voltage voltage); |
1346 | |
1347 | static int dst_write_tuna(struct dvb_frontend *fe) |
1348 | { |
1349 | struct dst_state *state = fe->demodulator_priv; |
1350 | int retval; |
1351 | u8 reply; |
1352 | |
1353 | dprintk(2, "type_flags 0x%x\n" , state->type_flags); |
1354 | state->decode_freq = 0; |
1355 | state->decode_lock = state->decode_strength = state->decode_snr = 0; |
1356 | if (state->dst_type == DST_TYPE_IS_SAT) { |
1357 | if (!(state->diseq_flags & HAS_POWER)) |
1358 | dst_set_voltage(fe, voltage: SEC_VOLTAGE_13); |
1359 | } |
1360 | state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); |
1361 | mutex_lock(&state->dst_mutex); |
1362 | if ((dst_comm_init(state)) < 0) { |
1363 | dprintk(3, "DST Communication initialization failed.\n" ); |
1364 | goto error; |
1365 | } |
1366 | // if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { |
1367 | if ((state->type_flags & DST_TYPE_HAS_VLF) && |
1368 | (!(state->dst_type == DST_TYPE_IS_ATSC))) { |
1369 | |
1370 | state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); |
1371 | retval = write_dst(state, &state->tx_tuna[0], 10); |
1372 | } else { |
1373 | state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); |
1374 | retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM); |
1375 | } |
1376 | if (retval < 0) { |
1377 | dst_pio_disable(state); |
1378 | dprintk(3, "write not successful\n" ); |
1379 | goto werr; |
1380 | } |
1381 | if ((dst_pio_disable(state)) < 0) { |
1382 | dprintk(3, "DST PIO disable failed !\n" ); |
1383 | goto error; |
1384 | } |
1385 | if ((read_dst(state, &reply, GET_ACK) < 0)) { |
1386 | dprintk(3, "read verify not successful.\n" ); |
1387 | goto error; |
1388 | } |
1389 | if (reply != ACK) { |
1390 | dprintk(3, "write not acknowledged 0x%02x\n" , reply); |
1391 | goto error; |
1392 | } |
1393 | state->diseq_flags |= ATTEMPT_TUNE; |
1394 | retval = dst_get_tuna(state); |
1395 | werr: |
1396 | mutex_unlock(lock: &state->dst_mutex); |
1397 | return retval; |
1398 | |
1399 | error: |
1400 | mutex_unlock(lock: &state->dst_mutex); |
1401 | return -EIO; |
1402 | } |
1403 | |
1404 | /* |
1405 | * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 |
1406 | * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 |
1407 | * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 |
1408 | * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 |
1409 | * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 |
1410 | * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 |
1411 | * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 |
1412 | * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec |
1413 | * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 |
1414 | * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 |
1415 | * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 |
1416 | */ |
1417 | |
1418 | static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) |
1419 | { |
1420 | struct dst_state *state = fe->demodulator_priv; |
1421 | u8 packet[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; |
1422 | |
1423 | if (state->dst_type != DST_TYPE_IS_SAT) |
1424 | return -EOPNOTSUPP; |
1425 | if (cmd->msg_len > 0 && cmd->msg_len < 5) |
1426 | memcpy(&packet[3], cmd->msg, cmd->msg_len); |
1427 | else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5) |
1428 | memcpy(&packet[2], cmd->msg, cmd->msg_len); |
1429 | else |
1430 | return -EINVAL; |
1431 | packet[7] = dst_check_sum(&packet[0], 7); |
1432 | return dst_command(state, data: packet, len: 8); |
1433 | } |
1434 | |
1435 | static int dst_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) |
1436 | { |
1437 | int need_cmd, retval = 0; |
1438 | struct dst_state *state = fe->demodulator_priv; |
1439 | |
1440 | state->voltage = voltage; |
1441 | if (state->dst_type != DST_TYPE_IS_SAT) |
1442 | return -EOPNOTSUPP; |
1443 | |
1444 | need_cmd = 0; |
1445 | |
1446 | switch (voltage) { |
1447 | case SEC_VOLTAGE_13: |
1448 | case SEC_VOLTAGE_18: |
1449 | if ((state->diseq_flags & HAS_POWER) == 0) |
1450 | need_cmd = 1; |
1451 | state->diseq_flags |= HAS_POWER; |
1452 | state->tx_tuna[4] = 0x01; |
1453 | break; |
1454 | case SEC_VOLTAGE_OFF: |
1455 | need_cmd = 1; |
1456 | state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); |
1457 | state->tx_tuna[4] = 0x00; |
1458 | break; |
1459 | default: |
1460 | return -EINVAL; |
1461 | } |
1462 | |
1463 | if (need_cmd) |
1464 | retval = dst_tone_power_cmd(state); |
1465 | |
1466 | return retval; |
1467 | } |
1468 | |
1469 | static int dst_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) |
1470 | { |
1471 | struct dst_state *state = fe->demodulator_priv; |
1472 | |
1473 | state->tone = tone; |
1474 | if (state->dst_type != DST_TYPE_IS_SAT) |
1475 | return -EOPNOTSUPP; |
1476 | |
1477 | switch (tone) { |
1478 | case SEC_TONE_OFF: |
1479 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) |
1480 | state->tx_tuna[2] = 0x00; |
1481 | else |
1482 | state->tx_tuna[2] = 0xff; |
1483 | break; |
1484 | |
1485 | case SEC_TONE_ON: |
1486 | state->tx_tuna[2] = 0x02; |
1487 | break; |
1488 | default: |
1489 | return -EINVAL; |
1490 | } |
1491 | return dst_tone_power_cmd(state); |
1492 | } |
1493 | |
1494 | static int dst_send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd minicmd) |
1495 | { |
1496 | struct dst_state *state = fe->demodulator_priv; |
1497 | |
1498 | if (state->dst_type != DST_TYPE_IS_SAT) |
1499 | return -EOPNOTSUPP; |
1500 | state->minicmd = minicmd; |
1501 | switch (minicmd) { |
1502 | case SEC_MINI_A: |
1503 | state->tx_tuna[3] = 0x02; |
1504 | break; |
1505 | case SEC_MINI_B: |
1506 | state->tx_tuna[3] = 0xff; |
1507 | break; |
1508 | } |
1509 | return dst_tone_power_cmd(state); |
1510 | } |
1511 | |
1512 | |
1513 | static int bt8xx_dst_init(struct dvb_frontend *fe) |
1514 | { |
1515 | struct dst_state *state = fe->demodulator_priv; |
1516 | |
1517 | static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 }; |
1518 | static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 }; |
1519 | static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; |
1520 | static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; |
1521 | static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; |
1522 | static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; |
1523 | static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; |
1524 | |
1525 | state->inversion = INVERSION_OFF; |
1526 | state->voltage = SEC_VOLTAGE_13; |
1527 | state->tone = SEC_TONE_OFF; |
1528 | state->diseq_flags = 0; |
1529 | state->k22 = 0x02; |
1530 | state->bandwidth = 7000000; |
1531 | state->cur_jiff = jiffies; |
1532 | if (state->dst_type == DST_TYPE_IS_SAT) |
1533 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); |
1534 | else if (state->dst_type == DST_TYPE_IS_TERR) |
1535 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); |
1536 | else if (state->dst_type == DST_TYPE_IS_CABLE) |
1537 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); |
1538 | else if (state->dst_type == DST_TYPE_IS_ATSC) |
1539 | memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner)); |
1540 | |
1541 | return 0; |
1542 | } |
1543 | |
1544 | static int dst_read_status(struct dvb_frontend *fe, enum fe_status *status) |
1545 | { |
1546 | struct dst_state *state = fe->demodulator_priv; |
1547 | |
1548 | *status = 0; |
1549 | if (state->diseq_flags & HAS_LOCK) { |
1550 | // dst_get_signal(state); // don't require(?) to ask MCU |
1551 | if (state->decode_lock) |
1552 | *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; |
1553 | } |
1554 | |
1555 | return 0; |
1556 | } |
1557 | |
1558 | static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength) |
1559 | { |
1560 | struct dst_state *state = fe->demodulator_priv; |
1561 | |
1562 | int retval = dst_get_signal(state); |
1563 | *strength = state->decode_strength; |
1564 | |
1565 | return retval; |
1566 | } |
1567 | |
1568 | static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) |
1569 | { |
1570 | struct dst_state *state = fe->demodulator_priv; |
1571 | |
1572 | int retval = dst_get_signal(state); |
1573 | *snr = state->decode_snr; |
1574 | |
1575 | return retval; |
1576 | } |
1577 | |
1578 | static int dst_set_frontend(struct dvb_frontend *fe) |
1579 | { |
1580 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
1581 | int retval = -EINVAL; |
1582 | struct dst_state *state = fe->demodulator_priv; |
1583 | |
1584 | if (p != NULL) { |
1585 | retval = dst_set_freq(state, freq: p->frequency); |
1586 | if(retval != 0) |
1587 | return retval; |
1588 | dprintk(3, "Set Frequency=[%d]\n" , p->frequency); |
1589 | |
1590 | if (state->dst_type == DST_TYPE_IS_SAT) { |
1591 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) |
1592 | dst_set_inversion(state, inversion: p->inversion); |
1593 | dst_set_fec(state, fec: p->fec_inner); |
1594 | dst_set_symbolrate(state, srate: p->symbol_rate); |
1595 | dst_set_polarization(state); |
1596 | dprintk(3, "Set Symbolrate=[%d]\n" , p->symbol_rate); |
1597 | |
1598 | } else if (state->dst_type == DST_TYPE_IS_TERR) |
1599 | dst_set_bandwidth(state, bandwidth: p->bandwidth_hz); |
1600 | else if (state->dst_type == DST_TYPE_IS_CABLE) { |
1601 | dst_set_fec(state, fec: p->fec_inner); |
1602 | dst_set_symbolrate(state, srate: p->symbol_rate); |
1603 | dst_set_modulation(state, modulation: p->modulation); |
1604 | } |
1605 | retval = dst_write_tuna(fe); |
1606 | } |
1607 | |
1608 | return retval; |
1609 | } |
1610 | |
1611 | static int dst_tune_frontend(struct dvb_frontend* fe, |
1612 | bool re_tune, |
1613 | unsigned int mode_flags, |
1614 | unsigned int *delay, |
1615 | enum fe_status *status) |
1616 | { |
1617 | struct dst_state *state = fe->demodulator_priv; |
1618 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
1619 | |
1620 | if (re_tune) { |
1621 | dst_set_freq(state, freq: p->frequency); |
1622 | dprintk(3, "Set Frequency=[%d]\n" , 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, inversion: p->inversion); |
1627 | dst_set_fec(state, fec: p->fec_inner); |
1628 | dst_set_symbolrate(state, srate: p->symbol_rate); |
1629 | dst_set_polarization(state); |
1630 | dprintk(3, "Set Symbolrate=[%d]\n" , p->symbol_rate); |
1631 | |
1632 | } else if (state->dst_type == DST_TYPE_IS_TERR) |
1633 | dst_set_bandwidth(state, bandwidth: p->bandwidth_hz); |
1634 | else if (state->dst_type == DST_TYPE_IS_CABLE) { |
1635 | dst_set_fec(state, fec: p->fec_inner); |
1636 | dst_set_symbolrate(state, srate: p->symbol_rate); |
1637 | dst_set_modulation(state, modulation: p->modulation); |
1638 | } |
1639 | dst_write_tuna(fe); |
1640 | } |
1641 | |
1642 | if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) |
1643 | dst_read_status(fe, status); |
1644 | |
1645 | *delay = HZ/10; |
1646 | return 0; |
1647 | } |
1648 | |
1649 | static enum dvbfe_algo dst_get_tuning_algo(struct dvb_frontend *fe) |
1650 | { |
1651 | return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW; |
1652 | } |
1653 | |
1654 | static int dst_get_frontend(struct dvb_frontend *fe, |
1655 | struct dtv_frontend_properties *p) |
1656 | { |
1657 | struct dst_state *state = fe->demodulator_priv; |
1658 | |
1659 | p->frequency = state->decode_freq; |
1660 | if (state->dst_type == DST_TYPE_IS_SAT) { |
1661 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) |
1662 | p->inversion = state->inversion; |
1663 | p->symbol_rate = state->symbol_rate; |
1664 | p->fec_inner = dst_get_fec(state); |
1665 | } else if (state->dst_type == DST_TYPE_IS_TERR) { |
1666 | p->bandwidth_hz = state->bandwidth; |
1667 | } else if (state->dst_type == DST_TYPE_IS_CABLE) { |
1668 | p->symbol_rate = state->symbol_rate; |
1669 | p->fec_inner = dst_get_fec(state); |
1670 | p->modulation = dst_get_modulation(state); |
1671 | } |
1672 | |
1673 | return 0; |
1674 | } |
1675 | |
1676 | static void bt8xx_dst_release(struct dvb_frontend *fe) |
1677 | { |
1678 | struct dst_state *state = fe->demodulator_priv; |
1679 | if (state->dst_ca) { |
1680 | dvb_unregister_device(dvbdev: state->dst_ca); |
1681 | #ifdef CONFIG_MEDIA_ATTACH |
1682 | symbol_put(dst_ca_attach); |
1683 | #endif |
1684 | } |
1685 | kfree(objp: state); |
1686 | } |
1687 | |
1688 | static const struct dvb_frontend_ops dst_dvbt_ops; |
1689 | static const struct dvb_frontend_ops dst_dvbs_ops; |
1690 | static const struct dvb_frontend_ops dst_dvbc_ops; |
1691 | static const struct dvb_frontend_ops dst_atsc_ops; |
1692 | |
1693 | struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) |
1694 | { |
1695 | /* check if the ASIC is there */ |
1696 | if (dst_probe(state) < 0) { |
1697 | kfree(objp: state); |
1698 | return NULL; |
1699 | } |
1700 | /* determine settings based on type */ |
1701 | /* create dvb_frontend */ |
1702 | switch (state->dst_type) { |
1703 | case DST_TYPE_IS_TERR: |
1704 | memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); |
1705 | break; |
1706 | case DST_TYPE_IS_CABLE: |
1707 | memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); |
1708 | break; |
1709 | case DST_TYPE_IS_SAT: |
1710 | memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); |
1711 | break; |
1712 | case DST_TYPE_IS_ATSC: |
1713 | memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops)); |
1714 | break; |
1715 | default: |
1716 | pr_err("unknown DST type. please report to the LinuxTV.org DVB mailinglist.\n" ); |
1717 | kfree(objp: state); |
1718 | return NULL; |
1719 | } |
1720 | state->frontend.demodulator_priv = state; |
1721 | |
1722 | return state; /* Manu (DST is a card not a frontend) */ |
1723 | } |
1724 | |
1725 | EXPORT_SYMBOL_GPL(dst_attach); |
1726 | |
1727 | static const struct dvb_frontend_ops dst_dvbt_ops = { |
1728 | .delsys = { SYS_DVBT }, |
1729 | .info = { |
1730 | .name = "DST DVB-T" , |
1731 | .frequency_min_hz = 137 * MHz, |
1732 | .frequency_max_hz = 858 * MHz, |
1733 | .frequency_stepsize_hz = 166667, |
1734 | .caps = FE_CAN_FEC_AUTO | |
1735 | FE_CAN_QAM_AUTO | |
1736 | FE_CAN_QAM_16 | |
1737 | FE_CAN_QAM_32 | |
1738 | FE_CAN_QAM_64 | |
1739 | FE_CAN_QAM_128 | |
1740 | FE_CAN_QAM_256 | |
1741 | FE_CAN_TRANSMISSION_MODE_AUTO | |
1742 | FE_CAN_GUARD_INTERVAL_AUTO |
1743 | }, |
1744 | |
1745 | .release = bt8xx_dst_release, |
1746 | .init = bt8xx_dst_init, |
1747 | .tune = dst_tune_frontend, |
1748 | .set_frontend = dst_set_frontend, |
1749 | .get_frontend = dst_get_frontend, |
1750 | .get_frontend_algo = dst_get_tuning_algo, |
1751 | .read_status = dst_read_status, |
1752 | .read_signal_strength = dst_read_signal_strength, |
1753 | .read_snr = dst_read_snr, |
1754 | }; |
1755 | |
1756 | static const struct dvb_frontend_ops dst_dvbs_ops = { |
1757 | .delsys = { SYS_DVBS }, |
1758 | .info = { |
1759 | .name = "DST DVB-S" , |
1760 | .frequency_min_hz = 950 * MHz, |
1761 | .frequency_max_hz = 2150 * MHz, |
1762 | .frequency_stepsize_hz = 1 * MHz, |
1763 | .frequency_tolerance_hz = 29500 * kHz, |
1764 | .symbol_rate_min = 1000000, |
1765 | .symbol_rate_max = 45000000, |
1766 | /* . symbol_rate_tolerance = ???,*/ |
1767 | .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK |
1768 | }, |
1769 | |
1770 | .release = bt8xx_dst_release, |
1771 | .init = bt8xx_dst_init, |
1772 | .tune = dst_tune_frontend, |
1773 | .set_frontend = dst_set_frontend, |
1774 | .get_frontend = dst_get_frontend, |
1775 | .get_frontend_algo = dst_get_tuning_algo, |
1776 | .read_status = dst_read_status, |
1777 | .read_signal_strength = dst_read_signal_strength, |
1778 | .read_snr = dst_read_snr, |
1779 | .diseqc_send_burst = dst_send_burst, |
1780 | .diseqc_send_master_cmd = dst_set_diseqc, |
1781 | .set_voltage = dst_set_voltage, |
1782 | .set_tone = dst_set_tone, |
1783 | }; |
1784 | |
1785 | static const struct dvb_frontend_ops dst_dvbc_ops = { |
1786 | .delsys = { SYS_DVBC_ANNEX_A }, |
1787 | .info = { |
1788 | .name = "DST DVB-C" , |
1789 | .frequency_min_hz = 51 * MHz, |
1790 | .frequency_max_hz = 858 * MHz, |
1791 | .frequency_stepsize_hz = 62500, |
1792 | .symbol_rate_min = 1000000, |
1793 | .symbol_rate_max = 45000000, |
1794 | .caps = FE_CAN_FEC_AUTO | |
1795 | FE_CAN_QAM_AUTO | |
1796 | FE_CAN_QAM_16 | |
1797 | FE_CAN_QAM_32 | |
1798 | FE_CAN_QAM_64 | |
1799 | FE_CAN_QAM_128 | |
1800 | FE_CAN_QAM_256 |
1801 | }, |
1802 | |
1803 | .release = bt8xx_dst_release, |
1804 | .init = bt8xx_dst_init, |
1805 | .tune = dst_tune_frontend, |
1806 | .set_frontend = dst_set_frontend, |
1807 | .get_frontend = dst_get_frontend, |
1808 | .get_frontend_algo = dst_get_tuning_algo, |
1809 | .read_status = dst_read_status, |
1810 | .read_signal_strength = dst_read_signal_strength, |
1811 | .read_snr = dst_read_snr, |
1812 | }; |
1813 | |
1814 | static const struct dvb_frontend_ops dst_atsc_ops = { |
1815 | .delsys = { SYS_ATSC }, |
1816 | .info = { |
1817 | .name = "DST ATSC" , |
1818 | .frequency_min_hz = 510 * MHz, |
1819 | .frequency_max_hz = 858 * MHz, |
1820 | .frequency_stepsize_hz = 62500, |
1821 | .symbol_rate_min = 1000000, |
1822 | .symbol_rate_max = 45000000, |
1823 | .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB |
1824 | }, |
1825 | |
1826 | .release = bt8xx_dst_release, |
1827 | .init = bt8xx_dst_init, |
1828 | .tune = dst_tune_frontend, |
1829 | .set_frontend = dst_set_frontend, |
1830 | .get_frontend = dst_get_frontend, |
1831 | .get_frontend_algo = dst_get_tuning_algo, |
1832 | .read_status = dst_read_status, |
1833 | .read_signal_strength = dst_read_signal_strength, |
1834 | .read_snr = dst_read_snr, |
1835 | }; |
1836 | |
1837 | MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver" ); |
1838 | MODULE_AUTHOR("Jamie Honan, Manu Abraham" ); |
1839 | MODULE_LICENSE("GPL" ); |
1840 | |