diff options
author | Aapo Tahkola <aet@rasterburn.org> | 2006-09-23 19:00:41 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-02-21 10:34:49 -0500 |
commit | 5fecd9fd4287dd163fe1f1f0b1e86e931ed589c4 (patch) | |
tree | 00046e8dcbda12d939b1c9a0cbaeb1bcb6fb76f5 /drivers/media/dvb/dvb-usb/megasky.c | |
parent | ef7b8b725bdc59fb4a3f781f3e9f546ad01da792 (diff) |
V4L/DVB (5124): Dvb-usb: Initial support for MSI Mega Sky 580 based on Uli m9206
Currently, the driver works in bulk mode supporting both USB 2.0 and
1.0 with and without hardware pid filters.
The ULi m9205 also supports isochronous transfer mode, but I have
dropped support for it because it depends on firmware and does not work
on all USB host chips. Further, I have no firmware with remote
controller support for this mode.
Signed-off-by: Aapo Tahkola <aet@rasterburn.org>
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/dvb/dvb-usb/megasky.c')
-rw-r--r-- | drivers/media/dvb/dvb-usb/megasky.c | 693 |
1 files changed, 693 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-usb/megasky.c b/drivers/media/dvb/dvb-usb/megasky.c new file mode 100644 index 000000000000..2fda56df5d60 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/megasky.c | |||
@@ -0,0 +1,693 @@ | |||
1 | /* 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 | */ | ||
11 | #include "megasky.h" | ||
12 | |||
13 | #include "mt352.h" | ||
14 | #include "mt352_priv.h" | ||
15 | |||
16 | /* debug */ | ||
17 | int dvb_usb_megasky_debug; | ||
18 | module_param_named(debug,dvb_usb_megasky_debug, int, 0644); | ||
19 | MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); | ||
20 | |||
21 | static struct dvb_usb_rc_key megasky_rc_keys [] = { | ||
22 | { 0x0, 0x12, KEY_POWER }, | ||
23 | { 0x0, 0x1e, KEY_CYCLEWINDOWS }, /* min/max */ | ||
24 | { 0x0, 0x02, KEY_CHANNELUP }, | ||
25 | { 0x0, 0x05, KEY_CHANNELDOWN }, | ||
26 | { 0x0, 0x03, KEY_VOLUMEUP }, | ||
27 | { 0x0, 0x06, KEY_VOLUMEDOWN }, | ||
28 | { 0x0, 0x04, KEY_MUTE }, | ||
29 | { 0x0, 0x07, KEY_OK }, /* TS */ | ||
30 | { 0x0, 0x08, KEY_STOP }, | ||
31 | { 0x0, 0x09, KEY_MENU }, /* swap */ | ||
32 | { 0x0, 0x0a, KEY_REWIND }, | ||
33 | { 0x0, 0x1b, KEY_PAUSE }, | ||
34 | { 0x0, 0x1f, KEY_FASTFORWARD }, | ||
35 | { 0x0, 0x0c, KEY_RECORD }, | ||
36 | { 0x0, 0x0d, KEY_CAMERA }, /* screenshot */ | ||
37 | { 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */ | ||
38 | }; | ||
39 | |||
40 | static inline int m9206_read(struct usb_device *udev, u8 request, u16 value, u16 index, void *data, int size) | ||
41 | { | ||
42 | int ret; | ||
43 | |||
44 | ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | ||
45 | request, USB_TYPE_VENDOR | USB_DIR_IN, | ||
46 | value, index, data, size, 2000); | ||
47 | if (ret < 0) | ||
48 | return ret; | ||
49 | |||
50 | if (ret != size) | ||
51 | return -EIO; | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static inline int m9206_write(struct usb_device *udev, u8 request, u16 value, u16 index) | ||
57 | { | ||
58 | int ret; | ||
59 | |||
60 | ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
61 | request, USB_TYPE_VENDOR | USB_DIR_OUT, | ||
62 | value, index, NULL, 0, 2000); | ||
63 | msleep(3); | ||
64 | |||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | ||
69 | { | ||
70 | int i, ret = 0; | ||
71 | u8 rc_state[2]; | ||
72 | |||
73 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
74 | return -EAGAIN; | ||
75 | |||
76 | if ((ret = m9206_read(d->udev, 0x22, 0x0, 0xff51, rc_state, 1)) != 0) | ||
77 | goto unlock; | ||
78 | |||
79 | if ((ret = m9206_read(d->udev, 0x22, 0x0, 0xff52, rc_state + 1, 1)) != 0) | ||
80 | goto unlock; | ||
81 | |||
82 | for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++) | ||
83 | if (megasky_rc_keys[i].data == rc_state[1]) { | ||
84 | *event = megasky_rc_keys[i].event; | ||
85 | |||
86 | switch(rc_state[0]) { | ||
87 | case 0x80: | ||
88 | *state = REMOTE_NO_KEY_PRESSED; | ||
89 | goto unlock; | ||
90 | |||
91 | case 0x93: | ||
92 | case 0x92: | ||
93 | *state = REMOTE_KEY_PRESSED; | ||
94 | goto unlock; | ||
95 | |||
96 | case 0x91: | ||
97 | *state = REMOTE_KEY_REPEAT; | ||
98 | goto unlock; | ||
99 | |||
100 | default: | ||
101 | deb_rc("Unexpected rc response %x\n", rc_state[0]); | ||
102 | *state = REMOTE_NO_KEY_PRESSED; | ||
103 | goto unlock; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | if (rc_state[1] != 0) | ||
108 | deb_rc("Unknown rc key %x\n", rc_state[1]); | ||
109 | |||
110 | *state = REMOTE_NO_KEY_PRESSED; | ||
111 | |||
112 | unlock: | ||
113 | mutex_unlock(&d->i2c_mutex); | ||
114 | |||
115 | return ret; | ||
116 | } | ||
117 | |||
118 | /* I2C */ | ||
119 | |||
120 | static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) | ||
121 | { | ||
122 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
123 | int i; | ||
124 | int ret = 0; | ||
125 | |||
126 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
127 | return -EAGAIN; | ||
128 | |||
129 | if (num > 2) | ||
130 | return -EINVAL; | ||
131 | |||
132 | for (i = 0; i < num; i++) { | ||
133 | u8 w_len; | ||
134 | |||
135 | if ((ret = m9206_write(d->udev, 0x23, msg[i].addr, 0x80)) != 0) | ||
136 | goto unlock; | ||
137 | |||
138 | if ((ret = m9206_write(d->udev, 0x23, msg[i].buf[0], 0x0)) != 0) | ||
139 | goto unlock; | ||
140 | |||
141 | if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) { | ||
142 | if (msg[i].addr == 0x1e) | ||
143 | w_len = 0x1f; | ||
144 | else | ||
145 | w_len = 0xc5; | ||
146 | |||
147 | if ((ret = m9206_write(d->udev, 0x23, w_len, 0x80)) != 0) | ||
148 | goto unlock; | ||
149 | |||
150 | if ((ret = m9206_read(d->udev, 0x23, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0) | ||
151 | goto unlock; | ||
152 | |||
153 | i++; | ||
154 | } else { | ||
155 | if (msg[i].len != 2) | ||
156 | return -EINVAL; | ||
157 | |||
158 | if ((ret = m9206_write(d->udev, 0x23, msg[i].buf[1], 0x40)) != 0) | ||
159 | goto unlock; | ||
160 | } | ||
161 | } | ||
162 | ret = i; | ||
163 | unlock: | ||
164 | mutex_unlock(&d->i2c_mutex); | ||
165 | |||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | static u32 m9206_i2c_func(struct i2c_adapter *adapter) | ||
170 | { | ||
171 | return I2C_FUNC_I2C; | ||
172 | } | ||
173 | |||
174 | static struct i2c_algorithm m9206_i2c_algo = { | ||
175 | .master_xfer = m9206_i2c_xfer, | ||
176 | .functionality = m9206_i2c_func, | ||
177 | }; | ||
178 | |||
179 | /* Callbacks for DVB USB */ | ||
180 | static int megasky_identify_state (struct usb_device *udev, | ||
181 | struct dvb_usb_properties *props, | ||
182 | struct dvb_usb_device_description **desc, | ||
183 | int *cold) | ||
184 | { | ||
185 | struct usb_host_interface *alt; | ||
186 | |||
187 | alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1); | ||
188 | *cold = (alt == NULL) ? 1 : 0; | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int megasky_mt352_demod_init(struct dvb_frontend *fe) | ||
194 | { | ||
195 | int i; | ||
196 | static u8 buf1[] = { | ||
197 | CONFIG, 0x3d, | ||
198 | CLOCK_CTL, 0x30, | ||
199 | RESET, 0x80, | ||
200 | ADC_CTL_1, 0x40, | ||
201 | AGC_TARGET, 0x1c, | ||
202 | AGC_CTL, 0x20, | ||
203 | 0x69, 0x00, | ||
204 | 0x6a, 0xff, | ||
205 | 0x6b, 0xff, | ||
206 | 0x6c, 0x40, | ||
207 | 0x6d, 0xff, | ||
208 | 0x6e, 0x00, | ||
209 | 0x6f, 0x40, | ||
210 | 0x70, 0x40, | ||
211 | 0x93, 0x1a, | ||
212 | 0xb5, 0x7a, | ||
213 | ACQ_CTL, 0x50, | ||
214 | INPUT_FREQ_1, 0x31, | ||
215 | INPUT_FREQ_0, 0x05, | ||
216 | }; | ||
217 | |||
218 | for (i = 0; i < ARRAY_SIZE(buf1); i += 2) | ||
219 | mt352_write(fe, &buf1[i], 2); | ||
220 | |||
221 | deb_rc("Demod init!\n"); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | struct mt352_state; | ||
227 | |||
228 | |||
229 | #define W 0 | ||
230 | #define R 1 | ||
231 | /* Not actual hw limits. */ | ||
232 | #define QT1010_MIN_STEP 2000000 | ||
233 | #define QT1010_MIN_FREQ 48000000 | ||
234 | |||
235 | int qt1010_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len) | ||
236 | { | ||
237 | int i; | ||
238 | int div, mod; | ||
239 | struct { | ||
240 | u8 read, reg, value; | ||
241 | } rd[46] = { { W, 0x01, 0x80 }, | ||
242 | { W, 0x02, 0x3f }, | ||
243 | { W, 0x05, 0xff }, /* c */ | ||
244 | { W, 0x06, 0x44 }, | ||
245 | { W, 0x07, 0xff }, /* c */ | ||
246 | { W, 0x08, 0x08 }, | ||
247 | { W, 0x09, 0xff }, /* c */ | ||
248 | { W, 0x0a, 0xff }, /* c */ | ||
249 | { W, 0x0b, 0xff }, /* c */ | ||
250 | { W, 0x0c, 0xe1 }, | ||
251 | { W, 0x1a, 0xff }, /* 10 c */ | ||
252 | { W, 0x1b, 0x00 }, | ||
253 | { W, 0x1c, 0x89 }, | ||
254 | { W, 0x11, 0xff }, /* c */ | ||
255 | { W, 0x12, 0x91 }, | ||
256 | { W, 0x22, 0xff }, /* c */ | ||
257 | { W, 0x1e, 0x00 }, | ||
258 | { W, 0x1e, 0xd0 }, | ||
259 | { R, 0x22, 0xff }, /* c read */ | ||
260 | { W, 0x1e, 0x00 }, | ||
261 | { R, 0x05, 0xff }, /* 20 c read */ | ||
262 | { R, 0x22, 0xff }, /* c read */ | ||
263 | { W, 0x23, 0xd0 }, | ||
264 | { W, 0x1e, 0x00 }, | ||
265 | { W, 0x1e, 0xe0 }, | ||
266 | { R, 0x23, 0xff }, /* c read */ | ||
267 | { W, 0x1e, 0x00 }, | ||
268 | { W, 0x24, 0xd0 }, | ||
269 | { W, 0x1e, 0x00 }, | ||
270 | { W, 0x1e, 0xf0 }, | ||
271 | { R, 0x24, 0xff }, /* 30 c read */ | ||
272 | { W, 0x1e, 0x00 }, | ||
273 | { W, 0x14, 0x7f }, | ||
274 | { W, 0x15, 0x7f }, | ||
275 | { W, 0x05, 0xff }, /* c */ | ||
276 | { W, 0x06, 0x00 }, | ||
277 | { W, 0x15, 0x1f }, | ||
278 | { W, 0x16, 0xff }, | ||
279 | { W, 0x18, 0xff }, | ||
280 | { W, 0x1f, 0xff }, /* c */ | ||
281 | { W, 0x20, 0xff }, /* 40 c */ | ||
282 | { W, 0x21, 0x53 }, | ||
283 | { W, 0x25, 0xbd }, | ||
284 | { W, 0x26, 0x15 }, | ||
285 | { W, 0x02, 0x00 }, | ||
286 | { W, 0x01, 0x00 }, | ||
287 | }; | ||
288 | struct i2c_msg msg; | ||
289 | struct dvb_usb_device *d = fe->dvb->priv; | ||
290 | unsigned long freq = params->frequency; | ||
291 | |||
292 | if (freq % QT1010_MIN_STEP) | ||
293 | deb_rc("frequency not supported.\n"); | ||
294 | |||
295 | (void) buf; | ||
296 | (void) buf_len; | ||
297 | |||
298 | div = (freq - QT1010_MIN_FREQ) / QT1010_MIN_STEP; | ||
299 | mod = (div + 16 - 9) % 16; | ||
300 | |||
301 | /* 0x5 */ | ||
302 | if (div >= 377) | ||
303 | rd[2].value = 0x74; | ||
304 | else if (div >= 265) | ||
305 | rd[2].value = 0x54; | ||
306 | else if (div >= 121) | ||
307 | rd[2].value = 0x34; | ||
308 | else | ||
309 | rd[2].value = 0x14; | ||
310 | |||
311 | /* 0x7 */ | ||
312 | rd[4].value = (((freq - QT1010_MIN_FREQ) / 1000000) * 9975 + 12960000) / 320000; | ||
313 | |||
314 | /* 09 */ | ||
315 | if (mod < 4) | ||
316 | rd[6].value = 0x1d; | ||
317 | else | ||
318 | rd[6].value = 0x1c; | ||
319 | |||
320 | /* 0a */ | ||
321 | if (mod < 2) | ||
322 | rd[7].value = 0x09; | ||
323 | else if (mod < 4) | ||
324 | rd[7].value = 0x08; | ||
325 | else if (mod < 6) | ||
326 | rd[7].value = 0x0f; | ||
327 | else if (mod < 8) | ||
328 | rd[7].value = 0x0e; | ||
329 | else if (mod < 10) | ||
330 | rd[7].value = 0x0d; | ||
331 | else if (mod < 12) | ||
332 | rd[7].value = 0x0c; | ||
333 | else if (mod < 14) | ||
334 | rd[7].value = 0x0b; | ||
335 | else | ||
336 | rd[7].value = 0x0a; | ||
337 | |||
338 | /* 0b */ | ||
339 | if (div & 1) | ||
340 | rd[8].value = 0x45; | ||
341 | else | ||
342 | rd[8].value = 0x44; | ||
343 | |||
344 | /* 1a */ | ||
345 | if (div & 1) | ||
346 | rd[10].value = 0x78; | ||
347 | else | ||
348 | rd[10].value = 0xf8; | ||
349 | |||
350 | /* 11 */ | ||
351 | if (div >= 265) | ||
352 | rd[13].value = 0xf9; | ||
353 | else if (div >= 121) | ||
354 | rd[13].value = 0xfd; | ||
355 | else | ||
356 | rd[13].value = 0xf9; | ||
357 | |||
358 | /* 22 */ | ||
359 | if (div < 201) | ||
360 | rd[15].value = 0xd0; | ||
361 | else if (div < 217) | ||
362 | rd[15].value = 0xd3; | ||
363 | else if (div < 233) | ||
364 | rd[15].value = 0xd6; | ||
365 | else if (div < 249) | ||
366 | rd[15].value = 0xd9; | ||
367 | else if (div < 265) | ||
368 | rd[15].value = 0xda; | ||
369 | else | ||
370 | rd[15].value = 0xd0; | ||
371 | |||
372 | /* 05 */ | ||
373 | if (div >= 377) | ||
374 | rd[34].value = 0x70; | ||
375 | else if (div >= 265) | ||
376 | rd[34].value = 0x50; | ||
377 | else if (div >= 121) | ||
378 | rd[34].value = 0x30; | ||
379 | else | ||
380 | rd[34].value = 0x10; | ||
381 | |||
382 | /* 1f */ | ||
383 | if (mod < 4) | ||
384 | rd[39].value = 0x64; | ||
385 | else if (mod < 6) | ||
386 | rd[39].value = 0x66; | ||
387 | else if (mod < 8) | ||
388 | rd[39].value = 0x67; | ||
389 | else if (mod < 12) | ||
390 | rd[39].value = 0x68; | ||
391 | else if (mod < 14) | ||
392 | rd[39].value = 0x69; | ||
393 | else | ||
394 | rd[39].value = 0x6a; | ||
395 | |||
396 | /* 20 */ | ||
397 | if (mod < 4) | ||
398 | rd[40].value = 0x10; | ||
399 | else if (mod < 6) | ||
400 | rd[40].value = 0x11; | ||
401 | else if (mod < 10) | ||
402 | rd[40].value = 0x12; | ||
403 | else if (mod < 12) | ||
404 | rd[40].value = 0x13; | ||
405 | else if (mod < 14) | ||
406 | rd[40].value = 0x14; | ||
407 | else | ||
408 | rd[40].value = 0x15; | ||
409 | |||
410 | deb_rc("Now tuning... "); | ||
411 | for (i = 0; i < sizeof(rd) / sizeof(*rd); i++) { | ||
412 | if (rd[i].read) | ||
413 | continue; | ||
414 | |||
415 | msg.flags = 0; | ||
416 | msg.len = 2; | ||
417 | msg.addr = 0xc4; | ||
418 | msg.buf = &rd[i].reg; | ||
419 | |||
420 | if (i2c_transfer(&d->i2c_adap, &msg, 1) != 1) { | ||
421 | deb_rc("tuner write failed\n"); | ||
422 | return -EIO; | ||
423 | } | ||
424 | } | ||
425 | deb_rc("done\n"); | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | #undef W | ||
430 | #undef R | ||
431 | |||
432 | static struct mt352_config megasky_mt352_config = { | ||
433 | .demod_address = 0x1e, | ||
434 | .demod_init = megasky_mt352_demod_init, | ||
435 | }; | ||
436 | |||
437 | static int megasky_frontend_attach(struct dvb_usb_device *d) | ||
438 | { | ||
439 | deb_rc("megasky_frontend_attach!\n"); | ||
440 | |||
441 | if ((d->fe = mt352_attach(&megasky_mt352_config, &d->i2c_adap)) != NULL) { | ||
442 | d->fe->ops.tuner_ops.calc_regs = qt1010_set_params; | ||
443 | return 0; | ||
444 | } | ||
445 | return -EIO; | ||
446 | } | ||
447 | |||
448 | /* DVB USB Driver stuff */ | ||
449 | static struct dvb_usb_properties megasky_properties; | ||
450 | |||
451 | static int megasky_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
452 | { | ||
453 | struct dvb_usb_device *d; | ||
454 | struct usb_host_interface *alt; | ||
455 | int ret; | ||
456 | |||
457 | if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) { | ||
458 | deb_rc("probed!\n"); | ||
459 | |||
460 | alt = usb_altnum_to_altsetting(intf, 1); | ||
461 | if (alt == NULL) { | ||
462 | deb_rc("not alt found!\n"); | ||
463 | return -ENODEV; | ||
464 | } | ||
465 | |||
466 | ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, alt->desc.bAlternateSetting); | ||
467 | if (ret < 0) | ||
468 | return ret; | ||
469 | |||
470 | deb_rc("Changed to alternate setting!\n"); | ||
471 | |||
472 | /* Remote controller init. */ | ||
473 | if ((ret = m9206_write(d->udev, 0x22, 0xa8, 0xff55)) != 0) | ||
474 | return ret; | ||
475 | |||
476 | if ((ret = m9206_write(d->udev, 0x22, 0x51, 0xff54)) != 0) | ||
477 | return ret; | ||
478 | } | ||
479 | return ret; | ||
480 | } | ||
481 | |||
482 | static struct usb_device_id megasky_table [] = { | ||
483 | { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) }, | ||
484 | { } /* Terminating entry */ | ||
485 | }; | ||
486 | MODULE_DEVICE_TABLE (usb, megasky_table); | ||
487 | |||
488 | static int set_filter(struct dvb_usb_device *d, int type, int idx, int pid) | ||
489 | { | ||
490 | int ret = 0; | ||
491 | |||
492 | if (pid >= 0x8000) | ||
493 | return -EINVAL; | ||
494 | |||
495 | pid |= 0x8000; | ||
496 | |||
497 | if ((ret = m9206_write(d->udev, 0x25, pid, (type << 8) | (idx * 4) )) != 0) | ||
498 | return ret; | ||
499 | |||
500 | if ((ret = m9206_write(d->udev, 0x25, 0, (type << 8) | (idx * 4) )) != 0) | ||
501 | return ret; | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | static int m9206_pid_filter_ctrl(struct dvb_usb_device *d, int onoff) | ||
507 | { | ||
508 | int ret = 0; | ||
509 | |||
510 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
511 | return -EAGAIN; | ||
512 | |||
513 | deb_rc("filtering %s\n", onoff ? "on" : "off"); | ||
514 | if (onoff == 0) { | ||
515 | if ((ret = set_filter(d, 0x81, 1, 0x00)) != 0) | ||
516 | goto unlock; | ||
517 | |||
518 | if ((ret = set_filter(d, 0x82, 0, 0x02f5)) != 0) | ||
519 | goto unlock; | ||
520 | } | ||
521 | unlock: | ||
522 | mutex_unlock(&d->i2c_mutex); | ||
523 | |||
524 | return ret; | ||
525 | } | ||
526 | |||
527 | static int m9206_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff) | ||
528 | { | ||
529 | int ret = 0; | ||
530 | |||
531 | if (pid == 8192) | ||
532 | return m9206_pid_filter_ctrl(d, !onoff); | ||
533 | |||
534 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
535 | return -EAGAIN; | ||
536 | |||
537 | deb_rc("filter %d, pid %x, %s\n", index, pid, onoff ? "on" : "off"); | ||
538 | if (onoff == 0) | ||
539 | pid = 0; | ||
540 | |||
541 | if ((ret = set_filter(d, 0x81, 1, 0x01)) != 0) | ||
542 | goto unlock; | ||
543 | |||
544 | if ((ret = set_filter(d, 0x81, index + 2, pid)) != 0) | ||
545 | goto unlock; | ||
546 | |||
547 | if ((ret = set_filter(d, 0x82, 0, 0x02f5)) != 0) | ||
548 | goto unlock; | ||
549 | |||
550 | unlock: | ||
551 | mutex_unlock(&d->i2c_mutex); | ||
552 | |||
553 | return ret; | ||
554 | } | ||
555 | |||
556 | static int m9206_firmware_download(struct usb_device *udev, const struct firmware *fw) | ||
557 | { | ||
558 | u16 value, index, size; | ||
559 | u8 read[4], *buff; | ||
560 | int i, pass, ret = 0; | ||
561 | |||
562 | buff = kmalloc(65536, GFP_KERNEL); | ||
563 | |||
564 | if ((ret = m9206_read(udev, 0x25, 0x0, 0x8000, read, 4)) != 0) | ||
565 | goto done; | ||
566 | deb_rc("%x %x %x %x\n", read[0], read[1], read[2], read[3]); | ||
567 | |||
568 | if ((ret = m9206_read(udev, 0x30, 0x0, 0x0, read, 1)) != 0) | ||
569 | goto done; | ||
570 | deb_rc("%x\n", read[0]); | ||
571 | |||
572 | for (pass = 0; pass < 2; pass++) { | ||
573 | for (i = 0; i + (sizeof(u16) * 3) < fw->size;) { | ||
574 | value = le16_to_cpu(*(u16 *)(fw->data + i)); | ||
575 | i += sizeof(u16); | ||
576 | |||
577 | index = le16_to_cpu(*(u16 *)(fw->data + i)); | ||
578 | i += sizeof(u16); | ||
579 | |||
580 | size = le16_to_cpu(*(u16 *)(fw->data + i)); | ||
581 | i += sizeof(u16); | ||
582 | |||
583 | if (pass == 1) { | ||
584 | /* Will stall if using fw->data ... */ | ||
585 | memcpy(buff, fw->data + i, size); | ||
586 | |||
587 | ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), | ||
588 | 0x30, USB_TYPE_VENDOR | USB_DIR_OUT, | ||
589 | value, index, buff, size, 20); | ||
590 | if (ret != size) { | ||
591 | deb_rc("error while uploading fw!\n"); | ||
592 | ret = -EIO; | ||
593 | goto done; | ||
594 | } | ||
595 | msleep(3); | ||
596 | } | ||
597 | i += size; | ||
598 | } | ||
599 | if (i != fw->size) { | ||
600 | ret = -EINVAL; | ||
601 | goto done; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | msleep(36); | ||
606 | |||
607 | /* m9206 will disconnect itself from the bus after this. */ | ||
608 | (void) m9206_write(udev, 0x22, 0x01, 0xff69); | ||
609 | deb_rc("firmware uploaded!\n"); | ||
610 | |||
611 | done: | ||
612 | kfree(buff); | ||
613 | |||
614 | return ret; | ||
615 | } | ||
616 | |||
617 | static struct dvb_usb_properties megasky_properties = { | ||
618 | .caps = DVB_USB_IS_AN_I2C_ADAPTER | DVB_USB_HAS_PID_FILTER | | ||
619 | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_NEED_PID_FILTERING, | ||
620 | .pid_filter_count = 8, | ||
621 | |||
622 | .usb_ctrl = DEVICE_SPECIFIC, | ||
623 | .firmware = "dvb-usb-megasky-02.fw", | ||
624 | .download_firmware = m9206_firmware_download, | ||
625 | |||
626 | .pid_filter = m9206_pid_filter, | ||
627 | .pid_filter_ctrl = m9206_pid_filter_ctrl, | ||
628 | .frontend_attach = megasky_frontend_attach, | ||
629 | |||
630 | .rc_interval = 200, | ||
631 | .rc_key_map = megasky_rc_keys, | ||
632 | .rc_key_map_size = ARRAY_SIZE(megasky_rc_keys), | ||
633 | .rc_query = m9206_rc_query, | ||
634 | |||
635 | .size_of_priv = 0, | ||
636 | |||
637 | .identify_state = megasky_identify_state, | ||
638 | .i2c_algo = &m9206_i2c_algo, | ||
639 | |||
640 | .generic_bulk_ctrl_endpoint = 0x01, | ||
641 | .urb = { | ||
642 | .type = DVB_USB_BULK, | ||
643 | .count = 8, | ||
644 | .endpoint = 0x81, | ||
645 | .u = { | ||
646 | .bulk = { | ||
647 | .buffersize = 512, | ||
648 | } | ||
649 | } | ||
650 | }, | ||
651 | .num_device_descs = 1, | ||
652 | .devices = { | ||
653 | { "MSI Mega Sky 580 DVB-T USB2.0", | ||
654 | { &megasky_table[0], NULL }, | ||
655 | { NULL }, | ||
656 | }, | ||
657 | { NULL }, | ||
658 | } | ||
659 | }; | ||
660 | |||
661 | static struct usb_driver megasky_driver = { | ||
662 | .name = "dvb_usb_megasky", | ||
663 | .probe = megasky_probe, | ||
664 | .disconnect = dvb_usb_device_exit, | ||
665 | .id_table = megasky_table, | ||
666 | }; | ||
667 | |||
668 | /* module stuff */ | ||
669 | static int __init megasky_module_init(void) | ||
670 | { | ||
671 | int ret; | ||
672 | |||
673 | if ((ret = usb_register(&megasky_driver))) { | ||
674 | err("usb_register failed. Error number %d", ret); | ||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | static void __exit megasky_module_exit(void) | ||
682 | { | ||
683 | /* deregister this driver from the USB subsystem */ | ||
684 | usb_deregister(&megasky_driver); | ||
685 | } | ||
686 | |||
687 | module_init (megasky_module_init); | ||
688 | module_exit (megasky_module_exit); | ||
689 | |||
690 | MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>"); | ||
691 | MODULE_DESCRIPTION("Driver for MSI Mega Sky 580 DVB-T USB2.0"); | ||
692 | MODULE_VERSION("0.1"); | ||
693 | MODULE_LICENSE("GPL"); | ||