📄 wcfxs.c
字号:
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; printk("Start automatic calibration\n"); /* 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;}#endif/* wait 'foo' jiffies then return. DR - modified to use a better delay mechanism that the orginal busy-waiting method, which locked the kernel up for some rather long times (e.g. seconds), at least on non-preemptable kernels.*/static void wait_just_a_bit(int foo){ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(foo);}static int wcfxs_init_voicedaa(struct wcfxs *wc, int card, int fast, int manual, int sane){ unsigned char reg16=0, reg26=0, reg30=0, reg31=0; long newjiffies; wc->modtype[card] = MOD_TYPE_FXO; //printk("Entering: wcfxs_init_voicedaa\n"); /* Sanity check */ if (!sane && wcfxs_voicedaa_insane(wc, card)) return -2; /* Software reset */ wcfxs_setreg(wc, card, 1, 0x80); /* Wait just a bit */ wait_just_a_bit(HZ/10); /* Enable PCM, ulaw */ wcfxs_setreg(wc, card, 33, 0x28); /* Set On-hook speed, Ringer impedence, and ringer threshold */ reg16 |= (fxo_modes[_opermode].ohs << 6); reg16 |= (fxo_modes[_opermode].rz << 1); reg16 |= (fxo_modes[_opermode].rt); wcfxs_setreg(wc, card, 16, reg16); /* Set DC Termination: Tip/Ring voltage adjust, minimum operational current, current limitation */ reg26 |= (fxo_modes[_opermode].dcv << 6); reg26 |= (fxo_modes[_opermode].mini << 4); reg26 |= (fxo_modes[_opermode].ilim << 1); wcfxs_setreg(wc, card, 26, reg26); /* Set AC Impedence */ reg30 = (fxo_modes[_opermode].acim); wcfxs_setreg(wc, card, 30, reg30); /* Misc. DAA parameters */ reg31 = 0xa3; reg31 |= (fxo_modes[_opermode].ohs2 << 3); wcfxs_setreg(wc, card, 31, reg31); /* Set Transmit/Receive timeslot */ wcfxs_setreg(wc, card, 34, (card) * 8); wcfxs_setreg(wc, card, 35, 0x00); wcfxs_setreg(wc, card, 36, (card) * 8); wcfxs_setreg(wc, card, 37, 0x00); /* Enable ISO-Cap */ wcfxs_setreg(wc, card, 6, 0x00); /* Wait 1000ms for ISO-cap to come up */ newjiffies = jiffies; newjiffies += 2 * HZ; while((jiffies < newjiffies) && !(wcfxs_getreg(wc, card, 11) & 0xf0)) wait_just_a_bit(HZ/10); if (!(wcfxs_getreg(wc, card, 11) & 0xf0)) { printk("VoiceDAA did not bring up ISO link properly!\n"); return -1; } if (debug) printk(" ISO-Cap is now up, line side: %02x rev %02x\n", wcfxs_getreg(wc, card, 11) >> 4, (wcfxs_getreg(wc, card, 13) >> 2) & 0xf); /* Enable on-hook line monitor */ wcfxs_setreg(wc, card, 5, 0x08); /* DR 6/1105: Debug code used to trap bad reads, see notes in __write_8bits { int i; unsigned char r; for(i=0; i<1000; i++) { r = wcfxs_getreg(wc, card, 31); if (r != 0xa3) { printk("bad read! Check if CS is going low\n"); break; } } printk(" 1000 reads OK!\n"); } */ /* Optional digital loopback, used for testing Blackfin DMA */ if (loopback) { wcfxs_setreg(wc, card, 10, 0x01); printk("loopback enabled\n"); } return 0;}static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, int sane){ unsigned short tmp[5]; unsigned char r19; int x; int fxsmode=0; manual = 1; /* By default, don't send on hook */ wc->mod.fxs.idletxhookstate [card] = 1; /* Sanity check the ProSLIC */ if (!sane && wcfxs_proslic_insane(wc, card)) return -2; if (sane) { /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */ wcfxs_setreg(wc, card, 14, 0x10); } if (wcfxs_proslic_init_indirect_regs(wc, card)) { printk(KERN_INFO "Indirect Registers failed to initialize on module %d.\n", card); return -1; } /* Clear scratch pad area */ wcfxs_proslic_setreg_indirect(wc, card, 97,0); /* Clear digital loopback */ wcfxs_setreg(wc, card, 8, 0); /* Revision C optimization */ wcfxs_setreg(wc, card, 108, 0xeb); /* Disable automatic VBat switching for safety to prevent Q7 from accidently turning on and burning out. */ wcfxs_setreg(wc, card, 67, 0x17); /* Turn off Q7 */ wcfxs_setreg(wc, card, 66, 1); /* Flush ProSLIC digital filters by setting to clear, while saving old values */ for (x=0;x<5;x++) { tmp[x] = wcfxs_proslic_getreg_indirect(wc, card, x + 35); wcfxs_proslic_setreg_indirect(wc, card, x + 35, 0x8000); } /* Power up the DC-DC converter */ if (wcfxs_powerup_proslic(wc, card, fast)) { printk("Unable to do INITIAL ProSLIC powerup on module %d\n", card); return -1; } if (!fast) { /* Check for power leaks */ if (wcfxs_proslic_powerleak_test(wc, card)) { printk("ProSLIC module %d failed leakage test. Check for short circuit\n", card); } /* Power up again */ if (wcfxs_powerup_proslic(wc, card, fast)) { printk("Unable to do FINAL ProSLIC powerup on module %d\n", card); return -1; }#ifndef NO_CALIBRATION /* Perform calibration */ if(manual) { if (wcfxs_proslic_manual_calibrate(wc, card)) { //printk("Proslic failed on Manual Calibration\n"); if (wcfxs_proslic_manual_calibrate(wc, card)) { printk("Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n"); return -1; } printk("Proslic Passed Manual Calibration on Second Attempt\n"); } } else { if(wcfxs_proslic_calibrate(wc, card)) { //printk("ProSlic died on Auto Calibration.\n"); if (wcfxs_proslic_calibrate(wc, card)) { printk("Proslic Failed on Second Attempt to Auto Calibrate\n"); return -1; } printk("Proslic Passed Auto Calibration on Second Attempt\n"); } } /* Perform DC-DC calibration */ wcfxs_setreg(wc, card, 93, 0x99); r19 = wcfxs_getreg(wc, card, 107); if ((r19 < 0x2) || (r19 > 0xd)) { printk("DC-DC cal has a surprising direct 107 of 0x%02x!\n", r19); wcfxs_setreg(wc, card, 107, 0x8); } /* Save calibration vectors */ for (x=0;x<NUM_CAL_REGS;x++) wc->mod.fxs.calregs[card].vals[x] = wcfxs_getreg(wc, card, 96 + x);#endif } else { /* Restore calibration registers */ for (x=0;x<NUM_CAL_REGS;x++) wcfxs_setreg(wc, card, 96 + x, wc->mod.fxs.calregs[card].vals[x]); } /* Calibration complete, restore original values */ for (x=0;x<5;x++) { wcfxs_proslic_setreg_indirect(wc, card, x + 35, tmp[x]); } if (wcfxs_proslic_verify_indirect_regs(wc, card)) { printk(KERN_INFO "Indirect Registers failed verification.\n"); return -1; }#if 0 /* Disable Auto Power Alarm Detect and other "features" */ wcfxs_setreg(wc, card, 67, 0x0e); blah = wcfxs_getreg(wc, card, 67);#endif#if 0 if (wcfxs_proslic_setreg_indirect(wc, card, 97, 0x0)) { // Stanley: for the bad recording fix printk(KERN_INFO "ProSlic IndirectReg Died.\n"); return -1; }#endif wcfxs_setreg(wc, card, 1, 0x28); // U-Law 8-bit interface wcfxs_setreg(wc, card, 2, (card) * 8); // Tx Start count low byte 0 wcfxs_setreg(wc, card, 3, 0); // Tx Start count high byte 0 wcfxs_setreg(wc, card, 4, (card) * 8); // Rx Start count low byte 0 wcfxs_setreg(wc, card, 5, 0); // Rx Start count high byte 0 wcfxs_setreg(wc, card, 18, 0xff); // clear all interrupt wcfxs_setreg(wc, card, 19, 0xff); wcfxs_setreg(wc, card, 20, 0xff); wcfxs_setreg(wc, card, 73, 0x04); if (fxshonormode) { fxsmode = acim2tiss[fxo_modes[_opermode].acim]; wcfxs_setreg(wc, card, 10, 0x08 | fxsmode); if (fxo_modes[_opermode].ring_osc) wcfxs_proslic_setreg_indirect(wc, card, 20, fxo_modes[_opermode].ring_osc); if (fxo_modes[_opermode].ring_x) wcfxs_proslic_setreg_indirect(wc, card, 21, fxo_modes[_opermode].ring_x); } if (lowpower) wcfxs_setreg(wc, card, 72, 0x10);#if 0 wcfxs_setreg(wc, card, 21, 0x00); // enable interrupt wcfxs_setreg(wc, card, 22, 0x02); // Loop detection interrupt wcfxs_setreg(wc, card, 23, 0x01); // DTMF detection interrupt#endif#if 0 /* Enable loopback */ wcfxs_setreg(wc, card, 8, 0x2); wcfxs_setreg(wc, card, 14, 0x0); wcfxs_setreg(wc, card, 64, 0x0); wcfxs_setreg(wc, card, 1, 0x08);#endif /* Beef up Ringing voltage to 89V */ if (boostringer) { if (wcfxs_proslic_setreg_indirect(wc, card, 21, 0x1d1)) return -1; printk("Boosting ringinger on slot %d (89V peak)\n", card + 1); } else if (lowpower) { if (wcfxs_proslic_setreg_indirect(wc, card, 21, 0x108)) return -1; printk("Reducing ring power on slot %d (50V peak)\n", card + 1); } wcfxs_setreg(wc, card, 64, 0x01); return 0;}static int wcfxs_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data){ struct wcfxs_stats stats; struct wcfxs_regs regs; struct wcfxs_regop regop; struct wcfxs *wc = chan->pvt; int x; switch (cmd) { case ZT_ONHOOKTRANSFER: if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) return -EINVAL; if (get_user(x, (int *)data)) return -EFAULT; wc->mod.fxs.ohttimer[chan->chanpos - 1] = x << 3; wc->mod.fxs.idletxhookstate[chan->chanpos - 1] = 0x2; /* OHT mode when idle */ if (wc->mod.fxs.lasttxhook[chan->chanpos - 1] == 0x1) { /* Apply the change if appropriate */ wc->mod.fxs.lasttxhook[chan->chanpos - 1] = 0x2; wcfxs_setreg(wc, chan->chanpos - 1, 64, wc->mod.fxs.lasttxhook[chan->chanpos - 1]); } break; case WCFXS_GET_STATS: if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { stats.tipvolt = wcfxs_getreg(wc, chan->chanpos - 1, 80) * -376; stats.ringvolt = wcfxs_getreg(wc, chan->chanpos - 1, 81) * -376; stats.batvolt = wcfxs_getreg(wc, chan->chanpos - 1, 82) * -376; } else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { stats.tipvolt = (signed char)wcfxs_getreg(wc, chan->chanpos - 1, 29) * 1000; stats.ringvolt = (signed char)wcfxs_getreg(wc, chan->chanpos - 1, 29) * 1000; stats.batvolt = (signed char)wcfxs_getreg(wc, chan->chanpos - 1, 29) * 1000; } else return -EINVAL; if (copy_to_user((struct wcfxs_stats *)data, &stats, sizeof(stats))) return -EFAULT; break; case WCFXS_GET_REGS: if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { for (x=0;x<NUM_INDIRECT_REGS;x++) regs.indirect[x] = wcfxs_proslic_getreg_indirect(wc, chan->chanpos -1, x); for (x=0;x<NUM_REGS;x++) regs.direct[x] = wcfxs_getreg(wc, chan->chanpos - 1, x); } else { memset(®s, 0, sizeof(regs)); for (x=0;x<NUM_FXO_REGS;x++) regs.direct[x] = wcfxs_getreg(wc, chan->chanpos - 1, x); } if (copy_to_user((struct wcfxs_regs *)data, ®s, sizeof(regs))) return -EFAULT; break; case WCFXS_SET_REG: if (copy_from_user(®op, (struct wcfxs_regop *)data, sizeof(regop))) return -EFAULT; if (regop.indirect) { if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) return -EINVAL; printk("Setting indirect %d to 0x%04x on %d\n", regop.reg, regop.val, chan->chanpos); wcfxs_proslic_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val); } else { regop.val &= 0xff; printk("Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos); wcfxs_setreg(wc, chan->chanpos - 1, regop.reg, regop.val); } break; default: return -ENOTTY; } return 0;}static int wcfxs_open(struct zt_chan *chan){ struct wcfxs *wc = chan->pvt; if (!(wc->cardflag & (1 << (chan->chanpos - 1)))) return -ENODEV; if (wc->dead) return -ENODEV; wc->usecount++;#ifndef LINUX26 MOD_INC_USE_COUNT;#else try_module_get(THIS_MODULE);#endif return 0;}static int wcfxs_watchdog(struct zt_span *span, int event){ printk("TDM: Restarting DMA\n");#ifdef NOT_NEEDED_YET
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -