diff options
Diffstat (limited to 'drivers/media/usb/dvb-usb/ttusb2.c')
-rw-r--r-- | drivers/media/usb/dvb-usb/ttusb2.c | 820 |
1 files changed, 820 insertions, 0 deletions
diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c new file mode 100644 index 000000000000..e53a1061cb8e --- /dev/null +++ b/drivers/media/usb/dvb-usb/ttusb2.c | |||
@@ -0,0 +1,820 @@ | |||
1 | /* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones | ||
2 | * (e.g. Pinnacle 400e DVB-S USB2.0). | ||
3 | * | ||
4 | * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes. | ||
5 | * | ||
6 | * TDA8263 + TDA10086 | ||
7 | * | ||
8 | * I2C addresses: | ||
9 | * 0x08 - LNBP21PD - LNB power supply | ||
10 | * 0x0e - TDA10086 - Demodulator | ||
11 | * 0x50 - FX2 eeprom | ||
12 | * 0x60 - TDA8263 - Tuner | ||
13 | * 0x78 ??? | ||
14 | * | ||
15 | * Copyright (c) 2002 Holger Waechtler <holger@convergence.de> | ||
16 | * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net> | ||
17 | * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.org> | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or modify it | ||
20 | * under the terms of the GNU General Public License as published by the Free | ||
21 | * Software Foundation, version 2. | ||
22 | * | ||
23 | * see Documentation/dvb/README.dvb-usb for more information | ||
24 | */ | ||
25 | #define DVB_USB_LOG_PREFIX "ttusb2" | ||
26 | #include "dvb-usb.h" | ||
27 | |||
28 | #include "ttusb2.h" | ||
29 | |||
30 | #include "tda826x.h" | ||
31 | #include "tda10086.h" | ||
32 | #include "tda1002x.h" | ||
33 | #include "tda10048.h" | ||
34 | #include "tda827x.h" | ||
35 | #include "lnbp21.h" | ||
36 | /* CA */ | ||
37 | #include "dvb_ca_en50221.h" | ||
38 | |||
39 | /* debug */ | ||
40 | static int dvb_usb_ttusb2_debug; | ||
41 | #define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args) | ||
42 | module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644); | ||
43 | MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS); | ||
44 | static int dvb_usb_ttusb2_debug_ci; | ||
45 | module_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644); | ||
46 | MODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS); | ||
47 | |||
48 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
49 | |||
50 | #define ci_dbg(format, arg...) \ | ||
51 | do { \ | ||
52 | if (dvb_usb_ttusb2_debug_ci) \ | ||
53 | printk(KERN_DEBUG DVB_USB_LOG_PREFIX \ | ||
54 | ": %s " format "\n" , __func__, ## arg); \ | ||
55 | } while (0) | ||
56 | |||
57 | enum { | ||
58 | TT3650_CMD_CI_TEST = 0x40, | ||
59 | TT3650_CMD_CI_RD_CTRL, | ||
60 | TT3650_CMD_CI_WR_CTRL, | ||
61 | TT3650_CMD_CI_RD_ATTR, | ||
62 | TT3650_CMD_CI_WR_ATTR, | ||
63 | TT3650_CMD_CI_RESET, | ||
64 | TT3650_CMD_CI_SET_VIDEO_PORT | ||
65 | }; | ||
66 | |||
67 | struct ttusb2_state { | ||
68 | struct dvb_ca_en50221 ca; | ||
69 | struct mutex ca_mutex; | ||
70 | u8 id; | ||
71 | u16 last_rc_key; | ||
72 | }; | ||
73 | |||
74 | static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, | ||
75 | u8 *wbuf, int wlen, u8 *rbuf, int rlen) | ||
76 | { | ||
77 | struct ttusb2_state *st = d->priv; | ||
78 | u8 *s, *r = NULL; | ||
79 | int ret = 0; | ||
80 | |||
81 | s = kzalloc(wlen+4, GFP_KERNEL); | ||
82 | if (!s) | ||
83 | return -ENOMEM; | ||
84 | |||
85 | r = kzalloc(64, GFP_KERNEL); | ||
86 | if (!r) { | ||
87 | kfree(s); | ||
88 | return -ENOMEM; | ||
89 | } | ||
90 | |||
91 | s[0] = 0xaa; | ||
92 | s[1] = ++st->id; | ||
93 | s[2] = cmd; | ||
94 | s[3] = wlen; | ||
95 | memcpy(&s[4],wbuf,wlen); | ||
96 | |||
97 | ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0); | ||
98 | |||
99 | if (ret != 0 || | ||
100 | r[0] != 0x55 || | ||
101 | r[1] != s[1] || | ||
102 | r[2] != cmd || | ||
103 | (rlen > 0 && r[3] != rlen)) { | ||
104 | warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]); | ||
105 | kfree(s); | ||
106 | kfree(r); | ||
107 | return -EIO; | ||
108 | } | ||
109 | |||
110 | if (rlen > 0) | ||
111 | memcpy(rbuf, &r[4], rlen); | ||
112 | |||
113 | kfree(s); | ||
114 | kfree(r); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | /* ci */ | ||
120 | static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) | ||
121 | { | ||
122 | int ret; | ||
123 | u8 rx[60];/* (64 -4) */ | ||
124 | ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len); | ||
125 | if (!ret) | ||
126 | memcpy(data, rx, read_len); | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) | ||
131 | { | ||
132 | struct dvb_usb_device *d = ca->data; | ||
133 | struct ttusb2_state *state = d->priv; | ||
134 | int ret; | ||
135 | |||
136 | mutex_lock(&state->ca_mutex); | ||
137 | ret = tt3650_ci_msg(d, cmd, data, write_len, read_len); | ||
138 | mutex_unlock(&state->ca_mutex); | ||
139 | |||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) | ||
144 | { | ||
145 | u8 buf[3]; | ||
146 | int ret = 0; | ||
147 | |||
148 | if (slot) | ||
149 | return -EINVAL; | ||
150 | |||
151 | buf[0] = (address >> 8) & 0x0F; | ||
152 | buf[1] = address; | ||
153 | |||
154 | |||
155 | ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3); | ||
156 | |||
157 | ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]); | ||
158 | |||
159 | if (ret < 0) | ||
160 | return ret; | ||
161 | |||
162 | return buf[2]; | ||
163 | } | ||
164 | |||
165 | static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) | ||
166 | { | ||
167 | u8 buf[3]; | ||
168 | |||
169 | ci_dbg("%d 0x%04x 0x%02x", slot, address, value); | ||
170 | |||
171 | if (slot) | ||
172 | return -EINVAL; | ||
173 | |||
174 | buf[0] = (address >> 8) & 0x0F; | ||
175 | buf[1] = address; | ||
176 | buf[2] = value; | ||
177 | |||
178 | return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3); | ||
179 | } | ||
180 | |||
181 | static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) | ||
182 | { | ||
183 | u8 buf[2]; | ||
184 | int ret; | ||
185 | |||
186 | if (slot) | ||
187 | return -EINVAL; | ||
188 | |||
189 | buf[0] = address & 3; | ||
190 | |||
191 | ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2); | ||
192 | |||
193 | ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]); | ||
194 | |||
195 | if (ret < 0) | ||
196 | return ret; | ||
197 | |||
198 | return buf[1]; | ||
199 | } | ||
200 | |||
201 | static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) | ||
202 | { | ||
203 | u8 buf[2]; | ||
204 | |||
205 | ci_dbg("%d 0x%02x 0x%02x", slot, address, value); | ||
206 | |||
207 | if (slot) | ||
208 | return -EINVAL; | ||
209 | |||
210 | buf[0] = address; | ||
211 | buf[1] = value; | ||
212 | |||
213 | return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2); | ||
214 | } | ||
215 | |||
216 | static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable) | ||
217 | { | ||
218 | u8 buf[1]; | ||
219 | int ret; | ||
220 | |||
221 | ci_dbg("%d %d", slot, enable); | ||
222 | |||
223 | if (slot) | ||
224 | return -EINVAL; | ||
225 | |||
226 | buf[0] = enable; | ||
227 | |||
228 | ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); | ||
229 | if (ret < 0) | ||
230 | return ret; | ||
231 | |||
232 | if (enable != buf[0]) { | ||
233 | err("CI not %sabled.", enable ? "en" : "dis"); | ||
234 | return -EIO; | ||
235 | } | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) | ||
241 | { | ||
242 | return tt3650_ci_set_video_port(ca, slot, 0); | ||
243 | } | ||
244 | |||
245 | static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) | ||
246 | { | ||
247 | return tt3650_ci_set_video_port(ca, slot, 1); | ||
248 | } | ||
249 | |||
250 | static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) | ||
251 | { | ||
252 | struct dvb_usb_device *d = ca->data; | ||
253 | struct ttusb2_state *state = d->priv; | ||
254 | u8 buf[1]; | ||
255 | int ret; | ||
256 | |||
257 | ci_dbg("%d", slot); | ||
258 | |||
259 | if (slot) | ||
260 | return -EINVAL; | ||
261 | |||
262 | buf[0] = 0; | ||
263 | |||
264 | mutex_lock(&state->ca_mutex); | ||
265 | |||
266 | ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); | ||
267 | if (ret) | ||
268 | goto failed; | ||
269 | |||
270 | msleep(500); | ||
271 | |||
272 | buf[0] = 1; | ||
273 | |||
274 | ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); | ||
275 | if (ret) | ||
276 | goto failed; | ||
277 | |||
278 | msleep(500); | ||
279 | |||
280 | buf[0] = 0; /* FTA */ | ||
281 | |||
282 | ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); | ||
283 | |||
284 | msleep(1100); | ||
285 | |||
286 | failed: | ||
287 | mutex_unlock(&state->ca_mutex); | ||
288 | |||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) | ||
293 | { | ||
294 | u8 buf[1]; | ||
295 | int ret; | ||
296 | |||
297 | if (slot) | ||
298 | return -EINVAL; | ||
299 | |||
300 | ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1); | ||
301 | if (ret) | ||
302 | return ret; | ||
303 | |||
304 | if (1 == buf[0]) { | ||
305 | return DVB_CA_EN50221_POLL_CAM_PRESENT | | ||
306 | DVB_CA_EN50221_POLL_CAM_READY; | ||
307 | } | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static void tt3650_ci_uninit(struct dvb_usb_device *d) | ||
312 | { | ||
313 | struct ttusb2_state *state; | ||
314 | |||
315 | ci_dbg(""); | ||
316 | |||
317 | if (NULL == d) | ||
318 | return; | ||
319 | |||
320 | state = d->priv; | ||
321 | if (NULL == state) | ||
322 | return; | ||
323 | |||
324 | if (NULL == state->ca.data) | ||
325 | return; | ||
326 | |||
327 | dvb_ca_en50221_release(&state->ca); | ||
328 | |||
329 | memset(&state->ca, 0, sizeof(state->ca)); | ||
330 | } | ||
331 | |||
332 | static int tt3650_ci_init(struct dvb_usb_adapter *a) | ||
333 | { | ||
334 | struct dvb_usb_device *d = a->dev; | ||
335 | struct ttusb2_state *state = d->priv; | ||
336 | int ret; | ||
337 | |||
338 | ci_dbg(""); | ||
339 | |||
340 | mutex_init(&state->ca_mutex); | ||
341 | |||
342 | state->ca.owner = THIS_MODULE; | ||
343 | state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem; | ||
344 | state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem; | ||
345 | state->ca.read_cam_control = tt3650_ci_read_cam_control; | ||
346 | state->ca.write_cam_control = tt3650_ci_write_cam_control; | ||
347 | state->ca.slot_reset = tt3650_ci_slot_reset; | ||
348 | state->ca.slot_shutdown = tt3650_ci_slot_shutdown; | ||
349 | state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable; | ||
350 | state->ca.poll_slot_status = tt3650_ci_poll_slot_status; | ||
351 | state->ca.data = d; | ||
352 | |||
353 | ret = dvb_ca_en50221_init(&a->dvb_adap, | ||
354 | &state->ca, | ||
355 | /* flags */ 0, | ||
356 | /* n_slots */ 1); | ||
357 | if (ret) { | ||
358 | err("Cannot initialize CI: Error %d.", ret); | ||
359 | memset(&state->ca, 0, sizeof(state->ca)); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | info("CI initialized."); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) | ||
369 | { | ||
370 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
371 | static u8 obuf[60], ibuf[60]; | ||
372 | int i, write_read, read; | ||
373 | |||
374 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
375 | return -EAGAIN; | ||
376 | |||
377 | if (num > 2) | ||
378 | warn("more than 2 i2c messages at a time is not handled yet. TODO."); | ||
379 | |||
380 | for (i = 0; i < num; i++) { | ||
381 | write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD); | ||
382 | read = msg[i].flags & I2C_M_RD; | ||
383 | |||
384 | obuf[0] = (msg[i].addr << 1) | (write_read | read); | ||
385 | if (read) | ||
386 | obuf[1] = 0; | ||
387 | else | ||
388 | obuf[1] = msg[i].len; | ||
389 | |||
390 | /* read request */ | ||
391 | if (write_read) | ||
392 | obuf[2] = msg[i+1].len; | ||
393 | else if (read) | ||
394 | obuf[2] = msg[i].len; | ||
395 | else | ||
396 | obuf[2] = 0; | ||
397 | |||
398 | memcpy(&obuf[3], msg[i].buf, msg[i].len); | ||
399 | |||
400 | if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) { | ||
401 | err("i2c transfer failed."); | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | if (write_read) { | ||
406 | memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len); | ||
407 | i++; | ||
408 | } else if (read) | ||
409 | memcpy(msg[i].buf, &ibuf[3], msg[i].len); | ||
410 | } | ||
411 | |||
412 | mutex_unlock(&d->i2c_mutex); | ||
413 | return i; | ||
414 | } | ||
415 | |||
416 | static u32 ttusb2_i2c_func(struct i2c_adapter *adapter) | ||
417 | { | ||
418 | return I2C_FUNC_I2C; | ||
419 | } | ||
420 | |||
421 | static struct i2c_algorithm ttusb2_i2c_algo = { | ||
422 | .master_xfer = ttusb2_i2c_xfer, | ||
423 | .functionality = ttusb2_i2c_func, | ||
424 | }; | ||
425 | |||
426 | /* command to poll IR receiver (copied from pctv452e.c) */ | ||
427 | #define CMD_GET_IR_CODE 0x1b | ||
428 | |||
429 | /* IR */ | ||
430 | static int tt3650_rc_query(struct dvb_usb_device *d) | ||
431 | { | ||
432 | int ret; | ||
433 | u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */ | ||
434 | struct ttusb2_state *st = d->priv; | ||
435 | ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx)); | ||
436 | if (ret != 0) | ||
437 | return ret; | ||
438 | |||
439 | if (rx[8] & 0x01) { | ||
440 | /* got a "press" event */ | ||
441 | st->last_rc_key = (rx[3] << 8) | rx[2]; | ||
442 | deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]); | ||
443 | rc_keydown(d->rc_dev, st->last_rc_key, 0); | ||
444 | } else if (st->last_rc_key) { | ||
445 | rc_keyup(d->rc_dev); | ||
446 | st->last_rc_key = 0; | ||
447 | } | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | |||
453 | /* Callbacks for DVB USB */ | ||
454 | static int ttusb2_identify_state (struct usb_device *udev, struct | ||
455 | dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, | ||
456 | int *cold) | ||
457 | { | ||
458 | *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff) | ||
463 | { | ||
464 | u8 b = onoff; | ||
465 | ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0); | ||
466 | return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0); | ||
467 | } | ||
468 | |||
469 | |||
470 | static struct tda10086_config tda10086_config = { | ||
471 | .demod_address = 0x0e, | ||
472 | .invert = 0, | ||
473 | .diseqc_tone = 1, | ||
474 | .xtal_freq = TDA10086_XTAL_16M, | ||
475 | }; | ||
476 | |||
477 | static struct tda10023_config tda10023_config = { | ||
478 | .demod_address = 0x0c, | ||
479 | .invert = 0, | ||
480 | .xtal = 16000000, | ||
481 | .pll_m = 11, | ||
482 | .pll_p = 3, | ||
483 | .pll_n = 1, | ||
484 | .deltaf = 0xa511, | ||
485 | }; | ||
486 | |||
487 | static struct tda10048_config tda10048_config = { | ||
488 | .demod_address = 0x10 >> 1, | ||
489 | .output_mode = TDA10048_PARALLEL_OUTPUT, | ||
490 | .inversion = TDA10048_INVERSION_ON, | ||
491 | .dtv6_if_freq_khz = TDA10048_IF_4000, | ||
492 | .dtv7_if_freq_khz = TDA10048_IF_4500, | ||
493 | .dtv8_if_freq_khz = TDA10048_IF_5000, | ||
494 | .clk_freq_khz = TDA10048_CLK_16000, | ||
495 | .no_firmware = 1, | ||
496 | .set_pll = true , | ||
497 | .pll_m = 5, | ||
498 | .pll_n = 3, | ||
499 | .pll_p = 0, | ||
500 | }; | ||
501 | |||
502 | static struct tda827x_config tda827x_config = { | ||
503 | .config = 0, | ||
504 | }; | ||
505 | |||
506 | static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) | ||
507 | { | ||
508 | if (usb_set_interface(adap->dev->udev,0,3) < 0) | ||
509 | err("set interface to alts=3 failed"); | ||
510 | |||
511 | if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { | ||
512 | deb_info("TDA10086 attach failed\n"); | ||
513 | return -ENODEV; | ||
514 | } | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) | ||
520 | { | ||
521 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
522 | |||
523 | return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable); | ||
524 | } | ||
525 | |||
526 | static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) | ||
527 | { | ||
528 | if (usb_set_interface(adap->dev->udev, 0, 3) < 0) | ||
529 | err("set interface to alts=3 failed"); | ||
530 | |||
531 | if (adap->fe_adap[0].fe == NULL) { | ||
532 | /* FE 0 DVB-C */ | ||
533 | adap->fe_adap[0].fe = dvb_attach(tda10023_attach, | ||
534 | &tda10023_config, &adap->dev->i2c_adap, 0x48); | ||
535 | |||
536 | if (adap->fe_adap[0].fe == NULL) { | ||
537 | deb_info("TDA10023 attach failed\n"); | ||
538 | return -ENODEV; | ||
539 | } | ||
540 | tt3650_ci_init(adap); | ||
541 | } else { | ||
542 | adap->fe_adap[1].fe = dvb_attach(tda10048_attach, | ||
543 | &tda10048_config, &adap->dev->i2c_adap); | ||
544 | |||
545 | if (adap->fe_adap[1].fe == NULL) { | ||
546 | deb_info("TDA10048 attach failed\n"); | ||
547 | return -ENODEV; | ||
548 | } | ||
549 | |||
550 | /* tuner is behind TDA10023 I2C-gate */ | ||
551 | adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl; | ||
552 | |||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) | ||
559 | { | ||
560 | struct dvb_frontend *fe; | ||
561 | |||
562 | /* MFE: select correct FE to attach tuner since that's called twice */ | ||
563 | if (adap->fe_adap[1].fe == NULL) | ||
564 | fe = adap->fe_adap[0].fe; | ||
565 | else | ||
566 | fe = adap->fe_adap[1].fe; | ||
567 | |||
568 | /* attach tuner */ | ||
569 | if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) { | ||
570 | printk(KERN_ERR "%s: No tda827x found!\n", __func__); | ||
571 | return -ENODEV; | ||
572 | } | ||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap) | ||
577 | { | ||
578 | if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { | ||
579 | deb_info("TDA8263 attach failed\n"); | ||
580 | return -ENODEV; | ||
581 | } | ||
582 | |||
583 | if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) { | ||
584 | deb_info("LNBP21 attach failed\n"); | ||
585 | return -ENODEV; | ||
586 | } | ||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | /* DVB USB Driver stuff */ | ||
591 | static struct dvb_usb_device_properties ttusb2_properties; | ||
592 | static struct dvb_usb_device_properties ttusb2_properties_s2400; | ||
593 | static struct dvb_usb_device_properties ttusb2_properties_ct3650; | ||
594 | |||
595 | static void ttusb2_usb_disconnect(struct usb_interface *intf) | ||
596 | { | ||
597 | struct dvb_usb_device *d = usb_get_intfdata(intf); | ||
598 | |||
599 | tt3650_ci_uninit(d); | ||
600 | dvb_usb_device_exit(intf); | ||
601 | } | ||
602 | |||
603 | static int ttusb2_probe(struct usb_interface *intf, | ||
604 | const struct usb_device_id *id) | ||
605 | { | ||
606 | if (0 == dvb_usb_device_init(intf, &ttusb2_properties, | ||
607 | THIS_MODULE, NULL, adapter_nr) || | ||
608 | 0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400, | ||
609 | THIS_MODULE, NULL, adapter_nr) || | ||
610 | 0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650, | ||
611 | THIS_MODULE, NULL, adapter_nr)) | ||
612 | return 0; | ||
613 | return -ENODEV; | ||
614 | } | ||
615 | |||
616 | static struct usb_device_id ttusb2_table [] = { | ||
617 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, | ||
618 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) }, | ||
619 | { USB_DEVICE(USB_VID_TECHNOTREND, | ||
620 | USB_PID_TECHNOTREND_CONNECT_S2400) }, | ||
621 | { USB_DEVICE(USB_VID_TECHNOTREND, | ||
622 | USB_PID_TECHNOTREND_CONNECT_CT3650) }, | ||
623 | {} /* Terminating entry */ | ||
624 | }; | ||
625 | MODULE_DEVICE_TABLE (usb, ttusb2_table); | ||
626 | |||
627 | static struct dvb_usb_device_properties ttusb2_properties = { | ||
628 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
629 | |||
630 | .usb_ctrl = CYPRESS_FX2, | ||
631 | .firmware = "dvb-usb-pctv-400e-01.fw", | ||
632 | |||
633 | .size_of_priv = sizeof(struct ttusb2_state), | ||
634 | |||
635 | .num_adapters = 1, | ||
636 | .adapter = { | ||
637 | { | ||
638 | .num_frontends = 1, | ||
639 | .fe = {{ | ||
640 | .streaming_ctrl = NULL, // ttusb2_streaming_ctrl, | ||
641 | |||
642 | .frontend_attach = ttusb2_frontend_tda10086_attach, | ||
643 | .tuner_attach = ttusb2_tuner_tda826x_attach, | ||
644 | |||
645 | /* parameter for the MPEG2-data transfer */ | ||
646 | .stream = { | ||
647 | .type = USB_ISOC, | ||
648 | .count = 5, | ||
649 | .endpoint = 0x02, | ||
650 | .u = { | ||
651 | .isoc = { | ||
652 | .framesperurb = 4, | ||
653 | .framesize = 940, | ||
654 | .interval = 1, | ||
655 | } | ||
656 | } | ||
657 | } | ||
658 | }}, | ||
659 | } | ||
660 | }, | ||
661 | |||
662 | .power_ctrl = ttusb2_power_ctrl, | ||
663 | .identify_state = ttusb2_identify_state, | ||
664 | |||
665 | .i2c_algo = &ttusb2_i2c_algo, | ||
666 | |||
667 | .generic_bulk_ctrl_endpoint = 0x01, | ||
668 | |||
669 | .num_device_descs = 2, | ||
670 | .devices = { | ||
671 | { "Pinnacle 400e DVB-S USB2.0", | ||
672 | { &ttusb2_table[0], NULL }, | ||
673 | { NULL }, | ||
674 | }, | ||
675 | { "Pinnacle 450e DVB-S USB2.0", | ||
676 | { &ttusb2_table[1], NULL }, | ||
677 | { NULL }, | ||
678 | }, | ||
679 | } | ||
680 | }; | ||
681 | |||
682 | static struct dvb_usb_device_properties ttusb2_properties_s2400 = { | ||
683 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
684 | |||
685 | .usb_ctrl = CYPRESS_FX2, | ||
686 | .firmware = "dvb-usb-tt-s2400-01.fw", | ||
687 | |||
688 | .size_of_priv = sizeof(struct ttusb2_state), | ||
689 | |||
690 | .num_adapters = 1, | ||
691 | .adapter = { | ||
692 | { | ||
693 | .num_frontends = 1, | ||
694 | .fe = {{ | ||
695 | .streaming_ctrl = NULL, | ||
696 | |||
697 | .frontend_attach = ttusb2_frontend_tda10086_attach, | ||
698 | .tuner_attach = ttusb2_tuner_tda826x_attach, | ||
699 | |||
700 | /* parameter for the MPEG2-data transfer */ | ||
701 | .stream = { | ||
702 | .type = USB_ISOC, | ||
703 | .count = 5, | ||
704 | .endpoint = 0x02, | ||
705 | .u = { | ||
706 | .isoc = { | ||
707 | .framesperurb = 4, | ||
708 | .framesize = 940, | ||
709 | .interval = 1, | ||
710 | } | ||
711 | } | ||
712 | } | ||
713 | }}, | ||
714 | } | ||
715 | }, | ||
716 | |||
717 | .power_ctrl = ttusb2_power_ctrl, | ||
718 | .identify_state = ttusb2_identify_state, | ||
719 | |||
720 | .i2c_algo = &ttusb2_i2c_algo, | ||
721 | |||
722 | .generic_bulk_ctrl_endpoint = 0x01, | ||
723 | |||
724 | .num_device_descs = 1, | ||
725 | .devices = { | ||
726 | { "Technotrend TT-connect S-2400", | ||
727 | { &ttusb2_table[2], NULL }, | ||
728 | { NULL }, | ||
729 | }, | ||
730 | } | ||
731 | }; | ||
732 | |||
733 | static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { | ||
734 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
735 | |||
736 | .usb_ctrl = CYPRESS_FX2, | ||
737 | |||
738 | .size_of_priv = sizeof(struct ttusb2_state), | ||
739 | |||
740 | .rc.core = { | ||
741 | .rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */ | ||
742 | .rc_codes = RC_MAP_TT_1500, | ||
743 | .rc_query = tt3650_rc_query, | ||
744 | .allowed_protos = RC_TYPE_UNKNOWN, | ||
745 | }, | ||
746 | |||
747 | .num_adapters = 1, | ||
748 | .adapter = { | ||
749 | { | ||
750 | .num_frontends = 2, | ||
751 | .fe = {{ | ||
752 | .streaming_ctrl = NULL, | ||
753 | |||
754 | .frontend_attach = ttusb2_frontend_tda10023_attach, | ||
755 | .tuner_attach = ttusb2_tuner_tda827x_attach, | ||
756 | |||
757 | /* parameter for the MPEG2-data transfer */ | ||
758 | .stream = { | ||
759 | .type = USB_ISOC, | ||
760 | .count = 5, | ||
761 | .endpoint = 0x02, | ||
762 | .u = { | ||
763 | .isoc = { | ||
764 | .framesperurb = 4, | ||
765 | .framesize = 940, | ||
766 | .interval = 1, | ||
767 | } | ||
768 | } | ||
769 | } | ||
770 | }, { | ||
771 | .streaming_ctrl = NULL, | ||
772 | |||
773 | .frontend_attach = ttusb2_frontend_tda10023_attach, | ||
774 | .tuner_attach = ttusb2_tuner_tda827x_attach, | ||
775 | |||
776 | /* parameter for the MPEG2-data transfer */ | ||
777 | .stream = { | ||
778 | .type = USB_ISOC, | ||
779 | .count = 5, | ||
780 | .endpoint = 0x02, | ||
781 | .u = { | ||
782 | .isoc = { | ||
783 | .framesperurb = 4, | ||
784 | .framesize = 940, | ||
785 | .interval = 1, | ||
786 | } | ||
787 | } | ||
788 | } | ||
789 | }}, | ||
790 | }, | ||
791 | }, | ||
792 | |||
793 | .power_ctrl = ttusb2_power_ctrl, | ||
794 | .identify_state = ttusb2_identify_state, | ||
795 | |||
796 | .i2c_algo = &ttusb2_i2c_algo, | ||
797 | |||
798 | .generic_bulk_ctrl_endpoint = 0x01, | ||
799 | |||
800 | .num_device_descs = 1, | ||
801 | .devices = { | ||
802 | { "Technotrend TT-connect CT-3650", | ||
803 | .warm_ids = { &ttusb2_table[3], NULL }, | ||
804 | }, | ||
805 | } | ||
806 | }; | ||
807 | |||
808 | static struct usb_driver ttusb2_driver = { | ||
809 | .name = "dvb_usb_ttusb2", | ||
810 | .probe = ttusb2_probe, | ||
811 | .disconnect = ttusb2_usb_disconnect, | ||
812 | .id_table = ttusb2_table, | ||
813 | }; | ||
814 | |||
815 | module_usb_driver(ttusb2_driver); | ||
816 | |||
817 | MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); | ||
818 | MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0"); | ||
819 | MODULE_VERSION("1.0"); | ||
820 | MODULE_LICENSE("GPL"); | ||