summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2004-02-25 15:35:13 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2004-02-25 15:35:13 +0000
commit13b50215f07edae9c475a5db4c0e4263d2a38ca9 (patch)
tree2d0af57d9f6d7ea0164f31d65d571640653c65b4
parent01dc55fe58b624307911563577d0ad4e3732bf04 (diff)
Add support for FXO module
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@319 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rwxr-xr-xfxstest.c22
-rwxr-xr-xwcfxs.c374
-rwxr-xr-xwctdm.c374
3 files changed, 558 insertions, 212 deletions
diff --git a/fxstest.c b/fxstest.c
index df7a80c..a99943c 100755
--- a/fxstest.c
+++ b/fxstest.c
@@ -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(&regs, 0, sizeof(regs));
res = ioctl(fd, WCFXS_GET_REGS, &regs);
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");
}
diff --git a/wcfxs.c b/wcfxs.c
index 3ade91a..dfaa385 100755
--- a/wcfxs.c
+++ b/wcfxs.c
@@ -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(&regs, 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, &regs, 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(&regop, (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;
diff --git a/wctdm.c b/wctdm.c
index 3ade91a..dfaa385 100755
--- a/wctdm.c
+++ b/wctdm.c
@@ -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(&regs, 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, &regs, 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(&regop, (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;