📄 budget-ci.c
字号:
static int ciintf_write_cam_control(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value) { struct budget_ci* budget_ci = (struct budget_ci*) ca->data; if (slot != 0) return -EINVAL; return budget_debiwrite(budget_ci, DEBICICAM, DEBIADDR_IO | (address & 3), 1, value);}static int ciintf_slot_reset(struct dvb_ca_en50221* ca, int slot) { struct budget_ci* budget_ci = (struct budget_ci*) ca->data; struct saa7146_dev *saa = budget_ci->budget.dev; if (slot != 0) return -EINVAL; // trigger on RISING edge during reset so we know when READY is re-asserted saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); budget_ci->slot_status = SLOTSTATUS_RESET; budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0); dvb_delay(1); budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET); saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); return 0;}static int ciintf_slot_shutdown(struct dvb_ca_en50221* ca, int slot) { struct budget_ci* budget_ci = (struct budget_ci*) ca->data; struct saa7146_dev *saa = budget_ci->budget.dev; if (slot != 0) return -EINVAL; saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); return 0;}static int ciintf_slot_ts_enable(struct dvb_ca_en50221* ca, int slot) { struct budget_ci* budget_ci = (struct budget_ci*) ca->data; struct saa7146_dev *saa = budget_ci->budget.dev; int tmp; if (slot != 0) return -EINVAL; saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); tmp = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1); budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, tmp | CICONTROL_ENABLETS); ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); return 0;}static void ciintf_interrupt (unsigned long data){ struct budget_ci *budget_ci = (struct budget_ci*) data; struct saa7146_dev *saa = budget_ci->budget.dev; unsigned int flags; // ensure we don't get spurious IRQs during initialisation if (!budget_ci->budget.ci_present) return; flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1); // always set the GPIO mode back to "normal", in case the card is // yanked at an inopportune moment saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); if (flags & CICONTROL_CAMDETECT) { if (budget_ci->slot_status & SLOTSTATUS_NONE) { // CAM insertion IRQ budget_ci->slot_status = SLOTSTATUS_PRESENT; dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_INSERTED); } else if (budget_ci->slot_status & SLOTSTATUS_RESET) { // CAM ready (reset completed) budget_ci->slot_status = SLOTSTATUS_READY; dvb_ca_en50221_camready_irq(&budget_ci->ca, 0); } else if (budget_ci->slot_status & SLOTSTATUS_READY) { // FR/DA IRQ dvb_ca_en50221_frda_irq(&budget_ci->ca, 0); } } else { if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) { budget_ci->slot_status = SLOTSTATUS_NONE; dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_REMOVED); } }}static int ciintf_init(struct budget_ci* budget_ci){ struct saa7146_dev *saa = budget_ci->budget.dev; int flags; int result; memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221)); // enable DEBI pins saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800); // test if it is there if ((budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CIVERSION, 1) & 0xa0) != 0xa0) { result = -ENODEV; goto error; } // determine whether a CAM is present or not flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1); budget_ci->slot_status = SLOTSTATUS_NONE; if (flags & CICONTROL_CAMDETECT) budget_ci->slot_status = SLOTSTATUS_PRESENT; // register CI interface budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem; budget_ci->ca.read_cam_control = ciintf_read_cam_control; budget_ci->ca.write_cam_control = ciintf_write_cam_control; budget_ci->ca.slot_reset = ciintf_slot_reset; budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; budget_ci->ca.data = budget_ci; if ((result = dvb_ca_en50221_init(budget_ci->budget.dvb_adapter, &budget_ci->ca, DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | DVB_CA_EN50221_FLAG_IRQ_FR | DVB_CA_EN50221_FLAG_IRQ_DA, 1)) != 0) { printk("budget_ci: CI interface detected, but initialisation failed.\n"); goto error; } // Setup CI slot IRQ tasklet_init (&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci); saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03); budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET); // success! printk("budget_ci: CI interface initialised\n"); budget_ci->budget.ci_present = 1; // forge a fake CI IRQ so the CAM state is setup correctly flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; if (budget_ci->slot_status != SLOTSTATUS_NONE) flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); return 0;error: saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16)); return result;}static void ciintf_deinit(struct budget_ci* budget_ci){ struct saa7146_dev *saa = budget_ci->budget.dev; // disable CI interrupts saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03); saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); tasklet_kill(&budget_ci->ciintf_irq_tasklet); budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0); dvb_delay(1); budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET); // disable TS data stream to CI interface saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); // release the CA device dvb_ca_en50221_release(&budget_ci->ca); // disable DEBI pins saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));}static void budget_ci_irq (struct saa7146_dev *dev, u32 *isr){ struct budget_ci *budget_ci = (struct budget_ci*) dev->ext_priv; DEB_EE(("dev: %p, budget_ci: %p\n", dev, budget_ci)); if (*isr & MASK_06) tasklet_schedule (&budget_ci->msp430_irq_tasklet); if (*isr & MASK_10) ttpci_budget_irq10_handler (dev, isr); if ((*isr & MASK_03) && (budget_ci->budget.ci_present)) tasklet_schedule (&budget_ci->ciintf_irq_tasklet);}static int budget_ci_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info){ struct budget_ci *budget_ci; int err; if (!(budget_ci = kmalloc (sizeof(struct budget_ci), GFP_KERNEL))) return -ENOMEM; DEB_EE(("budget_ci: %p\n", budget_ci)); spin_lock_init(&budget_ci->debilock); budget_ci->budget.ci_present = 0; if ((err = ttpci_budget_init (&budget_ci->budget, dev, info))) { kfree (budget_ci); return err; } dev->ext_priv = budget_ci; tasklet_init (&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt, (unsigned long) budget_ci); msp430_ir_init (budget_ci); // UNCOMMENT TO TEST CI INTERFACE// ciintf_init(budget_ci); return 0;}static int budget_ci_detach (struct saa7146_dev* dev){ struct budget_ci *budget_ci = (struct budget_ci*) dev->ext_priv; struct saa7146_dev *saa = budget_ci->budget.dev; int err; if (budget_ci->budget.ci_present) ciintf_deinit(budget_ci); err = ttpci_budget_deinit (&budget_ci->budget); tasklet_kill (&budget_ci->msp430_irq_tasklet); msp430_ir_deinit (budget_ci); // disable frontend and CI interface saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); kfree (budget_ci); return err;}static struct saa7146_extension budget_extension; MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), { .vendor = 0, }};MODULE_DEVICE_TABLE(pci, pci_tbl);static struct saa7146_extension budget_extension = { .name = "budget_ci dvb\0", .flags = 0, .module = THIS_MODULE, .pci_tbl = &pci_tbl[0], .attach = budget_ci_attach, .detach = budget_ci_detach, .irq_mask = MASK_03 | MASK_06 | MASK_10, .irq_func = budget_ci_irq,}; static int __init budget_ci_init(void) { return saa7146_register_extension(&budget_extension);}static void __exit budget_ci_exit(void){ DEB_EE((".\n")); saa7146_unregister_extension(&budget_extension); }module_init(budget_ci_init);module_exit(budget_ci_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");MODULE_DESCRIPTION("driver for the SAA7146 based so-called " "budget PCI DVB cards w/ CI-module produced by " "Siemens, Technotrend, Hauppauge");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -