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 | |
1da177e4 | 561 | default: |
a427de6f | 562 | dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type); |
1da177e4 LT |
563 | return -EINVAL; |
564 | } | |
a427de6f | 565 | dprintk(verbose, DST_INFO, 1, "DST type: %s", otype); |
50b215a0 | 566 | |
1da177e4 LT |
567 | return 0; |
568 | } | |
569 | ||
50b215a0 JS |
570 | /* |
571 | Known cards list | |
572 | Satellite | |
573 | ------------------- | |
e6ac699a | 574 | 200103A |
50b215a0 JS |
575 | VP-1020 DST-MOT LG(old), TS=188 |
576 | ||
577 | VP-1020 DST-03T LG(new), TS=204 | |
578 | VP-1022 DST-03T LG(new), TS=204 | |
579 | VP-1025 DST-03T LG(new), TS=204 | |
580 | ||
581 | VP-1030 DSTMCI, LG(new), TS=188 | |
582 | VP-1032 DSTMCI, LG(new), TS=188 | |
583 | ||
584 | Cable | |
585 | ------------------- | |
586 | VP-2030 DCT-CI, Samsung, TS=204 | |
587 | VP-2021 DCT-CI, Unknown, TS=204 | |
588 | VP-2031 DCT-CI, Philips, TS=188 | |
589 | VP-2040 DCT-CI, Philips, TS=188, with CA daughter board | |
590 | VP-2040 DCT-CI, Philips, TS=204, without CA daughter board | |
591 | ||
592 | Terrestrial | |
593 | ------------------- | |
594 | VP-3050 DTTNXT TS=188 | |
595 | VP-3040 DTT-CI, Philips, TS=188 | |
596 | VP-3040 DTT-CI, Philips, TS=204 | |
597 | ||
598 | ATSC | |
599 | ------------------- | |
600 | VP-3220 ATSCDI, TS=188 | |
601 | VP-3250 ATSCAD, TS=188 | |
602 | ||
603 | */ | |
604 | ||
605 | struct dst_types dst_tlist[] = { | |
e6ac699a JS |
606 | { |
607 | .device_id = "200103A", | |
608 | .offset = 0, | |
609 | .dst_type = DST_TYPE_IS_SAT, | |
7d53421c | 610 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS, |
e6ac699a JS |
611 | .dst_feature = 0 |
612 | }, /* obsolete */ | |
613 | ||
50b215a0 JS |
614 | { |
615 | .device_id = "DST-020", | |
616 | .offset = 0, | |
617 | .dst_type = DST_TYPE_IS_SAT, | |
618 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, | |
619 | .dst_feature = 0 | |
620 | }, /* obsolete */ | |
621 | ||
622 | { | |
623 | .device_id = "DST-030", | |
624 | .offset = 0, | |
625 | .dst_type = DST_TYPE_IS_SAT, | |
626 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, | |
627 | .dst_feature = 0 | |
628 | }, /* obsolete */ | |
629 | ||
630 | { | |
631 | .device_id = "DST-03T", | |
632 | .offset = 0, | |
633 | .dst_type = DST_TYPE_IS_SAT, | |
634 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, | |
635 | .dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5 | |
636 | | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO | |
637 | }, | |
638 | ||
639 | { | |
640 | .device_id = "DST-MOT", | |
641 | .offset = 0, | |
642 | .dst_type = DST_TYPE_IS_SAT, | |
643 | .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, | |
644 | .dst_feature = 0 | |
645 | }, /* obsolete */ | |
646 | ||
647 | { | |
648 | .device_id = "DST-CI", | |
649 | .offset = 1, | |
650 | .dst_type = DST_TYPE_IS_SAT, | |
651 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, | |
652 | .dst_feature = DST_TYPE_HAS_CA | |
8385e46f | 653 | }, /* An OEM board */ |
50b215a0 JS |
654 | |
655 | { | |
656 | .device_id = "DSTMCI", | |
657 | .offset = 1, | |
658 | .dst_type = DST_TYPE_IS_SAT, | |
7d53421c | 659 | .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT, |
50b215a0 JS |
660 | .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 |
661 | | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC | |
662 | }, | |
663 | ||
664 | { | |
665 | .device_id = "DSTFCI", | |
666 | .offset = 1, | |
667 | .dst_type = DST_TYPE_IS_SAT, | |
668 | .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, | |
669 | .dst_feature = 0 | |
670 | }, /* unknown to vendor */ | |
671 | ||
672 | { | |
673 | .device_id = "DCT-CI", | |
674 | .offset = 1, | |
675 | .dst_type = DST_TYPE_IS_CABLE, | |
8385e46f | 676 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1 |
62121b1f | 677 | | DST_TYPE_HAS_FW_2, |
50b215a0 JS |
678 | .dst_feature = DST_TYPE_HAS_CA |
679 | }, | |
680 | ||
681 | { | |
682 | .device_id = "DCTNEW", | |
683 | .offset = 1, | |
684 | .dst_type = DST_TYPE_IS_CABLE, | |
62121b1f | 685 | .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD, |
50b215a0 JS |
686 | .dst_feature = 0 |
687 | }, | |
688 | ||
689 | { | |
690 | .device_id = "DTT-CI", | |
691 | .offset = 1, | |
692 | .dst_type = DST_TYPE_IS_TERR, | |
29b2f784 MA |
693 | .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE, |
694 | .dst_feature = DST_TYPE_HAS_CA | |
50b215a0 JS |
695 | }, |
696 | ||
697 | { | |
698 | .device_id = "DTTDIG", | |
699 | .offset = 1, | |
700 | .dst_type = DST_TYPE_IS_TERR, | |
701 | .type_flags = DST_TYPE_HAS_FW_2, | |
702 | .dst_feature = 0 | |
703 | }, | |
704 | ||
705 | { | |
706 | .device_id = "DTTNXT", | |
707 | .offset = 1, | |
708 | .dst_type = DST_TYPE_IS_TERR, | |
709 | .type_flags = DST_TYPE_HAS_FW_2, | |
710 | .dst_feature = DST_TYPE_HAS_ANALOG | |
711 | }, | |
712 | ||
713 | { | |
714 | .device_id = "ATSCDI", | |
715 | .offset = 1, | |
716 | .dst_type = DST_TYPE_IS_ATSC, | |
717 | .type_flags = DST_TYPE_HAS_FW_2, | |
718 | .dst_feature = 0 | |
719 | }, | |
720 | ||
721 | { | |
722 | .device_id = "ATSCAD", | |
723 | .offset = 1, | |
724 | .dst_type = DST_TYPE_IS_ATSC, | |
725 | .type_flags = DST_TYPE_HAS_FW_2, | |
726 | .dst_feature = 0 | |
727 | }, | |
728 | ||
729 | { } | |
730 | ||
731 | }; | |
732 | ||
62121b1f MA |
733 | static int dst_get_mac(struct dst_state *state) |
734 | { | |
735 | u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
736 | get_mac[7] = dst_check_sum(get_mac, 7); | |
737 | if (dst_command(state, get_mac, 8) < 0) { | |
738 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
739 | return -1; | |
740 | } | |
741 | memset(&state->mac_address, '\0', 8); | |
742 | memcpy(&state->mac_address, &state->rxbuffer, 6); | |
743 | dprintk(verbose, DST_ERROR, 1, "MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]", | |
744 | state->mac_address[0], state->mac_address[1], state->mac_address[2], | |
745 | state->mac_address[4], state->mac_address[5], state->mac_address[6]); | |
746 | ||
747 | return 0; | |
748 | } | |
749 | ||
750 | static int dst_fw_ver(struct dst_state *state) | |
751 | { | |
752 | u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
753 | get_ver[7] = dst_check_sum(get_ver, 7); | |
754 | if (dst_command(state, get_ver, 8) < 0) { | |
755 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
756 | return -1; | |
757 | } | |
758 | memset(&state->fw_version, '\0', 8); | |
759 | memcpy(&state->fw_version, &state->rxbuffer, 8); | |
760 | dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x", | |
761 | state->fw_version[0] >> 4, state->fw_version[0] & 0x0f, | |
762 | state->fw_version[1], | |
763 | state->fw_version[5], state->fw_version[6], | |
764 | state->fw_version[4], state->fw_version[3], state->fw_version[2]); | |
765 | ||
766 | return 0; | |
767 | } | |
768 | ||
769 | static int dst_card_type(struct dst_state *state) | |
770 | { | |
771 | u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
772 | get_type[7] = dst_check_sum(get_type, 7); | |
773 | if (dst_command(state, get_type, 8) < 0) { | |
774 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
775 | return -1; | |
776 | } | |
777 | memset(&state->card_info, '\0', 8); | |
778 | memcpy(&state->card_info, &state->rxbuffer, 8); | |
779 | dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]); | |
780 | ||
781 | return 0; | |
782 | } | |
783 | ||
784 | static int dst_get_vendor(struct dst_state *state) | |
785 | { | |
786 | u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
787 | get_vendor[7] = dst_check_sum(get_vendor, 7); | |
788 | if (dst_command(state, get_vendor, 8) < 0) { | |
789 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
790 | return -1; | |
791 | } | |
792 | memset(&state->vendor, '\0', 8); | |
793 | memcpy(&state->vendor, &state->rxbuffer, 8); | |
794 | dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]); | |
795 | ||
796 | return 0; | |
797 | } | |
50b215a0 | 798 | |
29b2f784 MA |
799 | static int dst_get_tuner_info(struct dst_state *state) |
800 | { | |
801 | u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
802 | u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
803 | ||
804 | get_tuner_1[7] = dst_check_sum(get_tuner_1, 7); | |
805 | get_tuner_2[7] = dst_check_sum(get_tuner_2, 7); | |
806 | if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { | |
807 | if (dst_command(state, get_tuner_2, 8) < 0) { | |
808 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
809 | return -1; | |
810 | } | |
811 | } else { | |
812 | if (dst_command(state, get_tuner_1, 8) < 0) { | |
813 | dprintk(verbose, DST_INFO, 1, "Unsupported Command"); | |
814 | return -1; | |
815 | } | |
816 | } | |
817 | memset(&state->board_info, '\0', 8); | |
818 | memcpy(&state->board_info, &state->rxbuffer, 8); | |
819 | if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { | |
820 | if (state->board_info[1] == 0x0b) { | |
821 | if (state->type_flags & DST_TYPE_HAS_TS204) | |
822 | state->type_flags &= ~DST_TYPE_HAS_TS204; | |
823 | state->type_flags |= DST_TYPE_HAS_NEWTUNE; | |
824 | dprintk(verbose, DST_INFO, 1, "DST type has TS=188"); | |
825 | } else { | |
826 | if (state->type_flags & DST_TYPE_HAS_NEWTUNE) | |
827 | state->type_flags &= ~DST_TYPE_HAS_NEWTUNE; | |
828 | state->type_flags |= DST_TYPE_HAS_TS204; | |
829 | dprintk(verbose, DST_INFO, 1, "DST type has TS=204"); | |
830 | } | |
831 | } else { | |
832 | if (state->board_info[0] == 0xbc) { | |
833 | if (state->type_flags & DST_TYPE_HAS_TS204) | |
834 | state->type_flags &= ~DST_TYPE_HAS_TS204; | |
835 | state->type_flags |= DST_TYPE_HAS_NEWTUNE; | |
836 | dprintk(verbose, DST_INFO, 1, "DST type has TS=188, Daughterboard=[%d]", state->board_info[1]); | |
837 | ||
838 | } else if (state->board_info[0] == 0xcc) { | |
839 | if (state->type_flags & DST_TYPE_HAS_NEWTUNE) | |
840 | state->type_flags &= ~DST_TYPE_HAS_NEWTUNE; | |
841 | state->type_flags |= DST_TYPE_HAS_TS204; | |
842 | dprintk(verbose, DST_INFO, 1, "DST type has TS=204 Daughterboard=[%d]", state->board_info[1]); | |
843 | } | |
844 | } | |
845 | ||
846 | return 0; | |
847 | } | |
848 | ||
50b215a0 | 849 | static int dst_get_device_id(struct dst_state *state) |
1da177e4 | 850 | { |
50b215a0 JS |
851 | u8 reply; |
852 | ||
1da177e4 | 853 | int i; |
50b215a0 JS |
854 | struct dst_types *p_dst_type; |
855 | u8 use_dst_type = 0; | |
856 | u32 use_type_flags = 0; | |
1da177e4 | 857 | |
50b215a0 | 858 | static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; |
1da177e4 | 859 | |
50b215a0 JS |
860 | device_type[7] = dst_check_sum(device_type, 7); |
861 | ||
862 | if (write_dst(state, device_type, FIXED_COMM)) | |
863 | return -1; /* Write failed */ | |
50b215a0 JS |
864 | if ((dst_pio_disable(state)) < 0) |
865 | return -1; | |
50b215a0 JS |
866 | if (read_dst(state, &reply, GET_ACK)) |
867 | return -1; /* Read failure */ | |
50b215a0 | 868 | if (reply != ACK) { |
a427de6f | 869 | dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply); |
50b215a0 | 870 | return -1; /* Unack'd write */ |
1da177e4 | 871 | } |
50b215a0 JS |
872 | if (!dst_wait_dst_ready(state, DEVICE_INIT)) |
873 | return -1; /* DST not ready yet */ | |
50b215a0 JS |
874 | if (read_dst(state, state->rxbuffer, FIXED_COMM)) |
875 | return -1; | |
876 | ||
877 | dst_pio_disable(state); | |
50b215a0 | 878 | if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { |
a427de6f | 879 | dprintk(verbose, DST_INFO, 1, "Checksum failure!"); |
50b215a0 | 880 | return -1; /* Checksum failure */ |
1da177e4 | 881 | } |
50b215a0 JS |
882 | state->rxbuffer[7] = '\0'; |
883 | ||
a427de6f | 884 | for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) { |
50b215a0 JS |
885 | if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) { |
886 | use_type_flags = p_dst_type->type_flags; | |
887 | use_dst_type = p_dst_type->dst_type; | |
888 | ||
889 | /* Card capabilities */ | |
890 | state->dst_hw_cap = p_dst_type->dst_feature; | |
a427de6f | 891 | dprintk(verbose, DST_ERROR, 1, "Recognise [%s]\n", p_dst_type->device_id); |
50b215a0 | 892 | |
1da177e4 LT |
893 | break; |
894 | } | |
895 | } | |
50b215a0 JS |
896 | |
897 | if (i >= sizeof (dst_tlist) / sizeof (dst_tlist [0])) { | |
a427de6f MA |
898 | dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]); |
899 | dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in"); | |
1da177e4 LT |
900 | use_dst_type = DST_TYPE_IS_SAT; |
901 | use_type_flags = DST_TYPE_HAS_SYMDIV; | |
902 | } | |
50b215a0 | 903 | dst_type_print(use_dst_type); |
1da177e4 LT |
904 | state->type_flags = use_type_flags; |
905 | state->dst_type = use_dst_type; | |
906 | dst_type_flags_print(state->type_flags); | |
907 | ||
1da177e4 LT |
908 | return 0; |
909 | } | |
910 | ||
50b215a0 JS |
911 | static int dst_probe(struct dst_state *state) |
912 | { | |
d28d5762 | 913 | sema_init(&state->dst_mutex, 1); |
50b215a0 | 914 | if ((rdc_8820_reset(state)) < 0) { |
a427de6f | 915 | dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); |
50b215a0 JS |
916 | return -1; |
917 | } | |
4a2cc126 JS |
918 | if (dst_addons & DST_TYPE_HAS_CA) |
919 | msleep(4000); | |
920 | else | |
921 | msleep(100); | |
922 | ||
50b215a0 | 923 | if ((dst_comm_init(state)) < 0) { |
a427de6f | 924 | dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed."); |
50b215a0 JS |
925 | return -1; |
926 | } | |
8385e46f | 927 | msleep(100); |
50b215a0 | 928 | if (dst_get_device_id(state) < 0) { |
a427de6f | 929 | dprintk(verbose, DST_ERROR, 1, "unknown device."); |
50b215a0 JS |
930 | return -1; |
931 | } | |
62121b1f MA |
932 | if (dst_get_mac(state) < 0) { |
933 | dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); | |
934 | return 0; | |
935 | } | |
29b2f784 MA |
936 | if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) { |
937 | if (dst_get_tuner_info(state) < 0) | |
938 | dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command"); | |
939 | } | |
4c09aa72 MA |
940 | if (state->type_flags & DST_TYPE_HAS_TS204) { |
941 | dst_packsize(state, 204); | |
942 | } | |
62121b1f MA |
943 | if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { |
944 | if (dst_fw_ver(state) < 0) { | |
945 | dprintk(verbose, DST_INFO, 1, "FW: Unsupported command"); | |
946 | return 0; | |
947 | } | |
948 | if (dst_card_type(state) < 0) { | |
949 | dprintk(verbose, DST_INFO, 1, "Card: Unsupported command"); | |
950 | return 0; | |
951 | } | |
952 | if (dst_get_vendor(state) < 0) { | |
953 | dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command"); | |
954 | return 0; | |
955 | } | |
956 | } | |
50b215a0 JS |
957 | |
958 | return 0; | |
959 | } | |
960 | ||
a427de6f | 961 | int dst_command(struct dst_state *state, u8 *data, u8 len) |
1da177e4 | 962 | { |
1da177e4 | 963 | u8 reply; |
d28d5762 MA |
964 | |
965 | down(&state->dst_mutex); | |
50b215a0 | 966 | if ((dst_comm_init(state)) < 0) { |
a427de6f | 967 | dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed."); |
d28d5762 | 968 | goto error; |
50b215a0 | 969 | } |
50b215a0 | 970 | if (write_dst(state, data, len)) { |
a427de6f | 971 | dprintk(verbose, DST_INFO, 1, "Tring to recover.. "); |
50b215a0 | 972 | if ((dst_error_recovery(state)) < 0) { |
a427de6f | 973 | dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); |
d28d5762 | 974 | goto error; |
50b215a0 | 975 | } |
d28d5762 | 976 | goto error; |
1da177e4 | 977 | } |
50b215a0 | 978 | if ((dst_pio_disable(state)) < 0) { |
a427de6f | 979 | dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed."); |
d28d5762 | 980 | goto error; |
1da177e4 | 981 | } |
8385e46f JS |
982 | if (state->type_flags & DST_TYPE_HAS_FW_1) |
983 | udelay(3000); | |
50b215a0 | 984 | if (read_dst(state, &reply, GET_ACK)) { |
a427de6f | 985 | dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); |
50b215a0 | 986 | if ((dst_error_recovery(state)) < 0) { |
a427de6f | 987 | dprintk(verbose, DST_INFO, 1, "Recovery Failed."); |
d28d5762 | 988 | goto error; |
50b215a0 | 989 | } |
d28d5762 | 990 | goto error; |
50b215a0 | 991 | } |
50b215a0 | 992 | if (reply != ACK) { |
a427de6f | 993 | dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply); |
d28d5762 | 994 | goto error; |
1da177e4 LT |
995 | } |
996 | if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) | |
d28d5762 | 997 | goto error; |
8385e46f JS |
998 | if (state->type_flags & DST_TYPE_HAS_FW_1) |
999 | udelay(3000); | |
1000 | else | |
1001 | udelay(2000); | |
50b215a0 | 1002 | if (!dst_wait_dst_ready(state, NO_DELAY)) |
d28d5762 | 1003 | goto error; |
50b215a0 | 1004 | if (read_dst(state, state->rxbuffer, FIXED_COMM)) { |
a427de6f | 1005 | dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); |
50b215a0 | 1006 | if ((dst_error_recovery(state)) < 0) { |
a427de6f | 1007 | dprintk(verbose, DST_INFO, 1, "Recovery failed."); |
d28d5762 | 1008 | goto error; |
50b215a0 | 1009 | } |
d28d5762 | 1010 | goto error; |
1da177e4 LT |
1011 | } |
1012 | if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { | |
a427de6f | 1013 | dprintk(verbose, DST_INFO, 1, "checksum failure"); |
d28d5762 | 1014 | goto error; |
1da177e4 | 1015 | } |
d28d5762 | 1016 | up(&state->dst_mutex); |
1da177e4 | 1017 | return 0; |
d28d5762 MA |
1018 | |
1019 | error: | |
1020 | up(&state->dst_mutex); | |
1021 | return -EIO; | |
1022 | ||
1da177e4 | 1023 | } |
50b215a0 | 1024 | EXPORT_SYMBOL(dst_command); |
1da177e4 | 1025 | |
a427de6f | 1026 | static int dst_get_signal(struct dst_state *state) |
1da177e4 LT |
1027 | { |
1028 | int retval; | |
1029 | u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; | |
5b5b5345 | 1030 | //dprintk("%s: Getting Signal strength and other parameters\n", __FUNCTION__); |
1da177e4 LT |
1031 | if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { |
1032 | state->decode_lock = state->decode_strength = state->decode_snr = 0; | |
1033 | return 0; | |
1034 | } | |
1035 | if (0 == (state->diseq_flags & HAS_LOCK)) { | |
1036 | state->decode_lock = state->decode_strength = state->decode_snr = 0; | |
1037 | return 0; | |
1038 | } | |
1039 | if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) { | |
1040 | retval = dst_command(state, get_signal, 8); | |
1041 | if (retval < 0) | |
1042 | return retval; | |
1043 | if (state->dst_type == DST_TYPE_IS_SAT) { | |
1044 | state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0; | |
1045 | state->decode_strength = state->rxbuffer[5] << 8; | |
1046 | state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; | |
1047 | } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) { | |
1048 | state->decode_lock = (state->rxbuffer[1]) ? 1 : 0; | |
1049 | state->decode_strength = state->rxbuffer[4] << 8; | |
1050 | state->decode_snr = state->rxbuffer[3] << 8; | |
1051 | } | |
1052 | state->cur_jiff = jiffies; | |
1053 | } | |
1054 | return 0; | |
1055 | } | |
1056 | ||
a427de6f | 1057 | static int dst_tone_power_cmd(struct dst_state *state) |
1da177e4 LT |
1058 | { |
1059 | u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; | |
1060 | ||
1061 | if (state->dst_type == DST_TYPE_IS_TERR) | |
1062 | return 0; | |
8f6da8f1 | 1063 | paket[4] = state->tx_tuna[4]; |
86360a3e | 1064 | paket[2] = state->tx_tuna[2]; |
203fe8b3 | 1065 | paket[3] = state->tx_tuna[3]; |
50b215a0 | 1066 | paket[7] = dst_check_sum (paket, 7); |
1da177e4 | 1067 | dst_command(state, paket, 8); |
203fe8b3 | 1068 | |
1da177e4 LT |
1069 | return 0; |
1070 | } | |
1071 | ||
a427de6f | 1072 | static int dst_get_tuna(struct dst_state *state) |
1da177e4 LT |
1073 | { |
1074 | int retval; | |
50b215a0 | 1075 | |
1da177e4 LT |
1076 | if ((state->diseq_flags & ATTEMPT_TUNE) == 0) |
1077 | return 0; | |
1078 | state->diseq_flags &= ~(HAS_LOCK); | |
50b215a0 | 1079 | if (!dst_wait_dst_ready(state, NO_DELAY)) |
f1016dec | 1080 | return -EIO; |
a427de6f | 1081 | if (state->type_flags & DST_TYPE_HAS_NEWTUNE) |
1da177e4 LT |
1082 | /* how to get variable length reply ???? */ |
1083 | retval = read_dst(state, state->rx_tuna, 10); | |
a427de6f | 1084 | else |
50b215a0 | 1085 | retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); |
1da177e4 | 1086 | if (retval < 0) { |
a427de6f | 1087 | dprintk(verbose, DST_DEBUG, 1, "read not successful"); |
f1016dec | 1088 | return retval; |
1da177e4 LT |
1089 | } |
1090 | if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { | |
1091 | if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { | |
a427de6f | 1092 | dprintk(verbose, DST_INFO, 1, "checksum failure ? "); |
f1016dec | 1093 | return -EIO; |
1da177e4 LT |
1094 | } |
1095 | } else { | |
1096 | if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { | |
a427de6f | 1097 | dprintk(verbose, DST_INFO, 1, "checksum failure? "); |
f1016dec | 1098 | return -EIO; |
1da177e4 LT |
1099 | } |
1100 | } | |
1101 | if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) | |
1102 | return 0; | |
f5648e8a TH |
1103 | if (state->dst_type == DST_TYPE_IS_SAT) { |
1104 | state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; | |
1105 | } else { | |
1106 | state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4]; | |
1107 | } | |
1108 | state->decode_freq = state->decode_freq * 1000; | |
1da177e4 | 1109 | state->decode_lock = 1; |
1da177e4 | 1110 | state->diseq_flags |= HAS_LOCK; |
7d53421c | 1111 | |
1da177e4 LT |
1112 | return 1; |
1113 | } | |
1114 | ||
a427de6f | 1115 | static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); |
1da177e4 | 1116 | |
a427de6f | 1117 | static int dst_write_tuna(struct dvb_frontend *fe) |
1da177e4 | 1118 | { |
a427de6f | 1119 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1120 | int retval; |
1121 | u8 reply; | |
1122 | ||
a427de6f | 1123 | dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags); |
1da177e4 LT |
1124 | state->decode_freq = 0; |
1125 | state->decode_lock = state->decode_strength = state->decode_snr = 0; | |
1126 | if (state->dst_type == DST_TYPE_IS_SAT) { | |
1127 | if (!(state->diseq_flags & HAS_POWER)) | |
1128 | dst_set_voltage(fe, SEC_VOLTAGE_13); | |
1129 | } | |
1130 | state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); | |
f1016dec | 1131 | down(&state->dst_mutex); |
50b215a0 | 1132 | if ((dst_comm_init(state)) < 0) { |
a427de6f | 1133 | dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); |
f1016dec | 1134 | goto error; |
50b215a0 | 1135 | } |
1da177e4 | 1136 | if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { |
1da177e4 LT |
1137 | state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); |
1138 | retval = write_dst(state, &state->tx_tuna[0], 10); | |
1139 | } else { | |
1140 | state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); | |
50b215a0 | 1141 | retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM); |
1da177e4 LT |
1142 | } |
1143 | if (retval < 0) { | |
50b215a0 | 1144 | dst_pio_disable(state); |
a427de6f | 1145 | dprintk(verbose, DST_DEBUG, 1, "write not successful"); |
f1016dec | 1146 | goto werr; |
1da177e4 | 1147 | } |
50b215a0 | 1148 | if ((dst_pio_disable(state)) < 0) { |
a427de6f | 1149 | dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !"); |
f1016dec | 1150 | goto error; |
50b215a0 | 1151 | } |
50b215a0 | 1152 | if ((read_dst(state, &reply, GET_ACK) < 0)) { |
a427de6f | 1153 | dprintk(verbose, DST_DEBUG, 1, "read verify not successful."); |
f1016dec | 1154 | goto error; |
1da177e4 | 1155 | } |
50b215a0 | 1156 | if (reply != ACK) { |
a427de6f | 1157 | dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply); |
f1016dec | 1158 | goto error; |
1da177e4 LT |
1159 | } |
1160 | state->diseq_flags |= ATTEMPT_TUNE; | |
f1016dec HS |
1161 | retval = dst_get_tuna(state); |
1162 | werr: | |
1163 | up(&state->dst_mutex); | |
1164 | return retval; | |
50b215a0 | 1165 | |
f1016dec HS |
1166 | error: |
1167 | up(&state->dst_mutex); | |
1168 | return -EIO; | |
1da177e4 LT |
1169 | } |
1170 | ||
1171 | /* | |
1172 | * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 | |
1173 | * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 | |
1174 | * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 | |
1175 | * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 | |
1176 | * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 | |
1177 | * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 | |
1178 | * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 | |
1179 | * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec | |
1180 | * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 | |
1181 | * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 | |
1182 | * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 | |
1183 | */ | |
1184 | ||
a427de6f | 1185 | static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) |
1da177e4 | 1186 | { |
a427de6f | 1187 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1188 | u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; |
1189 | ||
226d97ec | 1190 | if (state->dst_type != DST_TYPE_IS_SAT) |
1da177e4 | 1191 | return 0; |
1da177e4 LT |
1192 | if (cmd->msg_len == 0 || cmd->msg_len > 4) |
1193 | return -EINVAL; | |
1194 | memcpy(&paket[3], cmd->msg, cmd->msg_len); | |
1195 | paket[7] = dst_check_sum(&paket[0], 7); | |
1196 | dst_command(state, paket, 8); | |
1197 | return 0; | |
1198 | } | |
1199 | ||
a427de6f | 1200 | static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) |
1da177e4 | 1201 | { |
1da177e4 | 1202 | int need_cmd; |
a427de6f | 1203 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1204 | |
1205 | state->voltage = voltage; | |
226d97ec | 1206 | if (state->dst_type != DST_TYPE_IS_SAT) |
1da177e4 LT |
1207 | return 0; |
1208 | ||
1209 | need_cmd = 0; | |
50b215a0 | 1210 | |
a427de6f MA |
1211 | switch (voltage) { |
1212 | case SEC_VOLTAGE_13: | |
1213 | case SEC_VOLTAGE_18: | |
1214 | if ((state->diseq_flags & HAS_POWER) == 0) | |
1da177e4 | 1215 | need_cmd = 1; |
a427de6f MA |
1216 | state->diseq_flags |= HAS_POWER; |
1217 | state->tx_tuna[4] = 0x01; | |
1218 | break; | |
1219 | case SEC_VOLTAGE_OFF: | |
1220 | need_cmd = 1; | |
1221 | state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); | |
1222 | state->tx_tuna[4] = 0x00; | |
1223 | break; | |
1224 | default: | |
1225 | return -EINVAL; | |
1da177e4 | 1226 | } |
a427de6f | 1227 | |
50b215a0 | 1228 | if (need_cmd) |
1da177e4 | 1229 | dst_tone_power_cmd(state); |
50b215a0 | 1230 | |
1da177e4 LT |
1231 | return 0; |
1232 | } | |
1233 | ||
a427de6f | 1234 | static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) |
1da177e4 | 1235 | { |
a427de6f | 1236 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1237 | |
1238 | state->tone = tone; | |
226d97ec | 1239 | if (state->dst_type != DST_TYPE_IS_SAT) |
1da177e4 LT |
1240 | return 0; |
1241 | ||
1da177e4 | 1242 | switch (tone) { |
a427de6f MA |
1243 | case SEC_TONE_OFF: |
1244 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) | |
1245 | state->tx_tuna[2] = 0x00; | |
1246 | else | |
1247 | state->tx_tuna[2] = 0xff; | |
1248 | break; | |
50b215a0 | 1249 | |
a427de6f MA |
1250 | case SEC_TONE_ON: |
1251 | state->tx_tuna[2] = 0x02; | |
1252 | break; | |
1253 | default: | |
1254 | return -EINVAL; | |
1da177e4 LT |
1255 | } |
1256 | dst_tone_power_cmd(state); | |
50b215a0 | 1257 | |
1da177e4 LT |
1258 | return 0; |
1259 | } | |
1260 | ||
203fe8b3 MA |
1261 | static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) |
1262 | { | |
1263 | struct dst_state *state = fe->demodulator_priv; | |
1264 | ||
226d97ec | 1265 | if (state->dst_type != DST_TYPE_IS_SAT) |
203fe8b3 | 1266 | return 0; |
203fe8b3 | 1267 | state->minicmd = minicmd; |
203fe8b3 | 1268 | switch (minicmd) { |
a427de6f MA |
1269 | case SEC_MINI_A: |
1270 | state->tx_tuna[3] = 0x02; | |
1271 | break; | |
1272 | case SEC_MINI_B: | |
1273 | state->tx_tuna[3] = 0xff; | |
1274 | break; | |
203fe8b3 MA |
1275 | } |
1276 | dst_tone_power_cmd(state); | |
1277 | ||
1278 | return 0; | |
1279 | } | |
1280 | ||
1281 | ||
a427de6f | 1282 | static int dst_init(struct dvb_frontend *fe) |
1da177e4 | 1283 | { |
a427de6f MA |
1284 | struct dst_state *state = fe->demodulator_priv; |
1285 | ||
1286 | static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 }; | |
1287 | static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 }; | |
1288 | static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | |
1289 | static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | |
1290 | static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | |
1291 | static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; | |
1292 | ||
7d53421c | 1293 | state->inversion = INVERSION_OFF; |
1da177e4 LT |
1294 | state->voltage = SEC_VOLTAGE_13; |
1295 | state->tone = SEC_TONE_OFF; | |
1da177e4 LT |
1296 | state->diseq_flags = 0; |
1297 | state->k22 = 0x02; | |
1298 | state->bandwidth = BANDWIDTH_7_MHZ; | |
1299 | state->cur_jiff = jiffies; | |
a427de6f MA |
1300 | if (state->dst_type == DST_TYPE_IS_SAT) |
1301 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); | |
1302 | else if (state->dst_type == DST_TYPE_IS_TERR) | |
1303 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); | |
1304 | else if (state->dst_type == DST_TYPE_IS_CABLE) | |
1305 | memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); | |
1da177e4 LT |
1306 | |
1307 | return 0; | |
1308 | } | |
1309 | ||
a427de6f | 1310 | static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status) |
1da177e4 | 1311 | { |
a427de6f | 1312 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1313 | |
1314 | *status = 0; | |
1315 | if (state->diseq_flags & HAS_LOCK) { | |
7d53421c | 1316 | // dst_get_signal(state); // don't require(?) to ask MCU |
1da177e4 LT |
1317 | if (state->decode_lock) |
1318 | *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; | |
1319 | } | |
1320 | ||
1321 | return 0; | |
1322 | } | |
1323 | ||
a427de6f | 1324 | static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength) |
1da177e4 | 1325 | { |
a427de6f | 1326 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1327 | |
1328 | dst_get_signal(state); | |
1329 | *strength = state->decode_strength; | |
1330 | ||
1331 | return 0; | |
1332 | } | |
1333 | ||
a427de6f | 1334 | static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) |
1da177e4 | 1335 | { |
a427de6f | 1336 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1337 | |
1338 | dst_get_signal(state); | |
1339 | *snr = state->decode_snr; | |
1340 | ||
1341 | return 0; | |
1342 | } | |
1343 | ||
a427de6f | 1344 | static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) |
1da177e4 | 1345 | { |
a427de6f | 1346 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1347 | |
1348 | dst_set_freq(state, p->frequency); | |
a427de6f | 1349 | dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); |
50b215a0 | 1350 | |
1da177e4 | 1351 | if (state->dst_type == DST_TYPE_IS_SAT) { |
7d53421c MA |
1352 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) |
1353 | dst_set_inversion(state, p->inversion); | |
1da177e4 LT |
1354 | dst_set_fec(state, p->u.qpsk.fec_inner); |
1355 | dst_set_symbolrate(state, p->u.qpsk.symbol_rate); | |
7d53421c | 1356 | dst_set_polarization(state); |
a427de6f | 1357 | dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); |
50b215a0 | 1358 | |
a427de6f | 1359 | } else if (state->dst_type == DST_TYPE_IS_TERR) |
1da177e4 | 1360 | dst_set_bandwidth(state, p->u.ofdm.bandwidth); |
a427de6f | 1361 | else if (state->dst_type == DST_TYPE_IS_CABLE) { |
1da177e4 LT |
1362 | dst_set_fec(state, p->u.qam.fec_inner); |
1363 | dst_set_symbolrate(state, p->u.qam.symbol_rate); | |
7d53421c | 1364 | dst_set_modulation(state, p->u.qam.modulation); |
1da177e4 LT |
1365 | } |
1366 | dst_write_tuna(fe); | |
1367 | ||
1368 | return 0; | |
1369 | } | |
1370 | ||
a427de6f | 1371 | static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) |
1da177e4 | 1372 | { |
a427de6f | 1373 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1374 | |
1375 | p->frequency = state->decode_freq; | |
1da177e4 | 1376 | if (state->dst_type == DST_TYPE_IS_SAT) { |
7d53421c MA |
1377 | if (state->type_flags & DST_TYPE_HAS_OBS_REGS) |
1378 | p->inversion = state->inversion; | |
1da177e4 LT |
1379 | p->u.qpsk.symbol_rate = state->symbol_rate; |
1380 | p->u.qpsk.fec_inner = dst_get_fec(state); | |
1381 | } else if (state->dst_type == DST_TYPE_IS_TERR) { | |
1382 | p->u.ofdm.bandwidth = state->bandwidth; | |
1383 | } else if (state->dst_type == DST_TYPE_IS_CABLE) { | |
1384 | p->u.qam.symbol_rate = state->symbol_rate; | |
1385 | p->u.qam.fec_inner = dst_get_fec(state); | |
7d53421c | 1386 | p->u.qam.modulation = dst_get_modulation(state); |
1da177e4 LT |
1387 | } |
1388 | ||
1389 | return 0; | |
1390 | } | |
1391 | ||
a427de6f | 1392 | static void dst_release(struct dvb_frontend *fe) |
1da177e4 | 1393 | { |
a427de6f | 1394 | struct dst_state *state = fe->demodulator_priv; |
1da177e4 LT |
1395 | kfree(state); |
1396 | } | |
1397 | ||
1398 | static struct dvb_frontend_ops dst_dvbt_ops; | |
1399 | static struct dvb_frontend_ops dst_dvbs_ops; | |
1400 | static struct dvb_frontend_ops dst_dvbc_ops; | |
1401 | ||
a427de6f | 1402 | struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) |
1da177e4 | 1403 | { |
50b215a0 JS |
1404 | /* check if the ASIC is there */ |
1405 | if (dst_probe(state) < 0) { | |
2ea75330 | 1406 | kfree(state); |
50b215a0 JS |
1407 | return NULL; |
1408 | } | |
1da177e4 LT |
1409 | /* determine settings based on type */ |
1410 | switch (state->dst_type) { | |
1411 | case DST_TYPE_IS_TERR: | |
1412 | memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); | |
1413 | break; | |
1414 | case DST_TYPE_IS_CABLE: | |
1415 | memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); | |
1416 | break; | |
1417 | case DST_TYPE_IS_SAT: | |
1418 | memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); | |
1419 | break; | |
1420 | default: | |
a427de6f | 1421 | dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); |
2ea75330 | 1422 | kfree(state); |
50b215a0 | 1423 | return NULL; |
1da177e4 LT |
1424 | } |
1425 | ||
1426 | /* create dvb_frontend */ | |
1427 | state->frontend.ops = &state->ops; | |
1428 | state->frontend.demodulator_priv = state; | |
1da177e4 | 1429 | |
50b215a0 | 1430 | return state; /* Manu (DST is a card not a frontend) */ |
1da177e4 LT |
1431 | } |
1432 | ||
50b215a0 JS |
1433 | EXPORT_SYMBOL(dst_attach); |
1434 | ||
1da177e4 LT |
1435 | static struct dvb_frontend_ops dst_dvbt_ops = { |
1436 | ||
1437 | .info = { | |
1438 | .name = "DST DVB-T", | |
1439 | .type = FE_OFDM, | |
1440 | .frequency_min = 137000000, | |
1441 | .frequency_max = 858000000, | |
1442 | .frequency_stepsize = 166667, | |
1443 | .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | |
1444 | }, | |
1445 | ||
1446 | .release = dst_release, | |
1da177e4 | 1447 | .init = dst_init, |
1da177e4 LT |
1448 | .set_frontend = dst_set_frontend, |
1449 | .get_frontend = dst_get_frontend, | |
1da177e4 LT |
1450 | .read_status = dst_read_status, |
1451 | .read_signal_strength = dst_read_signal_strength, | |
1452 | .read_snr = dst_read_snr, | |
1453 | }; | |
1454 | ||
1455 | static struct dvb_frontend_ops dst_dvbs_ops = { | |
1456 | ||
1457 | .info = { | |
1458 | .name = "DST DVB-S", | |
1459 | .type = FE_QPSK, | |
1460 | .frequency_min = 950000, | |
1461 | .frequency_max = 2150000, | |
1462 | .frequency_stepsize = 1000, /* kHz for QPSK frontends */ | |
1463 | .frequency_tolerance = 29500, | |
1464 | .symbol_rate_min = 1000000, | |
1465 | .symbol_rate_max = 45000000, | |
1466 | /* . symbol_rate_tolerance = ???,*/ | |
1467 | .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK | |
1468 | }, | |
1469 | ||
1470 | .release = dst_release, | |
1da177e4 | 1471 | .init = dst_init, |
1da177e4 LT |
1472 | .set_frontend = dst_set_frontend, |
1473 | .get_frontend = dst_get_frontend, | |
1da177e4 LT |
1474 | .read_status = dst_read_status, |
1475 | .read_signal_strength = dst_read_signal_strength, | |
1476 | .read_snr = dst_read_snr, | |
203fe8b3 | 1477 | .diseqc_send_burst = dst_send_burst, |
1da177e4 LT |
1478 | .diseqc_send_master_cmd = dst_set_diseqc, |
1479 | .set_voltage = dst_set_voltage, | |
1480 | .set_tone = dst_set_tone, | |
1481 | }; | |
1482 | ||
1483 | static struct dvb_frontend_ops dst_dvbc_ops = { | |
1484 | ||
1485 | .info = { | |
1486 | .name = "DST DVB-C", | |
1487 | .type = FE_QAM, | |
1488 | .frequency_stepsize = 62500, | |
1489 | .frequency_min = 51000000, | |
1490 | .frequency_max = 858000000, | |
1491 | .symbol_rate_min = 1000000, | |
1492 | .symbol_rate_max = 45000000, | |
1493 | /* . symbol_rate_tolerance = ???,*/ | |
1494 | .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | |
1495 | }, | |
1496 | ||
1497 | .release = dst_release, | |
1da177e4 | 1498 | .init = dst_init, |
1da177e4 LT |
1499 | .set_frontend = dst_set_frontend, |
1500 | .get_frontend = dst_get_frontend, | |
1da177e4 LT |
1501 | .read_status = dst_read_status, |
1502 | .read_signal_strength = dst_read_signal_strength, | |
1503 | .read_snr = dst_read_snr, | |
1504 | }; | |
1505 | ||
1506 | MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver"); | |
50b215a0 | 1507 | MODULE_AUTHOR("Jamie Honan, Manu Abraham"); |
1da177e4 | 1508 | MODULE_LICENSE("GPL"); |