diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-11-15 06:43:53 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:02:10 -0500 |
commit | f380e1d2c9a1ff82a89ec68850ce53094359000e (patch) | |
tree | 00813ee13c2420a84bd8d2b98c1934cbaefb0858 /drivers/media | |
parent | 43efe70253dd13b2d22ee51bb474ece25b3b41b1 (diff) |
V4L/DVB (6593): Fix scode table loading
Xceive 2028/3028 has a concept of scode/dcode.
Scode is a table of 16 values (each with 12 bytes i2c sequence).
Dcode is the entry of Scode table that should be used, given a certain
frequency.
The idea is that, depending on what frequency is selected, and according with a
country-based (or standard-based?) table, the Xceive should be "hacked" to
fine-tune that specific frequency.
By default, Scode=0 is used, for undefined frequencies. Also, Scode=0 seems to
be the most used value.
This patch adds the capability of selecting a scode. However, extra work will
be needed to allow auto-selecting the proper scode, for a given set of
frequencies.
I'm not sure what would be the proper way for implementing the dcode selection.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/tuner-xc2028.c | 98 |
1 files changed, 77 insertions, 21 deletions
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index ac0c9c3cde98..e046c21be0b9 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c | |||
@@ -116,6 +116,8 @@ void dump_firm_type(unsigned int type) | |||
116 | { | 116 | { |
117 | if (type & BASE) | 117 | if (type & BASE) |
118 | printk("BASE "); | 118 | printk("BASE "); |
119 | if (type & INIT1) | ||
120 | printk("INIT1 "); | ||
119 | if (type & F8MHZ) | 121 | if (type & F8MHZ) |
120 | printk("F8MHZ "); | 122 | printk("F8MHZ "); |
121 | if (type & MTS) | 123 | if (type & MTS) |
@@ -201,7 +203,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) | |||
201 | 203 | ||
202 | tuner_info("%s called\n", __FUNCTION__); | 204 | tuner_info("%s called\n", __FUNCTION__); |
203 | 205 | ||
204 | tuner_info("Loading firmware %s\n", priv->ctrl.fname); | 206 | tuner_info("Reading firmware %s\n", priv->ctrl.fname); |
205 | rc = request_firmware(&fw, priv->ctrl.fname, priv->dev); | 207 | rc = request_firmware(&fw, priv->ctrl.fname, priv->dev); |
206 | if (rc < 0) { | 208 | if (rc < 0) { |
207 | if (rc == -ENOENT) | 209 | if (rc == -ENOENT) |
@@ -325,12 +327,11 @@ done: | |||
325 | return rc; | 327 | return rc; |
326 | } | 328 | } |
327 | 329 | ||
328 | static int load_firmware(struct dvb_frontend *fe, unsigned int type, | 330 | static int seek_firmware(struct dvb_frontend *fe, unsigned int type, |
329 | v4l2_std_id * id) | 331 | v4l2_std_id *id) |
330 | { | 332 | { |
331 | struct xc2028_data *priv = fe->tuner_priv; | 333 | struct xc2028_data *priv = fe->tuner_priv; |
332 | int i, rc; | 334 | int i; |
333 | unsigned char *p, *endp, buf[priv->max_len]; | ||
334 | 335 | ||
335 | tuner_info("%s called\n", __FUNCTION__); | 336 | tuner_info("%s called\n", __FUNCTION__); |
336 | 337 | ||
@@ -339,7 +340,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, | |||
339 | return -EINVAL; | 340 | return -EINVAL; |
340 | } | 341 | } |
341 | 342 | ||
342 | if ((type == 0) && (*id == 0)) | 343 | if (((type & ~SCODE) == 0) && (*id == 0)) |
343 | *id = V4L2_STD_PAL; | 344 | *id = V4L2_STD_PAL; |
344 | 345 | ||
345 | /* Seek for exact match */ | 346 | /* Seek for exact match */ |
@@ -356,21 +357,40 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, | |||
356 | 357 | ||
357 | /*FIXME: Would make sense to seek for type "hint" match ? */ | 358 | /*FIXME: Would make sense to seek for type "hint" match ? */ |
358 | 359 | ||
359 | tuner_info("Can't find firmware for type=%x, id=%lx\n", type, | 360 | i = -EINVAL; |
360 | (long int)*id); | 361 | goto ret; |
361 | return -EINVAL; | ||
362 | 362 | ||
363 | found: | 363 | found: |
364 | *id = priv->firm[i].id; | 364 | *id = priv->firm[i].id; |
365 | tuner_info("Found firmware for type=%x, id=%lx\n", type, (long int)*id); | ||
366 | 365 | ||
367 | p = priv->firm[i].ptr; | 366 | ret: |
367 | tuner_info("%s firmware for type=", (i < 0)? "Can't find": "Found"); | ||
368 | dump_firm_type(type); | ||
369 | printk("(%x), id %08lx.\n", type, (unsigned long)*id); | ||
370 | |||
371 | return i; | ||
372 | } | ||
373 | |||
374 | static int load_firmware(struct dvb_frontend *fe, unsigned int type, | ||
375 | v4l2_std_id *id) | ||
376 | { | ||
377 | struct xc2028_data *priv = fe->tuner_priv; | ||
378 | int pos, rc; | ||
379 | unsigned char *p, *endp, buf[priv->max_len]; | ||
380 | |||
381 | tuner_info("%s called\n", __FUNCTION__); | ||
382 | |||
383 | pos = seek_firmware(fe, type, id); | ||
384 | if (pos < 0) | ||
385 | return pos; | ||
386 | |||
387 | p = priv->firm[pos].ptr; | ||
368 | 388 | ||
369 | if (!p) { | 389 | if (!p) { |
370 | printk(KERN_ERR PREFIX "Firmware pointer were freed!"); | 390 | printk(KERN_ERR PREFIX "Firmware pointer were freed!"); |
371 | return -EINVAL; | 391 | return -EINVAL; |
372 | } | 392 | } |
373 | endp = p + priv->firm[i].size; | 393 | endp = p + priv->firm[pos].size; |
374 | 394 | ||
375 | while (p < endp) { | 395 | while (p < endp) { |
376 | __u16 size; | 396 | __u16 size; |
@@ -435,6 +455,42 @@ found: | |||
435 | return 0; | 455 | return 0; |
436 | } | 456 | } |
437 | 457 | ||
458 | static int load_scode(struct dvb_frontend *fe, unsigned int type, | ||
459 | v4l2_std_id *id, int scode) | ||
460 | { | ||
461 | struct xc2028_data *priv = fe->tuner_priv; | ||
462 | int pos, rc; | ||
463 | unsigned char *p; | ||
464 | |||
465 | tuner_info("%s called\n", __FUNCTION__); | ||
466 | |||
467 | pos = seek_firmware(fe, type, id); | ||
468 | if (pos < 0) | ||
469 | return pos; | ||
470 | |||
471 | p = priv->firm[pos].ptr; | ||
472 | |||
473 | if (!p) { | ||
474 | printk(KERN_ERR PREFIX "Firmware pointer were freed!"); | ||
475 | return -EINVAL; | ||
476 | } | ||
477 | |||
478 | if ((priv->firm[pos].size != 12 * 16) || (scode >= 16)) | ||
479 | return -EINVAL; | ||
480 | |||
481 | if (priv->version < 0x0202) { | ||
482 | send_seq(priv, {0x20, 0x00, 0x00, 0x00}); | ||
483 | } else { | ||
484 | send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); | ||
485 | } | ||
486 | |||
487 | i2c_send(rc, priv, p + 12 * scode, 12); | ||
488 | |||
489 | send_seq(priv, {0x00, 0x8c}); | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | |||
438 | static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, | 494 | static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, |
439 | v4l2_std_id std, fe_bandwidth_t bandwidth) | 495 | v4l2_std_id std, fe_bandwidth_t bandwidth) |
440 | { | 496 | { |
@@ -527,8 +583,8 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, | |||
527 | } | 583 | } |
528 | 584 | ||
529 | /* Load INIT1, if needed */ | 585 | /* Load INIT1, if needed */ |
530 | tuner_info("Trying to load init1 firmware\n"); | 586 | tuner_info("Load init1 firmware, if exists\n"); |
531 | type0 = BASE | INIT1 | priv->ctrl.type; | 587 | type0 = BASE | INIT1; |
532 | if (priv->ctrl.type == XC2028_FIRM_MTS) | 588 | if (priv->ctrl.type == XC2028_FIRM_MTS) |
533 | type0 |= MTS; | 589 | type0 |= MTS; |
534 | 590 | ||
@@ -541,9 +597,9 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, | |||
541 | if (priv->ctrl.type == XC2028_FIRM_MTS) | 597 | if (priv->ctrl.type == XC2028_FIRM_MTS) |
542 | type |= MTS; | 598 | type |= MTS; |
543 | 599 | ||
544 | tuner_info("firmware standard to load: %08lx\n", (unsigned long)std); | 600 | tuner_info("Firmware standard to load: %08lx\n", (unsigned long)std); |
545 | if (priv->firm_type & std) { | 601 | if (priv->firm_type & std) { |
546 | tuner_info("no need to load a std-specific firmware.\n"); | 602 | tuner_info("Std-specific firmware already loaded.\n"); |
547 | return 0; | 603 | return 0; |
548 | } | 604 | } |
549 | 605 | ||
@@ -551,11 +607,11 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, | |||
551 | if (rc < 0) | 607 | if (rc < 0) |
552 | return rc; | 608 | return rc; |
553 | 609 | ||
554 | /* Load SCODE firmware, if needed */ | 610 | /* Load SCODE firmware, if exists */ |
555 | tuner_info("Trying to load scode firmware\n"); | 611 | tuner_info("Trying to load scode 0\n"); |
556 | type0 = SCODE | priv->ctrl.type; | 612 | type |= SCODE; |
557 | if (priv->ctrl.type == XC2028_FIRM_MTS) | 613 | |
558 | type0 |= MTS; | 614 | rc = load_scode(fe, type, &std, 0); |
559 | 615 | ||
560 | version = xc2028_get_reg(priv, 0x0004); | 616 | version = xc2028_get_reg(priv, 0x0004); |
561 | hwmodel = xc2028_get_reg(priv, 0x0008); | 617 | hwmodel = xc2028_get_reg(priv, 0x0008); |