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