diff options
Diffstat (limited to 'drivers/media/dvb/dvb-usb/cxusb.c')
-rw-r--r-- | drivers/media/dvb/dvb-usb/cxusb.c | 294 |
1 files changed, 284 insertions, 10 deletions
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index d05fab01cccd..358ed153865f 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c | |||
@@ -11,10 +11,11 @@ | |||
11 | * design, so it can be reused for the "analogue-only" device (if it will | 11 | * design, so it can be reused for the "analogue-only" device (if it will |
12 | * appear at all). | 12 | * appear at all). |
13 | * | 13 | * |
14 | * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue | 14 | * TODO: Use the cx25840-driver for the analogue part |
15 | * part | ||
16 | * | 15 | * |
17 | * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) | 16 | * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) |
17 | * Copyright (C) 2005 Michael Krufky (mkrufky@m1k.net) | ||
18 | * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au) | ||
18 | * | 19 | * |
19 | * This program is free software; you can redistribute it and/or modify it | 20 | * This program is free software; you can redistribute it and/or modify it |
20 | * under the terms of the GNU General Public License as published by the Free | 21 | * under the terms of the GNU General Public License as published by the Free |
@@ -25,6 +26,9 @@ | |||
25 | #include "cxusb.h" | 26 | #include "cxusb.h" |
26 | 27 | ||
27 | #include "cx22702.h" | 28 | #include "cx22702.h" |
29 | #include "lgdt330x.h" | ||
30 | #include "mt352.h" | ||
31 | #include "mt352_priv.h" | ||
28 | 32 | ||
29 | /* debug */ | 33 | /* debug */ |
30 | int dvb_usb_cxusb_debug; | 34 | int dvb_usb_cxusb_debug; |
@@ -156,6 +160,99 @@ static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) | |||
156 | return 0; | 160 | return 0; |
157 | } | 161 | } |
158 | 162 | ||
163 | static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | ||
164 | { | ||
165 | struct dvb_usb_rc_key *keymap = d->props.rc_key_map; | ||
166 | u8 ircode[4]; | ||
167 | int i; | ||
168 | |||
169 | cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4); | ||
170 | |||
171 | *event = 0; | ||
172 | *state = REMOTE_NO_KEY_PRESSED; | ||
173 | |||
174 | for (i = 0; i < d->props.rc_key_map_size; i++) { | ||
175 | if (keymap[i].custom == ircode[2] && | ||
176 | keymap[i].data == ircode[3]) { | ||
177 | *event = keymap[i].event; | ||
178 | *state = REMOTE_KEY_PRESSED; | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | struct dvb_usb_rc_key dvico_mce_rc_keys[] = { | ||
188 | { 0xfe, 0x02, KEY_TV }, | ||
189 | { 0xfe, 0x0e, KEY_MP3 }, | ||
190 | { 0xfe, 0x1a, KEY_DVD }, | ||
191 | { 0xfe, 0x1e, KEY_FAVORITES }, | ||
192 | { 0xfe, 0x16, KEY_SETUP }, | ||
193 | { 0xfe, 0x46, KEY_POWER2 }, | ||
194 | { 0xfe, 0x0a, KEY_EPG }, | ||
195 | { 0xfe, 0x49, KEY_BACK }, | ||
196 | { 0xfe, 0x4d, KEY_MENU }, | ||
197 | { 0xfe, 0x51, KEY_UP }, | ||
198 | { 0xfe, 0x5b, KEY_LEFT }, | ||
199 | { 0xfe, 0x5f, KEY_RIGHT }, | ||
200 | { 0xfe, 0x53, KEY_DOWN }, | ||
201 | { 0xfe, 0x5e, KEY_OK }, | ||
202 | { 0xfe, 0x59, KEY_INFO }, | ||
203 | { 0xfe, 0x55, KEY_TAB }, | ||
204 | { 0xfe, 0x0f, KEY_PREVIOUSSONG },/* Replay */ | ||
205 | { 0xfe, 0x12, KEY_NEXTSONG }, /* Skip */ | ||
206 | { 0xfe, 0x42, KEY_ENTER }, /* Windows/Start */ | ||
207 | { 0xfe, 0x15, KEY_VOLUMEUP }, | ||
208 | { 0xfe, 0x05, KEY_VOLUMEDOWN }, | ||
209 | { 0xfe, 0x11, KEY_CHANNELUP }, | ||
210 | { 0xfe, 0x09, KEY_CHANNELDOWN }, | ||
211 | { 0xfe, 0x52, KEY_CAMERA }, | ||
212 | { 0xfe, 0x5a, KEY_TUNER }, /* Live */ | ||
213 | { 0xfe, 0x19, KEY_OPEN }, | ||
214 | { 0xfe, 0x0b, KEY_1 }, | ||
215 | { 0xfe, 0x17, KEY_2 }, | ||
216 | { 0xfe, 0x1b, KEY_3 }, | ||
217 | { 0xfe, 0x07, KEY_4 }, | ||
218 | { 0xfe, 0x50, KEY_5 }, | ||
219 | { 0xfe, 0x54, KEY_6 }, | ||
220 | { 0xfe, 0x48, KEY_7 }, | ||
221 | { 0xfe, 0x4c, KEY_8 }, | ||
222 | { 0xfe, 0x58, KEY_9 }, | ||
223 | { 0xfe, 0x13, KEY_ANGLE }, /* Aspect */ | ||
224 | { 0xfe, 0x03, KEY_0 }, | ||
225 | { 0xfe, 0x1f, KEY_ZOOM }, | ||
226 | { 0xfe, 0x43, KEY_REWIND }, | ||
227 | { 0xfe, 0x47, KEY_PLAYPAUSE }, | ||
228 | { 0xfe, 0x4f, KEY_FASTFORWARD }, | ||
229 | { 0xfe, 0x57, KEY_MUTE }, | ||
230 | { 0xfe, 0x0d, KEY_STOP }, | ||
231 | { 0xfe, 0x01, KEY_RECORD }, | ||
232 | { 0xfe, 0x4e, KEY_POWER }, | ||
233 | }; | ||
234 | |||
235 | static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) | ||
236 | { | ||
237 | static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 }; | ||
238 | static u8 reset [] = { RESET, 0x80 }; | ||
239 | static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; | ||
240 | static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; | ||
241 | static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; | ||
242 | static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; | ||
243 | |||
244 | mt352_write(fe, clock_config, sizeof(clock_config)); | ||
245 | udelay(200); | ||
246 | mt352_write(fe, reset, sizeof(reset)); | ||
247 | mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); | ||
248 | |||
249 | mt352_write(fe, agc_cfg, sizeof(agc_cfg)); | ||
250 | mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); | ||
251 | mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
159 | struct cx22702_config cxusb_cx22702_config = { | 256 | struct cx22702_config cxusb_cx22702_config = { |
160 | .demod_address = 0x63, | 257 | .demod_address = 0x63, |
161 | 258 | ||
@@ -165,17 +262,47 @@ struct cx22702_config cxusb_cx22702_config = { | |||
165 | .pll_set = dvb_usb_pll_set_i2c, | 262 | .pll_set = dvb_usb_pll_set_i2c, |
166 | }; | 263 | }; |
167 | 264 | ||
265 | struct lgdt330x_config cxusb_lgdt330x_config = { | ||
266 | .demod_address = 0x0e, | ||
267 | .demod_chip = LGDT3303, | ||
268 | .pll_set = dvb_usb_pll_set_i2c, | ||
269 | }; | ||
270 | |||
271 | struct mt352_config cxusb_dee1601_config = { | ||
272 | .demod_address = 0x0f, | ||
273 | .demod_init = cxusb_dee1601_demod_init, | ||
274 | .pll_set = dvb_usb_pll_set, | ||
275 | }; | ||
276 | |||
168 | /* Callbacks for DVB USB */ | 277 | /* Callbacks for DVB USB */ |
169 | static int cxusb_tuner_attach(struct dvb_usb_device *d) | 278 | static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d) |
170 | { | 279 | { |
171 | u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 }; | 280 | u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 }; |
172 | d->pll_addr = 0x61; | 281 | d->pll_addr = 0x61; |
173 | memcpy(d->pll_init,bpll,4); | 282 | memcpy(d->pll_init, bpll, 4); |
174 | d->pll_desc = &dvb_pll_fmd1216me; | 283 | d->pll_desc = &dvb_pll_fmd1216me; |
175 | return 0; | 284 | return 0; |
176 | } | 285 | } |
177 | 286 | ||
178 | static int cxusb_frontend_attach(struct dvb_usb_device *d) | 287 | static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d) |
288 | { | ||
289 | u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 }; | ||
290 | /* bpll[2] : unset bit 3, set bits 4&5 | ||
291 | bpll[3] : 0x50 - digital, 0x20 - analog */ | ||
292 | d->pll_addr = 0x61; | ||
293 | memcpy(d->pll_init, bpll, 4); | ||
294 | d->pll_desc = &dvb_pll_tdvs_tua6034; | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d) | ||
299 | { | ||
300 | d->pll_addr = 0x61; | ||
301 | d->pll_desc = &dvb_pll_thomson_dtt7579; | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d) | ||
179 | { | 306 | { |
180 | u8 b; | 307 | u8 b; |
181 | if (usb_set_interface(d->udev,0,6) < 0) | 308 | if (usb_set_interface(d->udev,0,6) < 0) |
@@ -189,22 +316,84 @@ static int cxusb_frontend_attach(struct dvb_usb_device *d) | |||
189 | return -EIO; | 316 | return -EIO; |
190 | } | 317 | } |
191 | 318 | ||
319 | static int cxusb_lgdt330x_frontend_attach(struct dvb_usb_device *d) | ||
320 | { | ||
321 | if (usb_set_interface(d->udev,0,7) < 0) | ||
322 | err("set interface failed"); | ||
323 | |||
324 | cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0); | ||
325 | |||
326 | if ((d->fe = lgdt330x_attach(&cxusb_lgdt330x_config, &d->i2c_adap)) != NULL) | ||
327 | return 0; | ||
328 | |||
329 | return -EIO; | ||
330 | } | ||
331 | |||
332 | static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d) | ||
333 | { | ||
334 | if (usb_set_interface(d->udev,0,0) < 0) | ||
335 | err("set interface failed"); | ||
336 | |||
337 | cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0); | ||
338 | |||
339 | if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) | ||
340 | return 0; | ||
341 | |||
342 | return -EIO; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * DViCO bluebird firmware needs the "warm" product ID to be patched into the | ||
347 | * firmware file before download. | ||
348 | */ | ||
349 | |||
350 | #define BLUEBIRD_01_ID_OFFSET 6638 | ||
351 | static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw) | ||
352 | { | ||
353 | if (fw->size < BLUEBIRD_01_ID_OFFSET + 4) | ||
354 | return -EINVAL; | ||
355 | |||
356 | if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) && | ||
357 | fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) { | ||
358 | |||
359 | /* FIXME: are we allowed to change the fw-data ? */ | ||
360 | fw->data[BLUEBIRD_01_ID_OFFSET + 2] = udev->descriptor.idProduct + 1; | ||
361 | fw->data[BLUEBIRD_01_ID_OFFSET + 3] = udev->descriptor.idProduct >> 8; | ||
362 | |||
363 | return usb_cypress_load_firmware(udev,fw,CYPRESS_FX2); | ||
364 | } | ||
365 | |||
366 | return -EINVAL; | ||
367 | } | ||
368 | |||
192 | /* DVB USB Driver stuff */ | 369 | /* DVB USB Driver stuff */ |
193 | static struct dvb_usb_properties cxusb_properties; | 370 | static struct dvb_usb_properties cxusb_medion_properties; |
371 | static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties; | ||
372 | static struct dvb_usb_properties cxusb_bluebird_dee1601_properties; | ||
194 | 373 | ||
195 | static int cxusb_probe(struct usb_interface *intf, | 374 | static int cxusb_probe(struct usb_interface *intf, |
196 | const struct usb_device_id *id) | 375 | const struct usb_device_id *id) |
197 | { | 376 | { |
198 | return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE,NULL); | 377 | if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 || |
378 | dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 || | ||
379 | dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0) { | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | return -EINVAL; | ||
199 | } | 384 | } |
200 | 385 | ||
201 | static struct usb_device_id cxusb_table [] = { | 386 | static struct usb_device_id cxusb_table [] = { |
202 | { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, | 387 | { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, |
388 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) }, | ||
389 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) }, | ||
390 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_COLD) }, | ||
391 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_WARM) }, | ||
203 | {} /* Terminating entry */ | 392 | {} /* Terminating entry */ |
204 | }; | 393 | }; |
205 | MODULE_DEVICE_TABLE (usb, cxusb_table); | 394 | MODULE_DEVICE_TABLE (usb, cxusb_table); |
206 | 395 | ||
207 | static struct dvb_usb_properties cxusb_properties = { | 396 | static struct dvb_usb_properties cxusb_medion_properties = { |
208 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | 397 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, |
209 | 398 | ||
210 | .usb_ctrl = CYPRESS_FX2, | 399 | .usb_ctrl = CYPRESS_FX2, |
@@ -213,8 +402,8 @@ static struct dvb_usb_properties cxusb_properties = { | |||
213 | 402 | ||
214 | .streaming_ctrl = cxusb_streaming_ctrl, | 403 | .streaming_ctrl = cxusb_streaming_ctrl, |
215 | .power_ctrl = cxusb_power_ctrl, | 404 | .power_ctrl = cxusb_power_ctrl, |
216 | .frontend_attach = cxusb_frontend_attach, | 405 | .frontend_attach = cxusb_cx22702_frontend_attach, |
217 | .tuner_attach = cxusb_tuner_attach, | 406 | .tuner_attach = cxusb_fmd1216me_tuner_attach, |
218 | 407 | ||
219 | .i2c_algo = &cxusb_i2c_algo, | 408 | .i2c_algo = &cxusb_i2c_algo, |
220 | 409 | ||
@@ -240,6 +429,91 @@ static struct dvb_usb_properties cxusb_properties = { | |||
240 | } | 429 | } |
241 | }; | 430 | }; |
242 | 431 | ||
432 | static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = { | ||
433 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
434 | |||
435 | .usb_ctrl = DEVICE_SPECIFIC, | ||
436 | .firmware = "dvb-usb-bluebird-01.fw", | ||
437 | .download_firmware = bluebird_patch_dvico_firmware_download, | ||
438 | /* use usb alt setting 0 for EP4 transfer (dvb-t), | ||
439 | use usb alt setting 7 for EP2 transfer (atsc) */ | ||
440 | |||
441 | .size_of_priv = sizeof(struct cxusb_state), | ||
442 | |||
443 | .streaming_ctrl = cxusb_streaming_ctrl, | ||
444 | .power_ctrl = cxusb_power_ctrl, | ||
445 | .frontend_attach = cxusb_lgdt330x_frontend_attach, | ||
446 | .tuner_attach = cxusb_lgh064f_tuner_attach, | ||
447 | |||
448 | .i2c_algo = &cxusb_i2c_algo, | ||
449 | |||
450 | .generic_bulk_ctrl_endpoint = 0x01, | ||
451 | /* parameter for the MPEG2-data transfer */ | ||
452 | .urb = { | ||
453 | .type = DVB_USB_BULK, | ||
454 | .count = 5, | ||
455 | .endpoint = 0x02, | ||
456 | .u = { | ||
457 | .bulk = { | ||
458 | .buffersize = 8192, | ||
459 | } | ||
460 | } | ||
461 | }, | ||
462 | |||
463 | .num_device_descs = 1, | ||
464 | .devices = { | ||
465 | { "DViCO FusionHDTV5 USB Gold", | ||
466 | { &cxusb_table[1], NULL }, | ||
467 | { &cxusb_table[2], NULL }, | ||
468 | }, | ||
469 | } | ||
470 | }; | ||
471 | |||
472 | static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = { | ||
473 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
474 | |||
475 | .usb_ctrl = DEVICE_SPECIFIC, | ||
476 | .firmware = "dvb-usb-bluebird-01.fw", | ||
477 | .download_firmware = bluebird_patch_dvico_firmware_download, | ||
478 | /* use usb alt setting 0 for EP4 transfer (dvb-t), | ||
479 | use usb alt setting 7 for EP2 transfer (atsc) */ | ||
480 | |||
481 | .size_of_priv = sizeof(struct cxusb_state), | ||
482 | |||
483 | .streaming_ctrl = cxusb_streaming_ctrl, | ||
484 | .power_ctrl = cxusb_power_ctrl, | ||
485 | .frontend_attach = cxusb_dee1601_frontend_attach, | ||
486 | .tuner_attach = cxusb_dee1601_tuner_attach, | ||
487 | |||
488 | .i2c_algo = &cxusb_i2c_algo, | ||
489 | |||
490 | .rc_interval = 150, | ||
491 | .rc_key_map = dvico_mce_rc_keys, | ||
492 | .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys), | ||
493 | .rc_query = cxusb_rc_query, | ||
494 | |||
495 | .generic_bulk_ctrl_endpoint = 0x01, | ||
496 | /* parameter for the MPEG2-data transfer */ | ||
497 | .urb = { | ||
498 | .type = DVB_USB_BULK, | ||
499 | .count = 5, | ||
500 | .endpoint = 0x04, | ||
501 | .u = { | ||
502 | .bulk = { | ||
503 | .buffersize = 8192, | ||
504 | } | ||
505 | } | ||
506 | }, | ||
507 | |||
508 | .num_device_descs = 1, | ||
509 | .devices = { | ||
510 | { "DViCO FusionHDTV DVB-T Dual USB", | ||
511 | { &cxusb_table[3], NULL }, | ||
512 | { &cxusb_table[4], NULL }, | ||
513 | }, | ||
514 | } | ||
515 | }; | ||
516 | |||
243 | static struct usb_driver cxusb_driver = { | 517 | static struct usb_driver cxusb_driver = { |
244 | .name = "dvb_usb_cxusb", | 518 | .name = "dvb_usb_cxusb", |
245 | .probe = cxusb_probe, | 519 | .probe = cxusb_probe, |