1 /* DVB USB compliant Linux driver for the AzureWave 6017 USB2.0 DVB-S
3 * see Documentation/dvb/README.dvb-usb for more information
9 #include "dvb_ca_en50221.h"
11 /* HACK: Should be moved to the right place */
12 #define USB_PID_AZUREWAVE_6007 0xccd
13 #define USB_PID_TERRATEC_H7 0x10b4
16 int dvb_usb_az6007_debug;
17 module_param_named(debug,dvb_usb_az6007_debug, int, 0644);
18 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
21 static int az6007_type =0;
22 module_param(az6007_type, int, 0644);
23 MODULE_PARM_DESC(az6007_type, "select delivery mode (0=DVB-T, 1=DVB-T");
25 //module_param_named(type, 6007_type, int, 0644);
26 //MODULE_PARM_DESC(type, "select delivery mode (0=DVB-T, 1=DVB-C)");
28 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
31 struct az6007_device_state {
32 struct dvb_ca_en50221 ca;
33 struct mutex ca_mutex;
36 /* Due to DRX-K - probably need changes */
37 int (*gate_ctrl)(struct dvb_frontend *, int);
38 struct semaphore pll_mutex;
42 struct drxk_config terratec_h7_drxk = {
46 .microcode_name = "dvb-usb-terratec-h5-drxk.fw",
49 static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
51 struct dvb_usb_adapter *adap = fe->sec_priv;
52 struct az6007_device_state *st;
68 status = st->gate_ctrl(fe, 1);
70 status = st->gate_ctrl(fe, 0);
76 struct mt2063_config az6007_mt2063_config = {
77 .tuner_address = 0x60,
81 /* check for mutex FIXME */
82 int az6007_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
86 ret = usb_control_msg(d->udev,
87 usb_rcvctrlpipe(d->udev,0),
89 USB_TYPE_VENDOR | USB_DIR_IN,
94 warn("usb in operation failed. (%d)", ret);
98 deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
99 debug_dump(b,blen,deb_xfer);
104 static int az6007_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
105 u16 index, u8 *b, int blen)
110 int i=0, cyc=0, rem=0;
115 deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
116 debug_dump(b,blen,deb_xfer);
122 for (i=0; i<cyc; i++)
124 if ((ret = usb_control_msg(d->udev,
125 usb_sndctrlpipe(d->udev,0),
127 USB_TYPE_VENDOR | USB_DIR_OUT,
128 value,index+i*64,b+i*64,64,
130 warn("usb out operation failed. (%d)",ret);
137 if ((ret = usb_control_msg(d->udev,
138 usb_sndctrlpipe(d->udev,0),
140 USB_TYPE_VENDOR | USB_DIR_OUT,
141 value,index+cyc*64,b+cyc*64,rem,
143 warn("usb out operation failed. (%d)",ret);
151 if ((ret = usb_control_msg(d->udev,
152 usb_sndctrlpipe(d->udev,0),
154 USB_TYPE_VENDOR | USB_DIR_OUT,
157 warn("usb out operation failed. (%d)",ret);
165 static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
170 /* keys for the enclosed remote control */
171 struct rc_map_table rc_map_az6007_table[] = {
176 /* remote control stuff (does not work with my box) */
177 static int az6007_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
184 /* remove the following return to enabled remote querying */
187 az6007_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
189 deb_rc("remote query key: %x %d\n",key[1],key[1]);
191 if (key[1] == 0x44) {
192 *state = REMOTE_NO_KEY_PRESSED;
196 for (i = 0; i < ARRAY_SIZE(az6007_rc_keys); i++)
197 if (az6007_rc_keys[i].custom == key[1]) {
198 *state = REMOTE_KEY_PRESSED;
199 *event = az6007_rc_keys[i].event;
207 int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
210 return az6007_usb_out_op(d,0xBC,v,3,NULL,1);
214 static int az6007_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
216 az6007_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6);
220 static int az6007_frontend_poweron(struct dvb_usb_adapter *adap)
228 info("az6007_frontend_poweron adap=%p adap->dev=%p", adap, adap->dev);
235 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
237 err("az6007_frontend_poweron failed!!!");
241 msleep_interruptible(200);
248 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
250 err("az6007_frontend_poweron failed!!!");
254 msleep_interruptible(200);
261 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
263 err("az6007_frontend_poweron failed!!!");
266 info("az6007_frontend_poweron: OK");
271 static int az6007_frontend_reset(struct dvb_usb_adapter *adap)
279 info("az6007_frontend_reset adap=%p adap->dev=%p", adap, adap->dev);
286 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
288 err("az6007_frontend_reset failed 1 !!!");
296 msleep_interruptible(200);
297 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
299 err("az6007_frontend_reset failed 2 !!!");
302 msleep_interruptible(200);
308 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
310 err("az6007_frontend_reset failed 3 !!!");
314 msleep_interruptible(200);
316 info("reset az6007 frontend");
321 static int az6007_led_on_off(struct usb_interface *intf, int onoff)
334 ret = usb_control_msg(interface_to_usbdev(intf),
335 usb_rcvctrlpipe(interface_to_usbdev(intf),0),
337 USB_TYPE_VENDOR | USB_DIR_OUT,
338 value,index,NULL,blen,
342 warn("usb in operation failed. (%d)", ret);
348 deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
353 static int az6007_frontend_tsbypass(struct dvb_usb_adapter *adap,int onoff)
366 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
371 static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
373 struct az6007_device_state *st = adap->priv;
379 az6007_frontend_poweron(adap);
380 az6007_frontend_reset(adap);
382 info("az6007_frontend_attach: drxk");
384 adap->fe = dvb_attach(drxk_attach, &terratec_h7_drxk,
385 &adap->dev->i2c_adap, &adap->fe2);
391 info("Setting hacks");
393 /* FIXME: do we need a pll semaphore? */
394 adap->fe->sec_priv = adap;
395 sema_init(&st->pll_mutex, 1);
396 st->gate_ctrl = adap->fe->ops.i2c_gate_ctrl;
397 adap->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
400 info("az6007_frontend_attach: mt2063");
401 /* Attach mt2063 to DVB-C frontend */
402 if (adap->fe->ops.i2c_gate_ctrl)
403 adap->fe->ops.i2c_gate_ctrl(adap->fe, 1);
404 if (!dvb_attach(mt2063_attach, adap->fe, &az6007_mt2063_config,
405 &adap->dev->i2c_adap)) {
410 if (adap->fe->ops.i2c_gate_ctrl)
411 adap->fe->ops.i2c_gate_ctrl(adap->fe, 0);
413 /* Hack - needed due to drxk */
414 adap->fe2->tuner_priv = adap->fe->tuner_priv;
415 memcpy(&adap->fe2->ops.tuner_ops,
416 &adap->fe->ops.tuner_ops,
417 sizeof(adap->fe->ops.tuner_ops));
422 dvb_frontend_detach(adap->fe);
429 static struct dvb_usb_device_properties az6007_properties;
432 az6007_usb_disconnect(struct usb_interface *intf)
434 dvb_usb_device_exit (intf);
438 static int az6007_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msgs[],int num)
440 struct dvb_usb_device *d = i2c_get_adapdata(adap);
449 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
452 for (i = 0; i < num; i++) {
453 addr = msgs[i].addr << 1;
455 && (msgs[i].len == 1)
456 && (!msgs[i].flags & I2C_M_RD)
457 && (msgs[i + 1].flags & I2C_M_RD)
458 && (msgs[i].addr == msgs[i + 1].addr)) {
460 * A write + read xfer for the same address, where
461 * the first xfer has just 1 byte length.
462 * Need to join both into one operation
464 if (dvb_usb_az6007_debug & 2)
466 "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ",
467 addr, msgs[i].len, msgs[i + 1].len);
469 index = msgs[i].buf[0];
470 value = addr | (1 << 8);
471 length = 6 + msgs[i + 1].len;
472 len = msgs[i + 1].len;
473 ret = az6007_usb_in_op(d,req,value,index,data,length);
475 for (j = 0; j < len; j++) {
476 msgs[i + 1].buf[j] = data[j + 5];
477 if (dvb_usb_az6007_debug & 2)
485 } else if (!(msgs[i].flags & I2C_M_RD)) {
487 if (dvb_usb_az6007_debug & 2)
489 "az6007 I2C xfer write addr=0x%x len=%d: ",
492 index = msgs[i].buf[0];
493 value = addr | (1 << 8);
494 length = msgs[i].len - 1;
495 len = msgs[i].len - 1;
496 if (dvb_usb_az6007_debug & 2)
498 "(0x%02x) ", msgs[i].buf[0]);
499 for (j = 0; j < len; j++)
501 data[j] = msgs[i].buf[j + 1];
502 if (dvb_usb_az6007_debug & 2)
506 ret = az6007_usb_out_op(d,req,value,index,data,length);
509 if (dvb_usb_az6007_debug & 2)
511 "az6007 I2C xfer read addr=0x%x len=%d: ",
514 index = msgs[i].buf[0];
516 length = msgs[i].len + 6;
518 ret = az6007_usb_in_op(d,req,value,index,data,length);
519 for (j = 0; j < len; j++)
521 msgs[i].buf[j] = data[j + 5];
522 if (dvb_usb_az6007_debug & 2)
524 "0x%02x ", data[j + 5]);
527 if (dvb_usb_az6007_debug & 2)
528 printk(KERN_CONT "\n");
533 mutex_unlock(&d->i2c_mutex);
536 info("%s ERROR: %i\n", __func__, ret);
543 static u32 az6007_i2c_func(struct i2c_adapter *adapter)
548 static struct i2c_algorithm az6007_i2c_algo = {
549 .master_xfer = az6007_i2c_xfer,
550 .functionality = az6007_i2c_func,
551 #ifdef NEED_ALGO_CONTROL
552 .algo_control = dummy_algo_control,
556 int az6007_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
557 struct dvb_usb_device_description **desc, int *cold)
560 s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
561 0xb7, USB_TYPE_VENDOR | USB_DIR_IN, 6, 0, b, 6, USB_CTRL_GET_TIMEOUT);
563 info("FW GET_VERSION length: %d",ret);
567 info("cold: %d", *cold);
571 static int az6007_usb_probe(struct usb_interface *intf,
572 const struct usb_device_id *id)
574 az6007_led_on_off(intf, 0);
576 return dvb_usb_device_init(intf, &az6007_properties,
577 THIS_MODULE, NULL, adapter_nr);
580 static struct usb_device_id az6007_usb_table [] = {
581 { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007) },
582 { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7) },
586 MODULE_DEVICE_TABLE(usb, az6007_usb_table);
588 static struct dvb_usb_device_properties az6007_properties = {
589 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
590 .usb_ctrl = CYPRESS_FX2,
591 //.download_firmware = az6007_download_firmware,
592 .firmware = "dvb-usb-az6007-03.fw",
595 .identify_state = az6007_identify_state,
599 //.caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
601 .streaming_ctrl = az6007_streaming_ctrl,
602 .frontend_attach = az6007_frontend_attach,
604 /* parameter for the MPEG2-data transfer */
615 .size_of_priv = sizeof(struct az6007_device_state),
618 //.power_ctrl = az6007_power_ctrl,
619 .read_mac_address = az6007_read_mac_addr,
622 .rc_map_table = rc_map_az6007_table,
623 .rc_map_size = ARRAY_SIZE(rc_map_az6007_table),
625 .rc_query = az6007_rc_query,
627 .i2c_algo = &az6007_i2c_algo,
629 .num_device_descs = 2,
631 { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)",
632 .cold_ids = { &az6007_usb_table[0], NULL },
633 .warm_ids = { NULL },
635 { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)",
636 .cold_ids = { &az6007_usb_table[1], NULL },
637 .warm_ids = { NULL },
643 /* usb specific object needed to register this driver with the usb subsystem */
644 static struct usb_driver az6007_usb_driver = {
645 .name = "dvb_usb_az6007",
646 .probe = az6007_usb_probe,
647 .disconnect = dvb_usb_device_exit,
648 //.disconnect = az6007_usb_disconnect,
649 .id_table = az6007_usb_table,
653 static int __init az6007_usb_module_init(void)
656 info("az6007 usb module init");
657 if ((result = usb_register(&az6007_usb_driver))) {
658 err("usb_register failed. (%d)",result);
665 static void __exit az6007_usb_module_exit(void)
667 /* deregister this driver from the USB subsystem */
668 info("az6007 usb module exit");
669 usb_deregister(&az6007_usb_driver);
672 module_init(az6007_usb_module_init);
673 module_exit(az6007_usb_module_exit);
675 MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
676 MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
677 MODULE_VERSION("1.0");
678 MODULE_LICENSE("GPL");