📄 wcfxs.c
字号:
static inline void wcfxs_proslic_check_hook(struct wcfxs *wc, int card){ char res; int hook; /* For some reason we have to debounce the hook detector. */ res = wcfxs_getreg(wc, card, 68); hook = (res & 1); if (hook != wc->mod.fxs.lastrxhook[card]) { /* Reset the debounce (must be multiple of 4ms) */ wc->mod.fxs.debounce[card] = 8 * (4 * 8);#if 0 printk("Resetting debounce card %d hook %d, %d\n", card, hook, wc->mod.fxs.debounce[card]);#endif } else { if (wc->mod.fxs.debounce[card] > 0) { wc->mod.fxs.debounce[card]-= 4 * ZT_CHUNKSIZE;#if 0 printk("Sustaining hook %d, %d\n", hook, wc->mod.fxs.debounce[card]);#endif if (!wc->mod.fxs.debounce[card]) {#if 0 printk("Counted down debounce, newhook: %d...\n", hook);#endif wc->mod.fxs.debouncehook[card] = hook; } if (!wc->mod.fxs.oldrxhook[card] && wc->mod.fxs.debouncehook[card]) { /* Off hook */#if 1 if (debug)#endif printk("wcfxs: Card %d Going off hook\n", card); zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); if (robust) wcfxs_init_proslic(wc, card, 1, 0, 1); wc->mod.fxs.oldrxhook[card] = 1; } else if (wc->mod.fxs.oldrxhook[card] && !wc->mod.fxs.debouncehook[card]) { /* On hook */#if 1 if (debug)#endif printk("wcfxs: Card %d Going on hook\n", card); zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK); wc->mod.fxs.oldrxhook[card] = 0; } } } wc->mod.fxs.lastrxhook[card] = hook; }static inline void wcfxs_proslic_recheck_sanity(struct wcfxs *wc, int card){ int res; /* Check loopback */ res = wcfxs_getreg(wc, card, 8); if (res) { printk("Ouch, part reset, quickly restoring reality (%d)\n", card); wcfxs_init_proslic(wc, card, 1, 0, 1); } else { res = wcfxs_getreg(wc, card, 64); if (!res && (res != wc->mod.fxs.lasttxhook[card])) { if (wc->mod.fxs.palarms[card]++ < MAX_ALARMS) { printk("Power alarm on module %d, resetting!\n", card + 1); if (wc->mod.fxs.lasttxhook[card] == 4) wc->mod.fxs.lasttxhook[card] = 1; wcfxs_setreg(wc, card, 64, wc->mod.fxs.lasttxhook[card]); } else { if (wc->mod.fxs.palarms[card] == MAX_ALARMS) printk("Too many power alarms on card %d, NOT resetting!\n", card + 1); } } }}#ifdef LINUX26static irqreturn_t wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs)#elsestatic void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs)#endif{ struct wcfxs *wc = dev_id; unsigned char ints; 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 (ints & 0x10) { /* Stop DMA, wait for watchdog */ printk("TDM PCI Master abort\n"); wcfxs_stop_dma(wc);#ifdef LINUX26 return IRQ_RETVAL(1);#else return;#endif } if (ints & 0x20) { printk("PCI Target abort\n");#ifdef LINUX26 return IRQ_RETVAL(1);#else return;#endif } for (x=0;x<4;x++) { if ((x < wc->cards) && (wc->cardflag & (1 << x)) && (wc->modtype[x] == MOD_TYPE_FXS)) { if (wc->mod.fxs.lasttxhook[x] == 0x4) { /* RINGing, prepare for OHT */ wc->mod.fxs.ohttimer[x] = OHT_TIMER << 3; wc->mod.fxs.idletxhookstate[x] = 0x2; /* OHT mode when idle */ } else { if (wc->mod.fxs.ohttimer[x]) { wc->mod.fxs.ohttimer[x]-= ZT_CHUNKSIZE; if (!wc->mod.fxs.ohttimer[x]) { wc->mod.fxs.idletxhookstate[x] = 0x1; /* Switch to active */ if (wc->mod.fxs.lasttxhook[x] == 0x2) { /* Apply the change if appropriate */ wc->mod.fxs.lasttxhook[x] = 0x1; wcfxs_setreg(wc, x, 64, wc->mod.fxs.lasttxhook[x]); } } } } } } if (ints & 0x0f) { wc->intcount++; x = wc->intcount % 4; if ((x < wc->cards) && (wc->cardflag & (1 << x))) { if (wc->modtype[x] == MOD_TYPE_FXS) { wcfxs_proslic_check_hook(wc, x); if (!(wc->intcount & 0xfc)) wcfxs_proslic_recheck_sanity(wc, x); } else if (wc->modtype[x] == MOD_TYPE_FXO) { wcfxs_voicedaa_check_hook(wc, x); } } if (!(wc->intcount % 10000)) { /* Accept an alarm once per 10 seconds */ for (x=0;x<4;x++) if (wc->modtype[x] == MOD_TYPE_FXS) { if (wc->mod.fxs.palarms[x]) wc->mod.fxs.palarms[x]--; } } wcfxs_receiveprep(wc, ints); wcfxs_transmitprep(wc, ints); }#ifdef LINUX26 return IRQ_RETVAL(1);#endif }static int wcfxs_voicedaa_insane(struct wcfxs *wc, int card){ int blah; blah = wcfxs_getreg(wc, card, 2); if (blah != 0x3) return -2; blah = wcfxs_getreg(wc, card, 11); if (debug) printk("VoiceDAA System: %02x\n", blah & 0xf); return 0;}static int wcfxs_proslic_insane(struct wcfxs *wc, int card){ int blah,insane_report; insane_report=0; blah = wcfxs_getreg(wc, card, 0); if (debug) printk("ProSLIC on module %d, product %d, version %d\n", card, (blah & 0x30) >> 4, (blah & 0xf));#if 0 if ((blah & 0x30) >> 4) { printk("ProSLIC on module %d is not a 3210.\n", card); return -1; }#endif if (((blah & 0xf) == 0) || ((blah & 0xf) == 0xf)) { /* SLIC not loaded */ return -1; } if ((blah & 0xf) < 3) { printk("ProSLIC 3210 version %d is too old\n", blah & 0xf); return -1; } blah = wcfxs_getreg(wc, card, 8); if (blah != 0x2) { printk("ProSLIC on module %d insane (1) %d should be 2\n", card, blah); return -1; } else if ( insane_report) printk("ProSLIC on module %d Reg 8 Reads %d Expected is 0x2\n",card,blah); blah = wcfxs_getreg(wc, card, 64); if (blah != 0x0) { printk("ProSLIC on module %d insane (2)\n", card); return -1; } else if ( insane_report) printk("ProSLIC on module %d Reg 64 Reads %d Expected is 0x0\n",card,blah); blah = wcfxs_getreg(wc, card, 11); if (blah != 0x33) { printk("ProSLIC on module %d insane (3)\n", card); return -1; } else if ( insane_report) printk("ProSLIC on module %d Reg 11 Reads %d Expected is 0x33\n",card,blah); /* Just be sure it's setup right. */ wcfxs_setreg(wc, card, 30, 0); if (debug) printk("ProSLIC on module %d seems sane.\n", card); return 0;}static int wcfxs_proslic_powerleak_test(struct wcfxs *wc, int card){ unsigned long origjiffies; unsigned char vbat; /* Turn off linefeed */ wcfxs_setreg(wc, card, 64, 0); /* Power down */ wcfxs_setreg(wc, card, 14, 0x10); /* Wait for one second */ origjiffies = jiffies; while((vbat = wcfxs_getreg(wc, card, 82)) > 0x6) { if ((jiffies - origjiffies) >= (HZ/2)) break;; } if (vbat < 0x06) { printk("Excessive leakage detected on module %d: %d volts (%02x) after %d ms\n", card, 376 * vbat / 1000, vbat, (int)((jiffies - origjiffies) * 1000 / HZ)); return -1; } else if (debug) { printk("Post-leakage voltage: %d volts\n", 376 * vbat / 1000); } return 0;}static int wcfxs_powerup_proslic(struct wcfxs *wc, int card, int fast){ unsigned char vbat; unsigned long origjiffies; int lim; /* Set period of DC-DC converter to 1/64 khz */ wcfxs_setreg(wc, card, 92, 0xff /* was 0xff */); /* Wait for VBat to powerup */ origjiffies = jiffies; /* Disable powerdown */ wcfxs_setreg(wc, card, 14, 0); /* If fast, don't bother checking anymore */ if (fast) return 0; while((vbat = wcfxs_getreg(wc, card, 82)) < 0xc0) { /* Wait no more than 500ms */ if ((jiffies - origjiffies) > HZ/2) { break; } } if (vbat < 0xc0) { printk("ProSLIC on module %d failed to powerup within %d ms (%d mV only)\n\n -- DID YOU REMEMBER TO PLUG IN THE HD POWER CABLE TO THE TDM400P??\n", card, (int)(((jiffies - origjiffies) * 1000 / HZ)), vbat * 375); return -1; } else if (debug) { printk("ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n", card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ))); } /* Proslic max allowed loop current, reg 71 LOOP_I_LIMIT */ /* If out of range, just set it to the default value */ lim = (loopcurrent - 20) / 3; if ( loopcurrent > 41 ) { lim = 0; if (debug) printk("Loop current out of range! Setting to default 20mA!\n"); } else if (debug) printk("Loop current set to %dmA!\n",(lim*3)+20); wcfxs_setreg(wc,card,LOOP_I_LIMIT,lim); /* Engage DC-DC converter */ wcfxs_setreg(wc, card, 93, 0x19 /* was 0x19 */);#if 0 origjiffies = jiffies; while(0x80 & wcfxs_getreg(wc, card, 93)) { if ((jiffies - origjiffies) > 2 * HZ) { printk("Timeout waiting for DC-DC calibration on module %d\n", card); return -1; } }#if 0 /* Wait a full two seconds */ while((jiffies - origjiffies) < 2 * HZ); /* Just check to be sure */ vbat = wcfxs_getreg(wc, card, 82); printk("ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n", card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ)));#endif#endif return 0;}static int wcfxs_proslic_manual_calibrate(struct wcfxs *wc, int card){ unsigned long origjiffies; unsigned char i; wcfxs_setreg(wc, card, 21, 0);//(0) Disable all interupts in DR21 wcfxs_setreg(wc, card, 22, 0);//(0)Disable all interupts in DR21 wcfxs_setreg(wc, card, 23, 0);//(0)Disable all interupts in DR21 wcfxs_setreg(wc, card, 64, 0);//(0) wcfxs_setreg(wc, card, 97, 0x18); //(0x18)Calibrations without the ADC and DAC offset and without common mode calibration. wcfxs_setreg(wc, card, 96, 0x47); //(0x47) Calibrate common mode and differential DAC mode DAC + ILIM origjiffies=jiffies; while( wcfxs_getreg(wc,card,96)!=0 ){ if((jiffies-origjiffies)>80) return -1; }//Initialized DR 98 and 99 to get consistant results.// 98 and 99 are the results registers and the search should have same intial conditions./*******************************The following is the manual gain mismatch calibration****************************//*******************************This is also available as a function *******************************************/ // Delay 10ms origjiffies=jiffies; while((jiffies-origjiffies)<1); wcfxs_proslic_setreg_indirect(wc, card, 88,0); wcfxs_proslic_setreg_indirect(wc,card,89,0); wcfxs_proslic_setreg_indirect(wc,card,90,0); wcfxs_proslic_setreg_indirect(wc,card,91,0); wcfxs_proslic_setreg_indirect(wc,card,92,0); wcfxs_proslic_setreg_indirect(wc,card,93,0); wcfxs_setreg(wc, card, 98,0x10); // This is necessary if the calibration occurs other than at reset time wcfxs_setreg(wc, card, 99,0x10); for ( i=0x1f; i>0; i--) { wcfxs_setreg(wc, card, 98,i); origjiffies=jiffies; while((jiffies-origjiffies)<4); if((wcfxs_getreg(wc,card,88)) == 0) break; } // for for ( i=0x1f; i>0; i--) { wcfxs_setreg(wc, card, 99,i); origjiffies=jiffies; while((jiffies-origjiffies)<4); if((wcfxs_getreg(wc,card,89)) == 0) break; }//for/*******************************The preceding is the manual gain mismatch calibration****************************//**********************************The following is the longitudinal Balance Cal***********************************/ wcfxs_setreg(wc,card,64,1); while((jiffies-origjiffies)<10); // Sleep 100? wcfxs_setreg(wc, card, 64, 0); wcfxs_setreg(wc, card, 23, 0x4); // enable interrupt for the balance Cal wcfxs_setreg(wc, card, 97, 0x1); // this is a singular calibration bit for longitudinal calibration wcfxs_setreg(wc, card, 96,0x40); wcfxs_getreg(wc,card,96); /* Read Reg 96 just cause */ wcfxs_setreg(wc, card, 21, 0xFF); wcfxs_setreg(wc, card, 22, 0xFF); wcfxs_setreg(wc, card, 23, 0xFF); /**The preceding is the longitudinal Balance Cal***/ return(0);}#if 1static int wcfxs_proslic_calibrate(struct wcfxs *wc, int card){ unsigned long origjiffies; int x; /* Perform all calibrations */ wcfxs_setreg(wc, card, 97, 0x1f); /* Begin, no speedup */ wcfxs_setreg(wc, card, 96, 0x5f); /* Wait for it to finish */ origjiffies = jiffies; while(wcfxs_getreg(wc, card, 96)) { if ((jiffies - origjiffies) > 2 * HZ) { printk("Timeout waiting for calibration of module %d\n", card); return -1; } } if (debug) { /* Print calibration parameters */ printk("Calibration Vector Regs 98 - 107: \n"); for (x=98;x<108;x++) { printk("%d: %02x\n", x, wcfxs_getreg(wc, card, x)); } } return 0;}#endifstatic void wait_just_a_bit(int foo)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -