📄 wcte11xp.c
字号:
}static void t1xxp_receiveprep(struct t1 *wc, int ints){ volatile unsigned char *rxbuf; volatile unsigned int *canary; int x; int y; unsigned int oldcan; if (ints & 0x04) { /* Just received first buffer */ rxbuf = wc->readchunk; canary = (unsigned int *)(wc->readchunk + ZT_CHUNKSIZE * 64 - 4); } else { rxbuf = wc->readchunk + ZT_CHUNKSIZE * 32; canary = (unsigned int *)(wc->readchunk + ZT_CHUNKSIZE * 32 - 4); } oldcan = *canary; if (((oldcan & 0xffff0000) >> 16) != CANARY) { /* Check top part */ if (debug) printk("Expecting top %04x, got %04x\n", CANARY, (oldcan & 0xffff0000) >> 16); wc->span.irqmisses++; } else if ((oldcan & 0xffff) != ((wc->canary - 1) & 0xffff)) { if (debug) printk("Expecting bottom %d, got %d\n", wc->canary - 1, oldcan & 0xffff); wc->span.irqmisses++; } for (y=0;y<ZT_CHUNKSIZE;y++) { for (x=0;x<wc->span.channels;x++) { /* XXX Optimize, remove * and + XXX */ /* Must map received channels into appropriate data */ wc->chans[x].readchunk[y] = rxbuf[32 * y + ((wc->chanmap[x] + WC_OFFSET + wc->offset) & 0x1f)]; } if (wc->spantype != TYPE_E1) { for (x=3;x<32;x+=4) { if (rxbuf[32 * y + ((x + WC_OFFSET) & 0x1f)] == 0x7f) { if (wc->offset != (x-3)) { /* Resync */ control_set_reg(wc, WC_CLOCK, 0x06 | wc->sync | clockextra); wc->clocktimeout = 100;#if 1 if (debug) printk("T1: Lost our place, resyncing\n");#endif } } } } else { if (!wc->clocktimeout && !wc->span.alarms) { if ((rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)] & 0x7f) != 0x1b) { if (wc->miss) { if (debug) printk("Double miss (%d, %d)...\n", wc->misslast, rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)]); control_set_reg(wc, WC_CLOCK, 0x06 | wc->sync | clockextra); wc->clocktimeout = 100; } else { wc->miss = 1; wc->misslast = rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)]; } } else { wc->miss = 0; } } else { wc->miss = 0; } } } /* 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 __t1_check_alarms(struct t1 *wc){ unsigned char c,d; int alarms; int x,j; if (!(wc->span.flags & ZT_FLAG_RUNNING)) return; c = __t1_framer_in(wc, 0x4c); if (wc->spanflags & FLAG_FALC12) d = __t1_framer_in(wc, 0x4f); else d = __t1_framer_in(wc, 0x4d); /* Assume no alarms */ alarms = 0; /* And consider only carrier alarms */ wc->span.alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN); if (wc->spantype == TYPE_E1) { if (c & 0x04) { /* No multiframe found, force RAI high after 400ms only if we haven't found a multiframe since last loss of frame */ if (!(wc->spanflags & FLAG_NMF)) { __t1_framer_out(wc, 0x20, 0x9f | 0x20); /* LIM0: Force RAI High */ wc->spanflags |= FLAG_NMF; printk("NMF workaround on!\n"); } __t1_framer_out(wc, 0x1e, 0xc3); /* Reset to CRC4 mode */ __t1_framer_out(wc, 0x1c, 0xf2); /* Force Resync */ __t1_framer_out(wc, 0x1c, 0xf0); /* Force Resync */ } else if (!(c & 0x02)) { if ((wc->spanflags & FLAG_NMF)) { __t1_framer_out(wc, 0x20, 0x9f); /* LIM0: Clear forced RAI */ wc->spanflags &= ~FLAG_NMF; printk("NMF workaround off!\n"); } } } else { /* Detect loopup code if we're not sending one */ if ((!wc->span.mainttimer) && (d & 0x08)) { /* Loop-up code detected */ if ((wc->loopupcnt++ > 80) && (wc->span.maintstat != ZT_MAINT_REMOTELOOP)) { __t1_framer_out(wc, 0x36, 0x08); /* LIM0: Disable any local loop */ __t1_framer_out(wc, 0x37, 0xf6 ); /* LIM1: Enable remote loop */ wc->span.maintstat = ZT_MAINT_REMOTELOOP; } } else wc->loopupcnt = 0; /* Same for loopdown code */ if ((!wc->span.mainttimer) && (d & 0x10)) { /* Loop-down code detected */ if ((wc->loopdowncnt++ > 80) && (wc->span.maintstat == ZT_MAINT_REMOTELOOP)) { __t1_framer_out(wc, 0x36, 0x08); /* LIM0: Disable any local loop */ __t1_framer_out(wc, 0x37, 0xf0 ); /* LIM1: Disable 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->span.chans[x].flags & ZT_FLAG_OPEN) || (wc->span.chans[x].flags & ZT_FLAG_NETDEV)) j++; if (!j) alarms |= ZT_ALARM_NOTOPEN; } if (c & 0xa0) { if (wc->alarmcount >= alarmdebounce) alarms |= ZT_ALARM_RED; else wc->alarmcount++; } else wc->alarmcount = 0; if (c & 0x4) alarms |= ZT_ALARM_BLUE; if (((!wc->span.alarms) && alarms) || (wc->span.alarms && (!alarms))) wc->checktiming = 1; /* Keep track of recovering */ if ((!alarms) && wc->span.alarms) wc->alarmtimer = ZT_ALARMSETTLE_TIME; if (wc->alarmtimer) alarms |= ZT_ALARM_RECOVER; /* If receiving alarms, go into Yellow alarm state */ if (alarms && !(wc->spanflags & FLAG_SENDINGYELLOW)) { unsigned char fmr4;#if 1 printk("wcte1xxp: Setting yellow alarm\n");#endif /* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */ fmr4 = __t1_framer_in(wc, 0x20); __t1_framer_out(wc, 0x20, fmr4 | 0x20); wc->spanflags |= FLAG_SENDINGYELLOW; } else if ((!alarms) && (wc->spanflags & FLAG_SENDINGYELLOW)) { unsigned char fmr4;#if 1 printk("wcte1xxp: Clearing yellow alarm\n");#endif /* We manually do yellow alarm to handle RECOVER */ fmr4 = __t1_framer_in(wc, 0x20); __t1_framer_out(wc, 0x20, fmr4 & ~0x20); wc->spanflags &= ~FLAG_SENDINGYELLOW; } /* Re-check the timing source when we enter/leave alarm, not withstanding yellow alarm */ if (c & 0x10) alarms |= ZT_ALARM_YELLOW; if (wc->span.mainttimer || wc->span.maintstat) alarms |= ZT_ALARM_LOOPBACK; wc->span.alarms = alarms; zt_alarm_notify(&wc->span);}static void __t1_do_counters(struct t1 *wc){ if (wc->alarmtimer) { if (!--wc->alarmtimer) { wc->span.alarms &= ~(ZT_ALARM_RECOVER); 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 t1 *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, 0x04 | wc->sync | clockextra); 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 */ __t1_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: break; case 2: __t1_check_sigbits(wc); break; case 4: /* Check alarms 1/4 as frequently */ if (!(wc->intcount & 0x30)) __t1_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 t1 *wc){ unsigned int falcver; unsigned int x; /* 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); if (t1e1override > -1) { if (t1e1override) wc->spantype = TYPE_E1; else wc->spantype = TYPE_T1; } else { if (control_get_reg(wc, WC_CLOCK) & 0x20) wc->spantype = TYPE_T1; else wc->spantype = TYPE_E1; } /* Check out the controller */ if (debug); printk("Controller version: %02x\n", control_get_reg(wc, WC_VERSION)); control_set_reg(wc, WC_LEDTEST, 0x00); if (wc->spantype == TYPE_E1) wc->chanmap = chanmap_e1; else wc->chanmap = chanmap_t1; /* Setup clock appropriately */ control_set_reg(wc, WC_CLOCK, 0x06 | wc->sync | clockextra); wc->clocktimeout = 100; /* Perform register test on FALC */ for (x=0;x<256;x++) { t1_framer_out(wc, 0x14, x); if ((falcver = t1_framer_in(wc, 0x14)) != x) printk("Wrote '%x' but read '%x'\n", x, falcver); } t1_framer_out(wc, 0x4a, 0xaa); falcver = t1_framer_in(wc ,0x4a); printk("FALC version: %08x\n", falcver); if (!falcver) wc->spanflags |= FLAG_FALC12; start_alarm(wc); return 0;}static int __devinit t1xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){ int res; struct t1 *wc; unsigned int *canary; if (pci_enable_device(pdev)) { res = -EIO; } else { wc = kmalloc(sizeof(struct t1), GFP_KERNEL); if (wc) { memset(wc, 0x0, sizeof(struct t1)); 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("wcte11xp: 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 */ wc->variety = "Digium Wildcard TE110P T1/E1"; /* 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 t1 *wc){ /* Kill clock */ control_set_reg(wc, WC_CLOCK, 0); /* Turn off LED's */ control_set_reg(wc, WC_LEDTEST, 0);}static void __devexit t1xxp_remove_one(struct pci_dev *pdev){ struct t1 *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, 0x79fe, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard TE110P T1/E1 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(alarmdebounce, int, 0600);module_param(loopback, int, 0600);module_param(t1e1override, int, 0600);module_param(clockextra, int, 0600);module_param(debug, int, 0600);#elseMODULE_PARM(alarmdebounce, "i");MODULE_PARM(loopback, "i");MODULE_PARM(t1e1override, "i");MODULE_PARM(clockextra, "i");MODULE_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 + -