📄 wcfxs.c
字号:
if (abs(b) < BATT_THRESH) { wc->mod.fxo.nobatttimer[card]++;#if 0 if (wc->mod.fxo.battery[card]) printk("Battery loss: %d (%d debounce)\n", b, wc->mod.fxo.battdebounce[card]);#endif if (wc->mod.fxo.battery[card] && !wc->mod.fxo.battdebounce[card]) { if (debug) printk("NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1); wc->mod.fxo.battery[card] = 0;#ifdef JAPAN if ((!wc->ohdebounce) && wc->offhook) { zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK); if (debug) printk("Signalled On Hook\n");#ifdef ZERO_BATT_RING wc->onhook++;#endif }#else zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);#endif wc->mod.fxo.battdebounce[card] = BATT_DEBOUNCE; } else if (!wc->mod.fxo.battery[card]) wc->mod.fxo.battdebounce[card] = BATT_DEBOUNCE; } else if (abs(b) > BATT_THRESH) { if (!wc->mod.fxo.battery[card] && !wc->mod.fxo.battdebounce[card]) { if (debug) printk("BATTERY on %d/%d (%s)!\n", wc->span.spanno, card + 1, (b < 0) ? "-" : "+"); #ifdef ZERO_BATT_RING if (wc->onhook) { wc->onhook = 0; zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); if (debug) printk("Signalled Off Hook\n"); }#else zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);#endif wc->mod.fxo.battery[card] = 1; wc->mod.fxo.nobatttimer[card] = 0; wc->mod.fxo.battdebounce[card] = BATT_DEBOUNCE; } else if (wc->mod.fxo.battery[card]) wc->mod.fxo.battdebounce[card] = BATT_DEBOUNCE; if (wc->mod.fxo.lastpol[card] >= 0) { if (b < 0) { wc->mod.fxo.lastpol[card] = -1; wc->mod.fxo.polaritydebounce[card] = POLARITY_DEBOUNCE; } } if (wc->mod.fxo.lastpol[card] <= 0) { if (b > 0) { wc->mod.fxo.lastpol[card] = 1; wc->mod.fxo.polaritydebounce[card] = POLARITY_DEBOUNCE; } } } else { /* It's something else... */ wc->mod.fxo.battdebounce[card] = BATT_DEBOUNCE; } if (wc->mod.fxo.battdebounce[card]) wc->mod.fxo.battdebounce[card] -= (NUM_CARDS/4); if (wc->mod.fxo.polaritydebounce[card]) { wc->mod.fxo.polaritydebounce[card]--; if (wc->mod.fxo.polaritydebounce[card] < 1) { if (wc->mod.fxo.lastpol[card] != wc->mod.fxo.polarity[card]) { if (debug) printk("%lu Polarity reversed (%d -> %d)\n", jiffies, wc->mod.fxo.polarity[card], wc->mod.fxo.lastpol[card]); if (wc->mod.fxo.polarity[card]) zt_qevent_lock(&wc->chans[card], ZT_EVENT_POLARITY); wc->mod.fxo.polarity[card] = wc->mod.fxo.lastpol[card]; } } }}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); } } }}/* handles regular interrupt processing, called every time we get a DMA interrupt which is every 1ms with ZT_CHUNKSIZE == 8 */void regular_interrupt_processing(u8 *read_samples, u8 *write_samples) { struct wcfxs *wc = devs; int x; wc->intcount++; x = wc->intcount % NUM_CARDS; /* as ISR is started before chips initialised we nee this test to ensure we don't test the hook switch and ring detect before chips initialised */ if (wcfxs_init_ok) { /* check hook switch (FXS) and ringing (FXO) */ 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) { /* ring detection, despite name */ 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]--; } } } /* handle speech samples */ wcfxs_transmitprep(wc, write_samples); wcfxs_receiveprep(wc, read_samples);}static int wcfxs_voicedaa_insane(struct wcfxs *wc, int card){ int blah; blah = wcfxs_getreg(wc, card, 2); if (debug) { printk("Testing for DAA...\n"); } if (blah != 0x3) { printk(" DAA not found! (blah = 0x%x)\n", blah); 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,blah1; insane_report=0; blah = wcfxs_getreg(wc, card, 0); if (debug) { printk("Testing for ProSLIC card = %d blah = 0x%x blah1 = 0x%x\n", card, blah, blah1); }#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)) { if (debug) { printk(" ProSLIC not loaded...\n"); } return -1; } if (debug) { printk("ProSLIC module %d, product %d, version %d\n", card, (blah & 0x30) >> 4, (blah & 0xf)); } if ((blah & 0xf) < 2) { printk("ProSLIC 3210 version %d is too old\n", blah & 0xf); return -1; } if (wcfxs_getreg(wc, card, 1) & 0x80){ /* ProSLIC 3215, not a 3210 */ wc->flags[card] |= FLAG_3215; printk("ProSLIC module is Si3215\n"); } 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; } } printk("reg 0: 0x%x \n", wcfxs_getreg(wc, card, 0)); printk("reg 14: 0x%x \n", wcfxs_getreg(wc, card, 14)); printk("reg 74: 0x%x \n", wcfxs_getreg(wc, card, 74)); printk("reg 80: 0x%x \n", wcfxs_getreg(wc, card, 80)); printk("reg 81: 0x%x \n", wcfxs_getreg(wc, card, 81)); printk("reg 92: 0x%x \n", wcfxs_getreg(wc, card, 92)); printk("reg 82: 0x%x \n", wcfxs_getreg(wc, card, 82)); printk("reg 83: 0x%x \n", wcfxs_getreg(wc, card, 83)); //return -1; 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; printk("Start manual calibration\n"); 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -