diff options
-rwxr-xr-x | fxstest.c | 22 | ||||
-rwxr-xr-x | wcfxs.c | 374 | ||||
-rwxr-xr-x | wctdm.c | 374 |
3 files changed, 558 insertions, 212 deletions
@@ -66,21 +66,31 @@ int main(int argc, char *argv[]) } } else if (!strcasecmp(argv[2], "regdump")) { struct wcfxs_regs regs; + int numregs = NUM_REGS; + memset(®s, 0, sizeof(regs)); res = ioctl(fd, WCFXS_GET_REGS, ®s); if (res) { fprintf(stderr, "Unable to get registers on channel %s\n", argv[1]); } else { + for (x=60;x<NUM_REGS;x++) { + if (regs.direct[x]) + break; + } + if (x == NUM_REGS) + numregs = 60; printf("Direct registers: \n"); - for (x=0;x<NUM_REGS;x++) { + for (x=0;x<numregs;x++) { printf("%3d. %02x ", x, regs.direct[x]); if ((x % 8) == 7) printf("\n"); } - printf("\n\nIndirect registers: \n"); - for (x=0;x<NUM_INDIRECT_REGS;x++) { - printf("%3d. %04x ", x, regs.indirect[x]); - if ((x % 6) == 5) - printf("\n"); + if (numregs == NUM_REGS) { + printf("\n\nIndirect registers: \n"); + for (x=0;x<NUM_INDIRECT_REGS;x++) { + printf("%3d. %04x ", x, regs.indirect[x]); + if ((x % 6) == 5) + printf("\n"); + } } printf("\n\n"); } @@ -1,5 +1,5 @@ /* - * Wilcard TDM400P FXS Interface Driver for Zapata Telephony interface + * Wilcard TDM400P TDM FXS/FXO Interface Driver for Zapata Telephony interface * * Written by Mark Spencer <markster@linux-support.net> * Matthew Fredrickson <creslin@linux-support.net> @@ -91,6 +91,8 @@ static alpha indirect_regs[] = #include <linux/zaptel.h> #endif +#define NUM_FXO_REGS 60 + #define WC_MAX_IFACES 128 #define WC_CNTL 0x00 @@ -140,6 +142,9 @@ static alpha indirect_regs[] = #define MAX_ALARMS 10 +#define MOD_TYPE_FXS 0 +#define MOD_TYPE_FXO 1 + struct wcfxs { struct pci_dev *dev; char *variety; @@ -158,6 +163,7 @@ struct wcfxs { spinlock_t lock; /* Receive hook state and debouncing */ + int modtype[NUM_CARDS]; int oldrxhook[NUM_CARDS]; int debouncehook[NUM_CARDS]; int lastrxhook[NUM_CARDS]; @@ -248,8 +254,8 @@ static inline void wcfxs_receiveprep(struct wcfxs *wc, unsigned char ints) zt_receive(&wc->span); } -static inline void wcfxs_check_hook(struct wcfxs *wc, int card); -static inline void wcfxs_recheck_sanity(struct wcfxs *wc, int card); +static inline void wcfxs_proslic_check_hook(struct wcfxs *wc, int card); +static inline void wcfxs_proslic_recheck_sanity(struct wcfxs *wc, int card); static void wcfxs_stop_dma(struct wcfxs *wc); static void wcfxs_reset_tdm(struct wcfxs *wc); @@ -281,6 +287,32 @@ static inline void __write_8bits(struct wcfxs *wc, unsigned char bits) outb(wc->ios, wc->ioaddr + WC_AUXD); } + +static inline void __reset_spi(struct wcfxs *wc) +{ + /* Drop chip select and clock once and raise and clock once */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + wc->ios &= ~BIT_CS; + outb(wc->ios, wc->ioaddr + WC_AUXD); + wc->ios |= BIT_SDI; + wc->ios &= ~BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Now raise SCLK high again and repeat */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Finally raise CS back high again */ + wc->ios |= BIT_CS; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Clock again */ + wc->ios &= ~BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Now raise SCLK high again and repeat */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + +} + static inline unsigned char __read_8bits(struct wcfxs *wc) { unsigned char res=0, c; @@ -334,7 +366,12 @@ static inline void __wcfxs_setcard(struct wcfxs *wc, int card) static void __wcfxs_setreg(struct wcfxs *wc, int card, unsigned char reg, unsigned char value) { __wcfxs_setcard(wc, card); - __write_8bits(wc, reg & 0x7f); + if (wc->modtype[card] == MOD_TYPE_FXO) { + __write_8bits(wc, 0x20); + __write_8bits(wc, reg & 0x7f); + } else { + __write_8bits(wc, reg & 0x7f); + } __write_8bits(wc, value); } @@ -349,10 +386,25 @@ static void wcfxs_setreg(struct wcfxs *wc, int card, unsigned char reg, unsigned static unsigned char __wcfxs_getreg(struct wcfxs *wc, int card, unsigned char reg) { __wcfxs_setcard(wc, card); - __write_8bits(wc, reg | 0x80); + if (wc->modtype[card] == MOD_TYPE_FXO) { + __write_8bits(wc, 0x60); + __write_8bits(wc, reg & 0x7f); + } else { + __write_8bits(wc, reg | 0x80); + } return __read_8bits(wc); } +static inline void reset_spi(struct wcfxs *wc, int card) +{ + unsigned long flags; + spin_lock_irqsave(&wc->lock, flags); + __wcfxs_setcard(wc, card); + __reset_spi(wc); + __reset_spi(wc); + spin_unlock_irqrestore(&wc->lock, flags); +} + static unsigned char wcfxs_getreg(struct wcfxs *wc, int card, unsigned char reg) { unsigned long flags; @@ -388,7 +440,7 @@ static int __wait_access(struct wcfxs *wc, int card) return 0; } -static int wcfxs_setreg_indirect(struct wcfxs *wc, int card, unsigned char address, unsigned short data) +static int wcfxs_proslic_setreg_indirect(struct wcfxs *wc, int card, unsigned char address, unsigned short data) { unsigned long flags; int res = -1; @@ -403,7 +455,7 @@ static int wcfxs_setreg_indirect(struct wcfxs *wc, int card, unsigned char addre return res; } -static int wcfxs_getreg_indirect(struct wcfxs *wc, int card, unsigned char address) +static int wcfxs_proslic_getreg_indirect(struct wcfxs *wc, int card, unsigned char address) { unsigned long flags; int res = -1; @@ -426,20 +478,20 @@ static int wcfxs_getreg_indirect(struct wcfxs *wc, int card, unsigned char addre return res; } -static int wcfxs_init_indirect_regs(struct wcfxs *wc, int card) +static int wcfxs_proslic_init_indirect_regs(struct wcfxs *wc, int card) { unsigned char i; for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++) { - if(wcfxs_setreg_indirect(wc, card, indirect_regs[i].address,indirect_regs[i].initial)) + if(wcfxs_proslic_setreg_indirect(wc, card, indirect_regs[i].address,indirect_regs[i].initial)) return -1; } return 0; } -static int wcfxs_verify_indirect_regs(struct wcfxs *wc, int card) +static int wcfxs_proslic_verify_indirect_regs(struct wcfxs *wc, int card) { int passed = 1; unsigned short i, initial; @@ -447,7 +499,7 @@ static int wcfxs_verify_indirect_regs(struct wcfxs *wc, int card) for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++) { - if((j = wcfxs_getreg_indirect(wc, card, (unsigned char) indirect_regs[i].address)) < 0) { + if((j = wcfxs_proslic_getreg_indirect(wc, card, (unsigned char) indirect_regs[i].address)) < 0) { printk("Failed to read indirect register %d\n", i); return -1; } @@ -470,6 +522,7 @@ static int wcfxs_verify_indirect_regs(struct wcfxs *wc, int card) } return 0; } + #ifdef LINUX26 static irqreturn_t wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) #else @@ -492,7 +545,7 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (ints & 0x10) { /* Stop DMA, wait for watchdog */ - printk("FXS PCI Master abort\n"); + printk("TDM PCI Master abort\n"); wcfxs_stop_dma(wc); #ifdef LINUX26 return IRQ_RETVAL(1); @@ -511,7 +564,8 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) } for (x=0;x<4;x++) { - if ((x < wc->cards) && (wc->cardflag & (1 << x))) { + if ((x < wc->cards) && (wc->cardflag & (1 << x)) && + (wc->modtype[x] == MOD_TYPE_FXS)) { if (wc->lasttxhook[x] == 0x4) { /* RINGing, prepare for OHT */ wc->ohttimer[x] = OHT_TIMER << 3; @@ -536,15 +590,19 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) wc->intcount++; x = wc->intcount % 4; if ((x < wc->cards) && (wc->cardflag & (1 << x))) { - wcfxs_check_hook(wc, x); - if (!(wc->intcount & 0xfc)) - wcfxs_recheck_sanity(wc, x); + if (wc->modtype[x] == MOD_TYPE_FXS) { + wcfxs_proslic_check_hook(wc, x); + if (!(wc->intcount & 0xfc)) + wcfxs_proslic_recheck_sanity(wc, x); + } } if (!(wc->intcount % 10000)) { /* Accept an alarm once per 10 seconds */ for (x=0;x<4;x++) - if (wc->palarms[x]) - wc->palarms[x]--; + if (wc->modtype[x] == MOD_TYPE_FXS) { + if (wc->palarms[x]) + wc->palarms[x]--; + } } wcfxs_receiveprep(wc, ints); wcfxs_transmitprep(wc, ints); @@ -555,6 +613,18 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) } +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; @@ -570,7 +640,7 @@ static int wcfxs_proslic_insane(struct wcfxs *wc, int card) return -1; } #endif - if ((blah & 0xf) == 0) { + if (((blah & 0xf) == 0) || ((blah & 0xf) == 0xf)) { /* SLIC not loaded */ return -1; } @@ -608,7 +678,7 @@ static int wcfxs_proslic_insane(struct wcfxs *wc, int card) return 0; } -static int wcfxs_powerleak_test(struct wcfxs *wc, int card) +static int wcfxs_proslic_powerleak_test(struct wcfxs *wc, int card) { unsigned long origjiffies; unsigned char vbat; @@ -701,7 +771,7 @@ static int wcfxs_powerup_proslic(struct wcfxs *wc, int card, int fast) } -static int wcfxs_manual_calibrate(struct wcfxs *wc, int card){ +static int wcfxs_proslic_manual_calibrate(struct wcfxs *wc, int card){ unsigned long origjiffies; unsigned char i; @@ -726,12 +796,12 @@ static int wcfxs_manual_calibrate(struct wcfxs *wc, int card){ // Delay 10ms origjiffies=jiffies; while((jiffies-origjiffies)<1); - wcfxs_setreg_indirect(wc, card, 88,0); - wcfxs_setreg_indirect(wc,card,89,0); - wcfxs_setreg_indirect(wc,card,90,0); - wcfxs_setreg_indirect(wc,card,91,0); - wcfxs_setreg_indirect(wc,card,92,0); - wcfxs_setreg_indirect(wc,card,93,0); + 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); @@ -775,7 +845,7 @@ static int wcfxs_manual_calibrate(struct wcfxs *wc, int card){ } #if 1 -static int wcfxs_calibrate(struct wcfxs *wc, int card) +static int wcfxs_proslic_calibrate(struct wcfxs *wc, int card) { unsigned long origjiffies; int x; @@ -804,6 +874,63 @@ static int wcfxs_calibrate(struct wcfxs *wc, int card) return 0; } #endif + +static int wcfxs_init_voicedaa(struct wcfxs *wc, int card, int fast, int manual, int sane) +{ + long newjiffies; + wc->modtype[card] = MOD_TYPE_FXO; + /* Sanity check the ProSLIC */ + reset_spi(wc, card); + if (!sane && wcfxs_voicedaa_insane(wc, card)) + return -2; + + /* Software reset */ + wcfxs_setreg(wc, card, 1, 0x80); + + /* Wait just a bit */ + newjiffies = jiffies + (HZ/10); + while(jiffies < newjiffies); + + /* Enable PCM, ulaw */ + wcfxs_setreg(wc, card, 33, 0x28); + + /* Misc. DAA parameters */ + wcfxs_setreg(wc, card, 31, 0xa3); + + /* Set AC Impedence */ + wcfxs_setreg(wc, card, 30, 0x00); + + /* Set DC Termination */ + wcfxs_setreg(wc, card, 26, 0xc0); + + /* Set Transmit/Receive timeslot */ + wcfxs_setreg(wc, card, 34, (3-card) * 8); + wcfxs_setreg(wc, card, 35, 0x00); + wcfxs_setreg(wc, card, 36, (3-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)); + + 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, 0x40); + return 0; + +} + static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, int sane) { @@ -822,13 +949,13 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, wcfxs_setreg(wc, card, 14, 0x10); } - if (wcfxs_init_indirect_regs(wc, card)) { + 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_setreg_indirect(wc, card, 97,0); + wcfxs_proslic_setreg_indirect(wc, card, 97,0); /* Clear digital loopback */ wcfxs_setreg(wc, card, 8, 0); @@ -846,8 +973,8 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, /* Flush ProSLIC digital filters by setting to clear, while saving old values */ for (x=0;x<5;x++) { - tmp[x] = wcfxs_getreg_indirect(wc, card, x + 35); - wcfxs_setreg_indirect(wc, card, x + 35, 0x8000); + 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 */ @@ -859,7 +986,7 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, if (!fast) { /* Check for power leaks */ - if (wcfxs_powerleak_test(wc, card)) { + if (wcfxs_proslic_powerleak_test(wc, card)) { printk("ProSLIC module %d failed leakage test. Check for short circuit\n", card); } /* Power up again */ @@ -870,9 +997,9 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, #ifndef NO_CALIBRATION /* Perform calibration */ if(manual) { - if (wcfxs_manual_calibrate(wc, card)) { + if (wcfxs_proslic_manual_calibrate(wc, card)) { //printk("Proslic failed on Manual Calibration\n"); - if (wcfxs_manual_calibrate(wc, card)) { + if (wcfxs_proslic_manual_calibrate(wc, card)) { printk("Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n"); return -1; } @@ -880,9 +1007,9 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, } } else { - if(wcfxs_calibrate(wc, card)) { + if(wcfxs_proslic_calibrate(wc, card)) { //printk("ProSlic died on Auto Calibration.\n"); - if (wcfxs_calibrate(wc, card)) { + if (wcfxs_proslic_calibrate(wc, card)) { printk("Proslic Failed on Second Attempt to Auto Calibrate\n"); return -1; } @@ -894,10 +1021,10 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, } /* Calibration complete, restore original values */ for (x=0;x<5;x++) { - wcfxs_setreg_indirect(wc, card, x + 35, tmp[x]); + wcfxs_proslic_setreg_indirect(wc, card, x + 35, tmp[x]); } - if (wcfxs_verify_indirect_regs(wc, card)) { + if (wcfxs_proslic_verify_indirect_regs(wc, card)) { printk(KERN_INFO "Indirect Registers failed verification.\n"); return -1; } @@ -910,7 +1037,7 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, #endif #if 0 - if (wcfxs_setreg_indirect(wc, card, 97, 0x0)) { // Stanley: for the bad recording fix + if (wcfxs_proslic_setreg_indirect(wc, card, 97, 0x0)) { // Stanley: for the bad recording fix printk(KERN_INFO "ProSlic IndirectReg Died.\n"); return -1; } @@ -943,16 +1070,14 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, #endif #ifdef BOOST_RINGER - wcfxs_setreg(wc, card, 74, 0x3f); - /* Beef up Ringing voltage to 89V */ - if (wcfxs_setreg_indirect(wc, card, 21, 0x1e1)) + if (wcfxs_proslic_setreg_indirect(wc, card, 23, 0x1d1)) return -1; #endif return 0; } -static inline void wcfxs_recheck_sanity(struct wcfxs *wc, int card) +static inline void wcfxs_proslic_recheck_sanity(struct wcfxs *wc, int card) { int res; /* Check loopback */ @@ -976,7 +1101,7 @@ static inline void wcfxs_recheck_sanity(struct wcfxs *wc, int card) } } -static inline void wcfxs_check_hook(struct wcfxs *wc, int card) +static inline void wcfxs_proslic_check_hook(struct wcfxs *wc, int card) { char res; int hook; @@ -1038,17 +1163,26 @@ static int wcfxs_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long dat int x; switch (cmd) { case WCFXS_GET_STATS: + if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) + return -EINVAL; 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; if (copy_to_user((struct wcfxs_stats *)data, &stats, sizeof(stats))) return -EFAULT; break; case WCFXS_GET_REGS: - for (x=0;x<NUM_INDIRECT_REGS;x++) - regs.indirect[x] = wcfxs_getreg_indirect(wc, chan->chanpos -1, x); - for (x=0;x<NUM_REGS;x++) - regs.direct[x] = wcfxs_getreg(wc, chan->chanpos - 1, x); + if (wc->modtype == 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; @@ -1056,25 +1190,16 @@ static int wcfxs_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long dat 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_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val); + 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; - case ZT_ONHOOKTRANSFER: - if (copy_from_user(&x, (int *)data, sizeof(x))) - return -EFAULT; - /* RINGing, prepare for OHT */ - wc->ohttimer[x] = x << 3; - wc->idletxhookstate[chan->chanpos - 1] = 0x2; /* OHT mode when idle */ - if (!wc->lasttxhook[chan->chanpos - 1]) { - wc->lasttxhook[chan->chanpos-1] = wc->idletxhookstate[chan->chanpos-1]; - wcfxs_setreg(wc, chan->chanpos - 1, 64, wc->lasttxhook[chan->chanpos-1]); - } - break; default: return -ENOTTY; } @@ -1090,15 +1215,13 @@ static int wcfxs_open(struct zt_chan *chan) if (wc->dead) return -ENODEV; wc->usecount++; -#ifndef LINUX26 MOD_INC_USE_COUNT; -#endif return 0; } static int wcfxs_watchdog(struct zt_span *span, int event) { - printk("FXS: Restarting DMA\n"); + printk("TDM: Restarting DMA\n"); wcfxs_restart_dma(span->pvt); return 0; } @@ -1108,9 +1231,7 @@ static int wcfxs_close(struct zt_chan *chan) struct wcfxs *wc = chan->pvt; int x; wc->usecount--; -#ifndef LINUX26 MOD_DEC_USE_COUNT; -#endif for (x=0;x<wc->cards;x++) wc->idletxhookstate[x] = 1; /* If we're dead, release us now */ @@ -1123,36 +1244,51 @@ static int wcfxs_hooksig(struct zt_chan *chan, zt_txsig_t txsig) { struct wcfxs *wc = chan->pvt; int reg=0; - switch(txsig) { - case ZT_TXSIG_ONHOOK: - switch(chan->sig) { - case ZT_SIG_FXOKS: - case ZT_SIG_FXOLS: + if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { + /* XXX Enable hooksig for FXO XXX */ + switch(txsig) { + case ZT_TXSIG_START: + case ZT_TXSIG_OFFHOOK: + wcfxs_setreg(wc, chan->chanpos - 1, 5, 0x41); + break; + case ZT_TXSIG_ONHOOK: + wcfxs_setreg(wc, chan->chanpos - 1, 5, 0x40); + break; + default: + printk("wcfxo: Can't set tx state to %d\n", txsig); + } + } else { + switch(txsig) { + case ZT_TXSIG_ONHOOK: + switch(chan->sig) { + case ZT_SIG_FXOKS: + case ZT_SIG_FXOLS: + wc->lasttxhook[chan->chanpos-1] = wc->idletxhookstate[chan->chanpos-1]; + break; + case ZT_SIG_FXOGS: + wc->lasttxhook[chan->chanpos-1] = 3; + break; + } + break; + case ZT_TXSIG_OFFHOOK: wc->lasttxhook[chan->chanpos-1] = wc->idletxhookstate[chan->chanpos-1]; break; - case ZT_SIG_FXOGS: - wc->lasttxhook[chan->chanpos-1] = 3; + case ZT_TXSIG_START: + wc->lasttxhook[chan->chanpos-1] = 4; + break; + case ZT_TXSIG_KEWL: + wc->lasttxhook[chan->chanpos-1] = 0; break; + default: + printk("wcfxs: Can't set tx state to %d\n", txsig); } - break; - case ZT_TXSIG_OFFHOOK: - wc->lasttxhook[chan->chanpos-1] = wc->idletxhookstate[chan->chanpos-1]; - break; - case ZT_TXSIG_START: - wc->lasttxhook[chan->chanpos-1] = 4; - break; - case ZT_TXSIG_KEWL: - wc->lasttxhook[chan->chanpos-1] = 0; - break; - default: - printk("wcfxs: Can't set tx state to %d\n", txsig); - } - if (debug) - printk("Setting hook state to %d (%02x)\n", txsig, reg); + if (debug) + printk("Setting FXS hook state to %d (%02x)\n", txsig, reg); #if 1 - wcfxs_setreg(wc, chan->chanpos - 1, 64, wc->lasttxhook[chan->chanpos-1]); + wcfxs_setreg(wc, chan->chanpos - 1, 64, wc->lasttxhook[chan->chanpos-1]); #endif + } return 0; } @@ -1160,12 +1296,13 @@ static int wcfxs_initialize(struct wcfxs *wc) { int x; /* Zapata stuff */ - sprintf(wc->span.name, "WCFXS/%d", wc->pos); + sprintf(wc->span.name, "WCTDM/%d", wc->pos); sprintf(wc->span.desc, "%s Board %d", wc->variety, wc->pos + 1); wc->span.deflaw = ZT_LAW_MULAW; for (x=0;x<wc->cards;x++) { - sprintf(wc->chans[x].name, "WCFXS/%d/%d", wc->pos, x); - wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_SF; + sprintf(wc->chans[x].name, "WCTDM/%d/%d", wc->pos, x); + wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_SF; + wc->chans[x].sigcap |= ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF; wc->chans[x].chanpos = x+1; wc->chans[x].pvt = wc; } @@ -1187,6 +1324,20 @@ static int wcfxs_initialize(struct wcfxs *wc) return 0; } +static void wcfxs_post_initialize(struct wcfxs *wc) +{ + int x; + /* Finalize signalling */ + for (x=0;x<wc->cards;x++) { + if (wc->cardflag & (1 << x)) { + if (wc->modtype[x] == MOD_TYPE_FXO) + wc->chans[x].sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF; + else + wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_SF; + } + } +} + static int wcfxs_hardware_init(struct wcfxs *wc) { /* Hardware stuff */ @@ -1220,7 +1371,7 @@ static int wcfxs_hardware_init(struct wcfxs *wc) return -1; } /* Go to half-duty FSYNC */ - __wcfxs_setcreg(wc, WC_SYNC, 0x00); + __wcfxs_setcreg(wc, WC_SYNC, 0x01); y = __wcfxs_getcreg(wc, WC_SYNC); } else { printk("No freshmaker chip\n"); @@ -1270,25 +1421,34 @@ static int wcfxs_hardware_init(struct wcfxs *wc) for (x=0;x<wc->cards;x++) { int sane=0,ret=0; +#if 1 /* Init with Auto Calibration */ if (!(ret=wcfxs_init_proslic(wc, x, 0, 0, sane))) { wc->cardflag |= (1 << x); - printk("Module %d: Installed -- AUTO\n",x); + printk("Module %d: Installed -- AUTO FXS\n",x); } else { - if(ret!=-2) sane=1; - /* Init with Manual Calibration */ - if (!wcfxs_init_proslic(wc, x, 0, 1, sane)) { + if(ret!=-2) { + sane=1; + /* Init with Manual Calibration */ + if (!wcfxs_init_proslic(wc, x, 0, 1, sane)) { + wc->cardflag |= (1 << x); + printk("Module %d: Installed -- MANUAL FXS\n",x); + } else { + printk("Module %d: FAILED FXS\n", x); + } + } else if (!(ret = wcfxs_init_voicedaa(wc, x, 0, 0, sane))) { wc->cardflag |= (1 << x); - printk("Module %d: Installed -- MANUAL\n",x); - } else + printk("Module %d: Installed -- AUTO FXO\n",x); + } else printk("Module %d: Not installed\n", x); } +#endif } /* Return error if nothing initialized okay. */ if (!wc->cardflag) return -1; - __wcfxs_setcreg(wc, WC_SYNC, wc->cardflag << 1); + __wcfxs_setcreg(wc, WC_SYNC, (wc->cardflag << 1) | 0x1); return 0; } @@ -1387,6 +1547,11 @@ static int __devinit wcfxs_init_one(struct pci_dev *pdev, const struct pci_devic if (wcfxs_initialize(wc)) { printk("wcfxs: Unable to intialize FXS\n"); + /* Set Reset Low */ + x=inb(wc->ioaddr + WC_CNTL); + outb((~0x1)&x, wc->ioaddr + WC_CNTL); + /* Free Resources */ + free_irq(pdev->irq, wc); if (wc->freeregion) release_region(wc->ioaddr, 0xff); pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma); @@ -1400,7 +1565,7 @@ static int __devinit wcfxs_init_one(struct pci_dev *pdev, const struct pci_devic /* Keep track of which device we are */ pci_set_drvdata(pdev, wc); - if (request_irq(pdev->irq, wcfxs_interrupt, SA_SHIRQ, "wcfxs", wc)) { + if (request_irq(pdev->irq, wcfxs_interrupt, SA_SHIRQ, "wctdm", wc)) { printk("wcfxs: Unable to request IRQ %d\n", pdev->irq); if (wc->freeregion) release_region(wc->ioaddr, 0xff); @@ -1418,14 +1583,17 @@ static int __devinit wcfxs_init_one(struct pci_dev *pdev, const struct pci_devic outb((~0x1)&x, wc->ioaddr + WC_CNTL); /* Free Resources */ free_irq(pdev->irq, wc); - zt_unregister(&wc->span); if (wc->freeregion) release_region(wc->ioaddr, 0xff); pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma); pci_set_drvdata(pdev, NULL); kfree(wc); return -EIO; + } + + wcfxs_post_initialize(wc); + /* Enable interrupts */ wcfxs_enable_interrupts(wc); /* Initialize Write/Buffers to all blank data */ @@ -1434,7 +1602,7 @@ static int __devinit wcfxs_init_one(struct pci_dev *pdev, const struct pci_devic /* Start DMA */ wcfxs_start_dma(wc); - printk("Found a Wildcard FXS: %s (%d modules)\n", wc->variety, wc->cards); + printk("Found a Wildcard TDM: %s (%d modules)\n", wc->variety, wc->cards); res = 0; } else res = -ENOMEM; @@ -1,5 +1,5 @@ /* - * Wilcard TDM400P FXS Interface Driver for Zapata Telephony interface + * Wilcard TDM400P TDM FXS/FXO Interface Driver for Zapata Telephony interface * * Written by Mark Spencer <markster@linux-support.net> * Matthew Fredrickson <creslin@linux-support.net> @@ -91,6 +91,8 @@ static alpha indirect_regs[] = #include <linux/zaptel.h> #endif +#define NUM_FXO_REGS 60 + #define WC_MAX_IFACES 128 #define WC_CNTL 0x00 @@ -140,6 +142,9 @@ static alpha indirect_regs[] = #define MAX_ALARMS 10 +#define MOD_TYPE_FXS 0 +#define MOD_TYPE_FXO 1 + struct wcfxs { struct pci_dev *dev; char *variety; @@ -158,6 +163,7 @@ struct wcfxs { spinlock_t lock; /* Receive hook state and debouncing */ + int modtype[NUM_CARDS]; int oldrxhook[NUM_CARDS]; int debouncehook[NUM_CARDS]; int lastrxhook[NUM_CARDS]; @@ -248,8 +254,8 @@ static inline void wcfxs_receiveprep(struct wcfxs *wc, unsigned char ints) zt_receive(&wc->span); } -static inline void wcfxs_check_hook(struct wcfxs *wc, int card); -static inline void wcfxs_recheck_sanity(struct wcfxs *wc, int card); +static inline void wcfxs_proslic_check_hook(struct wcfxs *wc, int card); +static inline void wcfxs_proslic_recheck_sanity(struct wcfxs *wc, int card); static void wcfxs_stop_dma(struct wcfxs *wc); static void wcfxs_reset_tdm(struct wcfxs *wc); @@ -281,6 +287,32 @@ static inline void __write_8bits(struct wcfxs *wc, unsigned char bits) outb(wc->ios, wc->ioaddr + WC_AUXD); } + +static inline void __reset_spi(struct wcfxs *wc) +{ + /* Drop chip select and clock once and raise and clock once */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + wc->ios &= ~BIT_CS; + outb(wc->ios, wc->ioaddr + WC_AUXD); + wc->ios |= BIT_SDI; + wc->ios &= ~BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Now raise SCLK high again and repeat */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Finally raise CS back high again */ + wc->ios |= BIT_CS; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Clock again */ + wc->ios &= ~BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Now raise SCLK high again and repeat */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + +} + static inline unsigned char __read_8bits(struct wcfxs *wc) { unsigned char res=0, c; @@ -334,7 +366,12 @@ static inline void __wcfxs_setcard(struct wcfxs *wc, int card) static void __wcfxs_setreg(struct wcfxs *wc, int card, unsigned char reg, unsigned char value) { __wcfxs_setcard(wc, card); - __write_8bits(wc, reg & 0x7f); + if (wc->modtype[card] == MOD_TYPE_FXO) { + __write_8bits(wc, 0x20); + __write_8bits(wc, reg & 0x7f); + } else { + __write_8bits(wc, reg & 0x7f); + } __write_8bits(wc, value); } @@ -349,10 +386,25 @@ static void wcfxs_setreg(struct wcfxs *wc, int card, unsigned char reg, unsigned static unsigned char __wcfxs_getreg(struct wcfxs *wc, int card, unsigned char reg) { __wcfxs_setcard(wc, card); - __write_8bits(wc, reg | 0x80); + if (wc->modtype[card] == MOD_TYPE_FXO) { + __write_8bits(wc, 0x60); + __write_8bits(wc, reg & 0x7f); + } else { + __write_8bits(wc, reg | 0x80); + } return __read_8bits(wc); } +static inline void reset_spi(struct wcfxs *wc, int card) +{ + unsigned long flags; + spin_lock_irqsave(&wc->lock, flags); + __wcfxs_setcard(wc, card); + __reset_spi(wc); + __reset_spi(wc); + spin_unlock_irqrestore(&wc->lock, flags); +} + static unsigned char wcfxs_getreg(struct wcfxs *wc, int card, unsigned char reg) { unsigned long flags; @@ -388,7 +440,7 @@ static int __wait_access(struct wcfxs *wc, int card) return 0; } -static int wcfxs_setreg_indirect(struct wcfxs *wc, int card, unsigned char address, unsigned short data) +static int wcfxs_proslic_setreg_indirect(struct wcfxs *wc, int card, unsigned char address, unsigned short data) { unsigned long flags; int res = -1; @@ -403,7 +455,7 @@ static int wcfxs_setreg_indirect(struct wcfxs *wc, int card, unsigned char addre return res; } -static int wcfxs_getreg_indirect(struct wcfxs *wc, int card, unsigned char address) +static int wcfxs_proslic_getreg_indirect(struct wcfxs *wc, int card, unsigned char address) { unsigned long flags; int res = -1; @@ -426,20 +478,20 @@ static int wcfxs_getreg_indirect(struct wcfxs *wc, int card, unsigned char addre return res; } -static int wcfxs_init_indirect_regs(struct wcfxs *wc, int card) +static int wcfxs_proslic_init_indirect_regs(struct wcfxs *wc, int card) { unsigned char i; for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++) { - if(wcfxs_setreg_indirect(wc, card, indirect_regs[i].address,indirect_regs[i].initial)) + if(wcfxs_proslic_setreg_indirect(wc, card, indirect_regs[i].address,indirect_regs[i].initial)) return -1; } return 0; } -static int wcfxs_verify_indirect_regs(struct wcfxs *wc, int card) +static int wcfxs_proslic_verify_indirect_regs(struct wcfxs *wc, int card) { int passed = 1; unsigned short i, initial; @@ -447,7 +499,7 @@ static int wcfxs_verify_indirect_regs(struct wcfxs *wc, int card) for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++) { - if((j = wcfxs_getreg_indirect(wc, card, (unsigned char) indirect_regs[i].address)) < 0) { + if((j = wcfxs_proslic_getreg_indirect(wc, card, (unsigned char) indirect_regs[i].address)) < 0) { printk("Failed to read indirect register %d\n", i); return -1; } @@ -470,6 +522,7 @@ static int wcfxs_verify_indirect_regs(struct wcfxs *wc, int card) } return 0; } + #ifdef LINUX26 static irqreturn_t wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) #else @@ -492,7 +545,7 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (ints & 0x10) { /* Stop DMA, wait for watchdog */ - printk("FXS PCI Master abort\n"); + printk("TDM PCI Master abort\n"); wcfxs_stop_dma(wc); #ifdef LINUX26 return IRQ_RETVAL(1); @@ -511,7 +564,8 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) } for (x=0;x<4;x++) { - if ((x < wc->cards) && (wc->cardflag & (1 << x))) { + if ((x < wc->cards) && (wc->cardflag & (1 << x)) && + (wc->modtype[x] == MOD_TYPE_FXS)) { if (wc->lasttxhook[x] == 0x4) { /* RINGing, prepare for OHT */ wc->ohttimer[x] = OHT_TIMER << 3; @@ -536,15 +590,19 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) wc->intcount++; x = wc->intcount % 4; if ((x < wc->cards) && (wc->cardflag & (1 << x))) { - wcfxs_check_hook(wc, x); - if (!(wc->intcount & 0xfc)) - wcfxs_recheck_sanity(wc, x); + if (wc->modtype[x] == MOD_TYPE_FXS) { + wcfxs_proslic_check_hook(wc, x); + if (!(wc->intcount & 0xfc)) + wcfxs_proslic_recheck_sanity(wc, x); + } } if (!(wc->intcount % 10000)) { /* Accept an alarm once per 10 seconds */ for (x=0;x<4;x++) - if (wc->palarms[x]) - wc->palarms[x]--; + if (wc->modtype[x] == MOD_TYPE_FXS) { + if (wc->palarms[x]) + wc->palarms[x]--; + } } wcfxs_receiveprep(wc, ints); wcfxs_transmitprep(wc, ints); @@ -555,6 +613,18 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) } +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; @@ -570,7 +640,7 @@ static int wcfxs_proslic_insane(struct wcfxs *wc, int card) return -1; } #endif - if ((blah & 0xf) == 0) { + if (((blah & 0xf) == 0) || ((blah & 0xf) == 0xf)) { /* SLIC not loaded */ return -1; } @@ -608,7 +678,7 @@ static int wcfxs_proslic_insane(struct wcfxs *wc, int card) return 0; } -static int wcfxs_powerleak_test(struct wcfxs *wc, int card) +static int wcfxs_proslic_powerleak_test(struct wcfxs *wc, int card) { unsigned long origjiffies; unsigned char vbat; @@ -701,7 +771,7 @@ static int wcfxs_powerup_proslic(struct wcfxs *wc, int card, int fast) } -static int wcfxs_manual_calibrate(struct wcfxs *wc, int card){ +static int wcfxs_proslic_manual_calibrate(struct wcfxs *wc, int card){ unsigned long origjiffies; unsigned char i; @@ -726,12 +796,12 @@ static int wcfxs_manual_calibrate(struct wcfxs *wc, int card){ // Delay 10ms origjiffies=jiffies; while((jiffies-origjiffies)<1); - wcfxs_setreg_indirect(wc, card, 88,0); - wcfxs_setreg_indirect(wc,card,89,0); - wcfxs_setreg_indirect(wc,card,90,0); - wcfxs_setreg_indirect(wc,card,91,0); - wcfxs_setreg_indirect(wc,card,92,0); - wcfxs_setreg_indirect(wc,card,93,0); + 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); @@ -775,7 +845,7 @@ static int wcfxs_manual_calibrate(struct wcfxs *wc, int card){ } #if 1 -static int wcfxs_calibrate(struct wcfxs *wc, int card) +static int wcfxs_proslic_calibrate(struct wcfxs *wc, int card) { unsigned long origjiffies; int x; @@ -804,6 +874,63 @@ static int wcfxs_calibrate(struct wcfxs *wc, int card) return 0; } #endif + +static int wcfxs_init_voicedaa(struct wcfxs *wc, int card, int fast, int manual, int sane) +{ + long newjiffies; + wc->modtype[card] = MOD_TYPE_FXO; + /* Sanity check the ProSLIC */ + reset_spi(wc, card); + if (!sane && wcfxs_voicedaa_insane(wc, card)) + return -2; + + /* Software reset */ + wcfxs_setreg(wc, card, 1, 0x80); + + /* Wait just a bit */ + newjiffies = jiffies + (HZ/10); + while(jiffies < newjiffies); + + /* Enable PCM, ulaw */ + wcfxs_setreg(wc, card, 33, 0x28); + + /* Misc. DAA parameters */ + wcfxs_setreg(wc, card, 31, 0xa3); + + /* Set AC Impedence */ + wcfxs_setreg(wc, card, 30, 0x00); + + /* Set DC Termination */ + wcfxs_setreg(wc, card, 26, 0xc0); + + /* Set Transmit/Receive timeslot */ + wcfxs_setreg(wc, card, 34, (3-card) * 8); + wcfxs_setreg(wc, card, 35, 0x00); + wcfxs_setreg(wc, card, 36, (3-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)); + + 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, 0x40); + return 0; + +} + static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, int sane) { @@ -822,13 +949,13 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, wcfxs_setreg(wc, card, 14, 0x10); } - if (wcfxs_init_indirect_regs(wc, card)) { + 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_setreg_indirect(wc, card, 97,0); + wcfxs_proslic_setreg_indirect(wc, card, 97,0); /* Clear digital loopback */ wcfxs_setreg(wc, card, 8, 0); @@ -846,8 +973,8 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, /* Flush ProSLIC digital filters by setting to clear, while saving old values */ for (x=0;x<5;x++) { - tmp[x] = wcfxs_getreg_indirect(wc, card, x + 35); - wcfxs_setreg_indirect(wc, card, x + 35, 0x8000); + 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 */ @@ -859,7 +986,7 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, if (!fast) { /* Check for power leaks */ - if (wcfxs_powerleak_test(wc, card)) { + if (wcfxs_proslic_powerleak_test(wc, card)) { printk("ProSLIC module %d failed leakage test. Check for short circuit\n", card); } /* Power up again */ @@ -870,9 +997,9 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, #ifndef NO_CALIBRATION /* Perform calibration */ if(manual) { - if (wcfxs_manual_calibrate(wc, card)) { + if (wcfxs_proslic_manual_calibrate(wc, card)) { //printk("Proslic failed on Manual Calibration\n"); - if (wcfxs_manual_calibrate(wc, card)) { + if (wcfxs_proslic_manual_calibrate(wc, card)) { printk("Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n"); return -1; } @@ -880,9 +1007,9 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, } } else { - if(wcfxs_calibrate(wc, card)) { + if(wcfxs_proslic_calibrate(wc, card)) { //printk("ProSlic died on Auto Calibration.\n"); - if (wcfxs_calibrate(wc, card)) { + if (wcfxs_proslic_calibrate(wc, card)) { printk("Proslic Failed on Second Attempt to Auto Calibrate\n"); return -1; } @@ -894,10 +1021,10 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, } /* Calibration complete, restore original values */ for (x=0;x<5;x++) { - wcfxs_setreg_indirect(wc, card, x + 35, tmp[x]); + wcfxs_proslic_setreg_indirect(wc, card, x + 35, tmp[x]); } - if (wcfxs_verify_indirect_regs(wc, card)) { + if (wcfxs_proslic_verify_indirect_regs(wc, card)) { printk(KERN_INFO "Indirect Registers failed verification.\n"); return -1; } @@ -910,7 +1037,7 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, #endif #if 0 - if (wcfxs_setreg_indirect(wc, card, 97, 0x0)) { // Stanley: for the bad recording fix + if (wcfxs_proslic_setreg_indirect(wc, card, 97, 0x0)) { // Stanley: for the bad recording fix printk(KERN_INFO "ProSlic IndirectReg Died.\n"); return -1; } @@ -943,16 +1070,14 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, #endif #ifdef BOOST_RINGER - wcfxs_setreg(wc, card, 74, 0x3f); - /* Beef up Ringing voltage to 89V */ - if (wcfxs_setreg_indirect(wc, card, 21, 0x1e1)) + if (wcfxs_proslic_setreg_indirect(wc, card, 23, 0x1d1)) return -1; #endif return 0; } -static inline void wcfxs_recheck_sanity(struct wcfxs *wc, int card) +static inline void wcfxs_proslic_recheck_sanity(struct wcfxs *wc, int card) { int res; /* Check loopback */ @@ -976,7 +1101,7 @@ static inline void wcfxs_recheck_sanity(struct wcfxs *wc, int card) } } -static inline void wcfxs_check_hook(struct wcfxs *wc, int card) +static inline void wcfxs_proslic_check_hook(struct wcfxs *wc, int card) { char res; int hook; @@ -1038,17 +1163,26 @@ static int wcfxs_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long dat int x; switch (cmd) { case WCFXS_GET_STATS: + if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) + return -EINVAL; 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; if (copy_to_user((struct wcfxs_stats *)data, &stats, sizeof(stats))) return -EFAULT; break; case WCFXS_GET_REGS: - for (x=0;x<NUM_INDIRECT_REGS;x++) - regs.indirect[x] = wcfxs_getreg_indirect(wc, chan->chanpos -1, x); - for (x=0;x<NUM_REGS;x++) - regs.direct[x] = wcfxs_getreg(wc, chan->chanpos - 1, x); + if (wc->modtype == 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; @@ -1056,25 +1190,16 @@ static int wcfxs_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long dat 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_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val); + 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; - case ZT_ONHOOKTRANSFER: - if (copy_from_user(&x, (int *)data, sizeof(x))) - return -EFAULT; - /* RINGing, prepare for OHT */ - wc->ohttimer[x] = x << 3; - wc->idletxhookstate[chan->chanpos - 1] = 0x2; /* OHT mode when idle */ - if (!wc->lasttxhook[chan->chanpos - 1]) { - wc->lasttxhook[chan->chanpos-1] = wc->idletxhookstate[chan->chanpos-1]; - wcfxs_setreg(wc, chan->chanpos - 1, 64, wc->lasttxhook[chan->chanpos-1]); - } - break; default: return -ENOTTY; } @@ -1090,15 +1215,13 @@ static int wcfxs_open(struct zt_chan *chan) if (wc->dead) return -ENODEV; wc->usecount++; -#ifndef LINUX26 MOD_INC_USE_COUNT; -#endif return 0; } static int wcfxs_watchdog(struct zt_span *span, int event) { - printk("FXS: Restarting DMA\n"); + printk("TDM: Restarting DMA\n"); wcfxs_restart_dma(span->pvt); return 0; } @@ -1108,9 +1231,7 @@ static int wcfxs_close(struct zt_chan *chan) struct wcfxs *wc = chan->pvt; int x; wc->usecount--; -#ifndef LINUX26 MOD_DEC_USE_COUNT; -#endif for (x=0;x<wc->cards;x++) wc->idletxhookstate[x] = 1; /* If we're dead, release us now */ @@ -1123,36 +1244,51 @@ static int wcfxs_hooksig(struct zt_chan *chan, zt_txsig_t txsig) { struct wcfxs *wc = chan->pvt; int reg=0; - switch(txsig) { - case ZT_TXSIG_ONHOOK: - switch(chan->sig) { - case ZT_SIG_FXOKS: - case ZT_SIG_FXOLS: + if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { + /* XXX Enable hooksig for FXO XXX */ + switch(txsig) { + case ZT_TXSIG_START: + case ZT_TXSIG_OFFHOOK: + wcfxs_setreg(wc, chan->chanpos - 1, 5, 0x41); + break; + case ZT_TXSIG_ONHOOK: + wcfxs_setreg(wc, chan->chanpos - 1, 5, 0x40); + break; + default: + printk("wcfxo: Can't set tx state to %d\n", txsig); + } + } else { + switch(txsig) { + case ZT_TXSIG_ONHOOK: + switch(chan->sig) { + case ZT_SIG_FXOKS: + case ZT_SIG_FXOLS: + wc->lasttxhook[chan->chanpos-1] = wc->idletxhookstate[chan->chanpos-1]; + break; + case ZT_SIG_FXOGS: + wc->lasttxhook[chan->chanpos-1] = 3; + break; + } + break; + case ZT_TXSIG_OFFHOOK: wc->lasttxhook[chan->chanpos-1] = wc->idletxhookstate[chan->chanpos-1]; break; - case ZT_SIG_FXOGS: - wc->lasttxhook[chan->chanpos-1] = 3; + case ZT_TXSIG_START: + wc->lasttxhook[chan->chanpos-1] = 4; + break; + case ZT_TXSIG_KEWL: + wc->lasttxhook[chan->chanpos-1] = 0; break; + default: + printk("wcfxs: Can't set tx state to %d\n", txsig); } - break; - case ZT_TXSIG_OFFHOOK: - wc->lasttxhook[chan->chanpos-1] = wc->idletxhookstate[chan->chanpos-1]; - break; - case ZT_TXSIG_START: - wc->lasttxhook[chan->chanpos-1] = 4; - break; - case ZT_TXSIG_KEWL: - wc->lasttxhook[chan->chanpos-1] = 0; - break; - default: - printk("wcfxs: Can't set tx state to %d\n", txsig); - } - if (debug) - printk("Setting hook state to %d (%02x)\n", txsig, reg); + if (debug) + printk("Setting FXS hook state to %d (%02x)\n", txsig, reg); #if 1 - wcfxs_setreg(wc, chan->chanpos - 1, 64, wc->lasttxhook[chan->chanpos-1]); + wcfxs_setreg(wc, chan->chanpos - 1, 64, wc->lasttxhook[chan->chanpos-1]); #endif + } return 0; } @@ -1160,12 +1296,13 @@ static int wcfxs_initialize(struct wcfxs *wc) { int x; /* Zapata stuff */ - sprintf(wc->span.name, "WCFXS/%d", wc->pos); + sprintf(wc->span.name, "WCTDM/%d", wc->pos); sprintf(wc->span.desc, "%s Board %d", wc->variety, wc->pos + 1); wc->span.deflaw = ZT_LAW_MULAW; for (x=0;x<wc->cards;x++) { - sprintf(wc->chans[x].name, "WCFXS/%d/%d", wc->pos, x); - wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_SF; + sprintf(wc->chans[x].name, "WCTDM/%d/%d", wc->pos, x); + wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_SF; + wc->chans[x].sigcap |= ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF; wc->chans[x].chanpos = x+1; wc->chans[x].pvt = wc; } @@ -1187,6 +1324,20 @@ static int wcfxs_initialize(struct wcfxs *wc) return 0; } +static void wcfxs_post_initialize(struct wcfxs *wc) +{ + int x; + /* Finalize signalling */ + for (x=0;x<wc->cards;x++) { + if (wc->cardflag & (1 << x)) { + if (wc->modtype[x] == MOD_TYPE_FXO) + wc->chans[x].sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF; + else + wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_SF; + } + } +} + static int wcfxs_hardware_init(struct wcfxs *wc) { /* Hardware stuff */ @@ -1220,7 +1371,7 @@ static int wcfxs_hardware_init(struct wcfxs *wc) return -1; } /* Go to half-duty FSYNC */ - __wcfxs_setcreg(wc, WC_SYNC, 0x00); + __wcfxs_setcreg(wc, WC_SYNC, 0x01); y = __wcfxs_getcreg(wc, WC_SYNC); } else { printk("No freshmaker chip\n"); @@ -1270,25 +1421,34 @@ static int wcfxs_hardware_init(struct wcfxs *wc) for (x=0;x<wc->cards;x++) { int sane=0,ret=0; +#if 1 /* Init with Auto Calibration */ if (!(ret=wcfxs_init_proslic(wc, x, 0, 0, sane))) { wc->cardflag |= (1 << x); - printk("Module %d: Installed -- AUTO\n",x); + printk("Module %d: Installed -- AUTO FXS\n",x); } else { - if(ret!=-2) sane=1; - /* Init with Manual Calibration */ - if (!wcfxs_init_proslic(wc, x, 0, 1, sane)) { + if(ret!=-2) { + sane=1; + /* Init with Manual Calibration */ + if (!wcfxs_init_proslic(wc, x, 0, 1, sane)) { + wc->cardflag |= (1 << x); + printk("Module %d: Installed -- MANUAL FXS\n",x); + } else { + printk("Module %d: FAILED FXS\n", x); + } + } else if (!(ret = wcfxs_init_voicedaa(wc, x, 0, 0, sane))) { wc->cardflag |= (1 << x); - printk("Module %d: Installed -- MANUAL\n",x); - } else + printk("Module %d: Installed -- AUTO FXO\n",x); + } else printk("Module %d: Not installed\n", x); } +#endif } /* Return error if nothing initialized okay. */ if (!wc->cardflag) return -1; - __wcfxs_setcreg(wc, WC_SYNC, wc->cardflag << 1); + __wcfxs_setcreg(wc, WC_SYNC, (wc->cardflag << 1) | 0x1); return 0; } @@ -1387,6 +1547,11 @@ static int __devinit wcfxs_init_one(struct pci_dev *pdev, const struct pci_devic if (wcfxs_initialize(wc)) { printk("wcfxs: Unable to intialize FXS\n"); + /* Set Reset Low */ + x=inb(wc->ioaddr + WC_CNTL); + outb((~0x1)&x, wc->ioaddr + WC_CNTL); + /* Free Resources */ + free_irq(pdev->irq, wc); if (wc->freeregion) release_region(wc->ioaddr, 0xff); pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma); @@ -1400,7 +1565,7 @@ static int __devinit wcfxs_init_one(struct pci_dev *pdev, const struct pci_devic /* Keep track of which device we are */ pci_set_drvdata(pdev, wc); - if (request_irq(pdev->irq, wcfxs_interrupt, SA_SHIRQ, "wcfxs", wc)) { + if (request_irq(pdev->irq, wcfxs_interrupt, SA_SHIRQ, "wctdm", wc)) { printk("wcfxs: Unable to request IRQ %d\n", pdev->irq); if (wc->freeregion) release_region(wc->ioaddr, 0xff); @@ -1418,14 +1583,17 @@ static int __devinit wcfxs_init_one(struct pci_dev *pdev, const struct pci_devic outb((~0x1)&x, wc->ioaddr + WC_CNTL); /* Free Resources */ free_irq(pdev->irq, wc); - zt_unregister(&wc->span); if (wc->freeregion) release_region(wc->ioaddr, 0xff); pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma); pci_set_drvdata(pdev, NULL); kfree(wc); return -EIO; + } + + wcfxs_post_initialize(wc); + /* Enable interrupts */ wcfxs_enable_interrupts(wc); /* Initialize Write/Buffers to all blank data */ @@ -1434,7 +1602,7 @@ static int __devinit wcfxs_init_one(struct pci_dev *pdev, const struct pci_devic /* Start DMA */ wcfxs_start_dma(wc); - printk("Found a Wildcard FXS: %s (%d modules)\n", wc->variety, wc->cards); + printk("Found a Wildcard TDM: %s (%d modules)\n", wc->variety, wc->cards); res = 0; } else res = -ENOMEM; |