blob: 2f408d2e1ef349be29c3ae6ba97ee09df9b49bc5 [file] [log] [blame]
Antti Palosaaria51e34d2008-05-17 23:05:48 -03001/*
2 * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
3 *
4 * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * TODO:
21 * - add smart card reader support for Conditional Access (CA)
22 *
23 * Card reader in Anysee is nothing more than ISO 7816 card reader.
24 * There is no hardware CAM in any Anysee device sold.
25 * In my understanding it should be implemented by making own module
Antti Palosaari9fdd9ca2008-06-11 11:43:19 -030026 * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
27 * module registers serial interface that can be used to communicate
Antti Palosaaria51e34d2008-05-17 23:05:48 -030028 * with any ISO 7816 smart card.
29 *
30 * Any help according to implement serial smart card reader support
31 * is highly welcome!
32 */
33
34#include "anysee.h"
35#include "tda1002x.h"
36#include "mt352.h"
37#include "mt352_priv.h"
38#include "zl10353.h"
39
40/* debug */
41static int dvb_usb_anysee_debug;
42module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
43MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
44DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
45
Adrian Bunk53faa1b2008-07-21 16:33:42 -030046static struct mutex anysee_usb_mutex;
Antti Palosaaria51e34d2008-05-17 23:05:48 -030047
48static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
49 u8 *rbuf, u8 rlen)
50{
51 struct anysee_state *state = d->priv;
52 int act_len, ret;
53 u8 buf[64];
54
55 if (slen > sizeof(buf))
56 slen = sizeof(buf);
57 memcpy(&buf[0], sbuf, slen);
58 buf[60] = state->seq++;
59
60 if (mutex_lock_interruptible(&anysee_usb_mutex) < 0)
61 return -EAGAIN;
62
63 /* We need receive one message more after dvb_usb_generic_rw due
64 to weird transaction flow, which is 1 x send + 2 x receive. */
65 ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0);
66
67 if (!ret) {
68 /* receive 2nd answer */
69 ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
70 d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf),
71 &act_len, 2000);
72 if (ret)
73 err("%s: recv bulk message failed: %d", __func__, ret);
74 else {
75 deb_xfer("<<< ");
76 debug_dump(buf, act_len, deb_xfer);
77 }
78 }
79
80 /* read request, copy returned data to return buf */
81 if (!ret && rbuf && rlen)
82 memcpy(rbuf, buf, rlen);
83
84 mutex_unlock(&anysee_usb_mutex);
85
86 return ret;
87}
88
89static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
90{
91 u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01};
92 int ret;
93 ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1);
94 deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val);
95 return ret;
96}
97
98static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
99{
100 u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val};
101 deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val);
102 return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
103}
104
105static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
106{
107 u8 buf[] = {CMD_GET_HW_INFO};
108 return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3);
109}
110
111static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
112{
113 u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00};
114 deb_info("%s: onoff:%02x\n", __func__, onoff);
115 return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0);
116}
117
118static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval)
119{
120 u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval};
121 deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval);
122 return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
123}
124
125static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
126{
127 u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff};
128 deb_info("%s: onoff:%02x\n", __func__, onoff);
129 return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
130}
131
132static int anysee_init(struct dvb_usb_device *d)
133{
134 int ret;
135 /* LED light */
136 ret = anysee_led_ctrl(d, 0x01, 0x03);
137 if (ret)
138 return ret;
139
140 /* enable IR */
141 ret = anysee_ir_ctrl(d, 1);
142 if (ret)
143 return ret;
144
145 return 0;
146}
147
148/* I2C */
149static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
150 int num)
151{
152 struct dvb_usb_device *d = i2c_get_adapdata(adap);
153 int ret, inc, i = 0;
154
155 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
156 return -EAGAIN;
157
158 while (i < num) {
159 if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
160 u8 buf[6];
161 buf[0] = CMD_I2C_READ;
162 buf[1] = msg[i].addr + 1;
163 buf[2] = msg[i].buf[0];
164 buf[3] = 0x00;
165 buf[4] = 0x00;
166 buf[5] = 0x01;
167 ret = anysee_ctrl_msg(d, buf, sizeof(buf), msg[i+1].buf,
168 msg[i+1].len);
169 inc = 2;
170 } else {
171 u8 buf[4+msg[i].len];
172 buf[0] = CMD_I2C_WRITE;
173 buf[1] = msg[i].addr;
174 buf[2] = msg[i].len;
175 buf[3] = 0x01;
176 memcpy(&buf[4], msg[i].buf, msg[i].len);
177 ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
178 inc = 1;
179 }
180 if (ret)
181 return ret;
182
183 i += inc;
184 }
185
186 mutex_unlock(&d->i2c_mutex);
187
188 return i;
189}
190
191static u32 anysee_i2c_func(struct i2c_adapter *adapter)
192{
193 return I2C_FUNC_I2C;
194}
195
196static struct i2c_algorithm anysee_i2c_algo = {
197 .master_xfer = anysee_master_xfer,
198 .functionality = anysee_i2c_func,
199};
200
201static int anysee_mt352_demod_init(struct dvb_frontend *fe)
202{
203 static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 };
204 static u8 reset [] = { RESET, 0x80 };
205 static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
206 static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
207 static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
208 static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
209
210 mt352_write(fe, clock_config, sizeof(clock_config));
211 udelay(200);
212 mt352_write(fe, reset, sizeof(reset));
213 mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
214
215 mt352_write(fe, agc_cfg, sizeof(agc_cfg));
216 mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
217 mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
218
219 return 0;
220}
221
222/* Callbacks for DVB USB */
223static struct tda10023_config anysee_tda10023_config = {
224 .demod_address = 0x1a,
225 .invert = 0,
226 .xtal = 16000000,
227 .pll_m = 11,
228 .pll_p = 3,
229 .pll_n = 1,
Antti Palosaari5ae2fca2008-06-09 22:58:22 -0300230 .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
231 .deltaf = 0xfeeb,
Antti Palosaaria51e34d2008-05-17 23:05:48 -0300232};
233
234static struct mt352_config anysee_mt352_config = {
235 .demod_address = 0x1e,
236 .demod_init = anysee_mt352_demod_init,
237};
238
239static struct zl10353_config anysee_zl10353_config = {
240 .demod_address = 0x1e,
241 .parallel_ts = 1,
242};
243
244static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
245{
246 int ret;
247 struct anysee_state *state = adap->dev->priv;
248 u8 hw_info[3];
249 u8 io_d; /* IO port D */
250
251 /* check which hardware we have
252 We must do this call two times to get reliable values (hw bug). */
253 ret = anysee_get_hw_info(adap->dev, hw_info);
254 if (ret)
255 return ret;
256 ret = anysee_get_hw_info(adap->dev, hw_info);
257 if (ret)
258 return ret;
259
260 /* Meaning of these info bytes are guessed. */
261 info("firmware version:%d.%d.%d hardware id:%d",
262 0, hw_info[1], hw_info[2], hw_info[0]);
263
264 ret = anysee_read_reg(adap->dev, 0xb0, &io_d); /* IO port D */
265 if (ret)
266 return ret;
267 deb_info("%s: IO port D:%02x\n", __func__, io_d);
268
269 /* Select demod using trial and error method. */
270
271 /* Try to attach demodulator in following order:
272 model demod hw firmware
273 1. E30 MT352 02 0.2.1
274 2. E30 ZL10353 02 0.2.1
275 3. E30 Plus ZL10353 06 0.1.0
Antti Palosaari5ae2fca2008-06-09 22:58:22 -0300276 4. E30C Plus TDA10023 0a 0.1.0 rev 0.2
277 4. E30C Plus TDA10023 0f 0.1.2 rev 0.4
Antti Palosaaria51e34d2008-05-17 23:05:48 -0300278 */
279
280 /* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
281 adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
282 &adap->dev->i2c_adap);
283 if (adap->fe != NULL) {
284 state->tuner = DVB_PLL_THOMSON_DTT7579;
285 return 0;
286 }
287
288 /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
289 adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
290 &adap->dev->i2c_adap);
291 if (adap->fe != NULL) {
292 state->tuner = DVB_PLL_THOMSON_DTT7579;
293 return 0;
294 }
295
296 /* connect demod on IO port D for TDA10023 & ZL10353 */
297 ret = anysee_write_reg(adap->dev, 0xb0, 0x25);
298 if (ret)
299 return ret;
300
301 /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
302 adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
303 &adap->dev->i2c_adap);
304 if (adap->fe != NULL) {
305 state->tuner = DVB_PLL_THOMSON_DTT7579;
306 return 0;
307 }
308
Antti Palosaari5ae2fca2008-06-09 22:58:22 -0300309 /* IO port E - E30C rev 0.4 board requires this */
310 ret = anysee_write_reg(adap->dev, 0xb1, 0xa7);
311 if (ret)
312 return ret;
Antti Palosaaria51e34d2008-05-17 23:05:48 -0300313
314 /* Philips TDA10023 DVB-C demod */
315 adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
316 &adap->dev->i2c_adap, 0x48);
317 if (adap->fe != NULL) {
318 state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
319 return 0;
320 }
321
322 /* return IO port D to init value for safe */
323 ret = anysee_write_reg(adap->dev, 0xb0, io_d);
324 if (ret)
325 return ret;
326
327 err("Unkown Anysee version: %02x %02x %02x. "\
328 "Please report the <linux-dvb@linuxtv.org>.",
329 hw_info[0], hw_info[1], hw_info[2]);
330
331 return -ENODEV;
332}
333
334static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
335{
336 struct anysee_state *state = adap->dev->priv;
337 deb_info("%s: \n", __func__);
338
339 switch (state->tuner) {
340 case DVB_PLL_THOMSON_DTT7579:
341 /* Thomson dtt7579 (not sure) PLL inside of:
342 Samsung DNOS404ZH102A NIM
343 Samsung DNOS404ZH103A NIM */
344 dvb_attach(dvb_pll_attach, adap->fe, 0x61,
345 NULL, DVB_PLL_THOMSON_DTT7579);
346 break;
347 case DVB_PLL_SAMSUNG_DTOS403IH102A:
348 /* Unknown PLL inside of Samsung DTOS403IH102A tuner module */
349 dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
350 &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
351 break;
352 }
353
354 return 0;
355}
356
357static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
358{
359 u8 buf[] = {CMD_GET_IR_CODE};
360 struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
361 u8 ircode[2];
362 int i, ret;
363
364 ret = anysee_ctrl_msg(d, buf, sizeof(buf), &ircode[0], 2);
365 if (ret)
366 return ret;
367
368 *event = 0;
369 *state = REMOTE_NO_KEY_PRESSED;
370
371 for (i = 0; i < d->props.rc_key_map_size; i++) {
372 if (keymap[i].custom == ircode[0] &&
373 keymap[i].data == ircode[1]) {
374 *event = keymap[i].event;
375 *state = REMOTE_KEY_PRESSED;
376 return 0;
377 }
378 }
379 return 0;
380}
381
382static struct dvb_usb_rc_key anysee_rc_keys[] = {
383 { 0x01, 0x00, KEY_0 },
384 { 0x01, 0x01, KEY_1 },
385 { 0x01, 0x02, KEY_2 },
386 { 0x01, 0x03, KEY_3 },
387 { 0x01, 0x04, KEY_4 },
388 { 0x01, 0x05, KEY_5 },
389 { 0x01, 0x06, KEY_6 },
390 { 0x01, 0x07, KEY_7 },
391 { 0x01, 0x08, KEY_8 },
392 { 0x01, 0x09, KEY_9 },
393 { 0x01, 0x0a, KEY_POWER },
394 { 0x01, 0x0b, KEY_DOCUMENTS }, /* * */
395 { 0x01, 0x19, KEY_FAVORITES },
396 { 0x01, 0x20, KEY_SLEEP },
397 { 0x01, 0x21, KEY_MODE }, /* 4:3 / 16:9 select */
398 { 0x01, 0x22, KEY_ZOOM },
399 { 0x01, 0x47, KEY_TEXT },
400 { 0x01, 0x16, KEY_TV }, /* TV / radio select */
401 { 0x01, 0x1e, KEY_LANGUAGE }, /* Second Audio Program */
402 { 0x01, 0x1a, KEY_SUBTITLE },
403 { 0x01, 0x1b, KEY_CAMERA }, /* screenshot */
404 { 0x01, 0x42, KEY_MUTE },
405 { 0x01, 0x0e, KEY_MENU },
406 { 0x01, 0x0f, KEY_EPG },
407 { 0x01, 0x17, KEY_INFO },
408 { 0x01, 0x10, KEY_EXIT },
409 { 0x01, 0x13, KEY_VOLUMEUP },
410 { 0x01, 0x12, KEY_VOLUMEDOWN },
411 { 0x01, 0x11, KEY_CHANNELUP },
412 { 0x01, 0x14, KEY_CHANNELDOWN },
413 { 0x01, 0x15, KEY_OK },
414 { 0x01, 0x1d, KEY_RED },
415 { 0x01, 0x1f, KEY_GREEN },
416 { 0x01, 0x1c, KEY_YELLOW },
417 { 0x01, 0x44, KEY_BLUE },
418 { 0x01, 0x0c, KEY_SHUFFLE }, /* snapshot */
419 { 0x01, 0x48, KEY_STOP },
420 { 0x01, 0x50, KEY_PLAY },
421 { 0x01, 0x51, KEY_PAUSE },
422 { 0x01, 0x49, KEY_RECORD },
423 { 0x01, 0x18, KEY_PREVIOUS }, /* |<< */
424 { 0x01, 0x0d, KEY_NEXT }, /* >>| */
425 { 0x01, 0x24, KEY_PROG1 }, /* F1 */
426 { 0x01, 0x25, KEY_PROG2 }, /* F2 */
427};
428
429/* DVB USB Driver stuff */
430static struct dvb_usb_device_properties anysee_properties;
431
432static int anysee_probe(struct usb_interface *intf,
433 const struct usb_device_id *id)
434{
435 struct dvb_usb_device *d;
436 struct usb_host_interface *alt;
437 int ret;
438
439 mutex_init(&anysee_usb_mutex);
440
441 /* There is one interface with two alternate settings.
442 Alternate setting 0 is for bulk transfer.
443 Alternate setting 1 is for isochronous transfer.
444 We use bulk transfer (alternate setting 0). */
445 if (intf->num_altsetting < 1)
446 return -ENODEV;
447
448 ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
449 adapter_nr);
450 if (ret)
451 return ret;
452
453 alt = usb_altnum_to_altsetting(intf, 0);
454 if (alt == NULL) {
455 deb_info("%s: no alt found!\n", __func__);
456 return -ENODEV;
457 }
458
459 ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
460 alt->desc.bAlternateSetting);
461 if (ret)
462 return ret;
463
464 if (d)
465 ret = anysee_init(d);
466
467 return ret;
468}
469
470static struct usb_device_id anysee_table [] = {
471 { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) },
472 { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) },
473 { } /* Terminating entry */
474};
475MODULE_DEVICE_TABLE(usb, anysee_table);
476
477static struct dvb_usb_device_properties anysee_properties = {
478 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
479
480 .usb_ctrl = DEVICE_SPECIFIC,
481
482 .size_of_priv = sizeof(struct anysee_state),
483
484 .num_adapters = 1,
485 .adapter = {
486 {
487 .streaming_ctrl = anysee_streaming_ctrl,
488 .frontend_attach = anysee_frontend_attach,
489 .tuner_attach = anysee_tuner_attach,
490 .stream = {
491 .type = USB_BULK,
492 .count = 8,
493 .endpoint = 0x82,
494 .u = {
495 .bulk = {
496 .buffersize = 512,
497 }
498 }
499 },
500 }
501 },
502
503 .rc_key_map = anysee_rc_keys,
504 .rc_key_map_size = ARRAY_SIZE(anysee_rc_keys),
505 .rc_query = anysee_rc_query,
506 .rc_interval = 200, /* windows driver uses 500ms */
507
508 .i2c_algo = &anysee_i2c_algo,
509
510 .generic_bulk_ctrl_endpoint = 1,
511
512 .num_device_descs = 1,
513 .devices = {
514 {
515 .name = "Anysee DVB USB2.0",
516 .cold_ids = {NULL},
517 .warm_ids = {&anysee_table[0],
518 &anysee_table[1], NULL},
519 },
520 }
521};
522
523static struct usb_driver anysee_driver = {
524 .name = "dvb_usb_anysee",
525 .probe = anysee_probe,
526 .disconnect = dvb_usb_device_exit,
527 .id_table = anysee_table,
528};
529
530/* module stuff */
531static int __init anysee_module_init(void)
532{
533 int ret;
534
535 ret = usb_register(&anysee_driver);
536 if (ret)
537 err("%s: usb_register failed. Error number %d", __func__, ret);
538
539 return ret;
540}
541
542static void __exit anysee_module_exit(void)
543{
544 /* deregister this driver from the USB subsystem */
545 usb_deregister(&anysee_driver);
546}
547
548module_init(anysee_module_init);
549module_exit(anysee_module_exit);
550
551MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
552MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0");
553MODULE_LICENSE("GPL");