📄 hisax_fcpcipnp.c
字号:
/* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ bcs->ctrl.sr.xml = 0; bcs->ctrl.sr.cmd |= HDLC_CMD_XRS; adapter->write_ctrl(bcs, 1); bcs->ctrl.sr.cmd &= ~HDLC_CMD_XRS; if (!bcs->tx_skb) { DBG(0x10, "XDU without skb"); adapter->write_ctrl(bcs, 1); return; } /* only hdlc restarts the frame, transparent mode must continue */ if (bcs->mode == L1_MODE_HDLC) { skb_push(bcs->tx_skb, bcs->tx_cnt); bcs->tx_cnt = 0; }}static inline void hdlc_xpr_irq(struct fritz_bcs *bcs){ struct sk_buff *skb; skb = bcs->tx_skb; if (!skb) return; if (skb->len) { hdlc_fill_fifo(bcs); return; } bcs->tx_cnt = 0; bcs->tx_skb = NULL; B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize); dev_kfree_skb_irq(skb);}static void hdlc_irq_one(struct fritz_bcs *bcs, u32 stat){ DBG(0x10, "ch%d stat %#x", bcs->channel, stat); if (stat & HDLC_INT_RPR) { DBG(0x10, "RPR"); hdlc_rpr_irq(bcs, stat); } if (stat & HDLC_INT_XDU) { DBG(0x10, "XDU"); hdlc_xdu_irq(bcs); hdlc_xpr_irq(bcs); return; } if (stat & HDLC_INT_XPR) { DBG(0x10, "XPR"); hdlc_xpr_irq(bcs); }}static inline void hdlc_irq(struct fritz_adapter *adapter){ int nr; u32 stat; for (nr = 0; nr < 2; nr++) { stat = adapter->read_hdlc_status(adapter, nr); DBG(0x10, "HDLC %c stat %#x", 'A' + nr, stat); if (stat & HDLC_INT_MASK) hdlc_irq_one(&adapter->bcs[nr], stat); }}static void modehdlc(struct fritz_bcs *bcs, int mode){ struct fritz_adapter *adapter = bcs->adapter; DBG(0x40, "hdlc %c mode %d --> %d", 'A' + bcs->channel, bcs->mode, mode); if (bcs->mode == mode) return; bcs->fifo_size = 32; bcs->ctrl.ctrl = 0; bcs->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; switch (mode) { case L1_MODE_NULL: bcs->ctrl.sr.mode = HDLC_MODE_TRANS; adapter->write_ctrl(bcs, 5); break; case L1_MODE_TRANS: case L1_MODE_HDLC: bcs->rcvidx = 0; bcs->tx_cnt = 0; bcs->tx_skb = NULL; if (mode == L1_MODE_TRANS) { bcs->ctrl.sr.mode = HDLC_MODE_TRANS; } else { bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG; } adapter->write_ctrl(bcs, 5); bcs->ctrl.sr.cmd = HDLC_CMD_XRS; adapter->write_ctrl(bcs, 1); bcs->ctrl.sr.cmd = 0; break; } bcs->mode = mode;}static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg){ struct fritz_bcs *bcs = ifc->priv; struct sk_buff *skb = arg; int mode; DBG(0x10, "pr %#x", pr); switch (pr) { case PH_DATA | REQUEST: if (bcs->tx_skb) BUG(); bcs->tx_skb = skb; DBG_SKB(1, skb); hdlc_fill_fifo(bcs); break; case PH_ACTIVATE | REQUEST: mode = (int) arg; DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode); modehdlc(bcs, mode); B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL); break; case PH_DEACTIVATE | REQUEST: DBG(4,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1); modehdlc(bcs, L1_MODE_NULL); B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL); break; }}// ----------------------------------------------------------------------static irqreturn_tfcpci2_irq(int intno, void *dev, struct pt_regs *regs){ struct fritz_adapter *adapter = dev; unsigned char val; val = inb(adapter->io + AVM_STATUS0); if (!(val & AVM_STATUS0_IRQ_MASK)) /* hopefully a shared IRQ reqest */ return IRQ_NONE; DBG(2, "STATUS0 %#x", val); if (val & AVM_STATUS0_IRQ_ISAC) isacsx_irq(&adapter->isac); if (val & AVM_STATUS0_IRQ_HDLC) hdlc_irq(adapter); if (val & AVM_STATUS0_IRQ_ISAC) isacsx_irq(&adapter->isac); return IRQ_HANDLED;}static irqreturn_tfcpci_irq(int intno, void *dev, struct pt_regs *regs){ struct fritz_adapter *adapter = dev; unsigned char sval; sval = inb(adapter->io + 2); if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) /* possibly a shared IRQ reqest */ return IRQ_NONE; DBG(2, "sval %#x", sval); if (!(sval & AVM_STATUS0_IRQ_ISAC)) isac_irq(&adapter->isac); if (!(sval & AVM_STATUS0_IRQ_HDLC)) hdlc_irq(adapter); return IRQ_HANDLED;}// ----------------------------------------------------------------------static inline void fcpci2_init(struct fritz_adapter *adapter){ outb(AVM_STATUS0_RES_TIMER, adapter->io + AVM_STATUS0); outb(AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);}static inline void fcpci_init(struct fritz_adapter *adapter){ outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0); outb(AVM_STATUS1_ENA_IOM | adapter->irq, adapter->io + AVM_STATUS1); mdelay(10);}// ----------------------------------------------------------------------static int __devinit fcpcipnp_setup(struct fritz_adapter *adapter){ u32 val = 0; int retval; DBG(1,""); isac_init(&adapter->isac); // FIXME is this okay now retval = -EBUSY; if (!request_region(adapter->io, 32, "fcpcipnp")) goto err; switch (adapter->type) { case AVM_FRITZ_PCIV2: retval = request_irq(adapter->irq, fcpci2_irq, SA_SHIRQ, "fcpcipnp", adapter); break; case AVM_FRITZ_PCI: retval = request_irq(adapter->irq, fcpci_irq, SA_SHIRQ, "fcpcipnp", adapter); break; case AVM_FRITZ_PNP: retval = request_irq(adapter->irq, fcpci_irq, 0, "fcpcipnp", adapter); break; } if (retval) goto err_region; switch (adapter->type) { case AVM_FRITZ_PCIV2: case AVM_FRITZ_PCI: val = inl(adapter->io); break; case AVM_FRITZ_PNP: val = inb(adapter->io); val |= inb(adapter->io + 1) << 8; break; } DBG(1, "stat %#x Class %X Rev %d", val, val & 0xff, (val>>8) & 0xff); spin_lock_init(&adapter->hw_lock); adapter->isac.priv = adapter; switch (adapter->type) { case AVM_FRITZ_PCIV2: adapter->isac.read_isac = &fcpci2_read_isac; adapter->isac.write_isac = &fcpci2_write_isac; adapter->isac.read_isac_fifo = &fcpci2_read_isac_fifo; adapter->isac.write_isac_fifo = &fcpci2_write_isac_fifo; adapter->read_hdlc_status = &fcpci2_read_hdlc_status; adapter->write_ctrl = &fcpci2_write_ctrl; break; case AVM_FRITZ_PCI: adapter->isac.read_isac = &fcpci_read_isac; adapter->isac.write_isac = &fcpci_write_isac; adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo; adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo; adapter->read_hdlc_status = &fcpci_read_hdlc_status; adapter->write_ctrl = &fcpci_write_ctrl; break; case AVM_FRITZ_PNP: adapter->isac.read_isac = &fcpci_read_isac; adapter->isac.write_isac = &fcpci_write_isac; adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo; adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo; adapter->read_hdlc_status = &fcpnp_read_hdlc_status; adapter->write_ctrl = &fcpnp_write_ctrl; break; } // Reset outb(0, adapter->io + AVM_STATUS0); mdelay(10); outb(AVM_STATUS0_RESET, adapter->io + AVM_STATUS0); mdelay(10); outb(0, adapter->io + AVM_STATUS0); mdelay(10); switch (adapter->type) { case AVM_FRITZ_PCIV2: fcpci2_init(adapter); isacsx_setup(&adapter->isac); break; case AVM_FRITZ_PCI: case AVM_FRITZ_PNP: fcpci_init(adapter); isac_setup(&adapter->isac); break; } val = adapter->read_hdlc_status(adapter, 0); DBG(0x20, "HDLC A STA %x", val); val = adapter->read_hdlc_status(adapter, 1); DBG(0x20, "HDLC B STA %x", val); adapter->bcs[0].mode = -1; adapter->bcs[1].mode = -1; modehdlc(&adapter->bcs[0], L1_MODE_NULL); modehdlc(&adapter->bcs[1], L1_MODE_NULL); return 0; err_region: release_region(adapter->io, 32); err: return retval;}static void __devexit fcpcipnp_release(struct fritz_adapter *adapter){ DBG(1,""); outb(0, adapter->io + AVM_STATUS0); free_irq(adapter->irq, adapter); release_region(adapter->io, 32);}// ----------------------------------------------------------------------static struct fritz_adapter * __devinit new_adapter(void){ struct fritz_adapter *adapter; struct hisax_b_if *b_if[2]; int i; adapter = kmalloc(sizeof(struct fritz_adapter), GFP_KERNEL); if (!adapter) return NULL; memset(adapter, 0, sizeof(struct fritz_adapter)); adapter->isac.hisax_d_if.owner = THIS_MODULE; adapter->isac.hisax_d_if.ifc.priv = &adapter->isac; adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1; for (i = 0; i < 2; i++) { adapter->bcs[i].adapter = adapter; adapter->bcs[i].channel = i; adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; adapter->bcs[i].b_if.ifc.l2l1 = fritz_b_l2l1; } for (i = 0; i < 2; i++) b_if[i] = &adapter->bcs[i].b_if; hisax_register(&adapter->isac.hisax_d_if, b_if, "fcpcipnp", protocol); return adapter;}static void delete_adapter(struct fritz_adapter *adapter){ hisax_unregister(&adapter->isac.hisax_d_if); kfree(adapter);}static int __devinit fcpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent){ struct fritz_adapter *adapter; int retval; retval = -ENOMEM; adapter = new_adapter(); if (!adapter) goto err; pci_set_drvdata(pdev, adapter); if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) adapter->type = AVM_FRITZ_PCIV2; else adapter->type = AVM_FRITZ_PCI; retval = pci_enable_device(pdev); if (retval) goto err_free; adapter->io = pci_resource_start(pdev, 1); adapter->irq = pdev->irq; printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n", (char *) ent->driver_data, pci_name(pdev)); retval = fcpcipnp_setup(adapter); if (retval) goto err_free; return 0; err_free: delete_adapter(adapter); err: return retval;}#ifdef __ISAPNP__static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id){ struct fritz_adapter *adapter; int retval; if (!pdev) return(-ENODEV); retval = -ENOMEM; adapter = new_adapter(); if (!adapter) goto err; pnp_set_drvdata(pdev, adapter); adapter->type = AVM_FRITZ_PNP; pnp_disable_dev(pdev); retval = pnp_activate_dev(pdev); if (retval < 0) { printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __FUNCTION__, (char *)dev_id->driver_data, retval); goto err_free; } adapter->io = pnp_port_start(pdev, 0); adapter->irq = pnp_irq(pdev, 0); printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at IO %#x irq %d\n", (char *) dev_id->driver_data, adapter->io, adapter->irq); retval = fcpcipnp_setup(adapter); if (retval) goto err_free; return 0; err_free: delete_adapter(adapter); err: return retval;}static void __devexit fcpnp_remove(struct pnp_dev *pdev){ struct fritz_adapter *adapter = pnp_get_drvdata(pdev); if (adapter) { fcpcipnp_release(adapter); delete_adapter(adapter); } pnp_disable_dev(pdev);}static struct pnp_driver fcpnp_driver = { .name = "fcpnp", .probe = fcpnp_probe, .remove = __devexit_p(fcpnp_remove), .id_table = fcpnp_ids,};#endifstatic void __devexit fcpci_remove(struct pci_dev *pdev){ struct fritz_adapter *adapter = pci_get_drvdata(pdev); fcpcipnp_release(adapter); pci_disable_device(pdev); delete_adapter(adapter);}static struct pci_driver fcpci_driver = { .name = "fcpci", .probe = fcpci_probe, .remove = __devexit_p(fcpci_remove), .id_table = fcpci_ids,};static int __init hisax_fcpcipnp_init(void){ int retval; printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n"); retval = pci_register_driver(&fcpci_driver); if (retval) goto out;#ifdef __ISAPNP__ retval = pnp_register_driver(&fcpnp_driver); if (retval < 0) goto out_unregister_pci;#endif return 0; out_unregister_pci: pci_unregister_driver(&fcpci_driver); out: return retval;}static void __exit hisax_fcpcipnp_exit(void){#ifdef __ISAPNP__ pnp_unregister_driver(&fcpnp_driver);#endif pci_unregister_driver(&fcpci_driver);}module_init(hisax_fcpcipnp_init);module_exit(hisax_fcpcipnp_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -