1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver |
3 | * |
4 | * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org) |
5 | * |
6 | * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information |
7 | */ |
8 | |
9 | #include "m920x.h" |
10 | |
11 | #include "mt352.h" |
12 | #include "mt352_priv.h" |
13 | #include "qt1010.h" |
14 | #include "tda1004x.h" |
15 | #include "tda827x.h" |
16 | #include "mt2060.h" |
17 | |
18 | #include <media/tuner.h> |
19 | #include "tuner-simple.h" |
20 | #include <asm/unaligned.h> |
21 | |
22 | /* debug */ |
23 | static int dvb_usb_m920x_debug; |
24 | module_param_named(debug,dvb_usb_m920x_debug, int, 0644); |
25 | MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); |
26 | |
27 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
28 | |
29 | static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid); |
30 | |
31 | static inline int m920x_read(struct usb_device *udev, u8 request, u16 value, |
32 | u16 index, void *data, int size) |
33 | { |
34 | int ret; |
35 | |
36 | ret = usb_control_msg(dev: udev, usb_rcvctrlpipe(udev, 0), |
37 | request, USB_TYPE_VENDOR | USB_DIR_IN, |
38 | value, index, data, size, timeout: 2000); |
39 | if (ret < 0) { |
40 | printk(KERN_INFO "m920x_read = error: %d\n" , ret); |
41 | return ret; |
42 | } |
43 | |
44 | if (ret != size) { |
45 | deb("m920x_read = no data\n" ); |
46 | return -EIO; |
47 | } |
48 | |
49 | return 0; |
50 | } |
51 | |
52 | static inline int m920x_write(struct usb_device *udev, u8 request, |
53 | u16 value, u16 index) |
54 | { |
55 | return usb_control_msg(dev: udev, usb_sndctrlpipe(udev, 0), request, |
56 | USB_TYPE_VENDOR | USB_DIR_OUT, value, index, |
57 | NULL, size: 0, timeout: 2000); |
58 | } |
59 | |
60 | static inline int m920x_write_seq(struct usb_device *udev, u8 request, |
61 | struct m920x_inits *seq) |
62 | { |
63 | int ret; |
64 | do { |
65 | ret = m920x_write(udev, request, value: seq->data, index: seq->address); |
66 | if (ret != 0) |
67 | return ret; |
68 | |
69 | seq++; |
70 | } while (seq->address); |
71 | |
72 | return 0; |
73 | } |
74 | |
75 | static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq) |
76 | { |
77 | int ret, i, epi, flags = 0; |
78 | int adap_enabled[M9206_MAX_ADAPTERS] = { 0 }; |
79 | |
80 | /* Remote controller init. */ |
81 | if (d->props.rc.legacy.rc_query || d->props.rc.core.rc_query) { |
82 | deb("Initialising remote control\n" ); |
83 | ret = m920x_write_seq(udev: d->udev, M9206_CORE, seq: rc_seq); |
84 | if (ret != 0) { |
85 | deb("Initialising remote control failed\n" ); |
86 | return ret; |
87 | } |
88 | |
89 | deb("Initialising remote control success\n" ); |
90 | } |
91 | |
92 | for (i = 0; i < d->props.num_adapters; i++) |
93 | flags |= d->adapter[i].props.fe[0].caps; |
94 | |
95 | /* Some devices(Dposh) might crash if we attempt touch at all. */ |
96 | if (flags & DVB_USB_ADAP_HAS_PID_FILTER) { |
97 | for (i = 0; i < d->props.num_adapters; i++) { |
98 | epi = d->adapter[i].props.fe[0].stream.endpoint - 0x81; |
99 | |
100 | if (epi < 0 || epi >= M9206_MAX_ADAPTERS) { |
101 | printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n" ); |
102 | return -EINVAL; |
103 | } |
104 | |
105 | adap_enabled[epi] = 1; |
106 | } |
107 | |
108 | for (i = 0; i < M9206_MAX_ADAPTERS; i++) { |
109 | if (adap_enabled[i]) |
110 | continue; |
111 | |
112 | if ((ret = m920x_set_filter(d, type: 0x81 + i, idx: 0, pid: 0x0)) != 0) |
113 | return ret; |
114 | |
115 | if ((ret = m920x_set_filter(d, type: 0x81 + i, idx: 0, pid: 0x02f5)) != 0) |
116 | return ret; |
117 | } |
118 | } |
119 | |
120 | return 0; |
121 | } |
122 | |
123 | static int m920x_init_ep(struct usb_interface *intf) |
124 | { |
125 | struct usb_device *udev = interface_to_usbdev(intf); |
126 | struct usb_host_interface *alt; |
127 | |
128 | if ((alt = usb_altnum_to_altsetting(intf, altnum: 1)) == NULL) { |
129 | deb("No alt found!\n" ); |
130 | return -ENODEV; |
131 | } |
132 | |
133 | return usb_set_interface(dev: udev, ifnum: alt->desc.bInterfaceNumber, |
134 | alternate: alt->desc.bAlternateSetting); |
135 | } |
136 | |
137 | static inline void m920x_parse_rc_state(struct dvb_usb_device *d, u8 rc_state, |
138 | int *state) |
139 | { |
140 | struct m920x_state *m = d->priv; |
141 | |
142 | switch (rc_state) { |
143 | case 0x80: |
144 | *state = REMOTE_NO_KEY_PRESSED; |
145 | break; |
146 | |
147 | case 0x88: /* framing error or "invalid code" */ |
148 | case 0x99: |
149 | case 0xc0: |
150 | case 0xd8: |
151 | *state = REMOTE_NO_KEY_PRESSED; |
152 | m->rep_count = 0; |
153 | break; |
154 | |
155 | case 0x93: |
156 | case 0x92: |
157 | case 0x83: /* pinnacle PCTV310e */ |
158 | case 0x82: |
159 | m->rep_count = 0; |
160 | *state = REMOTE_KEY_PRESSED; |
161 | break; |
162 | |
163 | case 0x91: |
164 | case 0x81: /* pinnacle PCTV310e */ |
165 | /* prevent immediate auto-repeat */ |
166 | if (++m->rep_count > 2) |
167 | *state = REMOTE_KEY_REPEAT; |
168 | else |
169 | *state = REMOTE_NO_KEY_PRESSED; |
170 | break; |
171 | |
172 | default: |
173 | deb("Unexpected rc state %02x\n" , rc_state); |
174 | *state = REMOTE_NO_KEY_PRESSED; |
175 | break; |
176 | } |
177 | } |
178 | |
179 | static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) |
180 | { |
181 | int i, ret = 0; |
182 | u8 *rc_state; |
183 | |
184 | rc_state = kmalloc(size: 2, GFP_KERNEL); |
185 | if (!rc_state) |
186 | return -ENOMEM; |
187 | |
188 | ret = m920x_read(udev: d->udev, M9206_CORE, value: 0x0, M9206_RC_STATE, |
189 | data: rc_state, size: 1); |
190 | if (ret != 0) |
191 | goto out; |
192 | |
193 | ret = m920x_read(udev: d->udev, M9206_CORE, value: 0x0, M9206_RC_KEY, |
194 | data: rc_state + 1, size: 1); |
195 | if (ret != 0) |
196 | goto out; |
197 | |
198 | m920x_parse_rc_state(d, rc_state: rc_state[0], state); |
199 | |
200 | for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) |
201 | if (rc5_data(key: &d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) { |
202 | *event = d->props.rc.legacy.rc_map_table[i].keycode; |
203 | goto out; |
204 | } |
205 | |
206 | if (rc_state[1] != 0) |
207 | deb("Unknown rc key %02x\n" , rc_state[1]); |
208 | |
209 | *state = REMOTE_NO_KEY_PRESSED; |
210 | |
211 | out: |
212 | kfree(objp: rc_state); |
213 | return ret; |
214 | } |
215 | |
216 | static int m920x_rc_core_query(struct dvb_usb_device *d) |
217 | { |
218 | int ret = 0; |
219 | u8 *rc_state; |
220 | int state; |
221 | |
222 | rc_state = kmalloc(size: 2, GFP_KERNEL); |
223 | if (!rc_state) |
224 | return -ENOMEM; |
225 | |
226 | if ((ret = m920x_read(udev: d->udev, M9206_CORE, value: 0x0, M9206_RC_STATE, data: &rc_state[0], size: 1)) != 0) |
227 | goto out; |
228 | |
229 | if ((ret = m920x_read(udev: d->udev, M9206_CORE, value: 0x0, M9206_RC_KEY, data: &rc_state[1], size: 1)) != 0) |
230 | goto out; |
231 | |
232 | deb("state=0x%02x keycode=0x%02x\n" , rc_state[0], rc_state[1]); |
233 | |
234 | m920x_parse_rc_state(d, rc_state: rc_state[0], state: &state); |
235 | |
236 | if (state == REMOTE_NO_KEY_PRESSED) |
237 | rc_keyup(dev: d->rc_dev); |
238 | else if (state == REMOTE_KEY_REPEAT) |
239 | rc_repeat(dev: d->rc_dev); |
240 | else |
241 | rc_keydown(dev: d->rc_dev, protocol: RC_PROTO_UNKNOWN, scancode: rc_state[1], toggle: 0); |
242 | |
243 | out: |
244 | kfree(objp: rc_state); |
245 | return ret; |
246 | } |
247 | |
248 | /* I2C */ |
249 | static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) |
250 | { |
251 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
252 | int i, j; |
253 | int ret = 0; |
254 | |
255 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) |
256 | return -EAGAIN; |
257 | |
258 | for (i = 0; i < num; i++) { |
259 | if (msg[i].flags & (I2C_M_NO_RD_ACK | I2C_M_IGNORE_NAK | I2C_M_TEN) || msg[i].len == 0) { |
260 | /* For a 0 byte message, I think sending the address |
261 | * to index 0x80|0x40 would be the correct thing to |
262 | * do. However, zero byte messages are only used for |
263 | * probing, and since we don't know how to get the |
264 | * slave's ack, we can't probe. */ |
265 | ret = -ENOTSUPP; |
266 | goto unlock; |
267 | } |
268 | /* Send START & address/RW bit */ |
269 | if (!(msg[i].flags & I2C_M_NOSTART)) { |
270 | if ((ret = m920x_write(udev: d->udev, M9206_I2C, |
271 | value: (msg[i].addr << 1) | |
272 | (msg[i].flags & I2C_M_RD ? 0x01 : 0), index: 0x80)) != 0) |
273 | goto unlock; |
274 | /* Should check for ack here, if we knew how. */ |
275 | } |
276 | if (msg[i].flags & I2C_M_RD) { |
277 | char *read = kmalloc(size: 1, GFP_KERNEL); |
278 | if (!read) { |
279 | ret = -ENOMEM; |
280 | goto unlock; |
281 | } |
282 | |
283 | for (j = 0; j < msg[i].len; j++) { |
284 | /* Last byte of transaction? |
285 | * Send STOP, otherwise send ACK. */ |
286 | int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x01; |
287 | |
288 | if ((ret = m920x_read(udev: d->udev, M9206_I2C, value: 0x0, |
289 | index: 0x20 | stop, |
290 | data: read, size: 1)) != 0) { |
291 | kfree(objp: read); |
292 | goto unlock; |
293 | } |
294 | msg[i].buf[j] = read[0]; |
295 | } |
296 | |
297 | kfree(objp: read); |
298 | } else { |
299 | for (j = 0; j < msg[i].len; j++) { |
300 | /* Last byte of transaction? Then send STOP. */ |
301 | int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x00; |
302 | |
303 | if ((ret = m920x_write(udev: d->udev, M9206_I2C, value: msg[i].buf[j], index: stop)) != 0) |
304 | goto unlock; |
305 | /* Should check for ack here too. */ |
306 | } |
307 | } |
308 | } |
309 | ret = num; |
310 | |
311 | unlock: |
312 | mutex_unlock(lock: &d->i2c_mutex); |
313 | |
314 | return ret; |
315 | } |
316 | |
317 | static u32 m920x_i2c_func(struct i2c_adapter *adapter) |
318 | { |
319 | return I2C_FUNC_I2C; |
320 | } |
321 | |
322 | static struct i2c_algorithm m920x_i2c_algo = { |
323 | .master_xfer = m920x_i2c_xfer, |
324 | .functionality = m920x_i2c_func, |
325 | }; |
326 | |
327 | /* pid filter */ |
328 | static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid) |
329 | { |
330 | int ret = 0; |
331 | |
332 | if (pid >= 0x8000) |
333 | return -EINVAL; |
334 | |
335 | pid |= 0x8000; |
336 | |
337 | if ((ret = m920x_write(udev: d->udev, M9206_FILTER, value: pid, index: (type << 8) | (idx * 4) )) != 0) |
338 | return ret; |
339 | |
340 | if ((ret = m920x_write(udev: d->udev, M9206_FILTER, value: 0, index: (type << 8) | (idx * 4) )) != 0) |
341 | return ret; |
342 | |
343 | return ret; |
344 | } |
345 | |
346 | static int m920x_update_filters(struct dvb_usb_adapter *adap) |
347 | { |
348 | struct m920x_state *m = adap->dev->priv; |
349 | int enabled = m->filtering_enabled[adap->id]; |
350 | int i, ret = 0, filter = 0; |
351 | int ep = adap->props.fe[0].stream.endpoint; |
352 | |
353 | for (i = 0; i < M9206_MAX_FILTERS; i++) |
354 | if (m->filters[adap->id][i] == 8192) |
355 | enabled = 0; |
356 | |
357 | /* Disable all filters */ |
358 | if ((ret = m920x_set_filter(d: adap->dev, type: ep, idx: 1, pid: enabled)) != 0) |
359 | return ret; |
360 | |
361 | for (i = 0; i < M9206_MAX_FILTERS; i++) |
362 | if ((ret = m920x_set_filter(d: adap->dev, type: ep, idx: i + 2, pid: 0)) != 0) |
363 | return ret; |
364 | |
365 | /* Set */ |
366 | if (enabled) { |
367 | for (i = 0; i < M9206_MAX_FILTERS; i++) { |
368 | if (m->filters[adap->id][i] == 0) |
369 | continue; |
370 | |
371 | if ((ret = m920x_set_filter(d: adap->dev, type: ep, idx: filter + 2, pid: m->filters[adap->id][i])) != 0) |
372 | return ret; |
373 | |
374 | filter++; |
375 | } |
376 | } |
377 | |
378 | return ret; |
379 | } |
380 | |
381 | static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) |
382 | { |
383 | struct m920x_state *m = adap->dev->priv; |
384 | |
385 | m->filtering_enabled[adap->id] = onoff ? 1 : 0; |
386 | |
387 | return m920x_update_filters(adap); |
388 | } |
389 | |
390 | static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) |
391 | { |
392 | struct m920x_state *m = adap->dev->priv; |
393 | |
394 | m->filters[adap->id][index] = onoff ? pid : 0; |
395 | |
396 | return m920x_update_filters(adap); |
397 | } |
398 | |
399 | static int m920x_firmware_download(struct usb_device *udev, const struct firmware *fw) |
400 | { |
401 | u16 value, index, size; |
402 | u8 *read, *buff; |
403 | int i, pass, ret = 0; |
404 | |
405 | buff = kmalloc(size: 65536, GFP_KERNEL); |
406 | if (buff == NULL) |
407 | return -ENOMEM; |
408 | |
409 | read = kmalloc(size: 4, GFP_KERNEL); |
410 | if (!read) { |
411 | kfree(objp: buff); |
412 | return -ENOMEM; |
413 | } |
414 | |
415 | if ((ret = m920x_read(udev, M9206_FILTER, value: 0x0, index: 0x8000, data: read, size: 4)) != 0) |
416 | goto done; |
417 | deb("%*ph\n" , 4, read); |
418 | |
419 | if ((ret = m920x_read(udev, M9206_FW, value: 0x0, index: 0x0, data: read, size: 1)) != 0) |
420 | goto done; |
421 | deb("%x\n" , read[0]); |
422 | |
423 | for (pass = 0; pass < 2; pass++) { |
424 | for (i = 0; i + (sizeof(u16) * 3) < fw->size;) { |
425 | value = get_unaligned_le16(p: fw->data + i); |
426 | i += sizeof(u16); |
427 | |
428 | index = get_unaligned_le16(p: fw->data + i); |
429 | i += sizeof(u16); |
430 | |
431 | size = get_unaligned_le16(p: fw->data + i); |
432 | i += sizeof(u16); |
433 | |
434 | if (pass == 1) { |
435 | /* Will stall if using fw->data ... */ |
436 | memcpy(buff, fw->data + i, size); |
437 | |
438 | ret = usb_control_msg(dev: udev, usb_sndctrlpipe(udev,0), |
439 | M9206_FW, |
440 | USB_TYPE_VENDOR | USB_DIR_OUT, |
441 | value, index, data: buff, size, timeout: 20); |
442 | if (ret != size) { |
443 | deb("error while uploading fw!\n" ); |
444 | ret = -EIO; |
445 | goto done; |
446 | } |
447 | msleep(msecs: 3); |
448 | } |
449 | i += size; |
450 | } |
451 | if (i != fw->size) { |
452 | deb("bad firmware file!\n" ); |
453 | ret = -EINVAL; |
454 | goto done; |
455 | } |
456 | } |
457 | |
458 | msleep(msecs: 36); |
459 | |
460 | /* m920x will disconnect itself from the bus after this. */ |
461 | (void) m920x_write(udev, M9206_CORE, value: 0x01, M9206_FW_GO); |
462 | deb("firmware uploaded!\n" ); |
463 | |
464 | done: |
465 | kfree(objp: read); |
466 | kfree(objp: buff); |
467 | |
468 | return ret; |
469 | } |
470 | |
471 | /* Callbacks for DVB USB */ |
472 | static int m920x_identify_state(struct usb_device *udev, |
473 | const struct dvb_usb_device_properties *props, |
474 | const struct dvb_usb_device_description **desc, |
475 | int *cold) |
476 | { |
477 | struct usb_host_interface *alt; |
478 | |
479 | alt = usb_altnum_to_altsetting(intf: usb_ifnum_to_if(dev: udev, ifnum: 0), altnum: 1); |
480 | *cold = (alt == NULL) ? 1 : 0; |
481 | |
482 | return 0; |
483 | } |
484 | |
485 | /* demod configurations */ |
486 | static int m920x_mt352_demod_init(struct dvb_frontend *fe) |
487 | { |
488 | int ret; |
489 | static const u8 config[] = { CONFIG, 0x3d }; |
490 | static const u8 clock[] = { CLOCK_CTL, 0x30 }; |
491 | static const u8 reset[] = { RESET, 0x80 }; |
492 | static const u8 adc_ctl[] = { ADC_CTL_1, 0x40 }; |
493 | static const u8 agc[] = { AGC_TARGET, 0x1c, 0x20 }; |
494 | static const u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 }; |
495 | static const u8 unk1[] = { 0x93, 0x1a }; |
496 | static const u8 unk2[] = { 0xb5, 0x7a }; |
497 | |
498 | deb("Demod init!\n" ); |
499 | |
500 | if ((ret = mt352_write(fe, buf: config, ARRAY_SIZE(config))) != 0) |
501 | return ret; |
502 | if ((ret = mt352_write(fe, buf: clock, ARRAY_SIZE(clock))) != 0) |
503 | return ret; |
504 | if ((ret = mt352_write(fe, buf: reset, ARRAY_SIZE(reset))) != 0) |
505 | return ret; |
506 | if ((ret = mt352_write(fe, buf: adc_ctl, ARRAY_SIZE(adc_ctl))) != 0) |
507 | return ret; |
508 | if ((ret = mt352_write(fe, buf: agc, ARRAY_SIZE(agc))) != 0) |
509 | return ret; |
510 | if ((ret = mt352_write(fe, buf: sec_agc, ARRAY_SIZE(sec_agc))) != 0) |
511 | return ret; |
512 | if ((ret = mt352_write(fe, buf: unk1, ARRAY_SIZE(unk1))) != 0) |
513 | return ret; |
514 | if ((ret = mt352_write(fe, buf: unk2, ARRAY_SIZE(unk2))) != 0) |
515 | return ret; |
516 | |
517 | return 0; |
518 | } |
519 | |
520 | static struct mt352_config m920x_mt352_config = { |
521 | .demod_address = 0x0f, |
522 | .no_tuner = 1, |
523 | .demod_init = m920x_mt352_demod_init, |
524 | }; |
525 | |
526 | static struct tda1004x_config m920x_tda10046_08_config = { |
527 | .demod_address = 0x08, |
528 | .invert = 0, |
529 | .invert_oclk = 0, |
530 | .ts_mode = TDA10046_TS_SERIAL, |
531 | .xtal_freq = TDA10046_XTAL_16M, |
532 | .if_freq = TDA10046_FREQ_045, |
533 | .agc_config = TDA10046_AGC_TDA827X, |
534 | .gpio_config = TDA10046_GPTRI, |
535 | .request_firmware = NULL, |
536 | }; |
537 | |
538 | static struct tda1004x_config m920x_tda10046_0b_config = { |
539 | .demod_address = 0x0b, |
540 | .invert = 0, |
541 | .invert_oclk = 0, |
542 | .ts_mode = TDA10046_TS_SERIAL, |
543 | .xtal_freq = TDA10046_XTAL_16M, |
544 | .if_freq = TDA10046_FREQ_045, |
545 | .agc_config = TDA10046_AGC_TDA827X, |
546 | .gpio_config = TDA10046_GPTRI, |
547 | .request_firmware = NULL, /* uses firmware EEPROM */ |
548 | }; |
549 | |
550 | /* tuner configurations */ |
551 | static struct qt1010_config m920x_qt1010_config = { |
552 | .i2c_address = 0x62 |
553 | }; |
554 | |
555 | static struct mt2060_config m920x_mt2060_config = { |
556 | .i2c_address = 0x60, /* 0xc0 */ |
557 | .clock_out = 0, |
558 | }; |
559 | |
560 | |
561 | /* Callbacks for DVB USB */ |
562 | static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap) |
563 | { |
564 | deb("%s\n" ,__func__); |
565 | |
566 | adap->fe_adap[0].fe = dvb_attach(mt352_attach, |
567 | &m920x_mt352_config, |
568 | &adap->dev->i2c_adap); |
569 | if ((adap->fe_adap[0].fe) == NULL) |
570 | return -EIO; |
571 | |
572 | return 0; |
573 | } |
574 | |
575 | static int m920x_mt352_frontend_attach_vp7049(struct dvb_usb_adapter *adap) |
576 | { |
577 | struct m920x_inits vp7049_fe_init_seq[] = { |
578 | /* XXX without these commands the frontend cannot be detected, |
579 | * they must be sent BEFORE the frontend is attached */ |
580 | { 0xff28, 0x00 }, |
581 | { 0xff23, 0x00 }, |
582 | { 0xff28, 0x00 }, |
583 | { 0xff23, 0x00 }, |
584 | { 0xff21, 0x20 }, |
585 | { 0xff21, 0x60 }, |
586 | { 0xff28, 0x00 }, |
587 | { 0xff22, 0x00 }, |
588 | { 0xff20, 0x30 }, |
589 | { 0xff20, 0x20 }, |
590 | { 0xff20, 0x30 }, |
591 | { } /* terminating entry */ |
592 | }; |
593 | int ret; |
594 | |
595 | deb("%s\n" , __func__); |
596 | |
597 | ret = m920x_write_seq(udev: adap->dev->udev, M9206_CORE, seq: vp7049_fe_init_seq); |
598 | if (ret != 0) { |
599 | deb("Initialization of vp7049 frontend failed." ); |
600 | return ret; |
601 | } |
602 | |
603 | return m920x_mt352_frontend_attach(adap); |
604 | } |
605 | |
606 | static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap) |
607 | { |
608 | deb("%s\n" ,__func__); |
609 | |
610 | adap->fe_adap[0].fe = dvb_attach(tda10046_attach, |
611 | &m920x_tda10046_08_config, |
612 | &adap->dev->i2c_adap); |
613 | if ((adap->fe_adap[0].fe) == NULL) |
614 | return -EIO; |
615 | |
616 | return 0; |
617 | } |
618 | |
619 | static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap) |
620 | { |
621 | deb("%s\n" ,__func__); |
622 | |
623 | adap->fe_adap[0].fe = dvb_attach(tda10046_attach, |
624 | &m920x_tda10046_0b_config, |
625 | &adap->dev->i2c_adap); |
626 | if ((adap->fe_adap[0].fe) == NULL) |
627 | return -EIO; |
628 | |
629 | return 0; |
630 | } |
631 | |
632 | static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap) |
633 | { |
634 | deb("%s\n" ,__func__); |
635 | |
636 | if (dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL) |
637 | return -ENODEV; |
638 | |
639 | return 0; |
640 | } |
641 | |
642 | static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap) |
643 | { |
644 | deb("%s\n" ,__func__); |
645 | |
646 | if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL) |
647 | return -ENODEV; |
648 | |
649 | return 0; |
650 | } |
651 | |
652 | static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap) |
653 | { |
654 | deb("%s\n" ,__func__); |
655 | |
656 | if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) |
657 | return -ENODEV; |
658 | |
659 | return 0; |
660 | } |
661 | |
662 | static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) |
663 | { |
664 | dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, |
665 | &adap->dev->i2c_adap, 0x61, |
666 | TUNER_PHILIPS_FMD1216ME_MK3); |
667 | return 0; |
668 | } |
669 | |
670 | static int m920x_mt2060_tuner_attach(struct dvb_usb_adapter *adap) |
671 | { |
672 | deb("%s\n" , __func__); |
673 | |
674 | if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, |
675 | &m920x_mt2060_config, 1220) == NULL) |
676 | return -ENODEV; |
677 | |
678 | return 0; |
679 | } |
680 | |
681 | |
682 | /* device-specific initialization */ |
683 | static struct m920x_inits megasky_rc_init [] = { |
684 | { M9206_RC_INIT2, 0xa8 }, |
685 | { M9206_RC_INIT1, 0x51 }, |
686 | { } /* terminating entry */ |
687 | }; |
688 | |
689 | static struct m920x_inits tvwalkertwin_rc_init [] = { |
690 | { M9206_RC_INIT2, 0x00 }, |
691 | { M9206_RC_INIT1, 0xef }, |
692 | { 0xff28, 0x00 }, |
693 | { 0xff23, 0x00 }, |
694 | { 0xff21, 0x30 }, |
695 | { } /* terminating entry */ |
696 | }; |
697 | |
698 | static struct m920x_inits pinnacle310e_init[] = { |
699 | /* without these the tuner doesn't work */ |
700 | { 0xff20, 0x9b }, |
701 | { 0xff22, 0x70 }, |
702 | |
703 | /* rc settings */ |
704 | { 0xff50, 0x80 }, |
705 | { M9206_RC_INIT1, 0x00 }, |
706 | { M9206_RC_INIT2, 0xff }, |
707 | { } /* terminating entry */ |
708 | }; |
709 | |
710 | static struct m920x_inits vp7049_rc_init[] = { |
711 | { 0xff28, 0x00 }, |
712 | { 0xff23, 0x00 }, |
713 | { 0xff21, 0x70 }, |
714 | { M9206_RC_INIT2, 0x00 }, |
715 | { M9206_RC_INIT1, 0xff }, |
716 | { } /* terminating entry */ |
717 | }; |
718 | |
719 | /* ir keymaps */ |
720 | static struct rc_map_table rc_map_megasky_table[] = { |
721 | { 0x0012, KEY_POWER }, |
722 | { 0x001e, KEY_CYCLEWINDOWS }, /* min/max */ |
723 | { 0x0002, KEY_CHANNELUP }, |
724 | { 0x0005, KEY_CHANNELDOWN }, |
725 | { 0x0003, KEY_VOLUMEUP }, |
726 | { 0x0006, KEY_VOLUMEDOWN }, |
727 | { 0x0004, KEY_MUTE }, |
728 | { 0x0007, KEY_OK }, /* TS */ |
729 | { 0x0008, KEY_STOP }, |
730 | { 0x0009, KEY_MENU }, /* swap */ |
731 | { 0x000a, KEY_REWIND }, |
732 | { 0x001b, KEY_PAUSE }, |
733 | { 0x001f, KEY_FASTFORWARD }, |
734 | { 0x000c, KEY_RECORD }, |
735 | { 0x000d, KEY_CAMERA }, /* screenshot */ |
736 | { 0x000e, KEY_COFFEE }, /* "MTS" */ |
737 | }; |
738 | |
739 | static struct rc_map_table rc_map_tvwalkertwin_table[] = { |
740 | { 0x0001, KEY_ZOOM }, /* Full Screen */ |
741 | { 0x0002, KEY_CAMERA }, /* snapshot */ |
742 | { 0x0003, KEY_MUTE }, |
743 | { 0x0004, KEY_REWIND }, |
744 | { 0x0005, KEY_PLAYPAUSE }, /* Play/Pause */ |
745 | { 0x0006, KEY_FASTFORWARD }, |
746 | { 0x0007, KEY_RECORD }, |
747 | { 0x0008, KEY_STOP }, |
748 | { 0x0009, KEY_TIME }, /* Timeshift */ |
749 | { 0x000c, KEY_COFFEE }, /* Recall */ |
750 | { 0x000e, KEY_CHANNELUP }, |
751 | { 0x0012, KEY_POWER }, |
752 | { 0x0015, KEY_MENU }, /* source */ |
753 | { 0x0018, KEY_CYCLEWINDOWS }, /* TWIN PIP */ |
754 | { 0x001a, KEY_CHANNELDOWN }, |
755 | { 0x001b, KEY_VOLUMEDOWN }, |
756 | { 0x001e, KEY_VOLUMEUP }, |
757 | }; |
758 | |
759 | static struct rc_map_table rc_map_pinnacle310e_table[] = { |
760 | { 0x16, KEY_POWER }, |
761 | { 0x17, KEY_FAVORITES }, |
762 | { 0x0f, KEY_TEXT }, |
763 | { 0x48, KEY_PROGRAM }, /* preview */ |
764 | { 0x1c, KEY_EPG }, |
765 | { 0x04, KEY_LIST }, /* record list */ |
766 | { 0x03, KEY_1 }, |
767 | { 0x01, KEY_2 }, |
768 | { 0x06, KEY_3 }, |
769 | { 0x09, KEY_4 }, |
770 | { 0x1d, KEY_5 }, |
771 | { 0x1f, KEY_6 }, |
772 | { 0x0d, KEY_7 }, |
773 | { 0x19, KEY_8 }, |
774 | { 0x1b, KEY_9 }, |
775 | { 0x15, KEY_0 }, |
776 | { 0x0c, KEY_CANCEL }, |
777 | { 0x4a, KEY_CLEAR }, |
778 | { 0x13, KEY_BACK }, |
779 | { 0x00, KEY_TAB }, |
780 | { 0x4b, KEY_UP }, |
781 | { 0x4e, KEY_LEFT }, |
782 | { 0x52, KEY_RIGHT }, |
783 | { 0x51, KEY_DOWN }, |
784 | { 0x4f, KEY_ENTER }, /* could also be KEY_OK */ |
785 | { 0x1e, KEY_VOLUMEUP }, |
786 | { 0x0a, KEY_VOLUMEDOWN }, |
787 | { 0x05, KEY_CHANNELUP }, |
788 | { 0x02, KEY_CHANNELDOWN }, |
789 | { 0x11, KEY_RECORD }, |
790 | { 0x14, KEY_PLAY }, |
791 | { 0x4c, KEY_PAUSE }, |
792 | { 0x1a, KEY_STOP }, |
793 | { 0x40, KEY_REWIND }, |
794 | { 0x12, KEY_FASTFORWARD }, |
795 | { 0x41, KEY_PREVIOUSSONG }, /* Replay */ |
796 | { 0x42, KEY_NEXTSONG }, /* Skip */ |
797 | { 0x54, KEY_CAMERA }, /* Capture */ |
798 | /* { 0x50, KEY_SAP }, */ /* Sap */ |
799 | { 0x47, KEY_CYCLEWINDOWS }, /* Pip */ |
800 | { 0x4d, KEY_SCREEN }, /* FullScreen */ |
801 | { 0x08, KEY_SUBTITLE }, |
802 | { 0x0e, KEY_MUTE }, |
803 | /* { 0x49, KEY_LR }, */ /* L/R */ |
804 | { 0x07, KEY_SLEEP }, /* Hibernate */ |
805 | { 0x08, KEY_VIDEO }, /* A/V */ |
806 | { 0x0e, KEY_MENU }, /* Recall */ |
807 | { 0x45, KEY_ZOOMIN }, |
808 | { 0x46, KEY_ZOOMOUT }, |
809 | { 0x18, KEY_RED }, /* Red */ |
810 | { 0x53, KEY_GREEN }, /* Green */ |
811 | { 0x5e, KEY_YELLOW }, /* Yellow */ |
812 | { 0x5f, KEY_BLUE }, /* Blue */ |
813 | }; |
814 | |
815 | /* DVB USB Driver stuff */ |
816 | static struct dvb_usb_device_properties megasky_properties; |
817 | static struct dvb_usb_device_properties digivox_mini_ii_properties; |
818 | static struct dvb_usb_device_properties tvwalkertwin_properties; |
819 | static struct dvb_usb_device_properties dposh_properties; |
820 | static struct dvb_usb_device_properties pinnacle_pctv310e_properties; |
821 | static struct dvb_usb_device_properties vp7049_properties; |
822 | |
823 | static int m920x_probe(struct usb_interface *intf, |
824 | const struct usb_device_id *id) |
825 | { |
826 | struct dvb_usb_device *d = NULL; |
827 | int ret; |
828 | struct m920x_inits *rc_init_seq = NULL; |
829 | int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber; |
830 | |
831 | deb("Probing for m920x device at interface %d\n" , bInterfaceNumber); |
832 | |
833 | if (bInterfaceNumber == 0) { |
834 | /* Single-tuner device, or first interface on |
835 | * multi-tuner device |
836 | */ |
837 | |
838 | ret = dvb_usb_device_init(intf, &megasky_properties, |
839 | THIS_MODULE, &d, adapter_nums: adapter_nr); |
840 | if (ret == 0) { |
841 | rc_init_seq = megasky_rc_init; |
842 | goto found; |
843 | } |
844 | |
845 | ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties, |
846 | THIS_MODULE, &d, adapter_nums: adapter_nr); |
847 | if (ret == 0) { |
848 | /* No remote control, so no rc_init_seq */ |
849 | goto found; |
850 | } |
851 | |
852 | /* This configures both tuners on the TV Walker Twin */ |
853 | ret = dvb_usb_device_init(intf, &tvwalkertwin_properties, |
854 | THIS_MODULE, &d, adapter_nums: adapter_nr); |
855 | if (ret == 0) { |
856 | rc_init_seq = tvwalkertwin_rc_init; |
857 | goto found; |
858 | } |
859 | |
860 | ret = dvb_usb_device_init(intf, &dposh_properties, |
861 | THIS_MODULE, &d, adapter_nums: adapter_nr); |
862 | if (ret == 0) { |
863 | /* Remote controller not supported yet. */ |
864 | goto found; |
865 | } |
866 | |
867 | ret = dvb_usb_device_init(intf, &pinnacle_pctv310e_properties, |
868 | THIS_MODULE, &d, adapter_nums: adapter_nr); |
869 | if (ret == 0) { |
870 | rc_init_seq = pinnacle310e_init; |
871 | goto found; |
872 | } |
873 | |
874 | ret = dvb_usb_device_init(intf, &vp7049_properties, |
875 | THIS_MODULE, &d, adapter_nums: adapter_nr); |
876 | if (ret == 0) { |
877 | rc_init_seq = vp7049_rc_init; |
878 | goto found; |
879 | } |
880 | |
881 | return ret; |
882 | } else { |
883 | /* Another interface on a multi-tuner device */ |
884 | |
885 | /* The LifeView TV Walker Twin gets here, but struct |
886 | * tvwalkertwin_properties already configured both |
887 | * tuners, so there is nothing for us to do here |
888 | */ |
889 | } |
890 | |
891 | found: |
892 | if ((ret = m920x_init_ep(intf)) < 0) |
893 | return ret; |
894 | |
895 | if (d && (ret = m920x_init(d, rc_seq: rc_init_seq)) != 0) |
896 | return ret; |
897 | |
898 | return ret; |
899 | } |
900 | |
901 | enum { |
902 | MSI_MEGASKY580, |
903 | ANUBIS_MSI_DIGI_VOX_MINI_II, |
904 | ANUBIS_LIFEVIEW_TV_WALKER_TWIN_COLD, |
905 | ANUBIS_LIFEVIEW_TV_WALKER_TWIN_WARM, |
906 | DPOSH_M9206_COLD, |
907 | DPOSH_M9206_WARM, |
908 | VISIONPLUS_PINNACLE_PCTV310E, |
909 | AZUREWAVE_TWINHAN_VP7049, |
910 | }; |
911 | |
912 | static struct usb_device_id m920x_table[] = { |
913 | DVB_USB_DEV(MSI, MSI_MEGASKY580), |
914 | DVB_USB_DEV(ANUBIS_ELECTRONIC, ANUBIS_MSI_DIGI_VOX_MINI_II), |
915 | DVB_USB_DEV(ANUBIS_ELECTRONIC, ANUBIS_LIFEVIEW_TV_WALKER_TWIN_COLD), |
916 | DVB_USB_DEV(ANUBIS_ELECTRONIC, ANUBIS_LIFEVIEW_TV_WALKER_TWIN_WARM), |
917 | DVB_USB_DEV(DPOSH, DPOSH_M9206_COLD), |
918 | DVB_USB_DEV(DPOSH, DPOSH_M9206_WARM), |
919 | DVB_USB_DEV(VISIONPLUS, VISIONPLUS_PINNACLE_PCTV310E), |
920 | DVB_USB_DEV(AZUREWAVE, AZUREWAVE_TWINHAN_VP7049), |
921 | { } |
922 | }; |
923 | |
924 | MODULE_DEVICE_TABLE (usb, m920x_table); |
925 | |
926 | static struct dvb_usb_device_properties megasky_properties = { |
927 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, |
928 | |
929 | .usb_ctrl = DEVICE_SPECIFIC, |
930 | .firmware = "dvb-usb-megasky-02.fw" , |
931 | .download_firmware = m920x_firmware_download, |
932 | |
933 | .rc.legacy = { |
934 | .rc_interval = 100, |
935 | .rc_map_table = rc_map_megasky_table, |
936 | .rc_map_size = ARRAY_SIZE(rc_map_megasky_table), |
937 | .rc_query = m920x_rc_query, |
938 | }, |
939 | |
940 | .size_of_priv = sizeof(struct m920x_state), |
941 | |
942 | .identify_state = m920x_identify_state, |
943 | .num_adapters = 1, |
944 | .adapter = {{ |
945 | .num_frontends = 1, |
946 | .fe = {{ |
947 | |
948 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | |
949 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
950 | |
951 | .pid_filter_count = 8, |
952 | .pid_filter = m920x_pid_filter, |
953 | .pid_filter_ctrl = m920x_pid_filter_ctrl, |
954 | |
955 | .frontend_attach = m920x_mt352_frontend_attach, |
956 | .tuner_attach = m920x_qt1010_tuner_attach, |
957 | |
958 | .stream = { |
959 | .type = USB_BULK, |
960 | .count = 8, |
961 | .endpoint = 0x81, |
962 | .u = { |
963 | .bulk = { |
964 | .buffersize = 512, |
965 | } |
966 | } |
967 | }, |
968 | }}, |
969 | }}, |
970 | .i2c_algo = &m920x_i2c_algo, |
971 | |
972 | .num_device_descs = 1, |
973 | .devices = { |
974 | { "MSI Mega Sky 580 DVB-T USB2.0" , |
975 | { &m920x_table[MSI_MEGASKY580], NULL }, |
976 | { NULL }, |
977 | } |
978 | } |
979 | }; |
980 | |
981 | static struct dvb_usb_device_properties digivox_mini_ii_properties = { |
982 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, |
983 | |
984 | .usb_ctrl = DEVICE_SPECIFIC, |
985 | .firmware = "dvb-usb-digivox-02.fw" , |
986 | .download_firmware = m920x_firmware_download, |
987 | |
988 | .size_of_priv = sizeof(struct m920x_state), |
989 | |
990 | .identify_state = m920x_identify_state, |
991 | .num_adapters = 1, |
992 | .adapter = {{ |
993 | .num_frontends = 1, |
994 | .fe = {{ |
995 | |
996 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | |
997 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
998 | |
999 | .pid_filter_count = 8, |
1000 | .pid_filter = m920x_pid_filter, |
1001 | .pid_filter_ctrl = m920x_pid_filter_ctrl, |
1002 | |
1003 | .frontend_attach = m920x_tda10046_08_frontend_attach, |
1004 | .tuner_attach = m920x_tda8275_60_tuner_attach, |
1005 | |
1006 | .stream = { |
1007 | .type = USB_BULK, |
1008 | .count = 8, |
1009 | .endpoint = 0x81, |
1010 | .u = { |
1011 | .bulk = { |
1012 | .buffersize = 0x4000, |
1013 | } |
1014 | } |
1015 | }, |
1016 | }}, |
1017 | }}, |
1018 | .i2c_algo = &m920x_i2c_algo, |
1019 | |
1020 | .num_device_descs = 1, |
1021 | .devices = { |
1022 | { "MSI DIGI VOX mini II DVB-T USB2.0" , |
1023 | { &m920x_table[ANUBIS_MSI_DIGI_VOX_MINI_II], NULL }, |
1024 | { NULL }, |
1025 | }, |
1026 | } |
1027 | }; |
1028 | |
1029 | /* LifeView TV Walker Twin support by Nick Andrew <nick@nick-andrew.net> |
1030 | * |
1031 | * LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A |
1032 | * TDA10046 #0 is located at i2c address 0x08 |
1033 | * TDA10046 #1 is located at i2c address 0x0b |
1034 | * TDA8275A #0 is located at i2c address 0x60 |
1035 | * TDA8275A #1 is located at i2c address 0x61 |
1036 | */ |
1037 | static struct dvb_usb_device_properties tvwalkertwin_properties = { |
1038 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, |
1039 | |
1040 | .usb_ctrl = DEVICE_SPECIFIC, |
1041 | .firmware = "dvb-usb-tvwalkert.fw" , |
1042 | .download_firmware = m920x_firmware_download, |
1043 | |
1044 | .rc.legacy = { |
1045 | .rc_interval = 100, |
1046 | .rc_map_table = rc_map_tvwalkertwin_table, |
1047 | .rc_map_size = ARRAY_SIZE(rc_map_tvwalkertwin_table), |
1048 | .rc_query = m920x_rc_query, |
1049 | }, |
1050 | |
1051 | .size_of_priv = sizeof(struct m920x_state), |
1052 | |
1053 | .identify_state = m920x_identify_state, |
1054 | .num_adapters = 2, |
1055 | .adapter = {{ |
1056 | .num_frontends = 1, |
1057 | .fe = {{ |
1058 | |
1059 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | |
1060 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
1061 | |
1062 | .pid_filter_count = 8, |
1063 | .pid_filter = m920x_pid_filter, |
1064 | .pid_filter_ctrl = m920x_pid_filter_ctrl, |
1065 | |
1066 | .frontend_attach = m920x_tda10046_08_frontend_attach, |
1067 | .tuner_attach = m920x_tda8275_60_tuner_attach, |
1068 | |
1069 | .stream = { |
1070 | .type = USB_BULK, |
1071 | .count = 8, |
1072 | .endpoint = 0x81, |
1073 | .u = { |
1074 | .bulk = { |
1075 | .buffersize = 512, |
1076 | } |
1077 | } |
1078 | }}, |
1079 | }},{ |
1080 | .num_frontends = 1, |
1081 | .fe = {{ |
1082 | |
1083 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | |
1084 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
1085 | |
1086 | .pid_filter_count = 8, |
1087 | .pid_filter = m920x_pid_filter, |
1088 | .pid_filter_ctrl = m920x_pid_filter_ctrl, |
1089 | |
1090 | .frontend_attach = m920x_tda10046_0b_frontend_attach, |
1091 | .tuner_attach = m920x_tda8275_61_tuner_attach, |
1092 | |
1093 | .stream = { |
1094 | .type = USB_BULK, |
1095 | .count = 8, |
1096 | .endpoint = 0x82, |
1097 | .u = { |
1098 | .bulk = { |
1099 | .buffersize = 512, |
1100 | } |
1101 | } |
1102 | }}, |
1103 | }, |
1104 | }}, |
1105 | .i2c_algo = &m920x_i2c_algo, |
1106 | |
1107 | .num_device_descs = 1, |
1108 | .devices = { |
1109 | { .name = "LifeView TV Walker Twin DVB-T USB2.0" , |
1110 | .cold_ids = { &m920x_table[ANUBIS_LIFEVIEW_TV_WALKER_TWIN_COLD], NULL }, |
1111 | .warm_ids = { &m920x_table[ANUBIS_LIFEVIEW_TV_WALKER_TWIN_WARM], NULL }, |
1112 | }, |
1113 | } |
1114 | }; |
1115 | |
1116 | static struct dvb_usb_device_properties dposh_properties = { |
1117 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, |
1118 | |
1119 | .usb_ctrl = DEVICE_SPECIFIC, |
1120 | .firmware = "dvb-usb-dposh-01.fw" , |
1121 | .download_firmware = m920x_firmware_download, |
1122 | |
1123 | .size_of_priv = sizeof(struct m920x_state), |
1124 | |
1125 | .identify_state = m920x_identify_state, |
1126 | .num_adapters = 1, |
1127 | .adapter = {{ |
1128 | .num_frontends = 1, |
1129 | .fe = {{ |
1130 | /* Hardware pid filters don't work with this device/firmware */ |
1131 | |
1132 | .frontend_attach = m920x_mt352_frontend_attach, |
1133 | .tuner_attach = m920x_qt1010_tuner_attach, |
1134 | |
1135 | .stream = { |
1136 | .type = USB_BULK, |
1137 | .count = 8, |
1138 | .endpoint = 0x81, |
1139 | .u = { |
1140 | .bulk = { |
1141 | .buffersize = 512, |
1142 | } |
1143 | } |
1144 | }, |
1145 | }}, |
1146 | }}, |
1147 | .i2c_algo = &m920x_i2c_algo, |
1148 | |
1149 | .num_device_descs = 1, |
1150 | .devices = { |
1151 | { .name = "Dposh DVB-T USB2.0" , |
1152 | .cold_ids = { &m920x_table[DPOSH_M9206_COLD], NULL }, |
1153 | .warm_ids = { &m920x_table[DPOSH_M9206_WARM], NULL }, |
1154 | }, |
1155 | } |
1156 | }; |
1157 | |
1158 | static struct dvb_usb_device_properties pinnacle_pctv310e_properties = { |
1159 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, |
1160 | |
1161 | .usb_ctrl = DEVICE_SPECIFIC, |
1162 | .download_firmware = NULL, |
1163 | |
1164 | .rc.legacy = { |
1165 | .rc_interval = 100, |
1166 | .rc_map_table = rc_map_pinnacle310e_table, |
1167 | .rc_map_size = ARRAY_SIZE(rc_map_pinnacle310e_table), |
1168 | .rc_query = m920x_rc_query, |
1169 | }, |
1170 | |
1171 | .size_of_priv = sizeof(struct m920x_state), |
1172 | |
1173 | .identify_state = m920x_identify_state, |
1174 | .num_adapters = 1, |
1175 | .adapter = {{ |
1176 | .num_frontends = 1, |
1177 | .fe = {{ |
1178 | |
1179 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | |
1180 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
1181 | |
1182 | .pid_filter_count = 8, |
1183 | .pid_filter = m920x_pid_filter, |
1184 | .pid_filter_ctrl = m920x_pid_filter_ctrl, |
1185 | |
1186 | .frontend_attach = m920x_mt352_frontend_attach, |
1187 | .tuner_attach = m920x_fmd1216me_tuner_attach, |
1188 | |
1189 | .stream = { |
1190 | .type = USB_ISOC, |
1191 | .count = 5, |
1192 | .endpoint = 0x84, |
1193 | .u = { |
1194 | .isoc = { |
1195 | .framesperurb = 128, |
1196 | .framesize = 564, |
1197 | .interval = 1, |
1198 | } |
1199 | } |
1200 | }, |
1201 | }}, |
1202 | } }, |
1203 | .i2c_algo = &m920x_i2c_algo, |
1204 | |
1205 | .num_device_descs = 1, |
1206 | .devices = { |
1207 | { "Pinnacle PCTV 310e" , |
1208 | { &m920x_table[VISIONPLUS_PINNACLE_PCTV310E], NULL }, |
1209 | { NULL }, |
1210 | } |
1211 | } |
1212 | }; |
1213 | |
1214 | static struct dvb_usb_device_properties vp7049_properties = { |
1215 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, |
1216 | |
1217 | .usb_ctrl = DEVICE_SPECIFIC, |
1218 | .firmware = "dvb-usb-vp7049-0.95.fw" , |
1219 | .download_firmware = m920x_firmware_download, |
1220 | |
1221 | .rc.core = { |
1222 | .rc_interval = 150, |
1223 | .rc_codes = RC_MAP_TWINHAN_VP1027_DVBS, |
1224 | .rc_query = m920x_rc_core_query, |
1225 | .allowed_protos = RC_PROTO_BIT_UNKNOWN, |
1226 | }, |
1227 | |
1228 | .size_of_priv = sizeof(struct m920x_state), |
1229 | |
1230 | .identify_state = m920x_identify_state, |
1231 | .num_adapters = 1, |
1232 | .adapter = {{ |
1233 | .num_frontends = 1, |
1234 | .fe = {{ |
1235 | |
1236 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | |
1237 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
1238 | |
1239 | .pid_filter_count = 8, |
1240 | .pid_filter = m920x_pid_filter, |
1241 | .pid_filter_ctrl = m920x_pid_filter_ctrl, |
1242 | |
1243 | .frontend_attach = m920x_mt352_frontend_attach_vp7049, |
1244 | .tuner_attach = m920x_mt2060_tuner_attach, |
1245 | |
1246 | .stream = { |
1247 | .type = USB_BULK, |
1248 | .count = 8, |
1249 | .endpoint = 0x81, |
1250 | .u = { |
1251 | .bulk = { |
1252 | .buffersize = 512, |
1253 | } |
1254 | } |
1255 | }, |
1256 | } }, |
1257 | } }, |
1258 | .i2c_algo = &m920x_i2c_algo, |
1259 | |
1260 | .num_device_descs = 1, |
1261 | .devices = { |
1262 | { "DTV-DVB UDTT7049" , |
1263 | { &m920x_table[AZUREWAVE_TWINHAN_VP7049], NULL }, |
1264 | { NULL }, |
1265 | } |
1266 | } |
1267 | }; |
1268 | |
1269 | static struct usb_driver m920x_driver = { |
1270 | .name = "dvb_usb_m920x" , |
1271 | .probe = m920x_probe, |
1272 | .disconnect = dvb_usb_device_exit, |
1273 | .id_table = m920x_table, |
1274 | }; |
1275 | |
1276 | module_usb_driver(m920x_driver); |
1277 | |
1278 | MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>" ); |
1279 | MODULE_DESCRIPTION("DVB Driver for ULI M920x" ); |
1280 | MODULE_VERSION("0.1" ); |
1281 | MODULE_LICENSE("GPL" ); |
1282 | |