📄 wct4xxp.c
字号:
/* Start DMA, enabling DMA interrupts on read only */ wc->dmactrl = 0xc0000003 | (1 << 29); if (noburst) wc->dmactrl |= (1 << 26); __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); } spin_unlock_irqrestore(&wc->reglock, flags); if (wc->syncs[0] == span->spanno) printk("SPAN %d: Primary Sync Source\n",span->spanno); if (wc->syncs[1] == span->spanno) printk("SPAN %d: Secondary Sync Source\n",span->spanno); if (wc->syncs[2] == span->spanno) printk("SPAN %d: Tertiary Sync Source\n",span->spanno); if (wc->syncs[3] == span->spanno) printk("SPAN %d: Quaternary Sync Source\n",span->spanno); return 0;}static inline void e1_check(struct t4 *wc, int span, int val){ if ((wc->spans[span].channels > 24) && (wc->spans[span].flags & ZT_FLAG_RUNNING) && !(wc->spans[span].alarms) && (!wc->e1recover)) { if (val != 0x1b) { wc->e1check[span]++; } else wc->e1check[span] = 0; if (wc->e1check[span] > 100) { /* Wait 1000 ms */ wc->e1recover = 1000 * 8; memset(wc->e1check, 0, sizeof(wc->e1check)); if (debug) printk("Detected loss of E1 alignment on span %d!\n", span); t4_reset_dma(wc); } }}static void t4_receiveprep(struct t4 *wc, int irq){ volatile unsigned int *readchunk; int dbl = 0; int x,y,z; unsigned int tmp; int offset=0; if (!wc->t1e1) offset = 4; if (irq & 1) { /* First part */ readchunk = wc->readchunk; if (!wc->last0) dbl = 1; wc->last0 = 0; } else { readchunk = wc->readchunk + ZT_CHUNKSIZE * 32; if (wc->last0) dbl = 1; wc->last0 = 1; } if (dbl) { for (x=0;x<4;x++) wc->spans[x].irqmisses++; if (debug) printk("TE410P: Double/missed interrupt detected\n"); } for (x=0;x<ZT_CHUNKSIZE;x++) { for (z=0;z<24;z++) { /* All T1/E1 channels */ tmp = readchunk[z+1+offset]; wc->spans[3].chans[z].readchunk[x] = tmp & 0xff; wc->spans[2].chans[z].readchunk[x] = (tmp & 0xff00) >> 8; wc->spans[1].chans[z].readchunk[x] = (tmp & 0xff0000) >> 16; wc->spans[0].chans[z].readchunk[x] = tmp >> 24; } if (wc->t1e1) { if (wc->e1recover > 0) wc->e1recover--; tmp = readchunk[0]; e1_check(wc, 3, (tmp & 0x7f)); e1_check(wc, 2, (tmp & 0x7f00) >> 8); e1_check(wc, 1, (tmp & 0x7f0000) >> 16); e1_check(wc, 0, (tmp & 0x7f000000) >> 24); for (z=24;z<31;z++) { /* Only E1 channels now */ tmp = readchunk[z+1]; if (wc->spans[3].channels > 24) wc->spans[3].chans[z].readchunk[x] = tmp & 0xff; if (wc->spans[2].channels > 24) wc->spans[2].chans[z].readchunk[x] = (tmp & 0xff00) >> 8; if (wc->spans[1].channels > 24) wc->spans[1].chans[z].readchunk[x] = (tmp & 0xff0000) >> 16; if (wc->spans[0].channels > 24) wc->spans[0].chans[z].readchunk[x] = tmp >> 24; } } /* Advance pointer by 4 TDM frame lengths */ readchunk += 32; } for (x=0;x<4;x++) { if (wc->spans[x].flags & ZT_FLAG_RUNNING) { for (y=0;y<wc->spans[x].channels;y++) { /* Echo cancel double buffered data */ zt_ec_chunk(&wc->spans[x].chans[y], wc->spans[x].chans[y].readchunk, wc->ec_chunk2[x][y]); memcpy(wc->ec_chunk2[x][y],wc->ec_chunk1[x][y], ZT_CHUNKSIZE); memcpy(wc->ec_chunk1[x][y], wc->spans[x].chans[y].writechunk, ZT_CHUNKSIZE); } zt_receive(&wc->spans[x]); } }}static void t4_transmitprep(struct t4 *wc, int irq){ volatile unsigned int *writechunk; int x,y,z; unsigned int tmp; int offset=0; if (!wc->t1e1) offset = 4; if (irq & 1) { /* First part */ writechunk = wc->writechunk + 1; } else { writechunk = wc->writechunk + ZT_CHUNKSIZE * 32 + 1; } for (y=0;y<4;y++) { if (wc->spans[y].flags & ZT_FLAG_RUNNING) zt_transmit(&wc->spans[y]); } for (x=0;x<ZT_CHUNKSIZE;x++) { /* Once per chunk */ for (z=0;z<24;z++) { /* All T1/E1 channels */ tmp = (wc->spans[3].chans[z].writechunk[x]) | (wc->spans[2].chans[z].writechunk[x] << 8) | (wc->spans[1].chans[z].writechunk[x] << 16) | (wc->spans[0].chans[z].writechunk[x] << 24); writechunk[z+offset] = tmp; } if (wc->t1e1) { for (z=24;z<31;z++) { /* Only E1 channels now */ tmp = 0; if (wc->spans[3].channels > 24) tmp |= wc->spans[3].chans[z].writechunk[x]; if (wc->spans[2].channels > 24) tmp |= (wc->spans[2].chans[z].writechunk[x] << 8); if (wc->spans[1].channels > 24) tmp |= (wc->spans[1].chans[z].writechunk[x] << 16); if (wc->spans[0].channels > 24) tmp |= (wc->spans[0].chans[z].writechunk[x] << 24); writechunk[z] = tmp; } } /* Advance pointer by 4 TDM frame lengths */ writechunk += 32; }}static void __t4_check_sigbits(struct t4 *wc, int span){ int a,i,rxs; if (!(wc->spans[span].flags & ZT_FLAG_RUNNING)) return; if (wc->spantype[span] == TYPE_E1) { for (i = 0; i < 15; i++) { a = __t4_framer_in(wc, span, 0x71 + i); /* Get high channel in low bits */ rxs = (a & 0xf); if (!(wc->spans[span].chans[i+16].sig & ZT_SIG_CLEAR)) { if (wc->spans[span].chans[i+16].rxsig != rxs) zt_rbsbits(&wc->spans[span].chans[i+16], rxs); } rxs = (a >> 4) & 0xf; if (!(wc->spans[span].chans[i].sig & ZT_SIG_CLEAR)) { if (wc->spans[span].chans[i].rxsig != rxs) zt_rbsbits(&wc->spans[span].chans[i], rxs); } } } else if (wc->spans[span].lineconfig & ZT_CONFIG_D4) { for (i = 0; i < 24; i+=4) { a = __t4_framer_in(wc, span, 0x70 + (i>>2)); /* Get high channel in low bits */ rxs = (a & 0x3) << 2; if (!(wc->spans[span].chans[i+3].sig & ZT_SIG_CLEAR)) { if (wc->spans[span].chans[i+3].rxsig != rxs) zt_rbsbits(&wc->spans[span].chans[i+3], rxs); } rxs = (a & 0xc); if (!(wc->spans[span].chans[i+2].sig & ZT_SIG_CLEAR)) { if (wc->spans[span].chans[i+2].rxsig != rxs) zt_rbsbits(&wc->spans[span].chans[i+2], rxs); } rxs = (a >> 2) & 0xc; if (!(wc->spans[span].chans[i+1].sig & ZT_SIG_CLEAR)) { if (wc->spans[span].chans[i+1].rxsig != rxs) zt_rbsbits(&wc->spans[span].chans[i+1], rxs); } rxs = (a >> 4) & 0xc; if (!(wc->spans[span].chans[i].sig & ZT_SIG_CLEAR)) { if (wc->spans[span].chans[i].rxsig != rxs) zt_rbsbits(&wc->spans[span].chans[i], rxs); } } } else { for (i = 0; i < 24; i+=2) { a = __t4_framer_in(wc, span, 0x70 + (i>>1)); /* Get high channel in low bits */ rxs = (a & 0xf); if (!(wc->spans[span].chans[i+1].sig & ZT_SIG_CLEAR)) { if (wc->spans[span].chans[i+1].rxsig != rxs) zt_rbsbits(&wc->spans[span].chans[i+1], rxs); } rxs = (a >> 4) & 0xf; if (!(wc->spans[span].chans[i].sig & ZT_SIG_CLEAR)) { if (wc->spans[span].chans[i].rxsig != rxs) zt_rbsbits(&wc->spans[span].chans[i], rxs); } } }}static void __t4_do_counters(struct t4 *wc){ int span; for (span=0;span<4;span++) { if (wc->alarmtimer[span]) { if (!--wc->alarmtimer[span]) { wc->spans[span].alarms &= ~(ZT_ALARM_RECOVER); zt_alarm_notify(&wc->spans[span]); } } }}static void __t4_check_alarms(struct t4 *wc, int span){ unsigned char c,d; int alarms; int x,j; if (!(wc->spans[span].flags & ZT_FLAG_RUNNING)) return; c = __t4_framer_in(wc, span, 0x4c); d = __t4_framer_in(wc, span, 0x4d); /* Assume no alarms */ alarms = 0; /* And consider only carrier alarms */ wc->spans[span].alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN); if (wc->spantype[span] == 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[span] & FLAG_NMF)) { __t4_framer_out(wc, span, 0x20, 0x9f | 0x20); /* LIM0: Force RAI High */ wc->spanflags[span] |= FLAG_NMF; printk("NMF workaround on!\n"); } __t4_framer_out(wc, span, 0x1e, 0xc3); /* Reset to CRC4 mode */ __t4_framer_out(wc, span, 0x1c, 0xf2); /* Force Resync */ __t4_framer_out(wc, span, 0x1c, 0xf0); /* Force Resync */ } else if (!(c & 0x02)) { if ((wc->spanflags[span] & FLAG_NMF)) { __t4_framer_out(wc, span, 0x20, 0x9f); /* LIM0: Clear forced RAI */ wc->spanflags[span] &= ~FLAG_NMF; printk("NMF workaround off!\n"); } } } else { /* Detect loopup code if we're not sending one */ if ((!wc->spans[span].mainttimer) && (d & 0x08)) { /* Loop-up code detected */ if ((wc->loopupcnt[span]++ > 80) && (wc->spans[span].maintstat != ZT_MAINT_REMOTELOOP)) { __t4_framer_out(wc, span, 0x36, 0x08); /* LIM0: Disable any local loop */ __t4_framer_out(wc, span, 0x37, 0xf6 ); /* LIM1: Enable remote loop */ wc->spans[span].maintstat = ZT_MAINT_REMOTELOOP; } } else wc->loopupcnt[span] = 0; /* Same for loopdown code */ if ((!wc->spans[span].mainttimer) && (d & 0x10)) { /* Loop-down code detected */ if ((wc->loopdowncnt[span]++ > 80) && (wc->spans[span].maintstat == ZT_MAINT_REMOTELOOP)) { __t4_framer_out(wc, span, 0x36, 0x08); /* LIM0: Disable any local loop */ __t4_framer_out(wc, span, 0x37, 0xf0 ); /* LIM1: Disable remote loop */ wc->spans[span].maintstat = ZT_MAINT_NONE; } } else wc->loopdowncnt[span] = 0; } if (wc->spans[span].lineconfig & ZT_CONFIG_NOTOPEN) { for (x=0,j=0;x < wc->spans[span].channels;x++) if ((wc->spans[span].chans[x].flags & ZT_FLAG_OPEN) || (wc->spans[span].chans[x].flags & ZT_FLAG_NETDEV)) j++; if (!j) alarms |= ZT_ALARM_NOTOPEN; } if (c & 0xa0) { if (wc->alarmcount[span] >= alarmdebounce) alarms |= ZT_ALARM_RED; else wc->alarmcount[span]++; } else wc->alarmcount[span] = 0; if (c & 0x4) alarms |= ZT_ALARM_BLUE; if (((!wc->spans[span].alarms) && alarms) || (wc->spans[span].alarms && (!alarms))) wc->checktiming = 1; /* Keep track of recovering */ if ((!alarms) && wc->spans[span].alarms) wc->alarmtimer[span] = ZT_ALARMSETTLE_TIME; if (wc->alarmtimer[span]) alarms |= ZT_ALARM_RECOVER; /* If receiving alarms, go into Yellow alarm state */ if (alarms && !(wc->spanflags[span] & FLAG_SENDINGYELLOW)) { unsigned char fmr4;#if 1 printk("wct4xxp: Setting yellow alarm on span %d\n", span + 1);#endif /* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */ fmr4 = __t4_framer_in(wc, span, 0x20); __t4_framer_out(wc, span, 0x20, fmr4 | 0x20); wc->spanflags[span] |= FLAG_SENDINGYELLOW; } else if ((!alarms) && (wc->spanflags[span] & FLAG_SENDINGYELLOW)) { unsigned char fmr4;#if 1 printk("wct4xxp: Clearing yellow alarm on span %d\n", span + 1);#endif /* We manually do yellow alarm to handle RECOVER */ fmr4 = __t4_framer_in(wc, span, 0x20); __t4_framer_out(wc, span, 0x20, fmr4 & ~0x20); wc->spanflags[span] &= ~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->spans[span].mainttimer || wc->spans[span].maintstat) alarms |= ZT_ALARM_LOOPBACK; wc->spans[span].alarms = alarms; zt_alarm_notify(&wc->spans[span]);}static inline void __handle_leds(struct t4 *wc){ int x; wc->blinktimer++; for (x=0;x<4;x++) { if (wc->spans[x].flags & ZT_FLAG_RUNNING) { if (wc->spans[x].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE)) {#ifdef FANCY_ALARM if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) { __t4_set_led(wc, x, WC_RED); } if (wc->blinktimer == 0xf) { __t4_set_led(wc, x, WC_OFF); }#else if (wc->blinktimer == 160) { __t4_set_led(wc, x, WC_RED); } else if (wc->blinktimer == 480) { __t4_set_led(wc, x, WC_OFF); }#endif } else if (wc->spans[x].alarms & ZT_ALARM_YELLOW) { /* Yellow Alarm */ __t4_set_led(wc, x, WC_YELLOW); } else if (wc->spans[x].mainttimer || wc->spans[x].maintstat) {#ifdef FANCY_ALARM if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) { __t4_set_led(wc, x, WC_GREEN); } if (wc->blinktimer == 0xf) { __t4_set_led(wc, x, WC_OFF); }#else if (wc->blinktimer == 160) { __t4_set_led(wc, x, WC_GREEN); } else if (wc->blinktimer == 480) { __t4_set_led(wc, x, WC_OFF); }#endif } else { /* No Alarm */ __t4_set_led(wc, x, WC_GREEN); } } else __t4_set_led(wc, x, WC_OFF); }#ifdef FANCY_ALARM if (wc->blinktimer == 0xf) { wc->blinktimer = -1; wc->alarmpos++; if (wc->alarmpos >= (sizeof(altab) / sizeof(altab[0]))) wc->alarmpos = 0; }#else if (wc->blinktimer == 480) wc->blinktimer = 0;#endif}#ifdef LINUX26static irqreturn_t t4_interrupt(int irq, void *dev_id, struct pt_regs *regs)#elsestatic void t4_interrupt(int irq, void *dev_id, struct pt_regs *regs)#endif{ struct t4 *wc = dev_id; unsigned long flags; int x; unsigned int status;#if 0 unsigned int status2;#endif#if 0 if (wc->intcount < 20) printk("Pre-interrupt\n");#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -