blob: 292805aad69a9aff68e691f21b885cb900f56333 [file] [log] [blame]
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -03001/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver
2 *
3 * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org)
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation, version 2.
8 *
9 * see Documentation/dvb/README.dvb-usb for more information
10 */
Michael Krufkybaa2ed02006-09-23 20:01:29 -030011
Michael Krufky2aef7d02006-09-23 20:00:42 -030012#include "m920x.h"
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -030013
14#include "mt352.h"
15#include "mt352_priv.h"
Michael Krufky017cf012006-09-23 20:40:20 -030016#include "qt1010.h"
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -030017
18/* debug */
Michael Krufkybaa2ed02006-09-23 20:01:29 -030019int dvb_usb_m920x_debug;
20module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -030021MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
22
23static struct dvb_usb_rc_key megasky_rc_keys [] = {
24 { 0x0, 0x12, KEY_POWER },
25 { 0x0, 0x1e, KEY_CYCLEWINDOWS }, /* min/max */
26 { 0x0, 0x02, KEY_CHANNELUP },
27 { 0x0, 0x05, KEY_CHANNELDOWN },
28 { 0x0, 0x03, KEY_VOLUMEUP },
29 { 0x0, 0x06, KEY_VOLUMEDOWN },
30 { 0x0, 0x04, KEY_MUTE },
31 { 0x0, 0x07, KEY_OK }, /* TS */
32 { 0x0, 0x08, KEY_STOP },
33 { 0x0, 0x09, KEY_MENU }, /* swap */
34 { 0x0, 0x0a, KEY_REWIND },
35 { 0x0, 0x1b, KEY_PAUSE },
36 { 0x0, 0x1f, KEY_FASTFORWARD },
37 { 0x0, 0x0c, KEY_RECORD },
38 { 0x0, 0x0d, KEY_CAMERA }, /* screenshot */
39 { 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */
40};
41
42static inline int m9206_read(struct usb_device *udev, u8 request, u16 value, u16 index, void *data, int size)
43{
44 int ret;
45
46 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
47 request, USB_TYPE_VENDOR | USB_DIR_IN,
48 value, index, data, size, 2000);
49 if (ret < 0)
50 return ret;
51
52 if (ret != size)
53 return -EIO;
54
55 return 0;
56}
57
58static inline int m9206_write(struct usb_device *udev, u8 request, u16 value, u16 index)
59{
60 int ret;
61
62 ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
63 request, USB_TYPE_VENDOR | USB_DIR_OUT,
64 value, index, NULL, 0, 2000);
65 msleep(3);
66
67 return ret;
68}
69
70static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
71{
72 int i, ret = 0;
73 u8 rc_state[2];
74
75 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
76 return -EAGAIN;
77
78 if ((ret = m9206_read(d->udev, 0x22, 0x0, 0xff51, rc_state, 1)) != 0)
79 goto unlock;
80
81 if ((ret = m9206_read(d->udev, 0x22, 0x0, 0xff52, rc_state + 1, 1)) != 0)
82 goto unlock;
83
84 for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++)
85 if (megasky_rc_keys[i].data == rc_state[1]) {
86 *event = megasky_rc_keys[i].event;
87
88 switch(rc_state[0]) {
89 case 0x80:
90 *state = REMOTE_NO_KEY_PRESSED;
91 goto unlock;
92
93 case 0x93:
94 case 0x92:
95 *state = REMOTE_KEY_PRESSED;
96 goto unlock;
97
98 case 0x91:
99 *state = REMOTE_KEY_REPEAT;
100 goto unlock;
101
102 default:
103 deb_rc("Unexpected rc response %x\n", rc_state[0]);
104 *state = REMOTE_NO_KEY_PRESSED;
105 goto unlock;
106 }
107 }
108
109 if (rc_state[1] != 0)
110 deb_rc("Unknown rc key %x\n", rc_state[1]);
111
112 *state = REMOTE_NO_KEY_PRESSED;
113
114 unlock:
115 mutex_unlock(&d->i2c_mutex);
116
117 return ret;
118}
119
120/* I2C */
121
122static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
123{
124 struct dvb_usb_device *d = i2c_get_adapdata(adap);
125 int i;
126 int ret = 0;
127
128 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
129 return -EAGAIN;
130
131 if (num > 2)
132 return -EINVAL;
133
134 for (i = 0; i < num; i++) {
135 u8 w_len;
136
137 if ((ret = m9206_write(d->udev, 0x23, msg[i].addr, 0x80)) != 0)
138 goto unlock;
139
140 if ((ret = m9206_write(d->udev, 0x23, msg[i].buf[0], 0x0)) != 0)
141 goto unlock;
142
143 if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) {
144 if (msg[i].addr == 0x1e)
145 w_len = 0x1f;
146 else
147 w_len = 0xc5;
148
149 if ((ret = m9206_write(d->udev, 0x23, w_len, 0x80)) != 0)
150 goto unlock;
151
152 if ((ret = m9206_read(d->udev, 0x23, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0)
153 goto unlock;
154
155 i++;
156 } else {
157 if (msg[i].len != 2)
158 return -EINVAL;
159
160 if ((ret = m9206_write(d->udev, 0x23, msg[i].buf[1], 0x40)) != 0)
161 goto unlock;
162 }
163 }
164 ret = i;
165 unlock:
166 mutex_unlock(&d->i2c_mutex);
167
168 return ret;
169}
170
171static u32 m9206_i2c_func(struct i2c_adapter *adapter)
172{
173 return I2C_FUNC_I2C;
174}
175
176static struct i2c_algorithm m9206_i2c_algo = {
177 .master_xfer = m9206_i2c_xfer,
178 .functionality = m9206_i2c_func,
179};
180
181/* Callbacks for DVB USB */
Michael Krufky2a2bfa72006-09-23 20:13:12 -0300182static int megasky_identify_state(struct usb_device *udev,
183 struct dvb_usb_device_properties *props,
184 struct dvb_usb_device_description **desc,
185 int *cold)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300186{
187 struct usb_host_interface *alt;
188
189 alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1);
190 *cold = (alt == NULL) ? 1 : 0;
191
192 return 0;
193}
194
195static int megasky_mt352_demod_init(struct dvb_frontend *fe)
196{
197 int i;
198 static u8 buf1[] = {
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300199 CONFIG, 0x3d,
200 CLOCK_CTL, 0x30,
201 RESET, 0x80,
202 ADC_CTL_1, 0x40,
203 AGC_TARGET, 0x1c,
204 AGC_CTL, 0x20,
205 0x69, 0x00,
206 0x6a, 0xff,
207 0x6b, 0xff,
208 0x6c, 0x40,
209 0x6d, 0xff,
210 0x6e, 0x00,
211 0x6f, 0x40,
212 0x70, 0x40,
213 0x93, 0x1a,
214 0xb5, 0x7a,
215 ACQ_CTL, 0x50,
216 INPUT_FREQ_1, 0x31,
217 INPUT_FREQ_0, 0x05,
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300218 };
219
220 for (i = 0; i < ARRAY_SIZE(buf1); i += 2)
221 mt352_write(fe, &buf1[i], 2);
222
223 deb_rc("Demod init!\n");
224
225 return 0;
226}
227
228struct mt352_state;
229
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300230static struct mt352_config megasky_mt352_config = {
231 .demod_address = 0x1e,
232 .demod_init = megasky_mt352_demod_init,
233};
234
Michael Krufky01cb34d2006-09-23 20:01:29 -0300235static int megasky_frontend_attach(struct dvb_usb_adapter *adap)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300236{
237 deb_rc("megasky_frontend_attach!\n");
238
Michael Krufky01cb34d2006-09-23 20:01:29 -0300239 if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) != NULL) {
240 adap->fe->ops.tuner_ops.calc_regs = qt1010_set_params;
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300241 return 0;
242 }
243 return -EIO;
244}
245
246/* DVB USB Driver stuff */
Michael Krufky01cb34d2006-09-23 20:01:29 -0300247static struct dvb_usb_device_properties megasky_properties;
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300248
Michael Krufky2a2bfa72006-09-23 20:13:12 -0300249static int m920x_probe(struct usb_interface *intf, const struct usb_device_id *id)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300250{
251 struct dvb_usb_device *d;
252 struct usb_host_interface *alt;
253 int ret;
254
255 if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) {
256 deb_rc("probed!\n");
257
258 alt = usb_altnum_to_altsetting(intf, 1);
259 if (alt == NULL) {
260 deb_rc("not alt found!\n");
261 return -ENODEV;
262 }
263
264 ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, alt->desc.bAlternateSetting);
265 if (ret < 0)
266 return ret;
267
268 deb_rc("Changed to alternate setting!\n");
269
270 /* Remote controller init. */
271 if ((ret = m9206_write(d->udev, 0x22, 0xa8, 0xff55)) != 0)
272 return ret;
273
274 if ((ret = m9206_write(d->udev, 0x22, 0x51, 0xff54)) != 0)
275 return ret;
276 }
277 return ret;
278}
279
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300280static struct usb_device_id m920x_table [] = {
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300281 { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
282 { } /* Terminating entry */
283};
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300284MODULE_DEVICE_TABLE (usb, m920x_table);
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300285
Michael Krufky01cb34d2006-09-23 20:01:29 -0300286static int set_filter(struct dvb_usb_adapter *adap, int type, int idx, int pid)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300287{
288 int ret = 0;
289
290 if (pid >= 0x8000)
291 return -EINVAL;
292
293 pid |= 0x8000;
294
Michael Krufky01cb34d2006-09-23 20:01:29 -0300295 if ((ret = m9206_write(adap->dev->udev, 0x25, pid, (type << 8) | (idx * 4) )) != 0)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300296 return ret;
297
Michael Krufky01cb34d2006-09-23 20:01:29 -0300298 if ((ret = m9206_write(adap->dev->udev, 0x25, 0, (type << 8) | (idx * 4) )) != 0)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300299 return ret;
300
301 return ret;
302}
303
Michael Krufky01cb34d2006-09-23 20:01:29 -0300304static int m9206_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300305{
306 int ret = 0;
307
Michael Krufky01cb34d2006-09-23 20:01:29 -0300308 if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300309 return -EAGAIN;
310
311 deb_rc("filtering %s\n", onoff ? "on" : "off");
312 if (onoff == 0) {
Michael Krufky01cb34d2006-09-23 20:01:29 -0300313 if ((ret = set_filter(adap, 0x81, 1, 0x00)) != 0)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300314 goto unlock;
315
Michael Krufky01cb34d2006-09-23 20:01:29 -0300316 if ((ret = set_filter(adap, 0x82, 0, 0x02f5)) != 0)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300317 goto unlock;
318 }
319 unlock:
Michael Krufky01cb34d2006-09-23 20:01:29 -0300320 mutex_unlock(&adap->dev->i2c_mutex);
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300321
322 return ret;
323}
324
Michael Krufky01cb34d2006-09-23 20:01:29 -0300325static int m9206_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300326{
327 int ret = 0;
328
329 if (pid == 8192)
Michael Krufky01cb34d2006-09-23 20:01:29 -0300330 return m9206_pid_filter_ctrl(adap, !onoff);
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300331
Michael Krufky01cb34d2006-09-23 20:01:29 -0300332 if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300333 return -EAGAIN;
334
335 deb_rc("filter %d, pid %x, %s\n", index, pid, onoff ? "on" : "off");
336 if (onoff == 0)
337 pid = 0;
338
Michael Krufky01cb34d2006-09-23 20:01:29 -0300339 if ((ret = set_filter(adap, 0x81, 1, 0x01)) != 0)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300340 goto unlock;
341
Michael Krufky01cb34d2006-09-23 20:01:29 -0300342 if ((ret = set_filter(adap, 0x81, index + 2, pid)) != 0)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300343 goto unlock;
344
Michael Krufky01cb34d2006-09-23 20:01:29 -0300345 if ((ret = set_filter(adap, 0x82, 0, 0x02f5)) != 0)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300346 goto unlock;
347
348 unlock:
Michael Krufky01cb34d2006-09-23 20:01:29 -0300349 mutex_unlock(&adap->dev->i2c_mutex);
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300350
351 return ret;
352}
353
354static int m9206_firmware_download(struct usb_device *udev, const struct firmware *fw)
355{
356 u16 value, index, size;
357 u8 read[4], *buff;
358 int i, pass, ret = 0;
359
360 buff = kmalloc(65536, GFP_KERNEL);
361
362 if ((ret = m9206_read(udev, 0x25, 0x0, 0x8000, read, 4)) != 0)
363 goto done;
364 deb_rc("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
365
366 if ((ret = m9206_read(udev, 0x30, 0x0, 0x0, read, 1)) != 0)
367 goto done;
368 deb_rc("%x\n", read[0]);
369
370 for (pass = 0; pass < 2; pass++) {
371 for (i = 0; i + (sizeof(u16) * 3) < fw->size;) {
372 value = le16_to_cpu(*(u16 *)(fw->data + i));
373 i += sizeof(u16);
374
375 index = le16_to_cpu(*(u16 *)(fw->data + i));
376 i += sizeof(u16);
377
378 size = le16_to_cpu(*(u16 *)(fw->data + i));
379 i += sizeof(u16);
380
381 if (pass == 1) {
382 /* Will stall if using fw->data ... */
383 memcpy(buff, fw->data + i, size);
384
385 ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
386 0x30, USB_TYPE_VENDOR | USB_DIR_OUT,
387 value, index, buff, size, 20);
388 if (ret != size) {
389 deb_rc("error while uploading fw!\n");
390 ret = -EIO;
391 goto done;
392 }
393 msleep(3);
394 }
395 i += size;
396 }
397 if (i != fw->size) {
398 ret = -EINVAL;
399 goto done;
400 }
401 }
402
403 msleep(36);
404
405 /* m9206 will disconnect itself from the bus after this. */
406 (void) m9206_write(udev, 0x22, 0x01, 0xff69);
407 deb_rc("firmware uploaded!\n");
408
409 done:
410 kfree(buff);
411
412 return ret;
413}
414
Michael Krufky01cb34d2006-09-23 20:01:29 -0300415static struct dvb_usb_device_properties megasky_properties = {
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300416 .usb_ctrl = DEVICE_SPECIFIC,
417 .firmware = "dvb-usb-megasky-02.fw",
418 .download_firmware = m9206_firmware_download,
419
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300420 .rc_interval = 200,
421 .rc_key_map = megasky_rc_keys,
422 .rc_key_map_size = ARRAY_SIZE(megasky_rc_keys),
423 .rc_query = m9206_rc_query,
424
425 .size_of_priv = 0,
426
427 .identify_state = megasky_identify_state,
Michael Krufky01cb34d2006-09-23 20:01:29 -0300428 .num_adapters = 1,
429 .adapter = {{
430 .caps = DVB_USB_IS_AN_I2C_ADAPTER | DVB_USB_ADAP_HAS_PID_FILTER |
431 DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF |
432 DVB_USB_ADAP_NEED_PID_FILTERING,
433 .pid_filter_count = 8,
434 .pid_filter = m9206_pid_filter,
435 .pid_filter_ctrl = m9206_pid_filter_ctrl,
436
437 .frontend_attach = megasky_frontend_attach,
438
439 .stream = {
440 .type = USB_BULK,
441 .count = 8,
442 .endpoint = 0x81,
443 .u = {
444 .bulk = {
445 .buffersize = 512,
446 }
447 }
448 },
449 }},
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300450 .i2c_algo = &m9206_i2c_algo,
451
452 .generic_bulk_ctrl_endpoint = 0x01,
Michael Krufky01cb34d2006-09-23 20:01:29 -0300453
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300454 .num_device_descs = 1,
455 .devices = {
456 { "MSI Mega Sky 580 DVB-T USB2.0",
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300457 { &m920x_table[0], NULL },
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300458 { NULL },
459 },
460 { NULL },
461 }
462};
463
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300464static struct usb_driver m920x_driver = {
465 .name = "dvb_usb_m920x",
Michael Krufky2a2bfa72006-09-23 20:13:12 -0300466 .probe = m920x_probe,
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300467 .disconnect = dvb_usb_device_exit,
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300468 .id_table = m920x_table,
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300469};
470
471/* module stuff */
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300472static int __init m920x_module_init(void)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300473{
474 int ret;
475
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300476 if ((ret = usb_register(&m920x_driver))) {
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300477 err("usb_register failed. Error number %d", ret);
478 return ret;
479 }
480
481 return 0;
482}
483
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300484static void __exit m920x_module_exit(void)
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300485{
486 /* deregister this driver from the USB subsystem */
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300487 usb_deregister(&m920x_driver);
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300488}
489
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300490module_init (m920x_module_init);
491module_exit (m920x_module_exit);
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300492
493MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
Michael Krufkybaa2ed02006-09-23 20:01:29 -0300494MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / Uli m920x");
Aapo Tahkola5fecd9f2006-09-23 20:00:41 -0300495MODULE_VERSION("0.1");
496MODULE_LICENSE("GPL");