]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
50b215a0 JS |
2 | Frontend/Card driver for TwinHan DST Frontend |
3 | Copyright (C) 2003 Jamie Honan | |
4 | Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) | |
1da177e4 | 5 | |
50b215a0 JS |
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. | |
1da177e4 | 10 | |
50b215a0 JS |
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. | |
1da177e4 | 15 | |
50b215a0 JS |
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. | |
1da177e4 LT |
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> | |
1da177e4 LT |
29 | #include "dvb_frontend.h" |
30 | #include "dst_priv.h" | |
50b215a0 JS |
31 | #include "dst_common.h" |
32 | ||
50b215a0 JS |
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 | ||
50b215a0 JS |
37 | static unsigned int dst_addons; |
38 | module_param(dst_addons, int, 0644); | |
4a2cc126 | 39 | MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)"); |
1da177e4 | 40 | |
a427de6f MA |
41 | #define HAS_LOCK 1 |
42 | #define ATTEMPT_TUNE 2 | |
43 | #define HAS_POWER 4 | |
44 | ||
45 | #define DST_ERROR 0 | |
46 | #define DST_NOTICE 1 | |
47 | #define DST_INFO 2 | |
48 | #define DST_DEBUG 3 | |
49 | ||
50 | #define dprintk(x, y, z, format, arg...) do { \ | |
51 | if (z) { \ | |
52 | if ((x > DST_ERROR) && (x > y)) \ | |
53 | printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg); \ | |
54 | else if ((x > DST_NOTICE) && (x > y)) \ | |
55 | printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg); \ | |
56 | else if ((x > DST_INFO) && (x > y)) \ | |
57 | printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg); \ | |
58 | else if ((x > DST_DEBUG) && (x > y)) \ | |
59 | printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg); \ | |
60 | } else { \ | |
61 | if (x > y) \ | |
62 | printk(format, ##arg); \ | |
63 | } \ | |
64 | } while(0) | |
65 | ||
66 | ||
67 | static void dst_packsize(struct dst_state *state, int psize) | |
1da177e4 LT |
68 | { |
69 | union dst_gpio_packet bits; | |
70 | ||
71 | bits.psize = psize; | |
72 | bt878_device_control(state->bt, DST_IG_TS, &bits); | |
73 | } | |
74 | ||
a427de6f | 75 | int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay) |
1da177e4 LT |
76 | { |
77 | union dst_gpio_packet enb; | |
78 | union dst_gpio_packet bits; | |
79 | int err; | |
80 | ||
81 | enb.enb.mask = mask; | |
82 | enb.enb.enable = enbb; | |
50b215a0 | 83 | |
a427de6f | 84 | dprintk(verbose, DST_INFO, 1, "mask=[%04x], enbb=[%04x], outhigh=[%04x]", mask, enbb, outhigh); |
1da177e4 | 85 | if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { |
a427de6f | 86 | dprintk(verbose, DST_INFO, 1, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)", err, mask, enbb); |
1da177e4 LT |
87 | return -EREMOTEIO; |
88 | } | |
8385e46f | 89 | udelay(1000); |
1da177e4 LT |
90 | /* because complete disabling means no output, no need to do output packet */ |
91 | if (enbb == 0) | |
92 | return 0; | |
50b215a0 JS |
93 | if (delay) |
94 | msleep(10); | |
1da177e4 LT |
95 | bits.outp.mask = enbb; |
96 | bits.outp.highvals = outhigh; | |
1da177e4 | 97 | if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { |
a427de6f | 98 | dprintk(verbose, DST_INFO, 1, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)", err, enbb, outhigh); |
1da177e4 LT |
99 | return -EREMOTEIO; |
100 | } | |
a427de6f | 101 | |
1da177e4 LT |
102 | return 0; |
103 | } | |
50b215a0 | 104 | EXPORT_SYMBOL(dst_gpio_outb); |
1da177e4 | 105 | |
a427de6f | 106 | int dst_gpio_inb(struct dst_state *state, u8 *result) |
1da177e4 LT |
107 | { |
108 | union dst_gpio_packet rd_packet; | |
109 | int err; | |
110 | ||
111 | *result = 0; | |
1da177e4 | 112 | if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { |
a427de6f | 113 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)\n", err); |
1da177e4 LT |
114 | return -EREMOTEIO; |
115 | } | |
1da177e4 | 116 | *result = (u8) rd_packet.rd.value; |
a427de6f | 117 | |
1da177e4 LT |
118 | return 0; |
119 | } | |
50b215a0 | 120 | EXPORT_SYMBOL(dst_gpio_inb); |
1da177e4 | 121 | |
50b215a0 | 122 | int rdc_reset_state(struct dst_state *state) |
1da177e4 | 123 | { |
a427de6f | 124 | dprintk(verbose, DST_INFO, 1, "Resetting state machine"); |
50b215a0 | 125 | if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) { |
a427de6f | 126 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); |
50b215a0 JS |
127 | return -1; |
128 | } | |
1da177e4 | 129 | msleep(10); |
50b215a0 | 130 | if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) { |
a427de6f | 131 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); |
50b215a0 JS |
132 | msleep(10); |
133 | return -1; | |
134 | } | |
135 | ||
1da177e4 LT |
136 | return 0; |
137 | } | |
50b215a0 | 138 | EXPORT_SYMBOL(rdc_reset_state); |
1da177e4 | 139 | |
50b215a0 | 140 | int rdc_8820_reset(struct dst_state *state) |
1da177e4 | 141 | { |
a427de6f | 142 | dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); |
50b215a0 | 143 | if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { |
a427de6f | 144 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); |
50b215a0 JS |
145 | return -1; |
146 | } | |
8385e46f | 147 | udelay(1000); |
50b215a0 | 148 | if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { |
a427de6f | 149 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); |
50b215a0 JS |
150 | return -1; |
151 | } | |
152 | ||
1da177e4 LT |
153 | return 0; |
154 | } | |
50b215a0 | 155 | EXPORT_SYMBOL(rdc_8820_reset); |
1da177e4 | 156 | |
50b215a0 | 157 | int dst_pio_enable(struct dst_state *state) |
1da177e4 | 158 | { |
50b215a0 | 159 | if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { |
a427de6f | 160 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); |
50b215a0 JS |
161 | return -1; |
162 | } | |
8385e46f | 163 | udelay(1000); |
a427de6f | 164 | |
50b215a0 JS |
165 | return 0; |
166 | } | |
167 | EXPORT_SYMBOL(dst_pio_enable); | |
168 | ||
169 | int dst_pio_disable(struct dst_state *state) | |
170 | { | |
171 | if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) { | |
a427de6f | 172 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); |
50b215a0 JS |
173 | return -1; |
174 | } | |
8385e46f JS |
175 | if (state->type_flags & DST_TYPE_HAS_FW_1) |
176 | udelay(1000); | |
50b215a0 | 177 | |
1da177e4 LT |
178 | return 0; |
179 | } | |
50b215a0 | 180 | EXPORT_SYMBOL(dst_pio_disable); |
1da177e4 | 181 | |
50b215a0 | 182 | int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) |
1da177e4 LT |
183 | { |
184 | u8 reply; | |
1da177e4 | 185 | int i; |
50b215a0 | 186 | |
1da177e4 | 187 | for (i = 0; i < 200; i++) { |
50b215a0 | 188 | if (dst_gpio_inb(state, &reply) < 0) { |
a427de6f | 189 | dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb ERROR !"); |
50b215a0 JS |
190 | return -1; |
191 | } | |
50b215a0 | 192 | if ((reply & RDC_8820_PIO_0_ENABLE) == 0) { |
a427de6f | 193 | dprintk(verbose, DST_INFO, 1, "dst wait ready after %d", i); |
1da177e4 LT |
194 | return 1; |
195 | } | |
b46dd445 | 196 | msleep(10); |
50b215a0 | 197 | } |
a427de6f | 198 | dprintk(verbose, DST_NOTICE, 1, "dst wait NOT ready after %d", i); |
50b215a0 JS |
199 | |
200 | return 0; | |
201 | } | |
202 | EXPORT_SYMBOL(dst_wait_dst_ready); | |
203 | ||
204 | int dst_error_recovery(struct dst_state *state) | |
205 | { | |
a427de6f | 206 | dprintk(verbose, DST_NOTICE, 1, "Trying to return from previous errors."); |
50b215a0 JS |
207 | dst_pio_disable(state); |
208 | msleep(10); | |
209 | dst_pio_enable(state); | |
210 | msleep(10); | |
211 | ||
212 | return 0; | |
213 | } | |
214 | EXPORT_SYMBOL(dst_error_recovery); | |
215 | ||
216 | int dst_error_bailout(struct dst_state *state) | |
217 | { | |
a427de6f | 218 | dprintk(verbose, DST_INFO, 1, "Trying to bailout from previous error."); |
50b215a0 JS |
219 | rdc_8820_reset(state); |
220 | dst_pio_disable(state); | |
221 | msleep(10); | |
222 | ||
223 | return 0; | |
224 | } | |
225 | EXPORT_SYMBOL(dst_error_bailout); | |
226 | ||
a427de6f | 227 | int dst_comm_init(struct dst_state *state) |
50b215a0 | 228 | { |
a427de6f | 229 | dprintk(verbose, DST_INFO, 1, "Initializing DST."); |
50b215a0 | 230 | if ((dst_pio_enable(state)) < 0) { |
a427de6f | 231 | dprintk(verbose, DST_ERROR, 1, "PIO Enable Failed"); |
50b215a0 JS |
232 | return -1; |
233 | } | |
234 | if ((rdc_reset_state(state)) < 0) { | |
a427de6f | 235 | dprintk(verbose, DST_ERROR, 1, "RDC 8820 State RESET Failed."); |
50b215a0 | 236 | return -1; |
1da177e4 | 237 | } |
8385e46f JS |
238 | if (state->type_flags & DST_TYPE_HAS_FW_1) |
239 | msleep(100); | |
240 | else | |
241 | msleep(5); | |
242 | ||
1da177e4 LT |
243 | return 0; |
244 | } | |
50b215a0 | 245 | EXPORT_SYMBOL(dst_comm_init); |
1da177e4 | 246 | |
50b215a0 | 247 | int write_dst(struct dst_state *state, u8 *data, u8 len) |
1da177e4 LT |
248 | { |
249 | struct i2c_msg msg = { | |
a427de6f MA |
250 | .addr = state->config->demod_address, |
251 | .flags = 0, | |
252 | .buf = data, | |
253 | .len = len | |
1da177e4 | 254 | }; |
50b215a0 | 255 | |
1da177e4 | 256 | int err; |
a427de6f MA |
257 | u8 cnt, i; |
258 | ||
259 | dprintk(verbose, DST_NOTICE, 0, "writing [ "); | |
260 | for (i = 0; i < len; i++) | |
261 | dprintk(verbose, DST_NOTICE, 0, "%02x ", data[i]); | |
262 | dprintk(verbose, DST_NOTICE, 0, "]\n"); | |
263 | ||
50b215a0 | 264 | for (cnt = 0; cnt < 2; cnt++) { |
1da177e4 | 265 | if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { |
a427de6f | 266 | dprintk(verbose, DST_INFO, 1, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, data[0]); |
50b215a0 | 267 | dst_error_recovery(state); |
1da177e4 LT |
268 | continue; |
269 | } else | |
270 | break; | |
271 | } | |
50b215a0 | 272 | if (cnt >= 2) { |
a427de6f | 273 | dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); |
50b215a0 JS |
274 | dst_error_bailout(state); |
275 | ||
276 | return -1; | |
277 | } | |
278 | ||
1da177e4 LT |
279 | return 0; |
280 | } | |
50b215a0 | 281 | EXPORT_SYMBOL(write_dst); |
1da177e4 | 282 | |
a427de6f | 283 | int read_dst(struct dst_state *state, u8 *ret, u8 len) |
1da177e4 | 284 | { |
a427de6f MA |
285 | struct i2c_msg msg = { |
286 | .addr = state->config->demod_address, | |
287 | .flags = I2C_M_RD, | |
288 | .buf = ret, | |
289 | .len = len | |
290 | }; | |
291 | ||
1da177e4 LT |
292 | int err; |
293 | int cnt; | |
294 | ||
50b215a0 | 295 | for (cnt = 0; cnt < 2; cnt++) { |
1da177e4 | 296 | if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { |
a427de6f | 297 | dprintk(verbose, DST_INFO, 1, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, ret[0]); |
50b215a0 | 298 | dst_error_recovery(state); |
1da177e4 LT |
299 | continue; |
300 | } else | |
301 | break; | |
302 | } | |
50b215a0 | 303 | if (cnt >= 2) { |
a427de6f | 304 | dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); |
50b215a0 JS |
305 | dst_error_bailout(state); |
306 | ||
307 | return -1; | |
308 | } | |
a427de6f MA |
309 | dprintk(verbose, DST_DEBUG, 1, "reply is 0x%x", ret[0]); |
310 | for (err = 1; err < len; err++) | |
311 | dprintk(verbose, DST_DEBUG, 0, " 0x%x", ret[err]); | |
312 | if (err > 1) | |
313 | dprintk(verbose, DST_DEBUG, 0, "\n"); | |
50b215a0 | 314 | |
1da177e4 LT |
315 | return 0; |
316 | } | |
50b215a0 | 317 | EXPORT_SYMBOL(read_dst); |
1da177e4 | 318 | |
7d53421c | 319 | static int dst_set_polarization(struct dst_state *state) |
1da177e4 | 320 | { |
7d53421c | 321 | switch (state->voltage) { |
a427de6f MA |
322 | case SEC_VOLTAGE_13: /* Vertical */ |
323 | dprintk(verbose, DST_INFO, 1, "Polarization=[Vertical]"); | |
324 | state->tx_tuna[8] &= ~0x40; | |
325 | break; | |
326 | case SEC_VOLTAGE_18: /* Horizontal */ | |
327 | dprintk(verbose, DST_INFO, 1, "Polarization=[Horizontal]"); | |
328 | state->tx_tuna[8] |= 0x40; | |
329 | break; | |
330 | case SEC_VOLTAGE_OFF: | |
331 | break; | |
7d53421c MA |
332 | } |
333 | ||
334 | return 0; | |
335 | } | |
336 | ||
337 | static int dst_set_freq(struct dst_state *state, u32 freq) | |
338 | { | |
1da177e4 | 339 | state->frequency = freq; |
a427de6f | 340 | dprintk(verbose, DST_INFO, 1, "set Frequency %u", freq); |
1da177e4 | 341 | |
1da177e4 LT |
342 | if (state->dst_type == DST_TYPE_IS_SAT) { |
343 | freq = freq / 1000; | |
344 | if (freq < 950 || freq > 2150) | |
345 | return -EINVAL; | |
7d53421c MA |
346 | state->tx_tuna[2] = (freq >> 8); |
347 | state->tx_tuna[3] = (u8) freq; | |
348 | state->tx_tuna[4] = 0x01; | |
349 | state->tx_tuna[8] &= ~0x04; | |
350 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { | |
351 | if (freq < 1531) | |
352 | state->tx_tuna[8] |= 0x04; | |
353 | } | |
1da177e4 LT |
354 | } else if (state->dst_type == DST_TYPE_IS_TERR) { |
355 | freq = freq / 1000; | |
356 | if (freq < 137000 || freq > 858000) | |
357 | return -EINVAL; | |
7d53421c MA |
358 | state->tx_tuna[2] = (freq >> 16) & 0xff; |
359 | state->tx_tuna[3] = (freq >> 8) & 0xff; | |
360 | state->tx_tuna[4] = (u8) freq; | |
1da177e4 | 361 | } else if (state->dst_type == DST_TYPE_IS_CABLE) { |
62867429 | 362 | freq = freq / 1000; |
7d53421c MA |
363 | state->tx_tuna[2] = (freq >> 16) & 0xff; |
364 | state->tx_tuna[3] = (freq >> 8) & 0xff; | |
365 | state->tx_tuna[4] = (u8) freq; | |
1da177e4 LT |
366 | } else |
367 | return -EINVAL; | |
a427de6f | 368 | |
1da177e4 LT |
369 | return 0; |
370 | } | |
371 | ||
a427de6f | 372 | static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) |
1da177e4 | 373 | { |
1da177e4 LT |
374 | state->bandwidth = bandwidth; |
375 | ||
376 | if (state->dst_type != DST_TYPE_IS_TERR) | |
377 | return 0; | |
378 | ||
1da177e4 | 379 | switch (bandwidth) { |
a427de6f MA |
380 | case BANDWIDTH_6_MHZ: |
381 | if (state->dst_hw_cap & DST_TYPE_HAS_CA) | |
382 | state->tx_tuna[7] = 0x06; | |
383 | else { | |
384 | state->tx_tuna[6] = 0x06; | |
385 | state->tx_tuna[7] = 0x00; | |
386 | } | |
387 | break; | |
388 | case BANDWIDTH_7_MHZ: | |
389 | if (state->dst_hw_cap & DST_TYPE_HAS_CA) | |
390 | state->tx_tuna[7] = 0x07; | |
391 | else { | |
392 | state->tx_tuna[6] = 0x07; | |
393 | state->tx_tuna[7] = 0x00; | |
394 | } | |
395 | break; | |
396 | case BANDWIDTH_8_MHZ: | |
397 | if (state->dst_hw_cap & DST_TYPE_HAS_CA) | |
398 | state->tx_tuna[7] = 0x08; | |
399 | else { | |
400 | state->tx_tuna[6] = 0x08; | |
401 | state->tx_tuna[7] = 0x00; | |
402 | } | |
403 | break; | |
404 | default: | |
405 | return -EINVAL; | |
1da177e4 | 406 | } |
a427de6f | 407 | |
1da177e4 LT |
408 | return 0; |
409 | } | |
410 | ||
a427de6f | 411 | static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion) |
1da177e4 | 412 | { |
1da177e4 | 413 | state->inversion = inversion; |
1da177e4 | 414 | switch (inversion) { |
a427de6f MA |
415 | case INVERSION_OFF: /* Inversion = Normal */ |
416 | state->tx_tuna[8] &= ~0x80; | |
417 | break; | |
418 | case INVERSION_ON: | |
419 | state->tx_tuna[8] |= 0x80; | |
420 | break; | |
421 | default: | |
422 | return -EINVAL; | |
1da177e4 | 423 | } |
a427de6f | 424 | |
1da177e4 LT |
425 | return 0; |
426 | } | |
427 | ||
a427de6f | 428 | static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec) |
1da177e4 LT |
429 | { |
430 | state->fec = fec; | |
431 | return 0; | |
432 | } | |
433 | ||
a427de6f | 434 | static fe_code_rate_t dst_get_fec(struct dst_state *state) |
1da177e4 LT |
435 | { |
436 | return state->fec; | |
437 | } | |
438 | ||
a427de6f | 439 | static int dst_set_symbolrate(struct dst_state *state, u32 srate) |
1da177e4 | 440 | { |
1da177e4 LT |
441 | u32 symcalc; |
442 | u64 sval; | |
443 | ||
444 | state->symbol_rate = srate; | |
1da177e4 LT |
445 | if (state->dst_type == DST_TYPE_IS_TERR) { |
446 | return 0; | |
447 | } | |
a427de6f | 448 | dprintk(verbose, DST_INFO, 1, "set symrate %u", srate); |
1da177e4 | 449 | srate /= 1000; |
1da177e4 LT |
450 | if (state->type_flags & DST_TYPE_HAS_SYMDIV) { |
451 | sval = srate; | |
452 | sval <<= 20; | |
453 | do_div(sval, 88000); | |
454 | symcalc = (u32) sval; | |
a427de6f | 455 | dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc); |
f612c579 MA |
456 | state->tx_tuna[5] = (u8) (symcalc >> 12); |
457 | state->tx_tuna[6] = (u8) (symcalc >> 4); | |
458 | state->tx_tuna[7] = (u8) (symcalc << 4); | |
1da177e4 | 459 | } else { |
f612c579 MA |
460 | state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f; |
461 | state->tx_tuna[6] = (u8) (srate >> 8); | |
462 | state->tx_tuna[7] = (u8) srate; | |
463 | } | |
464 | state->tx_tuna[8] &= ~0x20; | |
465 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { | |
466 | if (srate > 8000) | |
467 | state->tx_tuna[8] |= 0x20; | |
1da177e4 | 468 | } |
1da177e4 LT |
469 | return 0; |
470 | } | |
471 | ||
7d53421c MA |
472 | |
473 | static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) | |
474 | { | |
475 | if (state->dst_type != DST_TYPE_IS_CABLE) | |
476 | return 0; | |
477 | ||
478 | state->modulation = modulation; | |
479 | switch (modulation) { | |
a427de6f MA |
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 | state->tx_tuna[8] = 0x00; | |
494 | break; | |
495 | case QPSK: | |
496 | case QAM_AUTO: | |
497 | case VSB_8: | |
498 | case VSB_16: | |
499 | default: | |
500 | return -EINVAL; | |
7d53421c MA |
501 | |
502 | } | |
503 | ||
504 | return 0; | |
505 | } | |
506 | ||
507 | static fe_modulation_t dst_get_modulation(struct dst_state *state) | |
508 | { | |
509 | return state->modulation; | |
510 | } | |
511 | ||
512 | ||
a427de6f | 513 | u8 dst_check_sum(u8 *buf, u32 len) |
1da177e4 LT |
514 | { |
515 | u32 i; | |
516 | u8 val = 0; | |
517 | if (!len) | |
518 | return 0; | |
519 | for (i = 0; i < len; i++) { | |
520 | val += buf[i]; | |
521 | } | |
522 | return ((~val) + 1); | |
523 | } | |
50b215a0 | 524 | EXPORT_SYMBOL(dst_check_sum); |
1da177e4 LT |
525 | |
526 | static void dst_type_flags_print(u32 type_flags) | |
527 | { | |
a427de6f | 528 | dprintk(verbose, DST_ERROR, 0, "DST type flags :"); |
1da177e4 | 529 | if (type_flags & DST_TYPE_HAS_NEWTUNE) |
a427de6f | 530 | dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_NEWTUNE); |
1da177e4 | 531 | if (type_flags & DST_TYPE_HAS_TS204) |
a427de6f | 532 | dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204); |
1da177e4 | 533 | if (type_flags & DST_TYPE_HAS_SYMDIV) |
a427de6f | 534 | dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV); |
50b215a0 | 535 | if (type_flags & DST_TYPE_HAS_FW_1) |
a427de6f | 536 | dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); |
50b215a0 | 537 | if (type_flags & DST_TYPE_HAS_FW_2) |
a427de6f | 538 | dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); |
50b215a0 | 539 | if (type_flags & DST_TYPE_HAS_FW_3) |
a427de6f MA |
540 | dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); |
541 | dprintk(verbose, DST_ERROR, 0, "\n"); | |
1da177e4 LT |
542 | } |
543 | ||
50b215a0 | 544 | |
a427de6f | 545 | static int dst_type_print(u8 type) |
1da177e4 LT |
546 | { |
547 | char *otype; | |
548 | switch (type) { | |
549 | case DST_TYPE_IS_SAT: | |
550 | otype = "satellite"; | |
551 | break; | |
50b215a0 | 552 | |
1da177e4 LT |
553 | case DST_TYPE_IS_TERR: |
554 | otype = "terrestrial"; | |
555 | break; | |
50b215a0 | 556 | |
1da177e4 LT |
557 | case DST_TYPE_IS_CABLE: |
558 | otype = "cable"; | |
559 | break; | |
50b215a0 | 560 | |
bc7386ba MA |
561 | case DST_TYPE_IS_ATSC: |
562 | otype = "atsc"; | |
563 | break; | |
564 | ||
1da177e4 | 565 | default: |
a427de6f | 566 | dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type); |
1da177e4 LT |
567 | return -EINVAL; |
568 | } | |
a427de6f | 569 | dprintk(verbose, DST_INFO, 1, "DST type: %s", otype); |
50b215a0 | 570 | |
1da177e4 LT |
571 | return 0; |
572 | } | |
573 | ||
50b215a0 JS |
574 | /* |
575 | Known cards list | |
576 | Satellite | |
577 | ------------------- | |
e6ac699a | 578 | 200103A |
50b215a0 JS |
579 | VP-1020 DST-MOT LG(old), TS=188 |
580 | ||
581 | VP-1020 DST-03T LG(new), TS=204 | |
582 | VP-1022 DST-03T LG(new), TS=204 | |
583 | VP-1025 DST-03T LG(new), TS=204 | |
584 | ||
585 | VP-1030 DSTMCI, LG(new), TS=188 | |
586 | VP-1032 DSTMCI, LG(new), TS=188 | |
587 | ||
588 | Cable | |
589 | ------------------- | |
590 | VP-2030 DCT-CI, Samsung, TS=204 | |
591 | VP-2021 DCT-CI, Unknown, TS=204 | |
592 | VP-2031 DCT-CI, Philips, TS=188 | |
593 | VP-2040 DCT-CI, Philips, TS=188, with CA daughter board | |
594 | VP-2040 DCT-CI, Philips, TS=204, without CA daughter board | |
595 | ||
596 | Terrestrial | |
597 | ------------------- | |
598 | VP-3050 DTTNXT TS=188 | |
599 | VP-3040 DTT-CI, Philips, TS=188 | |
600 | VP-3040 DTT-CI, Philips, TS=204 | |
601 | ||
602 | ATSC | |
603 | ------------------- | |
604 | VP-3220 ATSCDI, TS=188 | |
605 | VP-3250 ATSCAD, TS=188 | |
606 | ||
607 | */ | |
608 | ||
47a9e50e | 609 | static struct dst_types dst_tlist[] = { |
e6ac699a JS |
610 | { |
611 | .device_id = "200103A", | |
612 | .offset = 0, | |
613 | .dst_type = DST_TYPE_IS_SAT, | |
7d53421c | 614 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS, |
e6ac699a JS |
615 | .dst_feature = 0 |
616 | }, /* obsolete */ | |
617 | ||
50b215a0 JS |
618 | { |
619 | .device_id = "DST-020", | |
620 | .offset = 0, | |
621 | .dst_type = DST_TYPE_IS_SAT, | |
622 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, | |
623 | .dst_feature = 0 | |
624 | }, /* obsolete */ | |
625 | ||
626 | { | |
627 | .device_id = "DST-030", | |
628 | .offset = 0, | |
629 | .dst_type = DST_TYPE_IS_SAT, | |
630 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, | |
631 | .dst_feature = 0 | |
632 | }, /* obsolete */ | |
633 | ||
634 | { | |
635 | .device_id = "DST-03T", | |
636 | .offset = 0, | |
637 | .dst_type = DST_TYPE_IS_SAT, | |
638 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, | |
639 | .dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5 | |
640 | | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO | |
641 | }, | |
642 | ||
643 | { | |
644 | .device_id = "DST-MOT", | |
645 | .offset = 0, | |
646 | .dst_type = DST_TYPE_IS_SAT, | |
647 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, | |
648 | .dst_feature = 0 | |
649 | }, /* obsolete */ | |
650 | ||
651 | { | |
652 | .device_id = "DST-CI", | |
653 | .offset = 1, | |
654 | .dst_type = DST_TYPE_IS_SAT, | |
655 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, | |
656 | .dst_feature = DST_TYPE_HAS_CA | |
8385e46f | 657 | }, /* An OEM board */ |
50b215a0 JS |
658 | |
659 | { | |
660 | .device_id = "DSTMCI", | |
661 | .offset = 1, | |
662 | .dst_type = DST_TYPE_IS_SAT, | |
7d53421c | 663 | .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT, |
50b215a0 JS |
664 | .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 |
665 | | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC | |
666 | }, | |
667 | ||
668 | { | |
669 | .device_id = "DSTFCI", | |
670 | .offset = 1, | |
671 | .dst_type = DST_TYPE_IS_SAT, | |
672 | .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, | |
673 | .dst_feature = 0 | |
674 | }, /* unknown to vendor */ | |
675 | ||
676 | { | |
677 | .device_id = "DCT-CI", | |
678 | .offset = 1, | |
679 | .dst_type = DST_TYPE_IS_CABLE, | |
8385e46f | 680 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1 |
62121b1f | 681 | | DST_TYPE_HAS_FW_2, |
50b215a0 JS |
682 | .dst_feature = DST_TYPE_HAS_CA |
683 | }, | |
684 | ||
685 | { | |
686 | .device_id = "DCTNEW", | |
687 | .offset = 1, | |
688 | .dst_type = DST_TYPE_IS_CABLE, | |
62121b1f | 689 | .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD, |
50b215a0 JS |
690 | .dst_feature = 0 |
691 | }, | |
692 | ||
693 | { | |
694 | .device_id = "DTT-CI", | |
695 | .offset = 1, | |
696 | .dst_type = DST_TYPE_IS_TERR, | |
29b2f784 MA |
697 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE, |
698 | .dst_feature = DST_TYPE_HAS_CA | |
50b215a0 JS |
699 | }, |
700 | ||
701 | { | |
702 | .device_id = "DTTDIG", | |
703 | .offset = 1, | |
704 | .dst_type = DST_TYPE_IS_TERR, | |
705 | .type_flags = DST_TYPE_HAS_FW_2, | |
706 | .dst_feature = 0 | |
707 | }, | |
708 | ||
709 | { | |
710 | .device_id = "DTTNXT", | |
711 | .offset = 1, | |
712 | .dst_type = DST_TYPE_IS_TERR, | |
713 | .type_flags = DST_TYPE_HAS_FW_2, | |
714 | .dst_feature = DST_TYPE_HAS_ANALOG | |
715 | }, | |
716 | ||
717 | { | |
718 | .device_id = "ATSCDI", | |
719 | .offset = 1, | |
720 | .dst_type = DST_TYPE_IS_ATSC, | |
721 | .type_flags = DST_TYPE_HAS_FW_2, | |
722 | .dst_feature = 0 | |
723 | }, | |
724 | ||
725 | { | |
726 | .device_id = "ATSCAD", | |
727 | .offset = 1, | |
728 | .dst_type = DST_TYPE_IS_ATSC, | |
729 | .type_flags = DST_TYPE_HAS_FW_2, | |
730 | .dst_feature = 0 | |
731 | }, | |
732 | ||
733 | { } | |
734 | ||
735 | }; | |
736 | ||
62121b1f MA |
737 | static int dst_get_mac(struct dst_state *state) |
738 | { | |
739 | u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
740 | get_mac[7] = dst_check_sum(get_mac, 7); | |
741 | if (dst_command(state, get_mac, 8) < 0) { | |
742 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
743 | return -1; | |
744 | } | |
745 | memset(&state->mac_address, '\0', 8); | |
746 | memcpy(&state->mac_address, &state->rxbuffer, 6); | |
747 | dprintk(verbose, DST_ERROR, 1, "MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]", | |
748 | state->mac_address[0], state->mac_address[1], state->mac_address[2], | |
749 | state->mac_address[4], state->mac_address[5], state->mac_address[6]); | |
750 | ||
751 | return 0; | |
752 | } | |
753 | ||
754 | static int dst_fw_ver(struct dst_state *state) | |
755 | { | |
756 | u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
757 | get_ver[7] = dst_check_sum(get_ver, 7); | |
758 | if (dst_command(state, get_ver, 8) < 0) { | |
759 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
760 | return -1; | |
761 | } | |
762 | memset(&state->fw_version, '\0', 8); | |
763 | memcpy(&state->fw_version, &state->rxbuffer, 8); | |
764 | dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x", | |
765 | state->fw_version[0] >> 4, state->fw_version[0] & 0x0f, | |
766 | state->fw_version[1], | |
767 | state->fw_version[5], state->fw_version[6], | |
768 | state->fw_version[4], state->fw_version[3], state->fw_version[2]); | |
769 | ||
770 | return 0; | |
771 | } | |
772 | ||
773 | static int dst_card_type(struct dst_state *state) | |
774 | { | |
775 | u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
776 | get_type[7] = dst_check_sum(get_type, 7); | |
777 | if (dst_command(state, get_type, 8) < 0) { | |
778 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
779 | return -1; | |
780 | } | |
781 | memset(&state->card_info, '\0', 8); | |
782 | memcpy(&state->card_info, &state->rxbuffer, 8); | |
783 | dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]); | |
784 | ||
785 | return 0; | |
786 | } | |
787 | ||
788 | static int dst_get_vendor(struct dst_state *state) | |
789 | { | |
790 | u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
791 | get_vendor[7] = dst_check_sum(get_vendor, 7); | |
792 | if (dst_command(state, get_vendor, 8) < 0) { | |
793 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
794 | return -1; | |
795 | } | |
796 | memset(&state->vendor, '\0', 8); | |
797 | memcpy(&state->vendor, &state->rxbuffer, 8); | |
798 | dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]); | |
799 | ||
800 | return 0; | |
801 | } | |
50b215a0 | 802 | |
29b2f784 MA |
803 | static int dst_get_tuner_info(struct dst_state *state) |
804 | { | |
805 | u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
806 | u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
807 | ||
808 | get_tuner_1[7] = dst_check_sum(get_tuner_1, 7); | |
809 | get_tuner_2[7] = dst_check_sum(get_tuner_2, 7); | |
810 | if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { | |
811 | if (dst_command(state, get_tuner_2, 8) < 0) { | |
812 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
813 | return -1; | |
814 | } | |
815 | } else { | |
816 | if (dst_command(state, get_tuner_1, 8) < 0) { | |
817 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
818 | return -1; | |
819 | } | |
820 | } | |
821 | memset(&state->board_info, '\0', 8); | |
822 | memcpy(&state->board_info, &state->rxbuffer, 8); | |
823 | if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { | |
824 | if (state->board_info[1] == 0x0b) { | |
825 | if (state->type_flags & DST_TYPE_HAS_TS204) | |
826 | state->type_flags &= ~DST_TYPE_HAS_TS204; | |
827 | state->type_flags |= DST_TYPE_HAS_NEWTUNE; | |
828 | dprintk(verbose, DST_INFO, 1, "DST type has TS=188"); | |
829 | } else { | |
830 | if (state->type_flags & DST_TYPE_HAS_NEWTUNE) | |
831 | state->type_flags &= ~DST_TYPE_HAS_NEWTUNE; | |
832 | state->type_flags |= DST_TYPE_HAS_TS204; | |
833 | dprintk(verbose, DST_INFO, 1, "DST type has TS=204"); | |
834 | } | |
835 | } else { | |
836 | if (state->board_info[0] == 0xbc) { | |
837 | if (state->type_flags & DST_TYPE_HAS_TS204) | |
838 | state->type_flags &= ~DST_TYPE_HAS_TS204; | |
839 | state->type_flags |= DST_TYPE_HAS_NEWTUNE; | |
840 | dprintk(verbose, DST_INFO, 1, "DST type has TS=188, Daughterboard=[%d]", state->board_info[1]); | |
841 | ||
842 | } else if (state->board_info[0] == 0xcc) { | |
843 | if (state->type_flags & DST_TYPE_HAS_NEWTUNE) | |
844 | state->type_flags &= ~DST_TYPE_HAS_NEWTUNE; | |
845 | state->type_flags |= DST_TYPE_HAS_TS204; | |
846 | dprintk(verbose, DST_INFO, 1, "DST type has TS=204 Daughterboard=[%d]", state->board_info[1]); | |
847 | } | |
848 | } | |
849 | ||
850 | return 0; | |
851 | } | |
852 | ||
50b215a0 | 853 | static int dst_get_device_id(struct dst_state *state) |
1da177e4 | 854 | { |
50b215a0 JS |
855 | u8 reply; |
856 | ||
1da177e4 | 857 | int i; |
50b215a0 JS |
858 | struct dst_types *p_dst_type; |
859 | u8 use_dst_type = 0; | |
860 | u32 use_type_flags = 0; | |
1da177e4 | 861 | |
50b215a0 | 862 | static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; |
1da177e4 | 863 | |
50b215a0 JS |
864 | device_type[7] = dst_check_sum(device_type, 7); |
865 | ||
866 | if (write_dst(state, device_type, FIXED_COMM)) | |
867 | return -1; /* Write failed */ | |
50b215a0 JS |
868 | if ((dst_pio_disable(state)) < 0) |
869 | return -1; | |
50b215a0 JS |
870 | if (read_dst(state, &reply, GET_ACK)) |
871 | return -1; /* Read failure */ | |
50b215a0 | 872 | if (reply != ACK) { |
a427de6f | 873 | dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply); |
50b215a0 | 874 | return -1; /* Unack'd write */ |
1da177e4 | 875 | } |
50b215a0 JS |
876 | if (!dst_wait_dst_ready(state, DEVICE_INIT)) |
877 | return -1; /* DST not ready yet */ | |
50b215a0 JS |
878 | if (read_dst(state, state->rxbuffer, FIXED_COMM)) |
879 | return -1; | |
880 | ||
881 | dst_pio_disable(state); | |
50b215a0 | 882 | if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { |
a427de6f | 883 | dprintk(verbose, DST_INFO, 1, "Checksum failure!"); |
50b215a0 | 884 | return -1; /* Checksum failure */ |
1da177e4 | 885 | } |
50b215a0 JS |
886 | state->rxbuffer[7] = '\0'; |
887 | ||
a427de6f | 888 | for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) { |
50b215a0 JS |
889 | if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) { |
890 | use_type_flags = p_dst_type->type_flags; | |
891 | use_dst_type = p_dst_type->dst_type; | |
892 | ||
893 | /* Card capabilities */ | |
894 | state->dst_hw_cap = p_dst_type->dst_feature; | |
a427de6f | 895 | dprintk(verbose, DST_ERROR, 1, "Recognise [%s]\n", p_dst_type->device_id); |
50b215a0 | 896 | |
1da177e4 LT |
897 | break; |
898 | } | |
899 | } | |
50b215a0 JS |
900 | |
901 | if (i >= sizeof (dst_tlist) / sizeof (dst_tlist [0])) { | |
a427de6f MA |
902 | dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]); |
903 | dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in"); | |
1da177e4 LT |
904 | use_dst_type = DST_TYPE_IS_SAT; |
905 | use_type_flags = DST_TYPE_HAS_SYMDIV; | |
906 | } | |
50b215a0 | 907 | dst_type_print(use_dst_type); |
1da177e4 LT |
908 | state->type_flags = use_type_flags; |
909 | state->dst_type = use_dst_type; | |
910 | dst_type_flags_print(state->type_flags); | |
911 | ||
1da177e4 LT |
912 | return 0; |
913 | } | |
914 | ||
50b215a0 JS |
915 | static int dst_probe(struct dst_state *state) |
916 | { | |
3593cab5 | 917 | mutex_init(&state->dst_mutex); |
50b215a0 | 918 | if ((rdc_8820_reset(state)) < 0) { |
a427de6f | 919 | dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); |
50b215a0 JS |
920 | return -1; |
921 | } | |
4a2cc126 JS |
922 | if (dst_addons & DST_TYPE_HAS_CA) |
923 | msleep(4000); | |
924 | else | |
925 | msleep(100); | |
926 | ||
50b215a0 | 927 | if ((dst_comm_init(state)) < 0) { |
a427de6f | 928 | dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed."); |
50b215a0 JS |
929 | return -1; |
930 | } | |
8385e46f | 931 | msleep(100); |
50b215a0 | 932 | if (dst_get_device_id(state) < 0) { |
a427de6f | 933 | dprintk(verbose, DST_ERROR, 1, "unknown device."); |
50b215a0 JS |
934 | return -1; |
935 | } | |
62121b1f MA |
936 | if (dst_get_mac(state) < 0) { |
937 | dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); | |
938 | return 0; | |
939 | } | |
29b2f784 MA |
940 | if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) { |
941 | if (dst_get_tuner_info(state) < 0) | |
942 | dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command"); | |
943 | } | |
4c09aa72 MA |
944 | if (state->type_flags & DST_TYPE_HAS_TS204) { |
945 | dst_packsize(state, 204); | |
946 | } | |
62121b1f MA |
947 | if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { |
948 | if (dst_fw_ver(state) < 0) { | |
949 | dprintk(verbose, DST_INFO, 1, "FW: Unsupported command"); | |
950 | return 0; | |
951 | } | |
952 | if (dst_card_type(state) < 0) { | |
953 | dprintk(verbose, DST_INFO, 1, "Card: Unsupported command"); | |
954 | return 0; | |
955 | } | |
956 | if (dst_get_vendor(state) < 0) { | |
957 | dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command"); | |
958 | return 0; | |
959 | } | |
960 | } | |
50b215a0 JS |
961 | |
962 | return 0; | |
963 | } | |
964 | ||
a427de6f | 965 | int dst_command(struct dst_state *state, u8 *data, u8 len) |
1da177e4 | 966 | { |
1da177e4 | 967 | u8 reply; |
d28d5762 | 968 | |
3593cab5 | 969 | mutex_lock(&state->dst_mutex); |
50b215a0 | 970 | if ((dst_comm_init(state)) < 0) { |
a427de6f | 971 | dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed."); |
d28d5762 | 972 | goto error; |
50b215a0 | 973 | } |
50b215a0 | 974 | if (write_dst(state, data, len)) { |
a427de6f | 975 | dprintk(verbose, DST_INFO, 1, "Tring to recover.. "); |
50b215a0 | 976 | if ((dst_error_recovery(state)) < 0) { |
a427de6f | 977 | dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); |
d28d5762 | 978 | goto error; |
50b215a0 | 979 | } |
d28d5762 | 980 | goto error; |
1da177e4 | 981 | } |
50b215a0 | 982 | if ((dst_pio_disable(state)) < 0) { |
a427de6f | 983 | dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed."); |
d28d5762 | 984 | goto error; |
1da177e4 | 985 | } |
8385e46f JS |
986 | if (state->type_flags & DST_TYPE_HAS_FW_1) |
987 | udelay(3000); | |
50b215a0 | 988 | if (read_dst(state, &reply, GET_ACK)) { |
a427de6f | 989 | dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); |
50b215a0 | 990 | if ((dst_error_recovery(state)) < 0) { |
a427de6f | 991 | dprintk(verbose, DST_INFO, 1, "Recovery Failed."); |
d28d5762 | 992 | goto error; |
50b215a0 | 993 | } |
d28d5762 | 994 | goto error; |
50b215a0 | 995 | } |
50b215a0 | 996 | if (reply != ACK) { |
a427de6f | 997 | dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply); |
d28d5762 | 998 | goto error; |
1da177e4 LT |
999 | } |
1000 | if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) | |
d28d5762 | 1001 | goto error; |
8385e46f JS |
1002 | if (state->type_flags & DST_TYPE_HAS_FW_1) |
1003 | udelay(3000); | |
1004 | else | |
1005 | udelay(2000); | |
50b215a0 | 1006 | if (!dst_wait_dst_ready(state, NO_DELAY)) |
d28d5762 | 1007 | goto error; |
50b215a0 | 1008 | if (read_dst(state, state->rxbuffer, FIXED_COMM)) { |
a427de6f | 1009 | dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); |
50b215a0 | 1010 | if ((dst_error_recovery(state)) < 0) { |
a427de6f | 1011 | dprintk(verbose, DST_INFO, 1, "Recovery failed."); |
d28d5762 | 1012 | goto error; |
50b215a0 | 1013 | } |
d28d5762 | 1014 | goto error; |
1da177e4 LT |
1015 | } |
1016 | if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { | |
a427de6f | 1017 | dprintk(verbose, DST_INFO, 1, "checksum failure"); |
d28d5762 | 1018 | goto error; |
1da177e4 | 1019 | } |
3593cab5 | 1020 | mutex_unlock(&state->dst_mutex); |
1da177e4 | 1021 | return 0; |
d28d5762 MA |
1022 | |
1023 | error: | |
3593cab5 | 1024 | mutex_unlock(&state->dst_mutex); |
d28d5762 MA |
1025 | return -EIO; |
1026 | ||
1da177e4 | 1027 | } |
50b215a0 | 1028 | EXPORT_SYMBOL(dst_command); |
1da177e4 | 1029 | |
a427de6f | 1030 | static int dst_get_signal(struct dst_state *state) |
1da177e4 LT |
1031 | { |
1032 | int retval; | |
1033 | u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; | |
5b5b5345 | 1034 | //dprintk("%s: Getting Signal strength and other parameters\n", __FUNCTION__); |
1da177e4 LT |
1035 | if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { |
1036 | state->decode_lock = state->decode_strength = state->decode_snr = 0; | |
1037 | return 0; | |
1038 | } | |
1039 | if (0 == (state->diseq_flags & HAS_LOCK)) { | |
1040 | state->decode_lock = state->decode_strength = state->decode_snr = 0; | |
1041 | return 0; | |
1042 | } | |
1043 | if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) { | |
1044 | retval = dst_command(state, get_signal, 8); | |
1045 | if (retval < 0) | |
1046 | return retval; | |
1047 | if (state->dst_type == DST_TYPE_IS_SAT) { | |
1048 | state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0; | |
1049 | state->decode_strength = state->rxbuffer[5] << 8; | |
1050 | state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; | |
1051 | } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) { | |
1052 | state->decode_lock = (state->rxbuffer[1]) ? 1 : 0; | |
1053 | state->decode_strength = state->rxbuffer[4] << 8; | |
1054 | state->decode_snr = state->rxbuffer[3] << 8; | |
1055 | } | |
1056 | state->cur_jiff = jiffies; | |
1057 | } | |
1058 | return 0; | |
1059 | } | |
1060 | ||
a427de6f | 1061 | static int dst_tone_power_cmd(struct dst_state *state) |
1da177e4 LT |
1062 | { |
1063 | u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; | |
1064 | ||
1065 | if (state->dst_type == DST_TYPE_IS_TERR) | |
1066 | return 0; | |
8f6da8f1 | 1067 | paket[4] = state->tx_tuna[4]; |
86360a3e | 1068 | paket[2] = state->tx_tuna[2]; |
203fe8b3 | 1069 | paket[3] = state->tx_tuna[3]; |
50b215a0 | 1070 | paket[7] = dst_check_sum (paket, 7); |
1da177e4 | 1071 | dst_command(state, paket, 8); |
203fe8b3 | 1072 | |
1da177e4 LT |
1073 | return 0; |
1074 | } | |
1075 | ||
a427de6f | 1076 | static int dst_get_tuna(struct dst_state *state) |
1da177e4 LT |
1077 | { |
1078 | int retval; | |
50b215a0 | 1079 | |
1da177e4 LT |
1080 | if ((state->diseq_flags & ATTEMPT_TUNE) == 0) |
1081 | return 0; | |
1082 | state->diseq_flags &= ~(HAS_LOCK); | |
50b215a0 | 1083 | if (!dst_wait_dst_ready(state, NO_DELAY)) |
f1016dec | 1084 | return -EIO; |
a427de6f | 1085 | if (state->type_flags & DST_TYPE_HAS_NEWTUNE) |
1da177e4 LT |
1086 | /* how to get variable length reply ???? */ |
1087 | retval = read_dst(state, state->rx_tuna, 10); | |
a427de6f | 1088 | else |
50b215a0 | 1089 | retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); |
1da177e4 | 1090 | if (retval < 0) { |
a427de6f | 1091 | dprintk(verbose, DST_DEBUG, 1, "read not successful"); |
f1016dec | 1092 | return retval; |
1da177e4 LT |
1093 | } |
1094 | if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { | |
1095 | if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { | |
a427de6f | 1096 | dprintk(verbose, DST_INFO, 1, "checksum failure ? "); |
f1016dec | 1097 | return -EIO; |
1da177e4 LT |
1098 | } |
1099 | } else { | |
1100 | if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { | |
a427de6f | 1101 | dprintk(verbose, DST_INFO, 1, "checksum failure? "); |
f1016dec | 1102 | return -EIO; |
1da177e4 LT |
1103 | } |
1104 | } | |
1105 | if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) | |
1106 | return 0; | |
f5648e8a TH |
1107 | if (state->dst_type == DST_TYPE_IS_SAT) { |
1108 | state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; | |
1109 | } else { | |
1110 | state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4]; | |
1111 | } | |
1112 | state->decode_freq = state->decode_freq * 1000; | |
1da177e4 | 1113 | state->decode_lock = 1; |
1da177e4 | 1114 | state->diseq_flags |= HAS_LOCK; |
7d53421c | 1115 | |
1da177e4 LT |
1116 | return 1; |
1117 | } | |
1118 | ||
a427de6f | 1119 | static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); |
1da177e4 | 1120 | |
a427de6f | 1121 | static int dst_write_tuna(struct dvb_frontend *fe) |
1da177e4 | 1122 | { |
a427de6f | 1123 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1124 | int retval; |
1125 | u8 reply; | |
1126 | ||
a427de6f | 1127 | dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags); |
1da177e4 LT |
1128 | state->decode_freq = 0; |
1129 | state->decode_lock = state->decode_strength = state->decode_snr = 0; | |
1130 | if (state->dst_type == DST_TYPE_IS_SAT) { | |
1131 | if (!(state->diseq_flags & HAS_POWER)) | |
1132 | dst_set_voltage(fe, SEC_VOLTAGE_13); | |
1133 | } | |
1134 | state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); | |
3593cab5 | 1135 | mutex_lock(&state->dst_mutex); |
50b215a0 | 1136 | if ((dst_comm_init(state)) < 0) { |
a427de6f | 1137 | dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); |
f1016dec | 1138 | goto error; |
50b215a0 | 1139 | } |
1da177e4 | 1140 | if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { |
1da177e4 LT |
1141 | state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); |
1142 | retval = write_dst(state, &state->tx_tuna[0], 10); | |
1143 | } else { | |
1144 | state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); | |
50b215a0 | 1145 | retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM); |
1da177e4 LT |
1146 | } |
1147 | if (retval < 0) { | |
50b215a0 | 1148 | dst_pio_disable(state); |
a427de6f | 1149 | dprintk(verbose, DST_DEBUG, 1, "write not successful"); |
f1016dec | 1150 | goto werr; |
1da177e4 | 1151 | } |
50b215a0 | 1152 | if ((dst_pio_disable(state)) < 0) { |
a427de6f | 1153 | dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !"); |
f1016dec | 1154 | goto error; |
50b215a0 | 1155 | } |
50b215a0 | 1156 | if ((read_dst(state, &reply, GET_ACK) < 0)) { |
a427de6f | 1157 | dprintk(verbose, DST_DEBUG, 1, "read verify not successful."); |
f1016dec | 1158 | goto error; |
1da177e4 | 1159 | } |
50b215a0 | 1160 | if (reply != ACK) { |
a427de6f | 1161 | dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply); |
f1016dec | 1162 | goto error; |
1da177e4 LT |
1163 | } |
1164 | state->diseq_flags |= ATTEMPT_TUNE; | |
f1016dec HS |
1165 | retval = dst_get_tuna(state); |
1166 | werr: | |
3593cab5 | 1167 | mutex_unlock(&state->dst_mutex); |
f1016dec | 1168 | return retval; |
50b215a0 | 1169 | |
f1016dec | 1170 | error: |
3593cab5 | 1171 | mutex_unlock(&state->dst_mutex); |
f1016dec | 1172 | return -EIO; |
1da177e4 LT |
1173 | } |
1174 | ||
1175 | /* | |
1176 | * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 | |
1177 | * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 | |
1178 | * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 | |
1179 | * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 | |
1180 | * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 | |
1181 | * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 | |
1182 | * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 | |
1183 | * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec | |
1184 | * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 | |
1185 | * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 | |
1186 | * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 | |
1187 | */ | |
1188 | ||
a427de6f | 1189 | static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) |
1da177e4 | 1190 | { |
a427de6f | 1191 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1192 | u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; |
1193 | ||
226d97ec | 1194 | if (state->dst_type != DST_TYPE_IS_SAT) |
1da177e4 | 1195 | return 0; |
1da177e4 LT |
1196 | if (cmd->msg_len == 0 || cmd->msg_len > 4) |
1197 | return -EINVAL; | |
1198 | memcpy(&paket[3], cmd->msg, cmd->msg_len); | |
1199 | paket[7] = dst_check_sum(&paket[0], 7); | |
1200 | dst_command(state, paket, 8); | |
1201 | return 0; | |
1202 | } | |
1203 | ||
a427de6f | 1204 | static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) |
1da177e4 | 1205 | { |
1da177e4 | 1206 | int need_cmd; |
a427de6f | 1207 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1208 | |
1209 | state->voltage = voltage; | |
226d97ec | 1210 | if (state->dst_type != DST_TYPE_IS_SAT) |
1da177e4 LT |
1211 | return 0; |
1212 | ||
1213 | need_cmd = 0; | |
50b215a0 | 1214 | |
a427de6f MA |
1215 | switch (voltage) { |
1216 | case SEC_VOLTAGE_13: | |
1217 | case SEC_VOLTAGE_18: | |
1218 | if ((state->diseq_flags & HAS_POWER) == 0) | |
1da177e4 | 1219 | need_cmd = 1; |
a427de6f MA |
1220 | state->diseq_flags |= HAS_POWER; |
1221 | state->tx_tuna[4] = 0x01; | |
1222 | break; | |
1223 | case SEC_VOLTAGE_OFF: | |
1224 | need_cmd = 1; | |
1225 | state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); | |
1226 | state->tx_tuna[4] = 0x00; | |
1227 | break; | |
1228 | default: | |
1229 | return -EINVAL; | |
1da177e4 | 1230 | } |
a427de6f | 1231 | |
50b215a0 | 1232 | if (need_cmd) |
1da177e4 | 1233 | dst_tone_power_cmd(state); |
50b215a0 | 1234 | |
1da177e4 LT |
1235 | return 0; |
1236 | } | |
1237 | ||
a427de6f | 1238 | static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) |
1da177e4 | 1239 | { |
a427de6f | 1240 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1241 | |
1242 | state->tone = tone; | |
226d97ec | 1243 | if (state->dst_type != DST_TYPE_IS_SAT) |
1da177e4 LT |
1244 | return 0; |
1245 | ||
1da177e4 | 1246 | switch (tone) { |
a427de6f MA |
1247 | case SEC_TONE_OFF: |
1248 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) | |
1249 | state->tx_tuna[2] = 0x00; | |
1250 | else | |
1251 | state->tx_tuna[2] = 0xff; | |
1252 | break; | |
50b215a0 | 1253 | |
a427de6f MA |
1254 | case SEC_TONE_ON: |
1255 | state->tx_tuna[2] = 0x02; | |
1256 | break; | |
1257 | default: | |
1258 | return -EINVAL; | |
1da177e4 LT |
1259 | } |
1260 | dst_tone_power_cmd(state); | |
50b215a0 | 1261 | |
1da177e4 LT |
1262 | return 0; |
1263 | } | |
1264 | ||
203fe8b3 MA |
1265 | static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) |
1266 | { | |
1267 | struct dst_state *state = fe->demodulator_priv; | |
1268 | ||
226d97ec | 1269 | if (state->dst_type != DST_TYPE_IS_SAT) |
203fe8b3 | 1270 | return 0; |
203fe8b3 | 1271 | state->minicmd = minicmd; |
203fe8b3 | 1272 | switch (minicmd) { |
a427de6f MA |
1273 | case SEC_MINI_A: |
1274 | state->tx_tuna[3] = 0x02; | |
1275 | break; | |
1276 | case SEC_MINI_B: | |
1277 | state->tx_tuna[3] = 0xff; | |
1278 | break; | |
203fe8b3 MA |
1279 | } |
1280 | dst_tone_power_cmd(state); | |
1281 | ||
1282 | return 0; | |
1283 | } | |
1284 | ||
1285 | ||
a427de6f | 1286 | static int dst_init(struct dvb_frontend *fe) |
1da177e4 | 1287 | { |
a427de6f MA |
1288 | struct dst_state *state = fe->demodulator_priv; |
1289 | ||
1290 | static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 }; | |
1291 | static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 }; | |
1292 | static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | |
1293 | static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | |
1294 | static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | |
1295 | static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | |
1296 | ||
7d53421c | 1297 | state->inversion = INVERSION_OFF; |
1da177e4 LT |
1298 | state->voltage = SEC_VOLTAGE_13; |
1299 | state->tone = SEC_TONE_OFF; | |
1da177e4 LT |
1300 | state->diseq_flags = 0; |
1301 | state->k22 = 0x02; | |
1302 | state->bandwidth = BANDWIDTH_7_MHZ; | |
1303 | state->cur_jiff = jiffies; | |
a427de6f MA |
1304 | if (state->dst_type == DST_TYPE_IS_SAT) |
1305 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); | |
1306 | else if (state->dst_type == DST_TYPE_IS_TERR) | |
1307 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); | |
1308 | else if (state->dst_type == DST_TYPE_IS_CABLE) | |
1309 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); | |
1da177e4 LT |
1310 | |
1311 | return 0; | |
1312 | } | |
1313 | ||
a427de6f | 1314 | static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status) |
1da177e4 | 1315 | { |
a427de6f | 1316 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1317 | |
1318 | *status = 0; | |
1319 | if (state->diseq_flags & HAS_LOCK) { | |
7d53421c | 1320 | // dst_get_signal(state); // don't require(?) to ask MCU |
1da177e4 LT |
1321 | if (state->decode_lock) |
1322 | *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; | |
1323 | } | |
1324 | ||
1325 | return 0; | |
1326 | } | |
1327 | ||
a427de6f | 1328 | static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength) |
1da177e4 | 1329 | { |
a427de6f | 1330 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1331 | |
1332 | dst_get_signal(state); | |
1333 | *strength = state->decode_strength; | |
1334 | ||
1335 | return 0; | |
1336 | } | |
1337 | ||
a427de6f | 1338 | static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) |
1da177e4 | 1339 | { |
a427de6f | 1340 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1341 | |
1342 | dst_get_signal(state); | |
1343 | *snr = state->decode_snr; | |
1344 | ||
1345 | return 0; | |
1346 | } | |
1347 | ||
36cb557a AQ |
1348 | static int dst_set_frontend(struct dvb_frontend* fe, |
1349 | struct dvb_frontend_parameters* p, | |
1350 | unsigned int mode_flags, | |
1351 | int *delay, | |
1352 | fe_status_t *status) | |
1da177e4 | 1353 | { |
a427de6f | 1354 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 | 1355 | |
36cb557a AQ |
1356 | if (p != NULL) { |
1357 | dst_set_freq(state, p->frequency); | |
1358 | dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); | |
50b215a0 | 1359 | |
36cb557a AQ |
1360 | if (state->dst_type == DST_TYPE_IS_SAT) { |
1361 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) | |
1362 | dst_set_inversion(state, p->inversion); | |
1363 | dst_set_fec(state, p->u.qpsk.fec_inner); | |
1364 | dst_set_symbolrate(state, p->u.qpsk.symbol_rate); | |
1365 | dst_set_polarization(state); | |
1366 | dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); | |
1367 | ||
1368 | } else if (state->dst_type == DST_TYPE_IS_TERR) | |
1369 | dst_set_bandwidth(state, p->u.ofdm.bandwidth); | |
1370 | else if (state->dst_type == DST_TYPE_IS_CABLE) { | |
1371 | dst_set_fec(state, p->u.qam.fec_inner); | |
1372 | dst_set_symbolrate(state, p->u.qam.symbol_rate); | |
1373 | dst_set_modulation(state, p->u.qam.modulation); | |
1374 | } | |
1375 | dst_write_tuna(fe); | |
1da177e4 | 1376 | } |
1da177e4 | 1377 | |
36cb557a AQ |
1378 | if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) |
1379 | dst_read_status(fe, status); | |
1380 | ||
1381 | *delay = HZ/10; | |
1da177e4 LT |
1382 | return 0; |
1383 | } | |
1384 | ||
a427de6f | 1385 | static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) |
1da177e4 | 1386 | { |
a427de6f | 1387 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1388 | |
1389 | p->frequency = state->decode_freq; | |
1da177e4 | 1390 | if (state->dst_type == DST_TYPE_IS_SAT) { |
7d53421c MA |
1391 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) |
1392 | p->inversion = state->inversion; | |
1da177e4 LT |
1393 | p->u.qpsk.symbol_rate = state->symbol_rate; |
1394 | p->u.qpsk.fec_inner = dst_get_fec(state); | |
1395 | } else if (state->dst_type == DST_TYPE_IS_TERR) { | |
1396 | p->u.ofdm.bandwidth = state->bandwidth; | |
1397 | } else if (state->dst_type == DST_TYPE_IS_CABLE) { | |
1398 | p->u.qam.symbol_rate = state->symbol_rate; | |
1399 | p->u.qam.fec_inner = dst_get_fec(state); | |
7d53421c | 1400 | p->u.qam.modulation = dst_get_modulation(state); |
1da177e4 LT |
1401 | } |
1402 | ||
1403 | return 0; | |
1404 | } | |
1405 | ||
a427de6f | 1406 | static void dst_release(struct dvb_frontend *fe) |
1da177e4 | 1407 | { |
a427de6f | 1408 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1409 | kfree(state); |
1410 | } | |
1411 | ||
1412 | static struct dvb_frontend_ops dst_dvbt_ops; | |
1413 | static struct dvb_frontend_ops dst_dvbs_ops; | |
1414 | static struct dvb_frontend_ops dst_dvbc_ops; | |
bc7386ba | 1415 | static struct dvb_frontend_ops dst_atsc_ops; |
1da177e4 | 1416 | |
a427de6f | 1417 | struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) |
1da177e4 | 1418 | { |
50b215a0 JS |
1419 | /* check if the ASIC is there */ |
1420 | if (dst_probe(state) < 0) { | |
2ea75330 | 1421 | kfree(state); |
50b215a0 JS |
1422 | return NULL; |
1423 | } | |
1da177e4 | 1424 | /* determine settings based on type */ |
dea74869 | 1425 | /* create dvb_frontend */ |
1da177e4 LT |
1426 | switch (state->dst_type) { |
1427 | case DST_TYPE_IS_TERR: | |
dea74869 | 1428 | memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); |
1da177e4 LT |
1429 | break; |
1430 | case DST_TYPE_IS_CABLE: | |
dea74869 | 1431 | memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); |
1da177e4 LT |
1432 | break; |
1433 | case DST_TYPE_IS_SAT: | |
dea74869 | 1434 | memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); |
1da177e4 | 1435 | break; |
bc7386ba MA |
1436 | case DST_TYPE_IS_ATSC: |
1437 | memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops)); | |
1438 | break; | |
1da177e4 | 1439 | default: |
a427de6f | 1440 | dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); |
2ea75330 | 1441 | kfree(state); |
50b215a0 | 1442 | return NULL; |
1da177e4 | 1443 | } |
1da177e4 | 1444 | state->frontend.demodulator_priv = state; |
1da177e4 | 1445 | |
50b215a0 | 1446 | return state; /* Manu (DST is a card not a frontend) */ |
1da177e4 LT |
1447 | } |
1448 | ||
50b215a0 JS |
1449 | EXPORT_SYMBOL(dst_attach); |
1450 | ||
1da177e4 LT |
1451 | static struct dvb_frontend_ops dst_dvbt_ops = { |
1452 | ||
1453 | .info = { | |
1454 | .name = "DST DVB-T", | |
1455 | .type = FE_OFDM, | |
1456 | .frequency_min = 137000000, | |
1457 | .frequency_max = 858000000, | |
1458 | .frequency_stepsize = 166667, | |
1459 | .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | |
1460 | }, | |
1461 | ||
1462 | .release = dst_release, | |
1da177e4 | 1463 | .init = dst_init, |
36cb557a | 1464 | .tune = dst_set_frontend, |
1da177e4 | 1465 | .get_frontend = dst_get_frontend, |
1da177e4 LT |
1466 | .read_status = dst_read_status, |
1467 | .read_signal_strength = dst_read_signal_strength, | |
1468 | .read_snr = dst_read_snr, | |
1469 | }; | |
1470 | ||
1471 | static struct dvb_frontend_ops dst_dvbs_ops = { | |
1472 | ||
1473 | .info = { | |
1474 | .name = "DST DVB-S", | |
1475 | .type = FE_QPSK, | |
1476 | .frequency_min = 950000, | |
1477 | .frequency_max = 2150000, | |
1478 | .frequency_stepsize = 1000, /* kHz for QPSK frontends */ | |
1479 | .frequency_tolerance = 29500, | |
1480 | .symbol_rate_min = 1000000, | |
1481 | .symbol_rate_max = 45000000, | |
1482 | /* . symbol_rate_tolerance = ???,*/ | |
1483 | .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK | |
1484 | }, | |
1485 | ||
1486 | .release = dst_release, | |
1da177e4 | 1487 | .init = dst_init, |
36cb557a | 1488 | .tune = dst_set_frontend, |
1da177e4 | 1489 | .get_frontend = dst_get_frontend, |
1da177e4 LT |
1490 | .read_status = dst_read_status, |
1491 | .read_signal_strength = dst_read_signal_strength, | |
1492 | .read_snr = dst_read_snr, | |
203fe8b3 | 1493 | .diseqc_send_burst = dst_send_burst, |
1da177e4 LT |
1494 | .diseqc_send_master_cmd = dst_set_diseqc, |
1495 | .set_voltage = dst_set_voltage, | |
1496 | .set_tone = dst_set_tone, | |
1497 | }; | |
1498 | ||
1499 | static struct dvb_frontend_ops dst_dvbc_ops = { | |
1500 | ||
1501 | .info = { | |
1502 | .name = "DST DVB-C", | |
1503 | .type = FE_QAM, | |
1504 | .frequency_stepsize = 62500, | |
1505 | .frequency_min = 51000000, | |
1506 | .frequency_max = 858000000, | |
1507 | .symbol_rate_min = 1000000, | |
1508 | .symbol_rate_max = 45000000, | |
1509 | /* . symbol_rate_tolerance = ???,*/ | |
1510 | .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | |
1511 | }, | |
1512 | ||
1513 | .release = dst_release, | |
1da177e4 | 1514 | .init = dst_init, |
36cb557a | 1515 | .tune = dst_set_frontend, |
1da177e4 | 1516 | .get_frontend = dst_get_frontend, |
1da177e4 LT |
1517 | .read_status = dst_read_status, |
1518 | .read_signal_strength = dst_read_signal_strength, | |
1519 | .read_snr = dst_read_snr, | |
1520 | }; | |
1521 | ||
bc7386ba MA |
1522 | static struct dvb_frontend_ops dst_atsc_ops = { |
1523 | .info = { | |
1524 | .name = "DST ATSC", | |
1525 | .type = FE_ATSC, | |
1526 | .frequency_stepsize = 62500, | |
1527 | .frequency_min = 510000000, | |
1528 | .frequency_max = 858000000, | |
1529 | .symbol_rate_min = 1000000, | |
1530 | .symbol_rate_max = 45000000, | |
1531 | .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB | |
1532 | }, | |
1533 | ||
1534 | .release = dst_release, | |
1535 | .init = dst_init, | |
1536 | .tune = dst_set_frontend, | |
1537 | .get_frontend = dst_get_frontend, | |
1538 | .read_status = dst_read_status, | |
1539 | .read_signal_strength = dst_read_signal_strength, | |
1540 | .read_snr = dst_read_snr, | |
1541 | }; | |
1542 | ||
1543 | MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver"); | |
50b215a0 | 1544 | MODULE_AUTHOR("Jamie Honan, Manu Abraham"); |
1da177e4 | 1545 | MODULE_LICENSE("GPL"); |