blob: 1fc174b86a776c245d5f03b373b6743255c3c2a7 [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
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030020DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
21
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030022struct az6007_device_state {
23 struct dvb_ca_en50221 ca;
24 struct mutex ca_mutex;
25 u8 power_state;
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030026
27 /* Due to DRX-K - probably need changes */
28 int (*gate_ctrl)(struct dvb_frontend *, int);
29 struct semaphore pll_mutex;
30 bool dont_attach_fe1;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030031};
32
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030033struct drxk_config terratec_h7_drxk = {
34 .adr = 0x29,
35 .single_master = 1,
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -030036 .no_i2c_bridge = 0,
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030037 .microcode_name = "dvb-usb-terratec-h5-drxk.fw",
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030038};
39
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030040static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
41{
42 struct dvb_usb_adapter *adap = fe->sec_priv;
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -030043 struct az6007_device_state *st;
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030044 int status;
45
Mauro Carvalho Chehab22125012011-07-23 09:58:38 -030046 info("%s: %s", __func__, enable? "enable" : "disable" );
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -030047
48 if (!adap)
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030049 return -EINVAL;
50
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -030051 st = adap->priv;
52
53 if (!st)
54 return -EINVAL;
55
56
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030057 if (enable) {
Mauro Carvalho Chehab22125012011-07-23 09:58:38 -030058#if 0
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030059 down(&st->pll_mutex);
Mauro Carvalho Chehab22125012011-07-23 09:58:38 -030060#endif
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030061 status = st->gate_ctrl(fe, 1);
62 } else {
Mauro Carvalho Chehab22125012011-07-23 09:58:38 -030063#if 0
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030064 status = st->gate_ctrl(fe, 0);
Mauro Carvalho Chehab22125012011-07-23 09:58:38 -030065#endif
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -030066 up(&st->pll_mutex);
67 }
68 return status;
69}
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030070
71struct mt2063_config az6007_mt2063_config = {
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -030072 .tuner_address = 0x60,
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030073 .refclock = 36125000,
74};
75
76/* check for mutex FIXME */
77int az6007_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
78{
79 int ret = -1;
80
81 ret = usb_control_msg(d->udev,
82 usb_rcvctrlpipe(d->udev,0),
83 req,
84 USB_TYPE_VENDOR | USB_DIR_IN,
85 value,index,b,blen,
86 5000);
87
88 if (ret < 0) {
89 warn("usb in operation failed. (%d)", ret);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -030090 return -EIO;
91 }
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -030092
93 deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
94 debug_dump(b,blen,deb_xfer);
95
96 return ret;
97}
98
99static int az6007_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
100 u16 index, u8 *b, int blen)
101{
102 int ret;
103
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300104 deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
105 debug_dump(b,blen,deb_xfer);
106
Mauro Carvalho Chehab35753582011-07-23 10:12:12 -0300107 if (blen > 64) {
108 printk(KERN_ERR "az6007: doesn't suport I2C transactions longer than 64 bytes\n");
109 return -EOPNOTSUPP;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300110 }
Mauro Carvalho Chehab35753582011-07-23 10:12:12 -0300111
112 if ((ret = usb_control_msg(d->udev,
113 usb_sndctrlpipe(d->udev,0),
114 req,
115 USB_TYPE_VENDOR | USB_DIR_OUT,
116 value,index,b,blen,
117 5000)) != blen) {
118 warn("usb out operation failed. (%d)",ret);
119 return -EIO;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300120 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300121
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300122 return 0;
123}
124
125static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
126{
127 return 0;
128}
129
130/* keys for the enclosed remote control */
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300131struct rc_map_table rc_map_az6007_table[] = {
132 { 0x0001, KEY_1 },
133 { 0x0002, KEY_2 },
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300134};
135
136/* remote control stuff (does not work with my box) */
137static int az6007_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
138{
139 return 0;
140#if 0
141 u8 key[10];
142 int i;
143
144/* remove the following return to enabled remote querying */
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300145
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300146
147 az6007_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
148
149 deb_rc("remote query key: %x %d\n",key[1],key[1]);
150
151 if (key[1] == 0x44) {
152 *state = REMOTE_NO_KEY_PRESSED;
153 return 0;
154 }
155
156 for (i = 0; i < ARRAY_SIZE(az6007_rc_keys); i++)
157 if (az6007_rc_keys[i].custom == key[1]) {
158 *state = REMOTE_KEY_PRESSED;
159 *event = az6007_rc_keys[i].event;
160 break;
161 }
162 return 0;
163#endif
164}
165
166/*
167int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
168{
169 u8 v = onoff;
170 return az6007_usb_out_op(d,0xBC,v,3,NULL,1);
171}
172*/
173
174static int az6007_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
175{
176 az6007_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6);
177 return 0;
178}
179
180static int az6007_frontend_poweron(struct dvb_usb_adapter *adap)
181{
182 int ret;
183 u8 req;
184 u16 value;
185 u16 index;
186 int blen;
187
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300188 info("az6007_frontend_poweron adap=%p adap->dev=%p", adap, adap->dev);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300189
190 req = 0xBC;
Mauro Carvalho Chehab35753582011-07-23 10:12:12 -0300191 value = 1; /* power on */
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300192 index = 3;
193 blen =0;
194
195 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
196 {
197 err("az6007_frontend_poweron failed!!!");
198 return -EIO;
199 }
200
201 msleep_interruptible(200);
202
203 req = 0xBC;
Mauro Carvalho Chehab35753582011-07-23 10:12:12 -0300204 value = 0; /* power off */
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300205 index = 3;
206 blen =0;
207
208 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
209 {
210 err("az6007_frontend_poweron failed!!!");
211 return -EIO;
212 }
213
214 msleep_interruptible(200);
215
216 req = 0xBC;
Mauro Carvalho Chehab35753582011-07-23 10:12:12 -0300217 value = 1; /* power on */
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300218 index = 3;
219 blen =0;
220
221 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
222 {
223 err("az6007_frontend_poweron failed!!!");
224 return -EIO;
225 }
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300226 info("az6007_frontend_poweron: OK");
227
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300228 return 0;
229}
230
231static int az6007_frontend_reset(struct dvb_usb_adapter *adap)
232{
233 int ret;
234 u8 req;
235 u16 value;
236 u16 index;
237 int blen;
238
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300239 info("az6007_frontend_reset adap=%p adap->dev=%p", adap, adap->dev);
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300240
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300241 //reset demodulator
242 req = 0xC0;
243 value = 1;//high
244 index = 3;
245 blen =0;
246 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
247 {
248 err("az6007_frontend_reset failed 1 !!!");
249 return -EIO;
250 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300251
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300252 req = 0xC0;
253 value = 0;//low
254 index = 3;
255 blen =0;
256 msleep_interruptible(200);
257 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
258 {
259 err("az6007_frontend_reset failed 2 !!!");
260 return -EIO;
261 }
262 msleep_interruptible(200);
263 req = 0xC0;
264 value = 1;//high
265 index = 3;
266 blen =0;
267
268 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
269 {
270 err("az6007_frontend_reset failed 3 !!!");
271 return -EIO;
272 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300273
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300274 msleep_interruptible(200);
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300275
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300276 info("reset az6007 frontend");
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300277
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300278 return 0;
279}
280
281static int az6007_led_on_off(struct usb_interface *intf, int onoff)
282{
283 int ret = -1;
284 u8 req;
285 u16 value;
286 u16 index;
287 int blen;
288 //TS through
289 req = 0xBC;
290 value = onoff;
291 index = 0;
292 blen =0;
293
294 ret = usb_control_msg(interface_to_usbdev(intf),
295 usb_rcvctrlpipe(interface_to_usbdev(intf),0),
296 req,
297 USB_TYPE_VENDOR | USB_DIR_OUT,
298 value,index,NULL,blen,
299 2000);
300
301 if (ret < 0) {
302 warn("usb in operation failed. (%d)", ret);
303 ret = -EIO;
304 } else
305 ret = 0;
306
307
308 deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
309
310 return ret;
311}
312
313static int az6007_frontend_tsbypass(struct dvb_usb_adapter *adap,int onoff)
314{
315 int ret;
316 u8 req;
317 u16 value;
318 u16 index;
319 int blen;
320 //TS through
321 req = 0xC7;
322 value = onoff;
323 index = 0;
324 blen =0;
325
326 if((ret = az6007_usb_out_op(adap->dev,req,value,index,NULL,blen)) != 0)
327 return -EIO;
328 return 0;
329}
330
331static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
332{
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300333 struct az6007_device_state *st = adap->priv;
334
335 int result;
336
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300337 BUG_ON(!st);
338
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300339 az6007_frontend_poweron(adap);
340 az6007_frontend_reset(adap);
341
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300342 info("az6007_frontend_attach: drxk");
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300343
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300344 adap->fe = dvb_attach(drxk_attach, &terratec_h7_drxk,
345 &adap->dev->i2c_adap, &adap->fe2);
346 if (!adap->fe) {
347 result = -EINVAL;
348 goto out_free;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300349 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300350
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300351 info("Setting hacks");
352
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300353 /* FIXME: do we need a pll semaphore? */
354 adap->fe->sec_priv = adap;
355 sema_init(&st->pll_mutex, 1);
356 st->gate_ctrl = adap->fe->ops.i2c_gate_ctrl;
357 adap->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
358 adap->fe2->id = 1;
359
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300360 info("az6007_frontend_attach: mt2063");
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300361 /* Attach mt2063 to DVB-C frontend */
362 if (adap->fe->ops.i2c_gate_ctrl)
363 adap->fe->ops.i2c_gate_ctrl(adap->fe, 1);
364 if (!dvb_attach(mt2063_attach, adap->fe, &az6007_mt2063_config,
365 &adap->dev->i2c_adap)) {
366 result = -EINVAL;
367
368 goto out_free;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300369 }
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300370 if (adap->fe->ops.i2c_gate_ctrl)
371 adap->fe->ops.i2c_gate_ctrl(adap->fe, 0);
372
373 /* Hack - needed due to drxk */
374 adap->fe2->tuner_priv = adap->fe->tuner_priv;
375 memcpy(&adap->fe2->ops.tuner_ops,
376 &adap->fe->ops.tuner_ops,
377 sizeof(adap->fe->ops.tuner_ops));
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300378 return 0;
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300379
380out_free:
381 if (adap->fe)
382 dvb_frontend_detach(adap->fe);
383 adap->fe = NULL;
384 adap->fe2 = NULL;
385
386 return result;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300387}
388
389static struct dvb_usb_device_properties az6007_properties;
390
391static void
392az6007_usb_disconnect(struct usb_interface *intf)
393{
394 dvb_usb_device_exit (intf);
395}
396
397/* I2C */
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300398static int az6007_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msgs[],int num)
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300399{
400 struct dvb_usb_device *d = i2c_get_adapdata(adap);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300401 int i, j, len;
402 int ret = 0;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300403 u16 index;
404 u16 value;
405 int length;
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300406 u8 req, addr;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300407 u8 data[512];
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300408
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300409 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
410 return -EAGAIN;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300411
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300412 for (i = 0; i < num; i++) {
413 addr = msgs[i].addr << 1;
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300414 if (((i + 1) < num)
415 && (msgs[i].len == 1)
416 && (!msgs[i].flags & I2C_M_RD)
417 && (msgs[i + 1].flags & I2C_M_RD)
418 && (msgs[i].addr == msgs[i + 1].addr)) {
419 /*
420 * A write + read xfer for the same address, where
421 * the first xfer has just 1 byte length.
422 * Need to join both into one operation
423 */
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300424 if (dvb_usb_az6007_debug & 2)
425 printk(KERN_DEBUG
426 "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ",
427 addr, msgs[i].len, msgs[i + 1].len);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300428 req = 0xb9;
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300429 index = msgs[i].buf[0];
430 value = addr | (1 << 8);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300431 length = 6 + msgs[i + 1].len;
432 len = msgs[i + 1].len;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300433 ret = az6007_usb_in_op(d,req,value,index,data,length);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300434 if (ret >= len) {
435 for (j = 0; j < len; j++) {
436 msgs[i + 1].buf[j] = data[j + 5];
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300437 if (dvb_usb_az6007_debug & 2)
438 printk(KERN_CONT
439 "0x%02x ",
440 msgs[i + 1].buf[j]);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300441 }
442 } else
443 ret = -EIO;
444 i++;
445 } else if (!(msgs[i].flags & I2C_M_RD)) {
446 /* write bytes */
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300447 if (dvb_usb_az6007_debug & 2)
448 printk(KERN_DEBUG
449 "az6007 I2C xfer write addr=0x%x len=%d: ",
450 addr, msgs[i].len);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300451 req = 0xbd;
452 index = msgs[i].buf[0];
453 value = addr | (1 << 8);
454 length = msgs[i].len - 1;
455 len = msgs[i].len - 1;
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300456 if (dvb_usb_az6007_debug & 2)
457 printk(KERN_CONT
458 "(0x%02x) ", msgs[i].buf[0]);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300459 for (j = 0; j < len; j++)
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300460 {
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300461 data[j] = msgs[i].buf[j + 1];
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300462 if (dvb_usb_az6007_debug & 2)
463 printk(KERN_CONT
464 "0x%02x ", data[j]);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300465 }
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300466 ret = az6007_usb_out_op(d,req,value,index,data,length);
467 } else {
468 /* read bytes */
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300469 if (dvb_usb_az6007_debug & 2)
470 printk(KERN_DEBUG
471 "az6007 I2C xfer read addr=0x%x len=%d: ",
472 addr, msgs[i].len);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300473 req = 0xb9;
474 index = msgs[i].buf[0];
475 value = addr;
476 length = msgs[i].len + 6;
477 len = msgs[i].len;
478 ret = az6007_usb_in_op(d,req,value,index,data,length);
479 for (j = 0; j < len; j++)
480 {
481 msgs[i].buf[j] = data[j + 5];
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300482 if (dvb_usb_az6007_debug & 2)
483 printk(KERN_CONT
484 "0x%02x ", data[j + 5]);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300485 }
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300486 }
Mauro Carvalho Chehabd20a7f72011-07-23 09:51:12 -0300487 if (dvb_usb_az6007_debug & 2)
488 printk(KERN_CONT "\n");
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300489 if (ret < 0)
490 goto err;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300491 }
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300492err:
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300493 mutex_unlock(&d->i2c_mutex);
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300494
495 if (ret < 0) {
496 info("%s ERROR: %i\n", __func__, ret);
497 return ret;
498 }
499 return num;
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300500}
501
502
503static u32 az6007_i2c_func(struct i2c_adapter *adapter)
504{
505 return I2C_FUNC_I2C;
506}
507
508static struct i2c_algorithm az6007_i2c_algo = {
509 .master_xfer = az6007_i2c_xfer,
510 .functionality = az6007_i2c_func,
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300511};
512
513int az6007_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
514 struct dvb_usb_device_description **desc, int *cold)
515{
516 u8 b[16];
517 s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
518 0xb7, USB_TYPE_VENDOR | USB_DIR_IN, 6, 0, b, 6, USB_CTRL_GET_TIMEOUT);
519
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300520 info("FW GET_VERSION length: %d",ret);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300521
522 *cold = ret <= 0;
523
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300524 info("cold: %d", *cold);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300525 return 0;
526}
527
528static int az6007_usb_probe(struct usb_interface *intf,
529 const struct usb_device_id *id)
530{
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300531 az6007_led_on_off(intf, 0);
532
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300533 return dvb_usb_device_init(intf, &az6007_properties,
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300534 THIS_MODULE, NULL, adapter_nr);
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300535}
536
537static struct usb_device_id az6007_usb_table [] = {
538 { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007) },
539 { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7) },
540 { 0 },
541};
542
543MODULE_DEVICE_TABLE(usb, az6007_usb_table);
544
545static struct dvb_usb_device_properties az6007_properties = {
546 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
547 .usb_ctrl = CYPRESS_FX2,
548 //.download_firmware = az6007_download_firmware,
549 .firmware = "dvb-usb-az6007-03.fw",
550 .no_reconnect = 1,
551
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300552 .identify_state = az6007_identify_state,
553 .num_adapters = 1,
554 .adapter = {
555 {
556 //.caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
557
558 .streaming_ctrl = az6007_streaming_ctrl,
559 .frontend_attach = az6007_frontend_attach,
560
561 /* parameter for the MPEG2-data transfer */
562 .stream = {
563 .type = USB_BULK,
564 .count = 10,
565 .endpoint = 0x02,
566 .u = {
567 .bulk = {
568 .buffersize = 4096,
569 }
570 }
571 },
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300572 .size_of_priv = sizeof(struct az6007_device_state),
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300573 }
574 },
575 //.power_ctrl = az6007_power_ctrl,
576 .read_mac_address = az6007_read_mac_addr,
577
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300578 .rc.legacy = {
579 .rc_map_table = rc_map_az6007_table,
580 .rc_map_size = ARRAY_SIZE(rc_map_az6007_table),
581 .rc_interval = 400,
582 .rc_query = az6007_rc_query,
583 },
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300584 .i2c_algo = &az6007_i2c_algo,
585
586 .num_device_descs = 2,
587 .devices = {
588 { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)",
589 .cold_ids = { &az6007_usb_table[0], NULL },
590 .warm_ids = { NULL },
591 },
592 { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)",
593 .cold_ids = { &az6007_usb_table[1], NULL },
594 .warm_ids = { NULL },
595 },
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300596 { NULL },
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300597 }
598};
Mauro Carvalho Chehab6da34702011-07-21 18:31:14 -0300599
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300600/* usb specific object needed to register this driver with the usb subsystem */
601static struct usb_driver az6007_usb_driver = {
602 .name = "dvb_usb_az6007",
603 .probe = az6007_usb_probe,
604 .disconnect = dvb_usb_device_exit,
605 //.disconnect = az6007_usb_disconnect,
606 .id_table = az6007_usb_table,
607};
608
609/* module stuff */
610static int __init az6007_usb_module_init(void)
611{
612 int result;
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300613 info("az6007 usb module init");
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300614 if ((result = usb_register(&az6007_usb_driver))) {
615 err("usb_register failed. (%d)",result);
616 return result;
617 }
618
619 return 0;
620}
621
622static void __exit az6007_usb_module_exit(void)
623{
624 /* deregister this driver from the USB subsystem */
Mauro Carvalho Chehabcaa1a702011-07-22 10:31:25 -0300625 info("az6007 usb module exit");
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300626 usb_deregister(&az6007_usb_driver);
627}
628
629module_init(az6007_usb_module_init);
630module_exit(az6007_usb_module_exit);
631
632MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
633MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
Mauro Carvalho Chehab35753582011-07-23 10:12:12 -0300634MODULE_VERSION("1.1");
Mauro Carvalho Chehab71d67632011-07-21 17:46:41 -0300635MODULE_LICENSE("GPL");