📄 wct1xxp.c
字号:
} } } /* Store the next canary */ canary = (unsigned int *)(rxbuf + ZT_CHUNKSIZE * 32 - 4); *canary = (wc->canary++) | (CANARY << 16); for (x=0;x<wc->span.channels;x++) { zt_ec_chunk(&wc->chans[x], wc->chans[x].readchunk, wc->ec_chunk2[x]); memcpy(wc->ec_chunk2[x],wc->ec_chunk1[x],ZT_CHUNKSIZE); memcpy(wc->ec_chunk1[x],wc->chans[x].writechunk,ZT_CHUNKSIZE); } zt_receive(&wc->span);}static void __t1xxp_check_sigbits(struct t1xxp *wc, int x){ int a,b,i,y,rxs; if (wc->ise1) { /* Read 5 registers at a time, loading 10 channels at a time */ for (i = (x * 5); i < (x * 5) + 5; i++) { a = __t1_get_reg(wc, 0x31 + i); /* Get high channel in low bits */ rxs = (a & 0xf); if (!(wc->chans[i+16].sig & ZT_SIG_CLEAR)) { if (wc->chans[i+16].rxsig != rxs) zt_rbsbits(&wc->chans[i+16], rxs); } rxs = (a >> 4) & 0xf; if (!(wc->chans[i].sig & ZT_SIG_CLEAR)) { if (wc->chans[i].rxsig != rxs) zt_rbsbits(&wc->chans[i], rxs); } } } else { a = __t1_get_reg(wc, 0x60 + x); b = __t1_get_reg(wc, 0x63 + x); for (y=0;y<8;y++) { i = x * 8 + y; rxs = 0; if (a & (1 << y)) rxs |= ZT_ABIT; if (b & (1 << y)) rxs |= ZT_BBIT; if (!(wc->chans[i].sig & ZT_SIG_CLEAR)) { if (wc->chans[i].rxsig != rxs) zt_rbsbits(&wc->chans[i], rxs); } } }}static void __t1xxp_check_alarms(struct t1xxp *wc){ unsigned char c,d; int alarms; int x,j; if (wc->ise1) { __t1_set_reg(wc, 0x06, 0xff); c = __t1_get_reg(wc, 0x6); } else { /* Get RIR2 */ c = __t1_get_reg(wc, 0x31); wc->span.rxlevel = c >> 6; /* Get status register s*/ __t1_set_reg(wc, 0x20, 0xff); c = __t1_get_reg(wc, 0x20); } /* Assume no alarms */ alarms = 0; /* And consider only carrier alarms */ wc->span.alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN); if (wc->ise1) { /* XXX Implement me XXX */ } else { /* Detect loopup code if we're not sending one */ if ((!wc->span.mainttimer) && (c & 0x80)) { /* Loop-up code detected */ if ((wc->loopupcnt++ > 80) && (wc->span.maintstat != ZT_MAINT_REMOTELOOP)) { __t1_set_reg(wc, 0x1e, 0); /* No local loop */ __t1_set_reg(wc, 0x0a, 0x40); /* Remote Loop */ wc->span.maintstat = ZT_MAINT_REMOTELOOP; } } else { wc->loopupcnt = 0; } /* Same for loopdown code */ if ((!wc->span.mainttimer) && (c & 0x40)) { /* Loop-down code detected */ if ((wc->loopdowncnt++ > 80) && (wc->span.maintstat == ZT_MAINT_REMOTELOOP)) { __t1_set_reg(wc, 0x1e, 0); /* No local loop */ __t1_set_reg(wc, 0x0a, 0x0); /* No remote Loop */ wc->span.maintstat = ZT_MAINT_NONE; } } else wc->loopdowncnt = 0; } if (wc->span.lineconfig & ZT_CONFIG_NOTOPEN) { for (x=0,j=0;x < wc->span.channels;x++) if ((wc->chans[x].flags & ZT_FLAG_OPEN) || (wc->chans[x].flags & ZT_FLAG_NETDEV)) j++; if (!j) alarms |= ZT_ALARM_NOTOPEN; } if (wc->ise1) { if (c & 0x9) alarms |= ZT_ALARM_RED; if (c & 0x2) alarms |= ZT_ALARM_BLUE; } else { /* Check actual alarm status */ if (c & 0x3) alarms |= ZT_ALARM_RED; if (c & 0x8) alarms |= ZT_ALARM_BLUE; } /* Keep track of recovering */ if ((!alarms) && wc->span.alarms) wc->alarmtimer = ZT_ALARMSETTLE_TIME; /* If receiving alarms, go into Yellow alarm state */ if (alarms && (!wc->span.alarms)) {#if 0 printk("Going into yellow alarm\n");#endif if (wc->ise1) __t1_set_reg(wc, 0x21, 0x7f); else __t1_set_reg(wc, 0x35, 0x11); } if (wc->span.alarms != alarms) { d = __control_get_reg(wc, WC_CLOCK); start_alarm(wc); if (!(alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_LOOPBACK)) && wc->sync) { /* Use the recieve signalling */ wc->span.syncsrc = wc->span.spanno; d |= 1; } else { wc->span.syncsrc = 0; d &= ~1; } __control_set_reg(wc, WC_CLOCK, d); } if (wc->alarmtimer) alarms |= ZT_ALARM_RECOVER; if (c & 0x4) alarms |= ZT_ALARM_YELLOW; wc->span.alarms = alarms; zt_alarm_notify(&wc->span);}static void __t1xxp_do_counters(struct t1xxp *wc){ if (wc->alarmtimer) { if (!--wc->alarmtimer) { wc->span.alarms &= ~(ZT_ALARM_RECOVER); /* Clear yellow alarm */#if 0 printk("Coming out of alarm\n");#endif if (wc->ise1) __t1_set_reg(wc, 0x21, 0x5f); else __t1_set_reg(wc, 0x35, 0x10); zt_alarm_notify(&wc->span); } }}#ifdef LINUX26static irqreturn_t t1xxp_interrupt(int irq, void *dev_id, struct pt_regs *regs)#elsestatic void t1xxp_interrupt(int irq, void *dev_id, struct pt_regs *regs)#endif{ struct t1xxp *wc = dev_id; unsigned char ints; unsigned long flags; int x; ints = inb(wc->ioaddr + WC_INTSTAT); outb(ints, wc->ioaddr + WC_INTSTAT); if (!ints)#ifdef LINUX26 return IRQ_NONE;#else return;#endif if (!wc->intcount) { if (debug) printk("Got interrupt: 0x%04x\n", ints); } wc->intcount++; if (wc->clocktimeout && !--wc->clocktimeout) control_set_reg(wc, WC_CLOCK, 0x00 | wc->sync | wc->ise1); if (ints & 0x0f) { t1xxp_receiveprep(wc, ints); t1xxp_transmitprep(wc, ints); } spin_lock_irqsave(&wc->lock, flags);#if 1 __handle_leds(wc);#endif /* Count down timers */ __t1xxp_do_counters(wc); /* Do some things that we don't have to do very often */ x = wc->intcount & 15 /* 63 */; switch(x) { case 0: case 1: case 2: __t1xxp_check_sigbits(wc, x); break; case 4: /* Check alarms 1/4 as frequently */ if (!(wc->intcount & 0x30)) __t1xxp_check_alarms(wc); break; } spin_unlock_irqrestore(&wc->lock, flags); if (ints & 0x10) printk("PCI Master abort\n"); if (ints & 0x20) printk("PCI Target abort\n");#ifdef LINUX26 return IRQ_RETVAL(1);#endif }static int t1xxp_hardware_init(struct t1xxp *wc){ /* Hardware PCI stuff */ /* Reset chip and registers */ outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL); /* Set all outputs to 0 */ outb(0x00, wc->ioaddr + WC_AUXD); /* Set all to outputs except AUX1 (TDO). */ outb(0xfd, wc->ioaddr + WC_AUXC); /* Configure the serial port: double clock, 20ns width, no inversion, MSB first */ outb(0xc8, wc->ioaddr + WC_SERC); /* Internally delay FSC by one */ outb(0x01, wc->ioaddr + WC_FSCDELAY); /* Back to normal, with automatic DMA wrap around */ outb(DELAY | 0x01, wc->ioaddr + WC_CNTL); /* Make sure serial port and DMA are out of reset */ outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, WC_CNTL); /* Setup DMA Addresses */ /* Start at writedma */ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */ /* First frame */ outl(wc->writedma + ZT_CHUNKSIZE * 32 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */ /* Second frame */ outl(wc->writedma + ZT_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMAWE); /* End */ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */ /* First frame */ outl(wc->readdma + ZT_CHUNKSIZE * 32 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */ /* Second frame */ outl(wc->readdma + ZT_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMARE); /* End */ if (debug) printk("Setting up DMA (write/read = %08lx/%08lx)\n", (long)wc->writedma, (long)wc->readdma); /* Check out the controller */ if (debug) printk("Controller version: %02x\n", control_get_reg(wc, WC_VERSION)); control_set_reg(wc, WC_LEDTEST, 0x00); /* Sanity check also determines e1 or t1 */ if (t1xxp_framer_sanity_check(wc)) return -1; if (wc->ise1) wc->chanmap = chanmap_e1; else wc->chanmap = chanmap_t1; /* Setup clock appropriately */ control_set_reg(wc, WC_CLOCK, 0x02 | wc->sync | wc->ise1); wc->clocktimeout = 100; /* Reset the T1 and report */ t1xxp_framer_hard_reset(wc); start_alarm(wc); return 0;}static int __devinit t1xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){ int res; struct t1xxp *wc; unsigned int *canary; if (pci_enable_device(pdev)) { res = -EIO; } else { wc = kmalloc(sizeof(struct t1xxp), GFP_KERNEL); if (wc) { memset(wc, 0x0, sizeof(struct t1xxp)); spin_lock_init(&wc->lock); wc->ioaddr = pci_resource_start(pdev, 0); wc->dev = pdev; wc->offset = 28; /* And you thought 42 was the answer */ wc->writechunk = /* 32 channels, Double-buffer, Read/Write */ (unsigned char *)pci_alloc_consistent(pdev, ZT_MAX_CHUNKSIZE * 32 * 2 * 2, &wc->writedma); if (!wc->writechunk) { printk("wct1xxp: Unable to allocate DMA-able memory\n"); return -ENOMEM; } /* Read is after the whole write piece (in bytes) */ wc->readchunk = wc->writechunk + ZT_CHUNKSIZE * 32 * 2; /* Same thing... */ wc->readdma = wc->writedma + ZT_CHUNKSIZE * 32 * 2; /* Initialize Write/Buffers to all blank data */ memset((void *)wc->writechunk,0x00,ZT_MAX_CHUNKSIZE * 2 * 2 * 32); /* Initialize canary */ canary = (unsigned int *)(wc->readchunk + ZT_CHUNKSIZE * 64 - 4); *canary = (CANARY << 16) | (0xffff); /* Enable bus mastering */ pci_set_master(pdev); /* Keep track of which device we are */ pci_set_drvdata(pdev, wc); if (request_irq(pdev->irq, t1xxp_interrupt, SA_INTERRUPT | SA_SHIRQ, "t1xxp", wc)) { printk("t1xxp: Unable to request IRQ %d\n", pdev->irq); kfree(wc); return -EIO; } /* Initialize hardware */ t1xxp_hardware_init(wc); /* We now know which version of card we have */ if (wc->ise1) wc->variety = "Digium Wildcard E100P E1/PRA"; else wc->variety = "Digium Wildcard T100P T1/PRI"; /* Misc. software stuff */ t1xxp_software_init(wc); printk("Found a Wildcard: %s\n", wc->variety); res = 0; } else res = -ENOMEM; } return res;}static void t1xxp_stop_stuff(struct t1xxp *wc){ /* Kill clock */ control_set_reg(wc, WC_CLOCK, 0); /* Turn off LED's */ control_set_reg(wc, WC_LEDTEST, 0); /* Reset the T1 */ t1xxp_framer_hard_reset(wc);}static void __devexit t1xxp_remove_one(struct pci_dev *pdev){ struct t1xxp *wc = pci_get_drvdata(pdev); if (wc) { /* Stop any DMA */ __t1xxp_stop_dma(wc); /* In case hardware is still there */ __t1xxp_disable_interrupts(wc); t1xxp_stop_stuff(wc); /* Immediately free resources */ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 32 * 4, (void *)wc->writechunk, wc->writedma); free_irq(pdev->irq, wc); /* Reset PCI chip and registers */ outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL); /* Release span, possibly delayed */ if (!wc->usecount) t1xxp_release(wc); else wc->dead = 1; }}static struct pci_device_id t1xxp_pci_tbl[] = { { 0xe159, 0x0001, 0x6159, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard T100P T1/PRI or E100P E1/PRA Board" }, { 0 }};MODULE_DEVICE_TABLE(pci,t1xxp_pci_tbl);static struct pci_driver t1xxp_driver = { name: "t1xxp", probe: t1xxp_init_one,#ifdef LINUX26 remove: __devexit_p(t1xxp_remove_one),#else remove: t1xxp_remove_one,#endif suspend: NULL, resume: NULL, id_table: t1xxp_pci_tbl,};static int __init t1xxp_init(void){ int res; res = pci_module_init(&t1xxp_driver); if (res) return -ENODEV; return 0;}static void __exit t1xxp_cleanup(void){ pci_unregister_driver(&t1xxp_driver);}#ifdef LINUX26module_param(debug, int, 0600);#elseMODULE_PARM(debug, "i");#endifMODULE_DESCRIPTION("Wildcard T100P/E100P Zaptel Driver");MODULE_AUTHOR("Mark Spencer <markster@linux-support.net>");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifmodule_init(t1xxp_init);module_exit(t1xxp_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -