diff options
| -rw-r--r-- | drivers/media/dvb/ttpci/budget-ci.c | 105 |
1 files changed, 85 insertions, 20 deletions
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 5f91036f5b87..e64a609cf4ff 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c | |||
| @@ -71,6 +71,7 @@ struct budget_ci { | |||
| 71 | struct tasklet_struct msp430_irq_tasklet; | 71 | struct tasklet_struct msp430_irq_tasklet; |
| 72 | struct tasklet_struct ciintf_irq_tasklet; | 72 | struct tasklet_struct ciintf_irq_tasklet; |
| 73 | int slot_status; | 73 | int slot_status; |
| 74 | int ci_irq; | ||
| 74 | struct dvb_ca_en50221 ca; | 75 | struct dvb_ca_en50221 ca; |
| 75 | char ir_dev_name[50]; | 76 | char ir_dev_name[50]; |
| 76 | u8 tuner_pll_address; /* used for philips_tdm1316l configs */ | 77 | u8 tuner_pll_address; /* used for philips_tdm1316l configs */ |
| @@ -276,8 +277,10 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) | |||
| 276 | if (slot != 0) | 277 | if (slot != 0) |
| 277 | return -EINVAL; | 278 | return -EINVAL; |
| 278 | 279 | ||
| 279 | // trigger on RISING edge during reset so we know when READY is re-asserted | 280 | if (budget_ci->ci_irq) { |
| 280 | saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); | 281 | // trigger on RISING edge during reset so we know when READY is re-asserted |
| 282 | saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); | ||
| 283 | } | ||
| 281 | budget_ci->slot_status = SLOTSTATUS_RESET; | 284 | budget_ci->slot_status = SLOTSTATUS_RESET; |
| 282 | ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); | 285 | ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); |
| 283 | msleep(1); | 286 | msleep(1); |
| @@ -370,11 +373,50 @@ static void ciintf_interrupt(unsigned long data) | |||
| 370 | } | 373 | } |
| 371 | } | 374 | } |
| 372 | 375 | ||
| 376 | static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) | ||
| 377 | { | ||
| 378 | struct budget_ci *budget_ci = (struct budget_ci *) ca->data; | ||
| 379 | unsigned int flags; | ||
| 380 | |||
| 381 | // ensure we don't get spurious IRQs during initialisation | ||
| 382 | if (!budget_ci->budget.ci_present) | ||
| 383 | return -EINVAL; | ||
| 384 | |||
| 385 | // read the CAM status | ||
| 386 | flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); | ||
| 387 | if (flags & CICONTROL_CAMDETECT) { | ||
| 388 | // mark it as present if it wasn't before | ||
| 389 | if (budget_ci->slot_status & SLOTSTATUS_NONE) { | ||
| 390 | budget_ci->slot_status = SLOTSTATUS_PRESENT; | ||
| 391 | } | ||
| 392 | |||
| 393 | // during a RESET, we check if we can read from IO memory to see when CAM is ready | ||
| 394 | if (budget_ci->slot_status & SLOTSTATUS_RESET) { | ||
| 395 | if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) { | ||
| 396 | budget_ci->slot_status = SLOTSTATUS_READY; | ||
| 397 | } | ||
| 398 | } | ||
| 399 | } else { | ||
| 400 | budget_ci->slot_status = SLOTSTATUS_NONE; | ||
| 401 | } | ||
| 402 | |||
| 403 | if (budget_ci->slot_status != SLOTSTATUS_NONE) { | ||
| 404 | if (budget_ci->slot_status & SLOTSTATUS_READY) { | ||
| 405 | return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; | ||
| 406 | } | ||
| 407 | return DVB_CA_EN50221_POLL_CAM_PRESENT; | ||
| 408 | } | ||
| 409 | |||
| 410 | return 0; | ||
| 411 | } | ||
| 412 | |||
| 373 | static int ciintf_init(struct budget_ci *budget_ci) | 413 | static int ciintf_init(struct budget_ci *budget_ci) |
| 374 | { | 414 | { |
| 375 | struct saa7146_dev *saa = budget_ci->budget.dev; | 415 | struct saa7146_dev *saa = budget_ci->budget.dev; |
| 376 | int flags; | 416 | int flags; |
| 377 | int result; | 417 | int result; |
| 418 | int ci_version; | ||
| 419 | int ca_flags; | ||
| 378 | 420 | ||
| 379 | memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221)); | 421 | memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221)); |
| 380 | 422 | ||
| @@ -382,16 +424,29 @@ static int ciintf_init(struct budget_ci *budget_ci) | |||
| 382 | saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800); | 424 | saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800); |
| 383 | 425 | ||
| 384 | // test if it is there | 426 | // test if it is there |
| 385 | if ((ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0) & 0xa0) != 0xa0) { | 427 | ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0); |
| 428 | if ((ci_version & 0xa0) != 0xa0) { | ||
| 386 | result = -ENODEV; | 429 | result = -ENODEV; |
| 387 | goto error; | 430 | goto error; |
| 388 | } | 431 | } |
| 432 | |||
| 389 | // determine whether a CAM is present or not | 433 | // determine whether a CAM is present or not |
| 390 | flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); | 434 | flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); |
| 391 | budget_ci->slot_status = SLOTSTATUS_NONE; | 435 | budget_ci->slot_status = SLOTSTATUS_NONE; |
| 392 | if (flags & CICONTROL_CAMDETECT) | 436 | if (flags & CICONTROL_CAMDETECT) |
| 393 | budget_ci->slot_status = SLOTSTATUS_PRESENT; | 437 | budget_ci->slot_status = SLOTSTATUS_PRESENT; |
| 394 | 438 | ||
| 439 | // version 0xa2 of the CI firmware doesn't generate interrupts | ||
| 440 | if (ci_version == 0xa2) { | ||
| 441 | ca_flags = 0; | ||
| 442 | budget_ci->ci_irq = 0; | ||
| 443 | } else { | ||
| 444 | ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | | ||
| 445 | DVB_CA_EN50221_FLAG_IRQ_FR | | ||
| 446 | DVB_CA_EN50221_FLAG_IRQ_DA; | ||
| 447 | budget_ci->ci_irq = 1; | ||
| 448 | } | ||
| 449 | |||
| 395 | // register CI interface | 450 | // register CI interface |
| 396 | budget_ci->ca.owner = THIS_MODULE; | 451 | budget_ci->ca.owner = THIS_MODULE; |
| 397 | budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; | 452 | budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; |
| @@ -401,23 +456,27 @@ static int ciintf_init(struct budget_ci *budget_ci) | |||
| 401 | budget_ci->ca.slot_reset = ciintf_slot_reset; | 456 | budget_ci->ca.slot_reset = ciintf_slot_reset; |
| 402 | budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; | 457 | budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; |
| 403 | budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; | 458 | budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; |
| 459 | budget_ci->ca.poll_slot_status = ciintf_poll_slot_status; | ||
| 404 | budget_ci->ca.data = budget_ci; | 460 | budget_ci->ca.data = budget_ci; |
| 405 | if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter, | 461 | if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter, |
| 406 | &budget_ci->ca, | 462 | &budget_ci->ca, |
| 407 | DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | | 463 | ca_flags, 1)) != 0) { |
| 408 | DVB_CA_EN50221_FLAG_IRQ_FR | | ||
| 409 | DVB_CA_EN50221_FLAG_IRQ_DA, 1)) != 0) { | ||
| 410 | printk("budget_ci: CI interface detected, but initialisation failed.\n"); | 464 | printk("budget_ci: CI interface detected, but initialisation failed.\n"); |
| 411 | goto error; | 465 | goto error; |
| 412 | } | 466 | } |
| 467 | |||
| 413 | // Setup CI slot IRQ | 468 | // Setup CI slot IRQ |
| 414 | tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci); | 469 | if (budget_ci->ci_irq) { |
| 415 | if (budget_ci->slot_status != SLOTSTATUS_NONE) { | 470 | tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci); |
| 416 | saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); | 471 | if (budget_ci->slot_status != SLOTSTATUS_NONE) { |
| 417 | } else { | 472 | saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); |
| 418 | saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); | 473 | } else { |
| 474 | saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); | ||
| 475 | } | ||
| 476 | saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03); | ||
| 419 | } | 477 | } |
| 420 | saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03); | 478 | |
| 479 | // enable interface | ||
| 421 | ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, | 480 | ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, |
| 422 | CICONTROL_RESET, 1, 0); | 481 | CICONTROL_RESET, 1, 0); |
| 423 | 482 | ||
| @@ -426,10 +485,12 @@ static int ciintf_init(struct budget_ci *budget_ci) | |||
| 426 | budget_ci->budget.ci_present = 1; | 485 | budget_ci->budget.ci_present = 1; |
| 427 | 486 | ||
| 428 | // forge a fake CI IRQ so the CAM state is setup correctly | 487 | // forge a fake CI IRQ so the CAM state is setup correctly |
| 429 | flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; | 488 | if (budget_ci->ci_irq) { |
| 430 | if (budget_ci->slot_status != SLOTSTATUS_NONE) | 489 | flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; |
| 431 | flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; | 490 | if (budget_ci->slot_status != SLOTSTATUS_NONE) |
| 432 | dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); | 491 | flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; |
| 492 | dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); | ||
| 493 | } | ||
| 433 | 494 | ||
| 434 | return 0; | 495 | return 0; |
| 435 | 496 | ||
| @@ -443,9 +504,13 @@ static void ciintf_deinit(struct budget_ci *budget_ci) | |||
| 443 | struct saa7146_dev *saa = budget_ci->budget.dev; | 504 | struct saa7146_dev *saa = budget_ci->budget.dev; |
| 444 | 505 | ||
| 445 | // disable CI interrupts | 506 | // disable CI interrupts |
| 446 | saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03); | 507 | if (budget_ci->ci_irq) { |
| 447 | saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); | 508 | saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03); |
| 448 | tasklet_kill(&budget_ci->ciintf_irq_tasklet); | 509 | saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); |
| 510 | tasklet_kill(&budget_ci->ciintf_irq_tasklet); | ||
| 511 | } | ||
| 512 | |||
| 513 | // reset interface | ||
| 449 | ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); | 514 | ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); |
| 450 | msleep(1); | 515 | msleep(1); |
| 451 | ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, | 516 | ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, |
| @@ -473,7 +538,7 @@ static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr) | |||
| 473 | if (*isr & MASK_10) | 538 | if (*isr & MASK_10) |
| 474 | ttpci_budget_irq10_handler(dev, isr); | 539 | ttpci_budget_irq10_handler(dev, isr); |
| 475 | 540 | ||
| 476 | if ((*isr & MASK_03) && (budget_ci->budget.ci_present)) | 541 | if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) |
| 477 | tasklet_schedule(&budget_ci->ciintf_irq_tasklet); | 542 | tasklet_schedule(&budget_ci->ciintf_irq_tasklet); |
| 478 | } | 543 | } |
| 479 | 544 | ||
