From 58fb517415c5971aa4feb3bb84bfa9bad26bea63 Mon Sep 17 00:00:00 2001 From: markster Date: Mon, 11 Feb 2002 17:23:02 +0000 Subject: Version 0.1.6 from FTP git-svn-id: http://svn.digium.com/svn/zaptel/trunk@55 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- wct1xxp.c | 464 ++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 313 insertions(+), 151 deletions(-) (limited to 'wct1xxp.c') diff --git a/wct1xxp.c b/wct1xxp.c index 82a634c..c612f59 100755 --- a/wct1xxp.c +++ b/wct1xxp.c @@ -41,7 +41,9 @@ #define WC_MAX_CARDS 32 +/* #define TEST_REGS +*/ /* Define to get more attention-grabbing but slightly more I/O using alarm status */ @@ -79,11 +81,23 @@ #define WC_OFFSET 4 #define BIT_CS (1 << 7) - -#define BIT_OK (1 << 0) -#define BIT_TEST (1 << 1) -#define BIT_ERROR (1 << 2) -#define BIT_ALARM (1 << 3) +#define BIT_ADDR (0xf << 3) + +#define BIT_LED0 (1 << 0) +#define BIT_LED1 (1 << 1) +#define BIT_TEST (1 << 2) + +static char *chips[] = +{ + "DS2152", + "DS21352", + "DS21552", + "Unknown Chip (3)", + "DS2154", + "DS21354", + "DS21554", + "Unknown Chip (4)", +}; static int chanmap[] = { 2,1,0, @@ -108,11 +122,11 @@ struct t1xxp { /* Our offset for finding channel 1 */ int offset; char *variety; + int intcount; int usecount; int dead; + int blinktimer; int alarmtimer; - int alarm; - int alreadyrunning; #ifdef FANCY_ALARM int alarmpos; #endif @@ -133,31 +147,30 @@ static struct t1xxp *cards[WC_MAX_CARDS]; static inline void start_alarm(struct t1xxp *wc) { - wc->alarm = 1; #ifdef FANCY_ALARM wc->alarmpos = 0; #endif - wc->alarmtimer = 0; + wc->blinktimer = 0; } static inline void stop_alarm(struct t1xxp *wc) { - wc->alarm = 0; #ifdef FANCY_ALARM wc->alarmpos = 0; #endif - wc->alarmtimer = 0; + wc->blinktimer = 0; } -static inline void select_framer(struct t1xxp *wc) +static inline void __select_framer(struct t1xxp *wc, int reg) { - if (wc->outbyte & BIT_CS) { - wc->outbyte &= ~BIT_CS; - outb(wc->outbyte, wc->ioaddr + WC_AUXD); - } + /* Top four bits of address from AUX 6-3 */ + wc->outbyte &= ~BIT_CS; + wc->outbyte &= ~BIT_ADDR; + wc->outbyte |= (reg & 0xf0) >> 1; + outb(wc->outbyte, wc->ioaddr + WC_AUXD); } -static inline void select_control(struct t1xxp *wc) +static inline void __select_control(struct t1xxp *wc) { if (!(wc->outbyte & BIT_CS)) { wc->outbyte |= BIT_CS; @@ -175,41 +188,58 @@ static int t1xxp_open(struct zt_chan *chan) return 0; } -static int t1_get_reg(struct t1xxp *wc, int reg) +static int __t1_get_reg(struct t1xxp *wc, int reg) { unsigned char res; - select_framer(wc); - /* Send address */ - outb(reg & 0xff, wc->ioaddr + WC_USERREG + 4); + __select_framer(wc, reg); /* Get value */ - res = inb(wc->ioaddr + WC_USERREG); + res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); return res; } -static int t1_set_reg(struct t1xxp *wc, int reg, unsigned char val) +static int __t1_set_reg(struct t1xxp *wc, int reg, unsigned char val) { - select_framer(wc); + __select_framer(wc, reg); /* Send address */ - outb(reg & 0xff, wc->ioaddr + WC_USERREG + 4); - outb(val, wc->ioaddr + WC_USERREG); + outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); return 0; } -static int control_set_reg(struct t1xxp *wc, int reg, unsigned char val) +static int __control_set_reg(struct t1xxp *wc, int reg, unsigned char val) { - select_control(wc); + __select_control(wc); outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); return 0; } -static int control_get_reg(struct t1xxp *wc, int reg) +static int control_set_reg(struct t1xxp *wc, int reg, unsigned char val) +{ + long flags; + int res; + spin_lock_irqsave(&wc->lock, flags); + res = __control_set_reg(wc, reg, val); + spin_unlock_irqrestore(&wc->lock, flags); + return res; +} + +static int __control_get_reg(struct t1xxp *wc, int reg) { unsigned char res; - select_control(wc); + __select_control(wc); res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); return res; } +static int control_get_reg(struct t1xxp *wc, int reg) +{ + long flags; + int res; + spin_lock_irqsave(&wc->lock, flags); + res = __control_get_reg(wc, reg); + spin_unlock_irqrestore(&wc->lock, flags); + return res; +} + static void t1xxp_release(struct t1xxp *wc) { zt_unregister(&wc->span); @@ -249,12 +279,12 @@ static void t1xxp_start_dma(struct t1xxp *wc) printk("Started DMA\n"); } -static void t1xxp_stop_dma(struct t1xxp *wc) +static void __t1xxp_stop_dma(struct t1xxp *wc) { outb(0x00, wc->ioaddr + WC_OPER); } -static void t1xxp_disable_interrupts(struct t1xxp *wc) +static void __t1xxp_disable_interrupts(struct t1xxp *wc) { outb(0x00, wc->ioaddr + WC_MASK0); outb(0x00, wc->ioaddr + WC_MASK1); @@ -265,6 +295,11 @@ static void t1xxp_framer_start(struct t1xxp *wc) int i; char *coding, *framing; unsigned long endjiffies; + int alreadyrunning = wc->span.flags & ZT_FLAG_RUNNING; + long flags; + + spin_lock_irqsave(&wc->lock, flags); + /* Build up config */ i = 0x20; if (wc->span.lineconfig & ZT_CONFIG_ESF) { @@ -279,105 +314,101 @@ static void t1xxp_framer_start(struct t1xxp *wc) } else { framing = "AMI"; } - t1_set_reg(wc, 0x38, i); + __t1_set_reg(wc, 0x38, i); if (!(wc->span.lineconfig & ZT_CONFIG_ESF)) { /* 1c in FDL bit */ - t1_set_reg(wc, 0x7e, 0x1c); + __t1_set_reg(wc, 0x7e, 0x1c); } else { - t1_set_reg(wc, 0x7e, 0x00); + __t1_set_reg(wc, 0x7e, 0x00); } /* Set outgoing LBO */ - t1_set_reg(wc, 0x7c, wc->span.txlevel << 5); + __t1_set_reg(wc, 0x7c, wc->span.txlevel << 5); printk("Using %s/%s coding/framing\n", coding, framing); - if (!wc->alreadyrunning) { + if (!alreadyrunning) { /* Set LIRST bit to 1 */ - t1_set_reg(wc, 0x30, 0x1); + __t1_set_reg(wc, 0x0a, 0x80); + spin_unlock_irqrestore(&wc->lock, flags); /* Wait 100ms to give plenty of time for reset */ endjiffies = jiffies + 10; while(endjiffies < jiffies); - /* Reset elastic stores */ - t1_set_reg(wc, 0x30, 0x40); - wc->alreadyrunning = 1; - } -#if 0 - { - t1_set_reg(wc, 0x3c, 0xff); - t1_set_reg(wc, 0x3d, 0xff); - t1_set_reg(wc, 0x3e, 0xff); - int x; - for (i=0x20;i<0x40;i++) { - x = t1_get_reg(wc, i); - if (x) - printk("%02x: %02x\n", i, x); - } - for (i=0x60;i<0x80;i++) { - x = t1_get_reg(wc, i); - if (x) - printk("%02x: %02x\n", i, x); - } + spin_lock_irqsave(&wc->lock, flags); + + /* Reset LIRST bit and reset elastic stores */ + __t1_set_reg(wc, 0xa, 0x30); + + wc->span.flags |= ZT_FLAG_RUNNING; } -#endif + spin_unlock_irqrestore(&wc->lock, flags); +} + +static int t1xxp_framer_sanity_check(struct t1xxp *wc) +{ + int res; + int chipid; + long flags; + + /* Sanity check */ + spin_lock_irqsave(&wc->lock, flags); + res = __t1_get_reg(wc, 0x0f); + chipid = ((res & 0x80) >> 5) | ((res & 0x30) >> 4); + spin_unlock_irqrestore(&wc->lock, flags); + + printk("Framer: %s, Revision: %d\n", chips[chipid], res & 0xf); + return 0; } static int t1xxp_framer_hard_reset(struct t1xxp *wc) { int x; + long flags; + + spin_lock_irqsave(&wc->lock, flags); /* Initialize all registers to 0 */ - for (x=0x20;x<0x40;x++) - t1_set_reg(wc, x, 0); - for (x=0x60;x<0x80;x++) - t1_set_reg(wc, x, 0); + for (x=0x0;x<0x96;x++) + __t1_set_reg(wc, x, 0); /* Full-on sync required */ - t1_set_reg(wc, 0x2b, 0x08); + __t1_set_reg(wc, 0x2b, 0x08); /* RSYNC is an input */ - t1_set_reg(wc, 0x2c, 0x08); + __t1_set_reg(wc, 0x2c, 0x08); /* Enable tx RBS bits */ - t1_set_reg(wc, 0x35, 0x10); + __t1_set_reg(wc, 0x35, 0x10); /* TSYNC is output */ - t1_set_reg(wc, 0x36, 0x04); + __t1_set_reg(wc, 0x36, 0x04); /* Tx and Rx elastic store enabled, 2.048 Mhz (in theory) */ - t1_set_reg(wc, 0x37, 0x8c); -#ifdef TEST_REGS - printk("Testing framer registers...\n"); - t1_set_reg(wc, 0x6c, 0xff); - printk("Expecting ff, got %02x\n", t1_get_reg(wc, 0x6c)); - t1_set_reg(wc, 0x6c, 0x00); - printk("Expecting 00, got %02x\n", t1_get_reg(wc, 0x6c)); - t1_set_reg(wc, 0x6c, 0xaa); - printk("Expecting aa, got %02x\n", t1_get_reg(wc, 0x6c)); - t1_set_reg(wc, 0x6c, 0x55); - printk("Expecting 55, got %02x\n", t1_get_reg(wc, 0x6c)); - t1_set_reg(wc, 0x6c, 0x00); - printk("Testing control registers...\n"); - control_set_reg(wc, WC_LEDTEST, 0xff); - printk("Expecting ff, got %02x\n", control_get_reg(wc, WC_LEDTEST)); - control_set_reg(wc, WC_LEDTEST, 0x00); - printk("Expecting 00, got %02x\n", control_get_reg(wc, WC_LEDTEST)); - control_set_reg(wc, WC_LEDTEST, 0xaa); - printk("Expecting aa, got %02x\n", control_get_reg(wc, WC_LEDTEST)); - control_set_reg(wc, WC_LEDTEST, 0x55); - printk("Expecting 55, got %02x\n", control_get_reg(wc, WC_LEDTEST)); - control_set_reg(wc, WC_LEDTEST, 0x00); -#endif + __t1_set_reg(wc, 0x37, 0x9c); + + /* Setup Loopup / Loopdown codes */ + __t1_set_reg(wc, 0x12, 0x22); + __t1_set_reg(wc, 0x14, 0x80); + __t1_set_reg(wc, 0x15, 0x80); + spin_unlock_irqrestore(&wc->lock, flags); return 0; } static int t1xxp_rbsbits(struct zt_chan *chan, int bits) { struct t1xxp *wc = chan->pvt; + long flags; + int b,o; + unsigned char mask; + /* Byte offset */ - int b = (chan->chanpos - 1) / 8; - int o = (chan->chanpos - 1) % 8; - unsigned char mask = (1 << o); + spin_lock_irqsave(&wc->lock, flags); + + b = (chan->chanpos - 1) / 8; + o = (chan->chanpos - 1) % 8; + + mask = (1 << o); + if (bits & ZT_ABIT) { /* Set A-bit */ wc->txsiga[b] |= mask; @@ -392,10 +423,11 @@ static int t1xxp_rbsbits(struct zt_chan *chan, int bits) wc->txsigb[b] &= ~mask; } /* Output new values */ - t1_set_reg(wc, 0x70 + b, wc->txsiga[b]); - t1_set_reg(wc, 0x73 + b, wc->txsigb[b]); - t1_set_reg(wc, 0x76 + b, wc->txsiga[b]); - t1_set_reg(wc, 0x79 + b, wc->txsigb[b]); + __t1_set_reg(wc, 0x70 + b, wc->txsiga[b]); + __t1_set_reg(wc, 0x73 + b, wc->txsigb[b]); + __t1_set_reg(wc, 0x76 + b, wc->txsiga[b]); + __t1_set_reg(wc, 0x79 + b, wc->txsigb[b]); + spin_unlock_irqrestore(&wc->lock, flags); return 0; } @@ -412,6 +444,7 @@ static int t1xxp_startup(struct zt_span *span) struct t1xxp *wc = span->pvt; /* Reset framer with proper parameters and start */ t1xxp_framer_start(wc); + if (!(span->flags & ZT_FLAG_RUNNING)) { /* Only if we're not already going */ t1xxp_enable_interrupts(wc); @@ -424,9 +457,15 @@ static int t1xxp_startup(struct zt_span *span) static int t1xxp_shutdown(struct zt_span *span) { struct t1xxp *wc = span->pvt; - t1xxp_stop_dma(wc); - t1xxp_disable_interrupts(wc); + long flags; + + spin_lock_irqsave(&wc->lock, flags); + __t1xxp_stop_dma(wc); + __t1xxp_disable_interrupts(wc); span->flags &= ~ZT_FLAG_RUNNING; + spin_unlock_irqrestore(&wc->lock, flags); + + t1xxp_framer_hard_reset(wc); return 0; } @@ -436,7 +475,7 @@ static int t1xxp_maint(struct zt_span *span, int mode) return -1; } -static void t1xxp_set_clear(struct t1xxp *wc) +static void __t1xxp_set_clear(struct t1xxp *wc) { /* Setup registers */ int x,y; @@ -446,7 +485,7 @@ static void t1xxp_set_clear(struct t1xxp *wc) for (y=0;y<8;y++) if (wc->chans[x * 8 + y].sig & ZT_SIG_CLEAR) b |= (1 << y); - t1_set_reg(wc, 0x39 + x, b); + __t1_set_reg(wc, 0x39 + x, b); } } @@ -455,9 +494,12 @@ static int t1xxp_chanconfig(struct zt_chan *chan, int sigtype) struct t1xxp *wc = chan->pvt; int flags; int alreadyrunning = chan->span->flags & ZT_FLAG_RUNNING; + spin_lock_irqsave(&wc->lock, flags); + if (alreadyrunning) - t1xxp_set_clear(wc); + __t1xxp_set_clear(wc); + spin_unlock_irqrestore(&wc->lock, flags); return 0; } @@ -504,6 +546,7 @@ static int t1xxp_software_init(struct t1xxp *wc) wc->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF; wc->span.ioctl = t1xxp_ioctl; wc->span.pvt = wc; + wc->span.deflaw = ZT_LAW_MULAW; init_waitqueue_head(&wc->span.maintq); for (x=0;x<24;x++) { sprintf(wc->chans[x].name, "WCT1/%d/%d", wc->num, x + 1); @@ -521,34 +564,51 @@ static int t1xxp_software_init(struct t1xxp *wc) return 0; } -static inline void handle_leds(struct t1xxp *wc) +static inline void __handle_leds(struct t1xxp *wc) { - if (wc->alarm) { + int oldreg; + wc->blinktimer++; + if (wc->span.alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE)) { + /* Red/Blue alarm */ #ifdef FANCY_ALARM - if (wc->alarmtimer == (altab[wc->alarmpos] >> 1)) { - wc->ledtestreg = wc->ledtestreg | BIT_ALARM; - control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); + if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) { + wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0; + __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); } - if (wc->alarmtimer == 0xf) { - wc->ledtestreg = wc->ledtestreg & ~BIT_ALARM; - control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); - wc->alarmtimer = -1; + if (wc->blinktimer == 0xf) { + wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1); + __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); + wc->blinktimer = -1; wc->alarmpos++; if (wc->alarmpos >= (sizeof(altab) / sizeof(altab[0]))) wc->alarmpos = 0; } - wc->alarmtimer++; #else - wc->alarmtimer++; - if (wc->alarmtimer == 160) { - wc->ledtestreg = wc->ledtestreg | BIT_ALARM; - control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); - } else if (wc->alarmtimer == 480) { - wc->ledtestreg = wc->ledtestreg & ~BIT_ALARM; - control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); - wc->alarmtimer = 0; + if (wc->blinktimer == 160) { + wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0; + __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); + } else if (wc->blinktimer == 480) { + wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1); + __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); + wc->blinktimer = 0; } #endif + } else if (wc->span.alarms & ZT_ALARM_YELLOW) { + /* Yellow Alarm */ + if (!(wc->blinktimer % 2)) + wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0; + else + wc->ledtestreg = (wc->ledtestreg | BIT_LED0) & ~BIT_LED1; + __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); + } else { + /* No Alarm */ + oldreg = wc->ledtestreg; + if (wc->span.flags & ZT_FLAG_RUNNING) + wc->ledtestreg = (wc->ledtestreg | BIT_LED0) & ~BIT_LED1; + else + wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1); + if (oldreg != wc->ledtestreg) + __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); } } @@ -606,50 +666,140 @@ static void t1xxp_receiveprep(struct t1xxp *wc, int ints) zt_receive(&wc->span); } +static void __t1xxp_check_sigbits(struct t1xxp *wc, int x) +{ + int a,b,i,y,rxs; + + a = __t1_get_reg(wc, 0x60 + x); + b = __t1_get_reg(wc, 0x64 + x); + for (y=0;y<8;y++) { + i = x * 8 + y; + rxs = 0; + if (a & (1 << y)) + rxs |= ZT_ABIT; + if (b & (1 << y)) + rxs |= ZT_BBIT; + if (!(wc->chans[i].sig & ZT_SIG_CLEAR)) { + if (wc->chans[i].rxsig != rxs) + zt_rbsbits(&wc->chans[i], rxs); + } + } +} + +static void __t1xxp_check_alarms(struct t1xxp *wc) +{ + unsigned char c; + int alarms; + int x,j; + + /* Get RIR3 */ + c = __t1_get_reg(wc, 0x10); + wc->span.rxlevel = c >> 6; + + /* Get status register s*/ + __t1_set_reg(wc, 0x20, 0xff); + c = __t1_get_reg(wc, 0x20); + + /* Assume no alarms */ + alarms = 0; + + /* And consider only carrier alarms */ + wc->span.alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN); + + if (wc->span.lineconfig & ZT_CONFIG_NOTOPEN) { + for (x=0,j=0;x < wc->span.channels;x++) + if ((wc->chans[x].flags & ZT_FLAG_OPEN) || + (wc->chans[x].flags & ZT_FLAG_NETDEV)) + j++; + if (!j) + alarms |= ZT_ALARM_NOTOPEN; + } + + /* Check actual alarm status */ + if (c & 0x3) + alarms |= ZT_ALARM_RED; + if (c & 0x8) + alarms |= ZT_ALARM_BLUE; + + /* Keep track of recovering */ + if (!alarms && wc->span.alarms) + wc->alarmtimer = ZT_ALARMSETTLE_TIME; + if (wc->alarmtimer) + alarms |= ZT_ALARM_RECOVER; + + /* If receiving alarms, go into Yellow alarm state */ + if (alarms && !wc->span.alarms) { + printk("Going into yellow alarm\n"); + __t1_set_reg(wc, 0x35, 0x11); + } + + if (c & 0x4) + alarms |= ZT_ALARM_YELLOW; + + wc->span.alarms = alarms; + zt_alarm_notify(&wc->span); + +} + +static void __t1xxp_do_counters(struct t1xxp *wc) +{ + if (wc->alarmtimer) { + if (!--wc->alarmtimer) { + wc->span.alarms &= ~ZT_ALARM_RECOVER; + /* Clear yellow alarm */ + printk("Coming out of yellow alarm\n"); + __t1_set_reg(wc, 0x35, 0x10); + zt_alarm_notify(&wc->span); + } + } +} + static void t1xxp_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct t1xxp *wc = dev_id; - unsigned char ints, a,b, rxs; - static int gotint = 0; - int x,y,i; + unsigned char ints; + long flags; + int x; ints = inb(wc->ioaddr + WC_INTSTAT); + outb(ints, wc->ioaddr + WC_INTSTAT); + if (!ints) return; - outb(ints, wc->ioaddr + WC_INTSTAT); - if (!gotint) { + if (!wc->intcount) { printk("Got interrupt: 0x%04x\n", ints); } - gotint++; + wc->intcount++; if (ints & 0x0f) { - t1xxp_transmitprep(wc, ints); t1xxp_receiveprep(wc, ints); + t1xxp_transmitprep(wc, ints); } - handle_leds(wc); + spin_lock_irqsave(&wc->lock, flags); -#if 1 - if (!(gotint & 0xf0)) { - x = gotint & 0xf; - if (x < 3) { - a = t1_get_reg(wc, 0x60 + x); - b = t1_get_reg(wc, 0x64 + x); - for (y=0;y<8;y++) { - i = x * 8 + y; - rxs = 0; - if (a & (1 << y)) - rxs |= ZT_ABIT; - if (b & (1 << y)) - rxs |= ZT_BBIT; - if (!(wc->chans[i].sig & ZT_SIG_CLEAR)) { - if (wc->chans[i].rxsig != rxs) - zt_rbsbits(&wc->chans[i], rxs); - } - } - } - } + __handle_leds(wc); + + /* Count down timers */ + __t1xxp_do_counters(wc); + + /* Do some things that we don't have to do very often */ + x = wc->intcount & 63; + switch(x) { + case 0: + case 1: + case 2: + case 3: +#if 0 + __t1xxp_check_sigbits(wc, x); #endif + break; + case 4: + __t1xxp_check_alarms(wc); + break; + } + spin_unlock_irqrestore(&wc->lock, flags); + if (ints & 0x10) printk("PCI Master abort\n"); @@ -698,12 +848,16 @@ static int t1xxp_hardware_init(struct t1xxp *wc) /* Check out the controller */ printk("Controller version: %02x\n", control_get_reg(wc, WC_VERSION)); + + control_set_reg(wc, WC_LEDTEST, 0x00); control_set_reg(wc, WC_CLOCK, 0x00); + if (t1xxp_framer_sanity_check(wc)) + return -1; + /* Reset the T1 and report */ t1xxp_framer_hard_reset(wc); - /* Pretend we're in alarm */ start_alarm(wc); return 0; @@ -720,6 +874,7 @@ static int __devinit t1xxp_init_one(struct pci_dev *pdev, const struct pci_devic wc = kmalloc(sizeof(struct t1xxp), GFP_KERNEL); if (wc) { memset(wc, 0x0, sizeof(struct t1xxp)); + spin_lock_init(&wc->lock); wc->ioaddr = pci_resource_start(pdev, 0); wc->dev = pdev; wc->variety = (char *)(ent->driver_data); @@ -773,6 +928,10 @@ static void t1xxp_stop_stuff(struct t1xxp *wc) /* Turn off LED's */ control_set_reg(wc, WC_LEDTEST, 0); + + /* Reset the T1 */ + t1xxp_framer_hard_reset(wc); + } static void __devexit t1xxp_remove_one(struct pci_dev *pdev) @@ -781,10 +940,10 @@ static void __devexit t1xxp_remove_one(struct pci_dev *pdev) if (wc) { /* Stop any DMA */ - t1xxp_stop_dma(wc); + __t1xxp_stop_dma(wc); /* In case hardware is still there */ - t1xxp_disable_interrupts(wc); + __t1xxp_disable_interrupts(wc); t1xxp_stop_stuff(wc); @@ -833,6 +992,9 @@ static void __exit t1xxp_cleanup(void) MODULE_PARM(debug, "i"); MODULE_DESCRIPTION("Wildcard T100P Zaptel Driver"); MODULE_AUTHOR("Mark Spencer "); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif module_init(t1xxp_init); module_exit(t1xxp_cleanup); -- cgit v1.2.3