diff options
author | Michael Krufky <mkrufky@linuxtv.org> | 2006-09-23 19:00:42 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-02-21 10:34:49 -0500 |
commit | 2aef7d0fa0e35a3a26733bef147196c2926bd228 (patch) | |
tree | 251de9dac95f1d9cc930aa6ef8d753575fe84f68 /drivers/media/dvb/dvb-usb/m920x.c | |
parent | 5fecd9fd4287dd163fe1f1f0b1e86e931ed589c4 (diff) |
V4L/DVB (5125): Dvb-usb: rename megasky.[ch] to m920x.[ch]
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/m920x.c')
-rw-r--r-- | drivers/media/dvb/dvb-usb/m920x.c | 693 |
1 files changed, 693 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c new file mode 100644 index 000000000000..c50f484c843b --- /dev/null +++ b/drivers/media/dvb/dvb-usb/m920x.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 "m920x.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"); | ||