]>
Commit | Line | Data |
---|---|---|
bc2e3913 PB |
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" | |
76952c7e GM |
32 | #include "tda1002x.h" |
33 | #include "tda827x.h" | |
bc2e3913 PB |
34 | #include "lnbp21.h" |
35 | ||
36 | /* debug */ | |
37 | static int dvb_usb_ttusb2_debug; | |
38 | #define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args) | |
39 | module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644); | |
40 | MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS); | |
41 | ||
78e92006 JG |
42 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
43 | ||
bc2e3913 PB |
44 | struct ttusb2_state { |
45 | u8 id; | |
46 | }; | |
47 | ||
48 | static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, | |
49 | u8 *wbuf, int wlen, u8 *rbuf, int rlen) | |
50 | { | |
51 | struct ttusb2_state *st = d->priv; | |
52 | u8 s[wlen+4],r[64] = { 0 }; | |
53 | int ret = 0; | |
54 | ||
55 | memset(s,0,wlen+4); | |
56 | ||
57 | s[0] = 0xaa; | |
58 | s[1] = ++st->id; | |
59 | s[2] = cmd; | |
60 | s[3] = wlen; | |
61 | memcpy(&s[4],wbuf,wlen); | |
62 | ||
63 | ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0); | |
64 | ||
65 | if (ret != 0 || | |
66 | r[0] != 0x55 || | |
67 | r[1] != s[1] || | |
68 | r[2] != cmd || | |
69 | (rlen > 0 && r[3] != rlen)) { | |
70 | warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]); | |
71 | return -EIO; | |
72 | } | |
73 | ||
74 | if (rlen > 0) | |
75 | memcpy(rbuf, &r[4], rlen); | |
76 | ||
77 | return 0; | |
78 | } | |
79 | ||
80 | static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) | |
81 | { | |
82 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | |
83 | static u8 obuf[60], ibuf[60]; | |
84 | int i,read; | |
85 | ||
86 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | |
87 | return -EAGAIN; | |
88 | ||
89 | if (num > 2) | |
90 | warn("more than 2 i2c messages at a time is not handled yet. TODO."); | |
91 | ||
92 | for (i = 0; i < num; i++) { | |
93 | read = i+1 < num && (msg[i+1].flags & I2C_M_RD); | |
94 | ||
95 | obuf[0] = (msg[i].addr << 1) | read; | |
96 | obuf[1] = msg[i].len; | |
97 | ||
98 | /* read request */ | |
99 | if (read) | |
100 | obuf[2] = msg[i+1].len; | |
101 | else | |
102 | obuf[2] = 0; | |
103 | ||
104 | memcpy(&obuf[3],msg[i].buf,msg[i].len); | |
105 | ||
106 | if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) { | |
107 | err("i2c transfer failed."); | |
108 | break; | |
109 | } | |
110 | ||
111 | if (read) { | |
112 | memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len); | |
113 | i++; | |
114 | } | |
115 | } | |
116 | ||
117 | mutex_unlock(&d->i2c_mutex); | |
118 | return i; | |
119 | } | |
120 | ||
121 | static u32 ttusb2_i2c_func(struct i2c_adapter *adapter) | |
122 | { | |
123 | return I2C_FUNC_I2C; | |
124 | } | |
125 | ||
126 | static struct i2c_algorithm ttusb2_i2c_algo = { | |
127 | .master_xfer = ttusb2_i2c_xfer, | |
128 | .functionality = ttusb2_i2c_func, | |
129 | }; | |
130 | ||
131 | /* Callbacks for DVB USB */ | |
132 | static int ttusb2_identify_state (struct usb_device *udev, struct | |
133 | dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, | |
134 | int *cold) | |
135 | { | |
136 | *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; | |
137 | return 0; | |
138 | } | |
139 | ||
140 | static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff) | |
141 | { | |
142 | u8 b = onoff; | |
143 | ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0); | |
144 | return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0); | |
145 | } | |
146 | ||
147 | ||
148 | static struct tda10086_config tda10086_config = { | |
149 | .demod_address = 0x0e, | |
150 | .invert = 0, | |
ea75baf4 | 151 | .diseqc_tone = 1, |
9a1b04e4 | 152 | .xtal_freq = TDA10086_XTAL_16M, |
bc2e3913 PB |
153 | }; |
154 | ||
76952c7e GM |
155 | static struct tda10023_config tda10023_config = { |
156 | .demod_address = 0x0c, | |
157 | .invert = 0, | |
158 | .xtal = 16000000, | |
159 | .pll_m = 11, | |
160 | .pll_p = 3, | |
161 | .pll_n = 1, | |
162 | .deltaf = 0xa511, | |
163 | }; | |
164 | ||
165 | static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) | |
bc2e3913 PB |
166 | { |
167 | if (usb_set_interface(adap->dev->udev,0,3) < 0) | |
168 | err("set interface to alts=3 failed"); | |
169 | ||
170 | if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { | |
171 | deb_info("TDA10086 attach failed\n"); | |
172 | return -ENODEV; | |
173 | } | |
174 | ||
175 | return 0; | |
176 | } | |
177 | ||
76952c7e GM |
178 | static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) |
179 | { | |
180 | if (usb_set_interface(adap->dev->udev, 0, 3) < 0) | |
181 | err("set interface to alts=3 failed"); | |
182 | if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) { | |
183 | deb_info("TDA10023 attach failed\n"); | |
184 | return -ENODEV; | |
185 | } | |
186 | return 0; | |
187 | } | |
188 | ||
189 | static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) | |
190 | { | |
191 | if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) { | |
192 | printk(KERN_ERR "%s: No tda827x found!\n", __func__); | |
193 | return -ENODEV; | |
194 | } | |
195 | return 0; | |
196 | } | |
197 | ||
198 | static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap) | |
bc2e3913 PB |
199 | { |
200 | if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { | |
201 | deb_info("TDA8263 attach failed\n"); | |
202 | return -ENODEV; | |
203 | } | |
204 | ||
205 | if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) { | |
206 | deb_info("LNBP21 attach failed\n"); | |
207 | return -ENODEV; | |
208 | } | |
209 | return 0; | |
210 | } | |
211 | ||
212 | /* DVB USB Driver stuff */ | |
213 | static struct dvb_usb_device_properties ttusb2_properties; | |
8c899bce | 214 | static struct dvb_usb_device_properties ttusb2_properties_s2400; |
76952c7e | 215 | static struct dvb_usb_device_properties ttusb2_properties_ct3650; |
bc2e3913 PB |
216 | |
217 | static int ttusb2_probe(struct usb_interface *intf, | |
218 | const struct usb_device_id *id) | |
219 | { | |
78e92006 JG |
220 | if (0 == dvb_usb_device_init(intf, &ttusb2_properties, |
221 | THIS_MODULE, NULL, adapter_nr) || | |
222 | 0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400, | |
76952c7e GM |
223 | THIS_MODULE, NULL, adapter_nr) || |
224 | 0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650, | |
78e92006 | 225 | THIS_MODULE, NULL, adapter_nr)) |
8c899bce AW |
226 | return 0; |
227 | return -ENODEV; | |
bc2e3913 PB |
228 | } |
229 | ||
230 | static struct usb_device_id ttusb2_table [] = { | |
8c899bce AW |
231 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, |
232 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) }, | |
233 | { USB_DEVICE(USB_VID_TECHNOTREND, | |
234 | USB_PID_TECHNOTREND_CONNECT_S2400) }, | |
76952c7e GM |
235 | { USB_DEVICE(USB_VID_TECHNOTREND, |
236 | USB_PID_TECHNOTREND_CONNECT_CT3650) }, | |
8c899bce | 237 | {} /* Terminating entry */ |
bc2e3913 PB |
238 | }; |
239 | MODULE_DEVICE_TABLE (usb, ttusb2_table); | |
240 | ||
241 | static struct dvb_usb_device_properties ttusb2_properties = { | |
242 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | |
243 | ||
244 | .usb_ctrl = CYPRESS_FX2, | |
245 | .firmware = "dvb-usb-pctv-400e-01.fw", | |
246 | ||
247 | .size_of_priv = sizeof(struct ttusb2_state), | |
248 | ||
249 | .num_adapters = 1, | |
250 | .adapter = { | |
251 | { | |
252 | .streaming_ctrl = NULL, // ttusb2_streaming_ctrl, | |
253 | ||
76952c7e GM |
254 | .frontend_attach = ttusb2_frontend_tda10086_attach, |
255 | .tuner_attach = ttusb2_tuner_tda826x_attach, | |
bc2e3913 PB |
256 | |
257 | /* parameter for the MPEG2-data transfer */ | |
258 | .stream = { | |
259 | .type = USB_ISOC, | |
260 | .count = 5, | |
261 | .endpoint = 0x02, | |
262 | .u = { | |
263 | .isoc = { | |
264 | .framesperurb = 4, | |
265 | .framesize = 940, | |
266 | .interval = 1, | |
267 | } | |
268 | } | |
269 | } | |
270 | } | |
271 | }, | |
272 | ||
273 | .power_ctrl = ttusb2_power_ctrl, | |
274 | .identify_state = ttusb2_identify_state, | |
275 | ||
276 | .i2c_algo = &ttusb2_i2c_algo, | |
277 | ||
278 | .generic_bulk_ctrl_endpoint = 0x01, | |
279 | ||
ddc9ece8 | 280 | .num_device_descs = 2, |
bc2e3913 PB |
281 | .devices = { |
282 | { "Pinnacle 400e DVB-S USB2.0", | |
283 | { &ttusb2_table[0], NULL }, | |
284 | { NULL }, | |
285 | }, | |
ddc9ece8 CC |
286 | { "Pinnacle 450e DVB-S USB2.0", |
287 | { &ttusb2_table[1], NULL }, | |
288 | { NULL }, | |
289 | }, | |
bc2e3913 PB |
290 | } |
291 | }; | |
292 | ||
8c899bce AW |
293 | static struct dvb_usb_device_properties ttusb2_properties_s2400 = { |
294 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | |
295 | ||
296 | .usb_ctrl = CYPRESS_FX2, | |
297 | .firmware = "dvb-usb-tt-s2400-01.fw", | |
298 | ||
299 | .size_of_priv = sizeof(struct ttusb2_state), | |
300 | ||
301 | .num_adapters = 1, | |
302 | .adapter = { | |
303 | { | |
304 | .streaming_ctrl = NULL, | |
305 | ||
76952c7e GM |
306 | .frontend_attach = ttusb2_frontend_tda10086_attach, |
307 | .tuner_attach = ttusb2_tuner_tda826x_attach, | |
8c899bce AW |
308 | |
309 | /* parameter for the MPEG2-data transfer */ | |
310 | .stream = { | |
311 | .type = USB_ISOC, | |
312 | .count = 5, | |
313 | .endpoint = 0x02, | |
314 | .u = { | |
315 | .isoc = { | |
316 | .framesperurb = 4, | |
317 | .framesize = 940, | |
318 | .interval = 1, | |
319 | } | |
320 | } | |
321 | } | |
322 | } | |
323 | }, | |
324 | ||
325 | .power_ctrl = ttusb2_power_ctrl, | |
326 | .identify_state = ttusb2_identify_state, | |
327 | ||
328 | .i2c_algo = &ttusb2_i2c_algo, | |
329 | ||
330 | .generic_bulk_ctrl_endpoint = 0x01, | |
331 | ||
332 | .num_device_descs = 1, | |
333 | .devices = { | |
334 | { "Technotrend TT-connect S-2400", | |
335 | { &ttusb2_table[2], NULL }, | |
336 | { NULL }, | |
337 | }, | |
338 | } | |
339 | }; | |
340 | ||
76952c7e GM |
341 | static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { |
342 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | |
343 | ||
344 | .usb_ctrl = CYPRESS_FX2, | |
345 | ||
346 | .size_of_priv = sizeof(struct ttusb2_state), | |
347 | ||
348 | .num_adapters = 1, | |
349 | .adapter = { | |
350 | { | |
351 | .streaming_ctrl = NULL, | |
352 | ||
353 | .frontend_attach = ttusb2_frontend_tda10023_attach, | |
354 | .tuner_attach = ttusb2_tuner_tda827x_attach, | |
355 | ||
356 | /* parameter for the MPEG2-data transfer */ | |
357 | .stream = { | |
358 | .type = USB_ISOC, | |
359 | .count = 5, | |
360 | .endpoint = 0x02, | |
361 | .u = { | |
362 | .isoc = { | |
363 | .framesperurb = 4, | |
364 | .framesize = 940, | |
365 | .interval = 1, | |
366 | } | |
367 | } | |
368 | } | |
369 | }, | |
370 | }, | |
371 | ||
372 | .power_ctrl = ttusb2_power_ctrl, | |
373 | .identify_state = ttusb2_identify_state, | |
374 | ||
375 | .i2c_algo = &ttusb2_i2c_algo, | |
376 | ||
377 | .generic_bulk_ctrl_endpoint = 0x01, | |
378 | ||
379 | .num_device_descs = 1, | |
380 | .devices = { | |
381 | { "Technotrend TT-connect CT-3650", | |
382 | .warm_ids = { &ttusb2_table[3], NULL }, | |
383 | }, | |
384 | } | |
385 | }; | |
386 | ||
bc2e3913 PB |
387 | static struct usb_driver ttusb2_driver = { |
388 | .name = "dvb_usb_ttusb2", | |
389 | .probe = ttusb2_probe, | |
390 | .disconnect = dvb_usb_device_exit, | |
391 | .id_table = ttusb2_table, | |
392 | }; | |
393 | ||
394 | /* module stuff */ | |
395 | static int __init ttusb2_module_init(void) | |
396 | { | |
397 | int result; | |
398 | if ((result = usb_register(&ttusb2_driver))) { | |
399 | err("usb_register failed. Error number %d",result); | |
400 | return result; | |
401 | } | |
402 | ||
403 | return 0; | |
404 | } | |
405 | ||
406 | static void __exit ttusb2_module_exit(void) | |
407 | { | |
408 | /* deregister this driver from the USB subsystem */ | |
409 | usb_deregister(&ttusb2_driver); | |
410 | } | |
411 | ||
412 | module_init (ttusb2_module_init); | |
413 | module_exit (ttusb2_module_exit); | |
414 | ||
415 | MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); | |
416 | MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0"); | |
417 | MODULE_VERSION("1.0"); | |
418 | MODULE_LICENSE("GPL"); |