aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/dvb-usb/megasky.c
diff options
context:
space:
mode:
authorAapo Tahkola <aet@rasterburn.org>2006-09-23 19:00:41 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-02-21 10:34:49 -0500
commit5fecd9fd4287dd163fe1f1f0b1e86e931ed589c4 (patch)
tree00046e8dcbda12d939b1c9a0cbaeb1bcb6fb76f5 /drivers/media/dvb/dvb-usb/megasky.c
parentef7b8b725bdc59fb4a3f781f3e9f546ad01da792 (diff)
V4L/DVB (5124): Dvb-usb: Initial support for MSI Mega Sky 580 based on Uli m9206
Currently, the driver works in bulk mode supporting both USB 2.0 and 1.0 with and without hardware pid filters. The ULi m9205 also supports isochronous transfer mode, but I have dropped support for it because it depends on firmware and does not work on all USB host chips. Further, I have no firmware with remote controller support for this mode. Signed-off-by: Aapo Tahkola <aet@rasterburn.org> Signed-off-by: Michael Krufky <mkrufky@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/dvb/dvb-usb/megasky.c')
-rw-r--r--drivers/media/dvb/dvb-usb/megasky.c693
1 files changed, 693 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-usb/megasky.c b/drivers/media/dvb/dvb-usb/megasky.c
new file mode 100644
index 000000000000..2fda56df5d60
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/megasky.c
@@ -0,0 +1,693 @@
1/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver
2 *
3 * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org)
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation, version 2.
8 *
9 * see Documentation/dvb/README.dvb-usb for more information
10 */
11#include "megasky.h"
12
13#include "mt352.h"
14#include "mt352_priv.h"
15
16/* debug */
17int dvb_usb_megasky_debug;
18module_param_named(debug,dvb_usb_megasky_debug, int, 0644);
19MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
20
21static struct dvb_usb_rc_key megasky_rc_keys [] = {
22 { 0x0, 0x12, KEY_POWER },
23 { 0x0, 0x1e, KEY_CYCLEWINDOWS }, /* min/max */
24 { 0x0, 0x02, KEY_CHANNELUP },
25 { 0x0, 0x05, KEY_CHANNELDOWN },
26 { 0x0, 0x03, KEY_VOLUMEUP },
27 { 0x0, 0x06, KEY_VOLUMEDOWN },
28 { 0x0, 0x04, KEY_MUTE },
29 { 0x0, 0x07, KEY_OK }, /* TS */
30 { 0x0, 0x08, KEY_STOP },
31 { 0x0, 0x09, KEY_MENU }, /* swap */
32 { 0x0, 0x0a, KEY_REWIND },
33 { 0x0, 0x1b, KEY_PAUSE },
34 { 0x0, 0x1f, KEY_FASTFORWARD },
35 { 0x0, 0x0c, KEY_RECORD },
36 { 0x0, 0x0d, KEY_CAMERA }, /* screenshot */
37 { 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */
38};
39
40static inline int m9206_read(struct usb_device *udev, u8 request, u16 value, u16 index, void *data, int size)
41{
42 int ret;
43
44 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
45 request, USB_TYPE_VENDOR | USB_DIR_IN,
46 value, index, data, size, 2000);
47 if (ret < 0)
48 return ret;
49
50 if (ret != size)
51 return -EIO;
52
53 return 0;
54}
55
56static inline int m9206_write(struct usb_device *udev, u8 request, u16 value, u16 index)
57{
58 int ret;
59
60 ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
61 request, USB_TYPE_VENDOR | USB_DIR_OUT,
62 value, index, NULL, 0, 2000);
63 msleep(3);
64
65 return ret;
66}
67
68static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
69{
70 int i, ret = 0;
71 u8 rc_state[2];
72
73 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
74 return -EAGAIN;
75
76 if ((ret = m9206_read(d->udev, 0x22, 0x0, 0xff51, rc_state, 1)) != 0)
77 goto unlock;
78
79 if ((ret = m9206_read(d->udev, 0x22, 0x0, 0xff52, rc_state + 1, 1)) != 0)
80 goto unlock;
81
82 for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++)
83 if (megasky_rc_keys[i].data == rc_state[1]) {
84 *event = megasky_rc_keys[i].event;
85
86 switch(rc_state[0]) {
87 case 0x80:
88 *state = REMOTE_NO_KEY_PRESSED;
89 goto unlock;
90
91 case 0x93:
92 case 0x92:
93 *state = REMOTE_KEY_PRESSED;
94 goto unlock;
95
96 case 0x91:
97 *state = REMOTE_KEY_REPEAT;
98 goto unlock;
99
100 default:
101 deb_rc("Unexpected rc response %x\n", rc_state[0]);
102 *state = REMOTE_NO_KEY_PRESSED;
103 goto unlock;
104 }
105 }
106
107 if (rc_state[1] != 0)
108 deb_rc("Unknown rc key %x\n", rc_state[1]);
109
110 *state = REMOTE_NO_KEY_PRESSED;
111
112 unlock:
113 mutex_unlock(&d->i2c_mutex);
114
115 return ret;
116}
117
118/* I2C */
119
120static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
121{
122 struct dvb_usb_device *d = i2c_get_adapdata(adap);
123 int i;
124 int ret = 0;
125
126 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
127 return -EAGAIN;
128
129 if (num > 2)
130 return -EINVAL;
131
132 for (i = 0; i < num; i++) {
133 u8 w_len;
134
135 if ((ret = m9206_write(d->udev, 0x23, msg[i].addr, 0x80)) != 0)
136 goto unlock;
137
138 if ((ret = m9206_write(d->udev, 0x23, msg[i].buf[0], 0x0)) != 0)
139 goto unlock;
140
141 if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) {
142 if (msg[i].addr == 0x1e)
143 w_len = 0x1f;
144 else
145 w_len = 0xc5;
146
147 if ((ret = m9206_write(d->udev, 0x23, w_len, 0x80)) != 0)
148 goto unlock;
149
150 if ((ret = m9206_read(d->udev, 0x23, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0)
151 goto unlock;
152
153 i++;
154 } else {
155 if (msg[i].len != 2)
156 return -EINVAL;
157
158 if ((ret = m9206_write(d->udev, 0x23, msg[i].buf[1], 0x40)) != 0)
159 goto unlock;
160 }
161 }
162 ret = i;
163 unlock:
164 mutex_unlock(&d->i2c_mutex);
165
166 return ret;
167}
168
169static u32 m9206_i2c_func(struct i2c_adapter *adapter)
170{
171 return I2C_FUNC_I2C;
172}
173
174static struct i2c_algorithm m9206_i2c_algo = {
175 .master_xfer = m9206_i2c_xfer,
176 .functionality = m9206_i2c_func,
177};
178
179/* Callbacks for DVB USB */
180static int megasky_identify_state (struct usb_device *udev,
181 struct dvb_usb_properties *props,
182 struct dvb_usb_device_description **desc,
183 int *cold)
184{
185 struct usb_host_interface *alt;
186
187 alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1);
188 *cold = (alt == NULL) ? 1 : 0;
189
190 return 0;
191}
192
193static int megasky_mt352_demod_init(struct dvb_frontend *fe)
194{
195 int i;
196 static u8 buf1[] = {
197 CONFIG, 0x3d,
198 CLOCK_CTL, 0x30,
199 RESET, 0x80,
200 ADC_CTL_1, 0x40,
201 AGC_TARGET, 0x1c,
202 AGC_CTL, 0x20,
203 0x69, 0x00,
204 0x6a, 0xff,
205 0x6b, 0xff,
206 0x6c, 0x40,
207 0x6d, 0xff,
208 0x6e, 0x00,
209 0x6f, 0x40,
210 0x70, 0x40,
211 0x93, 0x1a,
212 0xb5, 0x7a,
213 ACQ_CTL, 0x50,
214 INPUT_FREQ_1, 0x31,
215 INPUT_FREQ_0, 0x05,
216 };
217
218 for (i = 0; i < ARRAY_SIZE(buf1); i += 2)
219 mt352_write(fe, &buf1[i], 2);
220
221 deb_rc("Demod init!\n");
222
223 return 0;
224}
225
226struct mt352_state;
227
228
229#define W 0
230#define R 1
231/* Not actual hw limits. */
232#define QT1010_MIN_STEP 2000000
233#define QT1010_MIN_FREQ 48000000
234
235int qt1010_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len)
236{
237 int i;
238 int div, mod;
239 struct {
240 u8 read, reg, value;
241 } rd[46] = { { W, 0x01, 0x80 },
242 { W, 0x02, 0x3f },
243 { W, 0x05, 0xff }, /* c */
244 { W, 0x06, 0x44 },
245 { W, 0x07, 0xff }, /* c */
246 { W, 0x08, 0x08 },
247 { W, 0x09, 0xff }, /* c */
248 { W, 0x0a, 0xff }, /* c */
249 { W, 0x0b, 0xff }, /* c */
250 { W, 0x0c, 0xe1 },
251 { W, 0x1a, 0xff }, /* 10 c */
252 { W, 0x1b, 0x00 },
253 { W, 0x1c, 0x89 },
254 { W, 0x11, 0xff }, /* c */
255 { W, 0x12, 0x91 },
256 { W, 0x22, 0xff }, /* c */
257 { W, 0x1e, 0x00 },
258 { W, 0x1e, 0xd0 },
259 { R, 0x22, 0xff }, /* c read */
260 { W, 0x1e, 0x00 },
261 { R, 0x05, 0xff }, /* 20 c read */
262 { R, 0x22, 0xff }, /* c read */
263 { W, 0x23, 0xd0 },
264 { W, 0x1e, 0x00 },
265 { W, 0x1e, 0xe0 },
266 { R, 0x23, 0xff }, /* c read */
267 { W, 0x1e, 0x00 },
268 { W, 0x24, 0xd0 },
269 { W, 0x1e, 0x00 },
270 { W, 0x1e, 0xf0 },
271 { R, 0x24, 0xff }, /* 30 c read */
272 { W, 0x1e, 0x00 },
273 { W, 0x14, 0x7f },
274 { W, 0x15, 0x7f },
275 { W, 0x05, 0xff }, /* c */
276 { W, 0x06, 0x00 },
277 { W, 0x15, 0x1f },
278 { W, 0x16, 0xff },
279 { W, 0x18, 0xff },
280 { W, 0x1f, 0xff }, /* c */
281 { W, 0x20, 0xff }, /* 40 c */
282 { W, 0x21, 0x53 },
283 { W, 0x25, 0xbd },
284 { W, 0x26, 0x15 },
285 { W, 0x02, 0x00 },
286 { W, 0x01, 0x00 },
287 };
288 struct i2c_msg msg;
289 struct dvb_usb_device *d = fe->dvb->priv;
290 unsigned long freq = params->frequency;
291
292 if (freq % QT1010_MIN_STEP)
293 deb_rc("frequency not supported.\n");
294
295 (void) buf;
296 (void) buf_len;
297
298 div = (freq - QT1010_MIN_FREQ) / QT1010_MIN_STEP;
299 mod = (div + 16 - 9) % 16;
300
301 /* 0x5 */
302 if (div >= 377)
303 rd[2].value = 0x74;
304 else if (div >= 265)
305 rd[2].value = 0x54;
306 else if (div >= 121)
307 rd[2].value = 0x34;
308 else
309 rd[2].value = 0x14;
310
311 /* 0x7 */
312 rd[4].value = (((freq - QT1010_MIN_FREQ) / 1000000) * 9975 + 12960000) / 320000;
313
314 /* 09 */
315 if (mod < 4)
316 rd[6].value = 0x1d;
317 else
318 rd[6].value = 0x1c;
319
320 /* 0a */
321 if (mod < 2)
322 rd[7].value = 0x09;
323 else if (mod < 4)
324 rd[7].value = 0x08;
325 else if (mod < 6)
326 rd[7].value = 0x0f;
327 else if (mod < 8)
328 rd[7].value = 0x0e;
329 else if (mod < 10)
330 rd[7].value = 0x0d;
331 else if (mod < 12)
332 rd[7].value = 0x0c;
333 else if (mod < 14)
334 rd[7].value = 0x0b;
335 else
336 rd[7].value = 0x0a;
337
338 /* 0b */
339 if (div & 1)
340 rd[8].value = 0x45;
341 else
342 rd[8].value = 0x44;
343
344 /* 1a */
345 if (div & 1)
346 rd[10].value = 0x78;
347 else
348 rd[10].value = 0xf8;
349
350 /* 11 */
351 if (div >= 265)
352 rd[13].value = 0xf9;
353 else if (div >= 121)
354 rd[13].value = 0xfd;
355 else
356 rd[13].value = 0xf9;
357
358 /* 22 */
359 if (div < 201)
360 rd[15].value = 0xd0;
361 else if (div < 217)
362 rd[15].value = 0xd3;
363 else if (div < 233)
364 rd[15].value = 0xd6;
365 else if (div < 249)
366 rd[15].value = 0xd9;
367 else if (div < 265)
368 rd[15].value = 0xda;
369 else
370 rd[15].value = 0xd0;
371
372 /* 05 */
373 if (div >= 377)
374 rd[34].value = 0x70;
375 else if (div >= 265)
376 rd[34].value = 0x50;
377 else if (div >= 121)
378 rd[34].value = 0x30;
379 else
380 rd[34].value = 0x10;
381
382 /* 1f */
383 if (mod < 4)
384 rd[39].value = 0x64;
385 else if (mod < 6)
386 rd[39].value = 0x66;
387 else if (mod < 8)
388 rd[39].value = 0x67;
389 else if (mod < 12)
390 rd[39].value = 0x68;
391 else if (mod < 14)
392 rd[39].value = 0x69;
393 else
394 rd[39].value = 0x6a;
395
396 /* 20 */
397 if (mod < 4)
398 rd[40].value = 0x10;
399 else if (mod < 6)
400 rd[40].value = 0x11;
401 else if (mod < 10)
402 rd[40].value = 0x12;
403 else if (mod < 12)
404 rd[40].value = 0x13;
405 else if (mod < 14)
406 rd[40].value = 0x14;
407 else
408 rd[40].value = 0x15;
409
410 deb_rc("Now tuning... ");
411 for (i = 0; i < sizeof(rd) / sizeof(*rd); i++) {
412 if (rd[i].read)
413 continue;
414
415 msg.flags = 0;
416 msg.len = 2;
417 msg.addr = 0xc4;
418 msg.buf = &rd[i].reg;
419
420 if (i2c_transfer(&d->i2c_adap, &msg, 1) != 1) {
421 deb_rc("tuner write failed\n");
422 return -EIO;
423 }
424 }
425 deb_rc("done\n");
426
427 return 0;
428}
429#undef W
430#undef R
431
432static struct mt352_config megasky_mt352_config = {
433 .demod_address = 0x1e,
434 .demod_init = megasky_mt352_demod_init,
435};
436
437static int megasky_frontend_attach(struct dvb_usb_device *d)
438{
439 deb_rc("megasky_frontend_attach!\n");
440
441 if ((d->fe = mt352_attach(&megasky_mt352_config, &d->i2c_adap)) != NULL) {
442 d->fe->ops.tuner_ops.calc_regs = qt1010_set_params;
443 return 0;
444 }
445 return -EIO;
446}
447
448/* DVB USB Driver stuff */
449static struct dvb_usb_properties megasky_properties;
450
451static int megasky_probe(struct usb_interface *intf, const struct usb_device_id *id)
452{
453 struct dvb_usb_device *d;
454 struct usb_host_interface *alt;
455 int ret;
456
457 if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) {
458 deb_rc("probed!\n");
459
460 alt = usb_altnum_to_altsetting(intf, 1);
461 if (alt == NULL) {
462 deb_rc("not alt found!\n");
463 return -ENODEV;
464 }
465
466 ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, alt->desc.bAlternateSetting);
467 if (ret < 0)
468 return ret;
469
470 deb_rc("Changed to alternate setting!\n");
471
472 /* Remote controller init. */
473 if ((ret = m9206_write(d->udev, 0x22, 0xa8, 0xff55)) != 0)
474 return ret;
475
476 if ((ret = m9206_write(d->udev, 0x22, 0x51, 0xff54)) != 0)
477 return ret;
478 }
479 return ret;
480}
481
482static struct usb_device_id megasky_table [] = {
483 { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
484 { } /* Terminating entry */
485};
486MODULE_DEVICE_TABLE (usb, megasky_table);
487
488static int set_filter(struct dvb_usb_device *d, int type, int idx, int pid)
489{
490 int ret = 0;
491
492 if (pid >= 0x8000)
493 return -EINVAL;
494
495 pid |= 0x8000;
496
497 if ((ret = m9206_write(d->udev, 0x25, pid, (type << 8) | (idx * 4) )) != 0)
498 return ret;
499
500 if ((ret = m9206_write(d->udev, 0x25, 0, (type << 8) | (idx * 4) )) != 0)
501 return ret;
502
503 return ret;
504}
505
506static int m9206_pid_filter_ctrl(struct dvb_usb_device *d, int onoff)
507{
508 int ret = 0;
509
510 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
511 return -EAGAIN;
512
513 deb_rc("filtering %s\n", onoff ? "on" : "off");
514 if (onoff == 0) {
515 if ((ret = set_filter(d, 0x81, 1, 0x00)) != 0)
516 goto unlock;
517
518 if ((ret = set_filter(d, 0x82, 0, 0x02f5)) != 0)
519 goto unlock;
520 }
521 unlock:
522 mutex_unlock(&d->i2c_mutex);
523
524 return ret;
525}
526
527static int m9206_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
528{
529 int ret = 0;
530
531 if (pid == 8192)
532 return m9206_pid_filter_ctrl(d, !onoff);
533
534 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
535 return -EAGAIN;
536
537 deb_rc("filter %d, pid %x, %s\n", index, pid, onoff ? "on" : "off");
538 if (onoff == 0)
539 pid = 0;
540
541 if ((ret = set_filter(d, 0x81, 1, 0x01)) != 0)
542 goto unlock;
543
544 if ((ret = set_filter(d, 0x81, index + 2, pid)) != 0)
545 goto unlock;
546
547 if ((ret = set_filter(d, 0x82, 0, 0x02f5)) != 0)
548 goto unlock;
549
550 unlock:
551 mutex_unlock(&d->i2c_mutex);
552
553 return ret;
554}
555
556static int m9206_firmware_download(struct usb_device *udev, const struct firmware *fw)
557{
558 u16 value, index, size;
559 u8 read[4], *buff;
560 int i, pass, ret = 0;
561
562 buff = kmalloc(65536, GFP_KERNEL);
563
564 if ((ret = m9206_read(udev, 0x25, 0x0, 0x8000, read, 4)) != 0)
565 goto done;
566 deb_rc("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
567
568 if ((ret = m9206_read(udev, 0x30, 0x0, 0x0, read, 1)) != 0)
569 goto done;
570 deb_rc("%x\n", read[0]);
571
572 for (pass = 0; pass < 2; pass++) {
573 for (i = 0; i + (sizeof(u16) * 3) < fw->size;) {
574 value = le16_to_cpu(*(u16 *)(fw->data + i));
575 i += sizeof(u16);
576
577 index = le16_to_cpu(*(u16 *)(fw->data + i));
578 i += sizeof(u16);
579
580 size = le16_to_cpu(*(u16 *)(fw->data + i));
581 i += sizeof(u16);
582
583 if (pass == 1) {
584 /* Will stall if using fw->data ... */
585 memcpy(buff, fw->data + i, size);
586
587 ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
588 0x30, USB_TYPE_VENDOR | USB_DIR_OUT,
589 value, index, buff, size, 20);
590 if (ret != size) {
591 deb_rc("error while uploading fw!\n");
592 ret = -EIO;
593 goto done;
594 }
595 msleep(3);
596 }
597 i += size;
598 }
599 if (i != fw->size) {
600 ret = -EINVAL;
601 goto done;
602 }
603 }
604
605 msleep(36);
606
607 /* m9206 will disconnect itself from the bus after this. */
608 (void) m9206_write(udev, 0x22, 0x01, 0xff69);
609 deb_rc("firmware uploaded!\n");
610
611 done:
612 kfree(buff);
613
614 return ret;
615}
616
617static struct dvb_usb_properties megasky_properties = {
618 .caps = DVB_USB_IS_AN_I2C_ADAPTER | DVB_USB_HAS_PID_FILTER |
619 DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_NEED_PID_FILTERING,
620 .pid_filter_count = 8,
621
622 .usb_ctrl = DEVICE_SPECIFIC,
623 .firmware = "dvb-usb-megasky-02.fw",
624 .download_firmware = m9206_firmware_download,
625
626 .pid_filter = m9206_pid_filter,
627 .pid_filter_ctrl = m9206_pid_filter_ctrl,
628 .frontend_attach = megasky_frontend_attach,
629
630 .rc_interval = 200,
631 .rc_key_map = megasky_rc_keys,
632 .rc_key_map_size = ARRAY_SIZE(megasky_rc_keys),
633 .rc_query = m9206_rc_query,
634
635 .size_of_priv = 0,
636
637 .identify_state = megasky_identify_state,
638 .i2c_algo = &m9206_i2c_algo,
639
640 .generic_bulk_ctrl_endpoint = 0x01,
641 .urb = {
642 .type = DVB_USB_BULK,
643 .count = 8,
644 .endpoint = 0x81,
645 .u = {
646 .bulk = {
647 .buffersize = 512,
648 }
649 }
650 },
651 .num_device_descs = 1,
652 .devices = {
653 { "MSI Mega Sky 580 DVB-T USB2.0",
654 { &megasky_table[0], NULL },
655 { NULL },
656 },
657 { NULL },
658 }
659};
660
661static struct usb_driver megasky_driver = {
662 .name = "dvb_usb_megasky",
663 .probe = megasky_probe,
664 .disconnect = dvb_usb_device_exit,
665 .id_table = megasky_table,
666};
667
668/* module stuff */
669static int __init megasky_module_init(void)
670{
671 int ret;
672
673 if ((ret = usb_register(&megasky_driver))) {
674 err("usb_register failed. Error number %d", ret);
675 return ret;
676 }
677
678 return 0;
679}
680
681static void __exit megasky_module_exit(void)
682{
683 /* deregister this driver from the USB subsystem */
684 usb_deregister(&megasky_driver);
685}
686
687module_init (megasky_module_init);
688module_exit (megasky_module_exit);
689
690MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
691MODULE_DESCRIPTION("Driver for MSI Mega Sky 580 DVB-T USB2.0");
692MODULE_VERSION("0.1");
693MODULE_LICENSE("GPL");