blob: 5873759f5db4f75b03c7dcccab7dd22b71b70011 [file] [log] [blame]
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -03001/* DVB USB compliant Linux driver for the AzureWave 6017 USB2.0 DVB-S
2 * receiver.
3 * see Documentation/dvb/README.dvb-usb for more information
4 */
5
6#include "az6007.h"
7#include "drxk.h"
8#include "mt2063.h"
9#include "dvb_ca_en50221.h"
10
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030011/* HACK: Should be moved to the right place */
12#define USB_PID_AZUREWAVE_6007 0xccd
13#define USB_PID_TERRATEC_H7 0x10b4
14
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030015/* debug */
16int dvb_usb_az6007_debug;
17module_param_named(debug,dvb_usb_az6007_debug, int, 0644);
18MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
19
20
21static int az6007_type =0;
22module_param(az6007_type, int, 0644);
23MODULE_PARM_DESC(az6007_type, "select delivery mode (0=DVB-T, 1=DVB-T");
24
25//module_param_named(type, 6007_type, int, 0644);
26//MODULE_PARM_DESC(type, "select delivery mode (0=DVB-T, 1=DVB-C)");
27
28DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
29
30
31struct az6007_device_state {
32 struct dvb_ca_en50221 ca;
33 struct mutex ca_mutex;
34 u8 power_state;
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030035
36 /* Due to DRX-K - probably need changes */
37 int (*gate_ctrl)(struct dvb_frontend *, int);
38 struct semaphore pll_mutex;
39 bool dont_attach_fe1;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030040};
41
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030042struct drxk_config terratec_h7_drxk = {
43 .adr = 0x29,
44 .single_master = 1,
45 .no_i2c_bridge = 1,
46 .microcode_name = "dvb-usb-terratec-h5-drxk.fw",
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030047};
48
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030049static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
50{
51 struct dvb_usb_adapter *adap = fe->sec_priv;
52 struct az6007_device_state *st = adap->priv;
53 int status;
54
55 if (!adap || !st)
56 return -EINVAL;
57
58 if (enable) {
59 down(&st->pll_mutex);
60 status = st->gate_ctrl(fe, 1);
61 } else {
62 status = st->gate_ctrl(fe, 0);
63 up(&st->pll_mutex);
64 }
65 return status;
66}
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030067
68struct mt2063_config az6007_mt2063_config = {
69 .tuner_address = 0xc0,
70 .refclock = 36125000,
71};
72
73/* check for mutex FIXME */
74int az6007_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
75{
76 int ret = -1;
77
78 ret = usb_control_msg(d->udev,
79 usb_rcvctrlpipe(d->udev,0),
80 req,
81 USB_TYPE_VENDOR | USB_DIR_IN,
82 value,index,b,blen,
83 5000);
84
85 if (ret < 0) {
86 warn("usb in operation failed. (%d)", ret);
87 ret = -EIO;
88 } else
89 ret = 0;
90
91
92 deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
93 debug_dump(b,blen,deb_xfer);
94
95 return ret;
96}
97
98static int az6007_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
99 u16 index, u8 *b, int blen)
100{
101 int ret;
102
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300103#if 0
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300104 int i=0, cyc=0, rem=0;
105 cyc = blen/64;
106 rem = blen%64;
107#endif
108
109 deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
110 debug_dump(b,blen,deb_xfer);
111
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300112
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300113#if 0
114 if (blen>64)
115 {
116 for (i=0; i<cyc; i++)
117 {
118 if ((ret = usb_control_msg(d->udev,
119 usb_sndctrlpipe(d->udev,0),
120 req,
121 USB_TYPE_VENDOR | USB_DIR_OUT,
122 value,index+i*64,b+i*64,64,
123 5000)) != 64) {
124 warn("usb out operation failed. (%d)",ret);
125 return -EIO;
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300126 }
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300127 }
128
129 if (rem>0)
130 {
131 if ((ret = usb_control_msg(d->udev,
132 usb_sndctrlpipe(d->udev,0),
133 req,
134 USB_TYPE_VENDOR | USB_DIR_OUT,
135 value,index+cyc*64,b+cyc*64,rem,
136 5000)) != rem) {
137 warn("usb out operation failed. (%d)",ret);
138 return -EIO;
139 }
140 }
141 }
142 else
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300143#endif
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300144 {
145 if ((ret = usb_control_msg(d->udev,
146 usb_sndctrlpipe(d->udev,0),
147 req,
148 USB_TYPE_VENDOR | USB_DIR_OUT,
149 value,index,b,blen,
150 5000)) != blen) {
151 warn("usb out operation failed. (%d)",ret);
152 return -EIO;
153 }
154 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300155
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300156 return 0;
157}
158
159static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
160{
161 return 0;
162}
163
164/* keys for the enclosed remote control */
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300165struct rc_map_table rc_map_az6007_table[] = {
166 { 0x0001, KEY_1 },
167 { 0x0002, KEY_2 },
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300168};
169
170/* remote control stuff (does not work with my box) */
171static int az6007_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
172{
173 return 0;
174#if 0
175 u8 key[10];
176 int i;
177
178/* remove the following return to enabled remote querying */
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300179
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300180
181 az6007_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
182
183 deb_rc("remote query key: %x %d\n",key[1],key[1]);
184
185 if (key[1] == 0x44) {
186 *state = REMOTE_NO_KEY_PRESSED;
187 return 0;
188 }
189
190 for (i = 0; i < ARRAY_SIZE(az6007_rc_keys); i++)
191 if (az6007_rc_keys[i].custom == key[1]) {
192 *state = REMOTE_KEY_PRESSED;
193 *event = az6007_rc_keys[i].event;
194 break;
195 }
196 return 0;
197#endif
198}
199
200/*
201int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
202{
203 u8 v = onoff;
204 return az6007_usb_out_op(d,0xBC,v,3,NULL,1);
205}
206*/
207
208static int az6007_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
209{
210 az6007_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6);
211 return 0;
212}
213
214static int az6007_frontend_poweron(struct dvb_usb_adapter *adap)
215{
216 int ret;
217 u8 req;
218 u16 value;
219 u16 index;
220 int blen;
221
222 info("az6007_frontend_poweron adap=%p adap->dev=%p\n", adap, adap->dev);
223
224 req = 0xBC;
225 value = 1;//power on
226 index = 3;
227 blen =0;
228
229 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
230 {
231 err("az6007_frontend_poweron failed!!!");
232 return -EIO;
233 }
234
235 msleep_interruptible(200);
236
237 req = 0xBC;
238 value = 0;//power on
239 index = 3;
240 blen =0;
241
242 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
243 {
244 err("az6007_frontend_poweron failed!!!");
245 return -EIO;
246 }
247
248 msleep_interruptible(200);
249
250 req = 0xBC;
251 value = 1;//power on
252 index = 3;
253 blen =0;
254
255 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
256 {
257 err("az6007_frontend_poweron failed!!!");
258 return -EIO;
259 }
260 info("az6007_frontend_poweron\n");
261 return 0;
262}
263
264static int az6007_frontend_reset(struct dvb_usb_adapter *adap)
265{
266 int ret;
267 u8 req;
268 u16 value;
269 u16 index;
270 int blen;
271
272 info("az6007_frontend_reset adap=%p adap->dev=%p\n", adap, adap->dev);
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300273
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300274 //reset demodulator
275 req = 0xC0;
276 value = 1;//high
277 index = 3;
278 blen =0;
279 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
280 {
281 err("az6007_frontend_reset failed 1 !!!");
282 return -EIO;
283 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300284
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300285 req = 0xC0;
286 value = 0;//low
287 index = 3;
288 blen =0;
289 msleep_interruptible(200);
290 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
291 {
292 err("az6007_frontend_reset failed 2 !!!");
293 return -EIO;
294 }
295 msleep_interruptible(200);
296 req = 0xC0;
297 value = 1;//high
298 index = 3;
299 blen =0;
300
301 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
302 {
303 err("az6007_frontend_reset failed 3 !!!");
304 return -EIO;
305 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300306
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300307 msleep_interruptible(200);
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300308
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300309 info("reset az6007 frontend\n");
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300310
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300311 return 0;
312}
313
314static int az6007_led_on_off(struct usb_interface *intf, int onoff)
315{
316 int ret = -1;
317 u8 req;
318 u16 value;
319 u16 index;
320 int blen;
321 //TS through
322 req = 0xBC;
323 value = onoff;
324 index = 0;
325 blen =0;
326
327 ret = usb_control_msg(interface_to_usbdev(intf),
328 usb_rcvctrlpipe(interface_to_usbdev(intf),0),
329 req,
330 USB_TYPE_VENDOR | USB_DIR_OUT,
331 value,index,NULL,blen,
332 2000);
333
334 if (ret < 0) {
335 warn("usb in operation failed. (%d)", ret);
336 ret = -EIO;
337 } else
338 ret = 0;
339
340
341 deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
342
343 return ret;
344}
345
346static int az6007_frontend_tsbypass(struct dvb_usb_adapter *adap,int onoff)
347{
348 int ret;
349 u8 req;
350 u16 value;
351 u16 index;
352 int blen;
353 //TS through
354 req = 0xC7;
355 value = onoff;
356 index = 0;
357 blen =0;
358
359 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
360 return -EIO;
361 return 0;
362}
363
364static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
365{
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300366 struct az6007_device_state *st = adap->priv;
367
368 int result;
369
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300370 az6007_frontend_poweron(adap);
371 az6007_frontend_reset(adap);
372
373 info("az6007_frontend_attach\n");
374
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300375 adap->fe = dvb_attach(drxk_attach, &terratec_h7_drxk,
376 &adap->dev->i2c_adap, &adap->fe2);
377 if (!adap->fe) {
378 result = -EINVAL;
379 goto out_free;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300380 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300381
382 /* FIXME: do we need a pll semaphore? */
383 adap->fe->sec_priv = adap;
384 sema_init(&st->pll_mutex, 1);
385 st->gate_ctrl = adap->fe->ops.i2c_gate_ctrl;
386 adap->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
387 adap->fe2->id = 1;
388
389 /* Attach mt2063 to DVB-C frontend */
390 if (adap->fe->ops.i2c_gate_ctrl)
391 adap->fe->ops.i2c_gate_ctrl(adap->fe, 1);
392 if (!dvb_attach(mt2063_attach, adap->fe, &az6007_mt2063_config,
393 &adap->dev->i2c_adap)) {
394 result = -EINVAL;
395
396 goto out_free;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300397 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300398 if (adap->fe->ops.i2c_gate_ctrl)
399 adap->fe->ops.i2c_gate_ctrl(adap->fe, 0);
400
401 /* Hack - needed due to drxk */
402 adap->fe2->tuner_priv = adap->fe->tuner_priv;
403 memcpy(&adap->fe2->ops.tuner_ops,
404 &adap->fe->ops.tuner_ops,
405 sizeof(adap->fe->ops.tuner_ops));
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300406 return 0;
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300407
408out_free:
409 if (adap->fe)
410 dvb_frontend_detach(adap->fe);
411 adap->fe = NULL;
412 adap->fe2 = NULL;
413
414 return result;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300415}
416
417static struct dvb_usb_device_properties az6007_properties;
418
419static void
420az6007_usb_disconnect(struct usb_interface *intf)
421{
422 dvb_usb_device_exit (intf);
423}
424
425/* I2C */
426static int az6007_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
427{
428 struct dvb_usb_device *d = i2c_get_adapdata(adap);
429 int j=0,len=0;
430 int ret=0;
431 u16 index;
432 u16 value;
433 int length;
434 u8 req;
435 u8 data[512];
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300436
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300437 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
438 return -EAGAIN;
439 if (num > 2)
440 warn("more than 2 i2c messages at a time is not handled yet. TODO.");
441
442
443 if (msg[0].addr == 0xc0) //MT2063
444 {
445 if (msg[0].flags != I2C_M_RD) //write
446 {
447 //printk("Tuner Tuner Write DevAddr=%02x RegAddr=%d\n", msg[0].addr, msg[0].buf[0]);
448 req = 0xBD;
449 index = msg[0].buf[0];
450 value = msg[0].addr | (1<<8);
451 length = msg[0].len - 1;
452 len = msg[0].len - 1;
453 //printk("Tuner Tuner WriteDATA len=%d ", len);
454 for(j=0;j<len;j++)
455 {
456 data[j] = msg[0].buf[j+1];
457 //printk("data[%d]=%02x ", j, data[j]);
458 }
459 //printk("\n");
460 ret = az6007_usb_out_op(d,req,value,index,data,length);
461 //ret = az6007_usb_out_op(d,req,value,index,&(msg[0].buf[1]),length);
462 }
463 else //read
464 {
465 //printk("Tuner Tuner Read DevAddr=%02x RegAddr=%02x\n", msg[0].addr, msg[0].buf[0]);
466 req = 0xB9;
467 index = msg[0].buf[0];
468 value = msg[0].addr + (1 << 8);
469 length = msg[1].len + 6;
470 ret = az6007_usb_in_op(d,req,value,index,data,length);
471 len = msg[1].len;
472 //printk("Tuner Tuner ReadDATA len=%d ", len);
473 for (j=0; j<len; j++)
474 {
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300475 msg[1].buf[j] = data[j+5];
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300476 //printk("data[%d]=%02x ", j, data[j+5]);
477 }
478 //printk("\n");
479 }
480 }
481 else
482 { //Demodulator
483 if (msg[0].flags != I2C_M_RD) //write
484 {
485 //printk("Demodulator Write DevAddr=%02x RegAddr=%d\n", msg[0].addr, msg[0].buf[0]);
486 req = 0xBD;
487 index = msg[0].buf[0];
488 value = msg[0].addr | (1<<8);
489 length = msg[0].len - 1;
490 len = msg[0].len - 1;
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300491 //printk("Demodulator WriteDATA len=%d ", len);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300492 for(j=0;j<len;j++)
493 {
494 data[j] = msg[0].buf[j+1];
495 //printk("data[%d]=%02x ", j, data[j]);
496 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300497 //printk("\n");
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300498 ret = az6007_usb_out_op(d,req,value,index,data,length);
499 }
500 else //read
501 {
502 //printk("Demodulator Read DevAddr=%02x RegAddr=%02x\n", msg[0].addr, msg[0].buf[0]);
503 req = 0xB9;
504 index = 0;
505 value = msg[0].addr + (0 << 8);
506 length = msg[0].len + 6;
507 ret = az6007_usb_in_op(d,req,value,index,data,length);
508 len = msg[0].len;
509 //printk("Demodulator ReadDATA len=%d ", len);
510 for (j=0; j<len; j++)
511 {
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300512 msg[0].buf[j] = data[j+5];
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300513 //printk("data[%d]=%02x ", j, data[j+5]);
514 }
515 //printk("\n");
516 }
517 }
518 mutex_unlock(&d->i2c_mutex);
519 return ret;
520}
521
522
523static u32 az6007_i2c_func(struct i2c_adapter *adapter)
524{
525 return I2C_FUNC_I2C;
526}
527
528static struct i2c_algorithm az6007_i2c_algo = {
529 .master_xfer = az6007_i2c_xfer,
530 .functionality = az6007_i2c_func,
531#ifdef NEED_ALGO_CONTROL
532 .algo_control = dummy_algo_control,
533#endif
534};
535
536int az6007_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
537 struct dvb_usb_device_description **desc, int *cold)
538{
539 u8 b[16];
540 s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
541 0xb7, USB_TYPE_VENDOR | USB_DIR_IN, 6, 0, b, 6, USB_CTRL_GET_TIMEOUT);
542
543 info("FW GET_VERSION length: %d\n",ret);
544
545 *cold = ret <= 0;
546
547 info("cold: %d\n", *cold);
548 return 0;
549}
550
551static int az6007_usb_probe(struct usb_interface *intf,
552 const struct usb_device_id *id)
553{
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300554 az6007_led_on_off(intf, 0);
555
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300556 return dvb_usb_device_init(intf, &az6007_properties,
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300557 THIS_MODULE, NULL, adapter_nr);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300558}
559
560static struct usb_device_id az6007_usb_table [] = {
561 { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007) },
562 { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7) },
563 { 0 },
564};
565
566MODULE_DEVICE_TABLE(usb, az6007_usb_table);
567
568static struct dvb_usb_device_properties az6007_properties = {
569 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
570 .usb_ctrl = CYPRESS_FX2,
571 //.download_firmware = az6007_download_firmware,
572 .firmware = "dvb-usb-az6007-03.fw",
573 .no_reconnect = 1,
574
575 .size_of_priv = sizeof(struct az6007_device_state),
576 .identify_state = az6007_identify_state,
577 .num_adapters = 1,
578 .adapter = {
579 {
580 //.caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
581
582 .streaming_ctrl = az6007_streaming_ctrl,
583 .frontend_attach = az6007_frontend_attach,
584
585 /* parameter for the MPEG2-data transfer */
586 .stream = {
587 .type = USB_BULK,
588 .count = 10,
589 .endpoint = 0x02,
590 .u = {
591 .bulk = {
592 .buffersize = 4096,
593 }
594 }
595 },
596 .size_of_priv = 0,//sizeof(struct az6007_state),
597 }
598 },
599 //.power_ctrl = az6007_power_ctrl,
600 .read_mac_address = az6007_read_mac_addr,
601
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300602 .rc.legacy = {
603 .rc_map_table = rc_map_az6007_table,
604 .rc_map_size = ARRAY_SIZE(rc_map_az6007_table),
605 .rc_interval = 400,
606 .rc_query = az6007_rc_query,
607 },
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300608 .i2c_algo = &az6007_i2c_algo,
609
610 .num_device_descs = 2,
611 .devices = {
612 { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)",
613 .cold_ids = { &az6007_usb_table[0], NULL },
614 .warm_ids = { NULL },
615 },
616 { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)",
617 .cold_ids = { &az6007_usb_table[1], NULL },
618 .warm_ids = { NULL },
619 },
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300620 { NULL },
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300621 }
622};
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300623
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300624/* usb specific object needed to register this driver with the usb subsystem */
625static struct usb_driver az6007_usb_driver = {
626 .name = "dvb_usb_az6007",
627 .probe = az6007_usb_probe,
628 .disconnect = dvb_usb_device_exit,
629 //.disconnect = az6007_usb_disconnect,
630 .id_table = az6007_usb_table,
631};
632
633/* module stuff */
634static int __init az6007_usb_module_init(void)
635{
636 int result;
637 info("henry :: az6007 usb module init");
638 if ((result = usb_register(&az6007_usb_driver))) {
639 err("usb_register failed. (%d)",result);
640 return result;
641 }
642
643 return 0;
644}
645
646static void __exit az6007_usb_module_exit(void)
647{
648 /* deregister this driver from the USB subsystem */
649 info("henry :: az6007 usb module exit");
650 usb_deregister(&az6007_usb_driver);
651}
652
653module_init(az6007_usb_module_init);
654module_exit(az6007_usb_module_exit);
655
656MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
657MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
658MODULE_VERSION("1.0");
659MODULE_LICENSE("GPL");