blob: ed376b8292ce183dd96e9dd1b254bf9e07b0f33d [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,
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -030045 .no_i2c_bridge = 0,
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030046 .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;
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -030052 struct az6007_device_state *st;
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030053 int status;
54
Mauro Carvalho Chehab22125012011-07-23 09:58:38 -030055 info("%s: %s", __func__, enable? "enable" : "disable" );
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -030056
57 if (!adap)
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030058 return -EINVAL;
59
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -030060 st = adap->priv;
61
62 if (!st)
63 return -EINVAL;
64
65
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030066 if (enable) {
Mauro Carvalho Chehab22125012011-07-23 09:58:38 -030067#if 0
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030068 down(&st->pll_mutex);
Mauro Carvalho Chehab22125012011-07-23 09:58:38 -030069#endif
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030070 status = st->gate_ctrl(fe, 1);
71 } else {
Mauro Carvalho Chehab22125012011-07-23 09:58:38 -030072#if 0
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030073 status = st->gate_ctrl(fe, 0);
Mauro Carvalho Chehab22125012011-07-23 09:58:38 -030074#endif
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030075 up(&st->pll_mutex);
76 }
77 return status;
78}
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030079
80struct mt2063_config az6007_mt2063_config = {
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -030081 .tuner_address = 0x60,
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030082 .refclock = 36125000,
83};
84
85/* check for mutex FIXME */
86int az6007_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
87{
88 int ret = -1;
89
90 ret = usb_control_msg(d->udev,
91 usb_rcvctrlpipe(d->udev,0),
92 req,
93 USB_TYPE_VENDOR | USB_DIR_IN,
94 value,index,b,blen,
95 5000);
96
97 if (ret < 0) {
98 warn("usb in operation failed. (%d)", ret);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -030099 return -EIO;
100 }
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300101
102 deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
103 debug_dump(b,blen,deb_xfer);
104
105 return ret;
106}
107
108static int az6007_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
109 u16 index, u8 *b, int blen)
110{
111 int ret;
112
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300113#if 0
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300114 int i=0, cyc=0, rem=0;
115 cyc = blen/64;
116 rem = blen%64;
117#endif
118
119 deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
120 debug_dump(b,blen,deb_xfer);
121
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300122
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300123#if 0
124 if (blen>64)
125 {
126 for (i=0; i<cyc; i++)
127 {
128 if ((ret = usb_control_msg(d->udev,
129 usb_sndctrlpipe(d->udev,0),
130 req,
131 USB_TYPE_VENDOR | USB_DIR_OUT,
132 value,index+i*64,b+i*64,64,
133 5000)) != 64) {
134 warn("usb out operation failed. (%d)",ret);
135 return -EIO;
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300136 }
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300137 }
138
139 if (rem>0)
140 {
141 if ((ret = usb_control_msg(d->udev,
142 usb_sndctrlpipe(d->udev,0),
143 req,
144 USB_TYPE_VENDOR | USB_DIR_OUT,
145 value,index+cyc*64,b+cyc*64,rem,
146 5000)) != rem) {
147 warn("usb out operation failed. (%d)",ret);
148 return -EIO;
149 }
150 }
151 }
152 else
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300153#endif
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300154 {
155 if ((ret = usb_control_msg(d->udev,
156 usb_sndctrlpipe(d->udev,0),
157 req,
158 USB_TYPE_VENDOR | USB_DIR_OUT,
159 value,index,b,blen,
160 5000)) != blen) {
161 warn("usb out operation failed. (%d)",ret);
162 return -EIO;
163 }
164 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300165
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300166 return 0;
167}
168
169static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
170{
171 return 0;
172}
173
174/* keys for the enclosed remote control */
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300175struct rc_map_table rc_map_az6007_table[] = {
176 { 0x0001, KEY_1 },
177 { 0x0002, KEY_2 },
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300178};
179
180/* remote control stuff (does not work with my box) */
181static int az6007_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
182{
183 return 0;
184#if 0
185 u8 key[10];
186 int i;
187
188/* remove the following return to enabled remote querying */
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300189
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300190
191 az6007_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
192
193 deb_rc("remote query key: %x %d\n",key[1],key[1]);
194
195 if (key[1] == 0x44) {
196 *state = REMOTE_NO_KEY_PRESSED;
197 return 0;
198 }
199
200 for (i = 0; i < ARRAY_SIZE(az6007_rc_keys); i++)
201 if (az6007_rc_keys[i].custom == key[1]) {
202 *state = REMOTE_KEY_PRESSED;
203 *event = az6007_rc_keys[i].event;
204 break;
205 }
206 return 0;
207#endif
208}
209
210/*
211int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
212{
213 u8 v = onoff;
214 return az6007_usb_out_op(d,0xBC,v,3,NULL,1);
215}
216*/
217
218static int az6007_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
219{
220 az6007_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6);
221 return 0;
222}
223
224static int az6007_frontend_poweron(struct dvb_usb_adapter *adap)
225{
226 int ret;
227 u8 req;
228 u16 value;
229 u16 index;
230 int blen;
231
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300232 info("az6007_frontend_poweron adap=%p adap->dev=%p", adap, adap->dev);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300233
234 req = 0xBC;
235 value = 1;//power on
236 index = 3;
237 blen =0;
238
239 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
240 {
241 err("az6007_frontend_poweron failed!!!");
242 return -EIO;
243 }
244
245 msleep_interruptible(200);
246
247 req = 0xBC;
248 value = 0;//power on
249 index = 3;
250 blen =0;
251
252 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
253 {
254 err("az6007_frontend_poweron failed!!!");
255 return -EIO;
256 }
257
258 msleep_interruptible(200);
259
260 req = 0xBC;
261 value = 1;//power on
262 index = 3;
263 blen =0;
264
265 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
266 {
267 err("az6007_frontend_poweron failed!!!");
268 return -EIO;
269 }
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300270 info("az6007_frontend_poweron: OK");
271
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300272 return 0;
273}
274
275static int az6007_frontend_reset(struct dvb_usb_adapter *adap)
276{
277 int ret;
278 u8 req;
279 u16 value;
280 u16 index;
281 int blen;
282
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300283 info("az6007_frontend_reset adap=%p adap->dev=%p", adap, adap->dev);
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300284
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300285 //reset demodulator
286 req = 0xC0;
287 value = 1;//high
288 index = 3;
289 blen =0;
290 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
291 {
292 err("az6007_frontend_reset failed 1 !!!");
293 return -EIO;
294 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300295
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300296 req = 0xC0;
297 value = 0;//low
298 index = 3;
299 blen =0;
300 msleep_interruptible(200);
301 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
302 {
303 err("az6007_frontend_reset failed 2 !!!");
304 return -EIO;
305 }
306 msleep_interruptible(200);
307 req = 0xC0;
308 value = 1;//high
309 index = 3;
310 blen =0;
311
312 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
313 {
314 err("az6007_frontend_reset failed 3 !!!");
315 return -EIO;
316 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300317
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300318 msleep_interruptible(200);
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300319
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300320 info("reset az6007 frontend");
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300321
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300322 return 0;
323}
324
325static int az6007_led_on_off(struct usb_interface *intf, int onoff)
326{
327 int ret = -1;
328 u8 req;
329 u16 value;
330 u16 index;
331 int blen;
332 //TS through
333 req = 0xBC;
334 value = onoff;
335 index = 0;
336 blen =0;
337
338 ret = usb_control_msg(interface_to_usbdev(intf),
339 usb_rcvctrlpipe(interface_to_usbdev(intf),0),
340 req,
341 USB_TYPE_VENDOR | USB_DIR_OUT,
342 value,index,NULL,blen,
343 2000);
344
345 if (ret < 0) {
346 warn("usb in operation failed. (%d)", ret);
347 ret = -EIO;
348 } else
349 ret = 0;
350
351
352 deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
353
354 return ret;
355}
356
357static int az6007_frontend_tsbypass(struct dvb_usb_adapter *adap,int onoff)
358{
359 int ret;
360 u8 req;
361 u16 value;
362 u16 index;
363 int blen;
364 //TS through
365 req = 0xC7;
366 value = onoff;
367 index = 0;
368 blen =0;
369
370 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
371 return -EIO;
372 return 0;
373}
374
375static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
376{
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300377 struct az6007_device_state *st = adap->priv;
378
379 int result;
380
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300381 BUG_ON(!st);
382
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300383 az6007_frontend_poweron(adap);
384 az6007_frontend_reset(adap);
385
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300386 info("az6007_frontend_attach: drxk");
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300387
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300388 adap->fe = dvb_attach(drxk_attach, &terratec_h7_drxk,
389 &adap->dev->i2c_adap, &adap->fe2);
390 if (!adap->fe) {
391 result = -EINVAL;
392 goto out_free;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300393 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300394
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300395 info("Setting hacks");
396
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300397 /* FIXME: do we need a pll semaphore? */
398 adap->fe->sec_priv = adap;
399 sema_init(&st->pll_mutex, 1);
400 st->gate_ctrl = adap->fe->ops.i2c_gate_ctrl;
401 adap->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
402 adap->fe2->id = 1;
403
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300404 info("az6007_frontend_attach: mt2063");
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300405 /* Attach mt2063 to DVB-C frontend */
406 if (adap->fe->ops.i2c_gate_ctrl)
407 adap->fe->ops.i2c_gate_ctrl(adap->fe, 1);
408 if (!dvb_attach(mt2063_attach, adap->fe, &az6007_mt2063_config,
409 &adap->dev->i2c_adap)) {
410 result = -EINVAL;
411
412 goto out_free;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300413 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300414 if (adap->fe->ops.i2c_gate_ctrl)
415 adap->fe->ops.i2c_gate_ctrl(adap->fe, 0);
416
417 /* Hack - needed due to drxk */
418 adap->fe2->tuner_priv = adap->fe->tuner_priv;
419 memcpy(&adap->fe2->ops.tuner_ops,
420 &adap->fe->ops.tuner_ops,
421 sizeof(adap->fe->ops.tuner_ops));
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300422 return 0;
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300423
424out_free:
425 if (adap->fe)
426 dvb_frontend_detach(adap->fe);
427 adap->fe = NULL;
428 adap->fe2 = NULL;
429
430 return result;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300431}
432
433static struct dvb_usb_device_properties az6007_properties;
434
435static void
436az6007_usb_disconnect(struct usb_interface *intf)
437{
438 dvb_usb_device_exit (intf);
439}
440
441/* I2C */
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300442static int az6007_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msgs[],int num)
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300443{
444 struct dvb_usb_device *d = i2c_get_adapdata(adap);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300445 int i, j, len;
446 int ret = 0;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300447 u16 index;
448 u16 value;
449 int length;
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300450 u8 req, addr;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300451 u8 data[512];
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300452
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300453 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
454 return -EAGAIN;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300455
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300456 for (i = 0; i < num; i++) {
457 addr = msgs[i].addr << 1;
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300458 if (((i + 1) < num)
459 && (msgs[i].len == 1)
460 && (!msgs[i].flags & I2C_M_RD)
461 && (msgs[i + 1].flags & I2C_M_RD)
462 && (msgs[i].addr == msgs[i + 1].addr)) {
463 /*
464 * A write + read xfer for the same address, where
465 * the first xfer has just 1 byte length.
466 * Need to join both into one operation
467 */
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300468 if (dvb_usb_az6007_debug & 2)
469 printk(KERN_DEBUG
470 "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ",
471 addr, msgs[i].len, msgs[i + 1].len);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300472 req = 0xb9;
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300473 index = msgs[i].buf[0];
474 value = addr | (1 << 8);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300475 length = 6 + msgs[i + 1].len;
476 len = msgs[i + 1].len;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300477 ret = az6007_usb_in_op(d,req,value,index,data,length);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300478 if (ret >= len) {
479 for (j = 0; j < len; j++) {
480 msgs[i + 1].buf[j] = data[j + 5];
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300481 if (dvb_usb_az6007_debug & 2)
482 printk(KERN_CONT
483 "0x%02x ",
484 msgs[i + 1].buf[j]);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300485 }
486 } else
487 ret = -EIO;
488 i++;
489 } else if (!(msgs[i].flags & I2C_M_RD)) {
490 /* write bytes */
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300491 if (dvb_usb_az6007_debug & 2)
492 printk(KERN_DEBUG
493 "az6007 I2C xfer write addr=0x%x len=%d: ",
494 addr, msgs[i].len);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300495 req = 0xbd;
496 index = msgs[i].buf[0];
497 value = addr | (1 << 8);
498 length = msgs[i].len - 1;
499 len = msgs[i].len - 1;
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300500 if (dvb_usb_az6007_debug & 2)
501 printk(KERN_CONT
502 "(0x%02x) ", msgs[i].buf[0]);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300503 for (j = 0; j < len; j++)
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300504 {
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300505 data[j] = msgs[i].buf[j + 1];
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300506 if (dvb_usb_az6007_debug & 2)
507 printk(KERN_CONT
508 "0x%02x ", data[j]);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300509 }
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300510 ret = az6007_usb_out_op(d,req,value,index,data,length);
511 } else {
512 /* read bytes */
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300513 if (dvb_usb_az6007_debug & 2)
514 printk(KERN_DEBUG
515 "az6007 I2C xfer read addr=0x%x len=%d: ",
516 addr, msgs[i].len);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300517 req = 0xb9;
518 index = msgs[i].buf[0];
519 value = addr;
520 length = msgs[i].len + 6;
521 len = msgs[i].len;
522 ret = az6007_usb_in_op(d,req,value,index,data,length);
523 for (j = 0; j < len; j++)
524 {
525 msgs[i].buf[j] = data[j + 5];
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300526 if (dvb_usb_az6007_debug & 2)
527 printk(KERN_CONT
528 "0x%02x ", data[j + 5]);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300529 }
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300530 }
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300531 if (dvb_usb_az6007_debug & 2)
532 printk(KERN_CONT "\n");
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300533 if (ret < 0)
534 goto err;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300535 }
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300536err:
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300537 mutex_unlock(&d->i2c_mutex);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300538
539 if (ret < 0) {
540 info("%s ERROR: %i\n", __func__, ret);
541 return ret;
542 }
543 return num;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300544}
545
546
547static u32 az6007_i2c_func(struct i2c_adapter *adapter)
548{
549 return I2C_FUNC_I2C;
550}
551
552static struct i2c_algorithm az6007_i2c_algo = {
553 .master_xfer = az6007_i2c_xfer,
554 .functionality = az6007_i2c_func,
555#ifdef NEED_ALGO_CONTROL
556 .algo_control = dummy_algo_control,
557#endif
558};
559
560int az6007_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
561 struct dvb_usb_device_description **desc, int *cold)
562{
563 u8 b[16];
564 s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
565 0xb7, USB_TYPE_VENDOR | USB_DIR_IN, 6, 0, b, 6, USB_CTRL_GET_TIMEOUT);
566
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300567 info("FW GET_VERSION length: %d",ret);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300568
569 *cold = ret <= 0;
570
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300571 info("cold: %d", *cold);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300572 return 0;
573}
574
575static int az6007_usb_probe(struct usb_interface *intf,
576 const struct usb_device_id *id)
577{
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300578 az6007_led_on_off(intf, 0);
579
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300580 return dvb_usb_device_init(intf, &az6007_properties,
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300581 THIS_MODULE, NULL, adapter_nr);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300582}
583
584static struct usb_device_id az6007_usb_table [] = {
585 { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007) },
586 { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7) },
587 { 0 },
588};
589
590MODULE_DEVICE_TABLE(usb, az6007_usb_table);
591
592static struct dvb_usb_device_properties az6007_properties = {
593 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
594 .usb_ctrl = CYPRESS_FX2,
595 //.download_firmware = az6007_download_firmware,
596 .firmware = "dvb-usb-az6007-03.fw",
597 .no_reconnect = 1,
598
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300599 .identify_state = az6007_identify_state,
600 .num_adapters = 1,
601 .adapter = {
602 {
603 //.caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
604
605 .streaming_ctrl = az6007_streaming_ctrl,
606 .frontend_attach = az6007_frontend_attach,
607
608 /* parameter for the MPEG2-data transfer */
609 .stream = {
610 .type = USB_BULK,
611 .count = 10,
612 .endpoint = 0x02,
613 .u = {
614 .bulk = {
615 .buffersize = 4096,
616 }
617 }
618 },
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300619 .size_of_priv = sizeof(struct az6007_device_state),
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300620 }
621 },
622 //.power_ctrl = az6007_power_ctrl,
623 .read_mac_address = az6007_read_mac_addr,
624
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300625 .rc.legacy = {
626 .rc_map_table = rc_map_az6007_table,
627 .rc_map_size = ARRAY_SIZE(rc_map_az6007_table),
628 .rc_interval = 400,
629 .rc_query = az6007_rc_query,
630 },
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300631 .i2c_algo = &az6007_i2c_algo,
632
633 .num_device_descs = 2,
634 .devices = {
635 { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)",
636 .cold_ids = { &az6007_usb_table[0], NULL },
637 .warm_ids = { NULL },
638 },
639 { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)",
640 .cold_ids = { &az6007_usb_table[1], NULL },
641 .warm_ids = { NULL },
642 },
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300643 { NULL },
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300644 }
645};
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300646
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300647/* usb specific object needed to register this driver with the usb subsystem */
648static struct usb_driver az6007_usb_driver = {
649 .name = "dvb_usb_az6007",
650 .probe = az6007_usb_probe,
651 .disconnect = dvb_usb_device_exit,
652 //.disconnect = az6007_usb_disconnect,
653 .id_table = az6007_usb_table,
654};
655
656/* module stuff */
657static int __init az6007_usb_module_init(void)
658{
659 int result;
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300660 info("az6007 usb module init");
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300661 if ((result = usb_register(&az6007_usb_driver))) {
662 err("usb_register failed. (%d)",result);
663 return result;
664 }
665
666 return 0;
667}
668
669static void __exit az6007_usb_module_exit(void)
670{
671 /* deregister this driver from the USB subsystem */
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300672 info("az6007 usb module exit");
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300673 usb_deregister(&az6007_usb_driver);
674}
675
676module_init(az6007_usb_module_init);
677module_exit(az6007_usb_module_exit);
678
679MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
680MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
681MODULE_VERSION("1.0");
682MODULE_LICENSE("GPL");