From 07d2942df868bbed234e7c7c3c23ba7356c977f4 Mon Sep 17 00:00:00 2001 From: markster Date: Wed, 5 Dec 2001 18:38:19 +0000 Subject: Version 0.1.4 from FTP git-svn-id: http://svn.digium.com/svn/zaptel/trunk@34 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- wct1xxp.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 422 insertions(+), 147 deletions(-) (limited to 'wct1xxp.c') diff --git a/wct1xxp.c b/wct1xxp.c index a173941..82a634c 100755 --- a/wct1xxp.c +++ b/wct1xxp.c @@ -32,13 +32,23 @@ #include #include #include +#include #ifdef STANDALONE_ZAPATA #include "zaptel.h" #else #include #endif -#define DELAY 0x30 /* 30 = 15 cycles, 10 = 8 cycles, 0 = 3 cycles */ +#define WC_MAX_CARDS 32 + +#define TEST_REGS + +/* Define to get more attention-grabbing but slightly more I/O using + alarm status */ +#define FANCY_ALARM + + +#define DELAY 0x0 /* 30 = 15 cycles, 10 = 8 cycles, 0 = 3 cycles */ #define WC_CNTL 0x00 #define WC_OPER 0x01 @@ -68,7 +78,7 @@ /* Offset between transmit and receive */ #define WC_OFFSET 4 -#define BIT_CS (1 << 5) +#define BIT_CS (1 << 7) #define BIT_OK (1 << 0) #define BIT_TEST (1 << 1) @@ -76,26 +86,41 @@ #define BIT_ALARM (1 << 3) static int chanmap[] = -{ 1,2,3, - 5,6,7, - 9,10,11, - 13,14,15, - 17,18,19, - 21,22,23, - 25,26,27, - 29,30,31 }; +{ 2,1,0, + 6,5,4, + 10,9,8, + 14,13,12, + 18,17,16, + 22,21,20, + 26,25,24, + 30,29,28 }; + +#ifdef FANCY_ALARM +static int altab[] = { +0, 0, 0, 1, 2, 3, 4, 6, 8, 9, 11, 13, 16, 18, 20, 22, 24, 25, 27, 28, 29, 30, 31, 31, 32, 31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0, +}; +#endif struct t1xxp { struct pci_dev *dev; + spinlock_t lock; + int num; + /* Our offset for finding channel 1 */ + int offset; char *variety; int usecount; int dead; int alarmtimer; int alarm; - int alarmthreshold; + int alreadyrunning; +#ifdef FANCY_ALARM + int alarmpos; +#endif unsigned char ledtestreg; unsigned char outbyte; unsigned long ioaddr; + unsigned char txsiga[3]; + unsigned char txsigb[3]; dma_addr_t readdma; dma_addr_t writedma; volatile unsigned char *writechunk; /* Double-word aligned write memory */ @@ -104,6 +129,26 @@ struct t1xxp { struct zt_chan chans[24]; /* Channels */ }; +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; +} + +static inline void stop_alarm(struct t1xxp *wc) +{ + wc->alarm = 0; +#ifdef FANCY_ALARM + wc->alarmpos = 0; +#endif + wc->alarmtimer = 0; +} + static inline void select_framer(struct t1xxp *wc) { if (wc->outbyte & BIT_CS) { @@ -120,23 +165,6 @@ static inline void select_control(struct t1xxp *wc) } } -static inline void select_page(struct t1xxp *wc, unsigned char reg) -{ - int page = (reg & 0x30) << 2; - if (wc->outbyte != page) { - /* Clear high bits */ - wc->outbyte &= 0x3f; - /* Set page */ - wc->outbyte |= page; - /* Make sure we've turned on the framer */ - wc->outbyte &= ~BIT_CS; - outb(wc->outbyte, wc->ioaddr + WC_AUXD); - } else if (wc->outbyte & BIT_CS) { - /* Check to be sure we don't still have to enable the framer */ - select_framer(wc); - } -} - static int t1xxp_open(struct zt_chan *chan) { struct t1xxp *wc = chan->pvt; @@ -150,15 +178,20 @@ static int t1xxp_open(struct zt_chan *chan) static int t1_get_reg(struct t1xxp *wc, int reg) { unsigned char res; - select_page(wc, reg); - res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); + select_framer(wc); + /* Send address */ + outb(reg & 0xff, wc->ioaddr + WC_USERREG + 4); + /* Get value */ + res = inb(wc->ioaddr + WC_USERREG); return res; } static int t1_set_reg(struct t1xxp *wc, int reg, unsigned char val) { - select_page(wc, reg); - outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); + select_framer(wc); + /* Send address */ + outb(reg & 0xff, wc->ioaddr + WC_USERREG + 4); + outb(val, wc->ioaddr + WC_USERREG); return 0; } @@ -179,6 +212,7 @@ static int control_get_reg(struct t1xxp *wc, int reg) static void t1xxp_release(struct t1xxp *wc) { + zt_unregister(&wc->span); kfree(wc); printk("Freed a Wildcard\n"); } @@ -194,19 +228,314 @@ static int t1xxp_close(struct zt_chan *chan) return 0; } +static void t1xxp_enable_interrupts(struct t1xxp *wc) +{ + /* Clear interrupts */ + outb(0xff, wc->ioaddr + WC_INTSTAT); + /* Enable interrupts (we care about all of them) */ + outb(0x3f, wc->ioaddr + WC_MASK0); + /* No external interrupts */ + outb(0x00, wc->ioaddr + WC_MASK1); +} + +static void t1xxp_start_dma(struct t1xxp *wc) +{ + /* Reset Master and TDM */ + outb(DELAY | 0x0f, wc->ioaddr + WC_CNTL); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + outb(DELAY | 0x01, wc->ioaddr + WC_CNTL); + outb(0x01, wc->ioaddr + WC_OPER); + printk("Started DMA\n"); +} + +static void t1xxp_stop_dma(struct t1xxp *wc) +{ + outb(0x00, wc->ioaddr + WC_OPER); +} + +static void t1xxp_disable_interrupts(struct t1xxp *wc) +{ + outb(0x00, wc->ioaddr + WC_MASK0); + outb(0x00, wc->ioaddr + WC_MASK1); +} + +static void t1xxp_framer_start(struct t1xxp *wc) +{ + int i; + char *coding, *framing; + unsigned long endjiffies; + /* Build up config */ + i = 0x20; + if (wc->span.lineconfig & ZT_CONFIG_ESF) { + coding = "ESF"; + i = 0x88; + } else { + coding = "SF"; + } + if (wc->span.lineconfig & ZT_CONFIG_B8ZS) { + framing = "B8ZS"; + i |= 0x44; + } else { + framing = "AMI"; + } + t1_set_reg(wc, 0x38, i); + if (!(wc->span.lineconfig & ZT_CONFIG_ESF)) { + /* 1c in FDL bit */ + t1_set_reg(wc, 0x7e, 0x1c); + } else { + t1_set_reg(wc, 0x7e, 0x00); + } + + /* Set outgoing LBO */ + t1_set_reg(wc, 0x7c, wc->span.txlevel << 5); + + printk("Using %s/%s coding/framing\n", coding, framing); + if (!wc->alreadyrunning) { + /* Set LIRST bit to 1 */ + t1_set_reg(wc, 0x30, 0x1); + + /* 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); + } + } +#endif +} + +static int t1xxp_framer_hard_reset(struct t1xxp *wc) +{ + int x; + /* 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); + + /* Full-on sync required */ + t1_set_reg(wc, 0x2b, 0x08); + + /* RSYNC is an input */ + t1_set_reg(wc, 0x2c, 0x08); + + /* Enable tx RBS bits */ + t1_set_reg(wc, 0x35, 0x10); + + /* TSYNC is output */ + 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 + return 0; +} + +static int t1xxp_rbsbits(struct zt_chan *chan, int bits) +{ + struct t1xxp *wc = chan->pvt; + /* Byte offset */ + int b = (chan->chanpos - 1) / 8; + int o = (chan->chanpos - 1) % 8; + unsigned char mask = (1 << o); + if (bits & ZT_ABIT) { + /* Set A-bit */ + wc->txsiga[b] |= mask; + } else { + /* Clear A-bit */ + wc->txsiga[b] &= ~mask; + } + if (bits & ZT_BBIT) { + /* Set B-bit */ + wc->txsigb[b] |= mask; + } else { + 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]); + return 0; +} + +static int t1xxp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) +{ + switch(cmd) { + default: + return -ENOTTY; + } +} + +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); + t1xxp_start_dma(wc); + span->flags |= ZT_FLAG_RUNNING; + } + return 0; +} + +static int t1xxp_shutdown(struct zt_span *span) +{ + struct t1xxp *wc = span->pvt; + t1xxp_stop_dma(wc); + t1xxp_disable_interrupts(wc); + span->flags &= ~ZT_FLAG_RUNNING; + return 0; +} + +static int t1xxp_maint(struct zt_span *span, int mode) +{ + /* XXX Implement me XXX */ + return -1; +} + +static void t1xxp_set_clear(struct t1xxp *wc) +{ + /* Setup registers */ + int x,y; + unsigned char b; + for (x=0;x<3;x++) { + b = 0; + 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); + } +} + +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); + spin_unlock_irqrestore(&wc->lock, flags); + return 0; +} + +static int t1xxp_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) +{ + span->lineconfig = lc->lineconfig; + span->txlevel = lc->lbo; + span->rxlevel = 0; + /* Do we want to SYNC on receive or not */ + span->syncsrc = lc->sync; + /* If already running, apply changes immediately */ + if (span->flags & ZT_FLAG_RUNNING) + return t1xxp_startup(span); + return 0; +} + +static int t1xxp_software_init(struct t1xxp *wc) +{ + int x; + /* Find position */ + for (x=0;x= WC_MAX_CARDS) + return -1; + wc->num = x; + sprintf(wc->span.name, "WCT1/%d", wc->num); + sprintf(wc->span.desc, "%s card %d", wc->variety, wc->num); + wc->span.spanconfig = t1xxp_spanconfig; + wc->span.chanconfig = t1xxp_chanconfig; + wc->span.startup = t1xxp_startup; + wc->span.shutdown = t1xxp_shutdown; + wc->span.rbsbits = t1xxp_rbsbits; + wc->span.maint = t1xxp_maint; + wc->span.open = t1xxp_open; + wc->span.close = t1xxp_close; + wc->span.channels = 24; + wc->span.chans = wc->chans; + wc->span.flags = ZT_FLAG_RBS; + wc->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF; + wc->span.ioctl = t1xxp_ioctl; + wc->span.pvt = wc; + init_waitqueue_head(&wc->span.maintq); + for (x=0;x<24;x++) { + sprintf(wc->chans[x].name, "WCT1/%d/%d", wc->num, x + 1); + wc->chans[x].sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | + ZT_SIG_FXSLS | ZT_SIG_FXSGS | + ZT_SIG_FXSKS | ZT_SIG_FXOLS | + ZT_SIG_FXOGS | ZT_SIG_FXOKS; + wc->chans[x].pvt = wc; + wc->chans[x].chanpos = x + 1; + } + if (zt_register(&wc->span, 0)) { + printk("Unable to register span with zaptel\n"); + return -1; + } + return 0; +} + static inline void handle_leds(struct t1xxp *wc) { if (wc->alarm) { #ifdef FANCY_ALARM - if (wc->alarmtimer == wc->alarmthreshold << 1) { - wc->ledtestreg = wc->ledtestreg & ~BIT_ALARM; + if (wc->alarmtimer == (altab[wc->alarmpos] >> 1)) { + wc->ledtestreg = wc->ledtestreg | BIT_ALARM; control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); } - if (wc->alarmtimer == 0x1f) { - wc->ledtestreg = wc->ledtestreg | BIT_ALARM; + if (wc->alarmtimer == 0xf) { + wc->ledtestreg = wc->ledtestreg & ~BIT_ALARM; control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); wc->alarmtimer = -1; - wc->alarmthreshold = (wc->alarmthreshold + 1 & 0x1f); + wc->alarmpos++; + if (wc->alarmpos >= (sizeof(altab) / sizeof(altab[0]))) + wc->alarmpos = 0; } wc->alarmtimer++; #else @@ -235,10 +564,12 @@ static void t1xxp_transmitprep(struct t1xxp *wc, int ints) /* Just finished sending second buffer, fill it now */ txbuf = wc->writechunk + 32 * ZT_CHUNKSIZE; } + zt_transmit(&wc->span); for (y=0;yoffset) & 0x1f)] = + wc->chans[x].writechunk[y]; } } } @@ -246,47 +577,78 @@ static void t1xxp_transmitprep(struct t1xxp *wc, int ints) static void t1xxp_receiveprep(struct t1xxp *wc, int ints) { volatile unsigned char *rxbuf; - static int looper=0; int x; - unsigned char tmpbuf[32]; + int y; if (ints & 0x08) { /* Just received first buffer */ rxbuf = wc->readchunk; } else { rxbuf = wc->readchunk + ZT_CHUNKSIZE * 32; } - for (x=0;x<24;x++) { - /* Must map received channels into appropriate data */ - tmpbuf[x] = rxbuf[(chanmap[x] + WC_OFFSET) & 0x1f]; + for (x=3;x<32;x+=4) { + if (rxbuf[(x + WC_OFFSET) & 0x1f] == 0x7f) { + if (wc->offset != (x-3)) { + wc->offset = x - 3; +#if 1 + printk("New offset: %d\n", wc->offset); +#endif + } + } } - if (!(looper++ % 1000)) { - memcpy(tmpbuf, rxbuf, 32); - for (x=0;x<24;x++) - printk("%d: %d\n", x, (int)tmpbuf[x]); + for (y=0;ychans[x].readchunk[y] = + rxbuf[32 * y + ((chanmap[x] + WC_OFFSET + wc->offset) & 0x1f)]; + } } - + zt_receive(&wc->span); } static void t1xxp_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct t1xxp *wc = dev_id; - unsigned char ints; - unsigned char b; + unsigned char ints, a,b, rxs; static int gotint = 0; + int x,y,i; ints = inb(wc->ioaddr + WC_INTSTAT); + if (!ints) + return; + outb(ints, wc->ioaddr + WC_INTSTAT); if (!gotint) { printk("Got interrupt: 0x%04x\n", ints); - gotint++; } + gotint++; if (ints & 0x0f) { t1xxp_transmitprep(wc, ints); t1xxp_receiveprep(wc, ints); } handle_leds(wc); - +#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); + } + } + } + } +#endif if (ints & 0x10) printk("PCI Master abort\n"); @@ -296,30 +658,8 @@ static void t1xxp_interrupt(int irq, void *dev_id, struct pt_regs *regs) } -static int t1xxp_reset(struct t1xxp *wc) -{ - char c; - c = t1_get_reg(wc, 0x30); - /* Reset the Line Interface */ - t1_set_reg(wc, 0x30, c | 0x1); - - /* Wait 50ms for this to finish */ - mdelay(50); - - /* Clear it */ - t1_set_reg(wc, 0x30, c); - - /* Reset the elastic stores */ - t1_set_reg(wc, 0x30, c | 0x40); - mdelay(1); - t1_set_reg(wc, 0x30, c); - - return 0; -} - static int t1xxp_hardware_init(struct t1xxp *wc) { - int x; /* Hardware PCI stuff */ /* Reset chip and registers */ outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL); @@ -354,83 +694,21 @@ static int t1xxp_hardware_init(struct t1xxp *wc) /* Second frame */ outl(wc->readdma + ZT_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMARE); /* End */ - printk("Setting up DMA (write/read = %08lx/%08lx)\n", wc->writedma, wc->readdma); - - /* Clear interrupts */ - outb(0xff, wc->ioaddr + WC_INTSTAT); + printk("Setting up DMA (write/read = %08x/%08x)\n", wc->writedma, wc->readdma); /* 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); + + /* Reset the T1 and report */ + t1xxp_framer_hard_reset(wc); /* Pretend we're in alarm */ - wc->alarm = 1; + start_alarm(wc); return 0; -#if 0 - /* Reset all registers on the 2151 */ - for (x=0x20;x<0x40;x++) - t1_set_reg(wc, x, 0); - for (x=0x60;x<0x80;x++) - t1_set_reg(wc, x, 0); - /* Sanity check the T1 */ - if (t1_get_reg(wc, 0x7c) != 0) { - printk("Unable to talk to T1 part\n"); - return -ENOSYS; - } - /* Enable elastic store for transmit and receive, - 2.048 Mhz bus */ - t1_set_reg(wc, 0x37, 0x8c | 0x01); - - /* TSync is an output */ - t1_set_reg(wc, 0x36, 0x04); - - /* RSync is an input (Elastic Store) */ - t1_set_reg(wc, 0x2c, 0x08); - - /* ESF/B8ZS */ - t1_set_reg(wc, 0x38, 0xcc); - { - /* XXX Take me out XXX */ - t1_set_reg(wc, 0x2d, 0xff); - t1_set_reg(wc, 0x2e, 0xff); - t1_set_reg(wc, 0x2f, 0xff); - } - return t1xxp_reset(wc); -#endif } -static void t1xxp_enable_interrupts(struct t1xxp *wc) -{ - /* Enable interrupts (we care about all of them) */ - outb(0x3f, wc->ioaddr + WC_MASK0); - /* No external interrupts */ - outb(0x00, wc->ioaddr + WC_MASK1); -} - -static void t1xxp_start_dma(struct t1xxp *wc) -{ - /* Reset Master and TDM */ - outb(DELAY | 0x0f, wc->ioaddr + WC_CNTL); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - outb(DELAY | 0x01, wc->ioaddr + WC_CNTL); - outb(0x01, wc->ioaddr + WC_OPER); - printk("Started DMA\n"); -} - -static void t1xxp_stop_dma(struct t1xxp *wc) -{ - outb(0x00, wc->ioaddr + WC_OPER); -} - -static void t1xxp_disable_interrupts(struct t1xxp *wc) -{ - outb(0x00, wc->ioaddr + WC_MASK0); - outb(0x00, wc->ioaddr + WC_MASK1); -} - - static int __devinit t1xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int res; @@ -474,14 +752,11 @@ static int __devinit t1xxp_init_one(struct pci_dev *pdev, const struct pci_devic kfree(wc); return -EIO; } - - + /* Initialize hardware */ t1xxp_hardware_init(wc); - /* Enable interrupts */ - t1xxp_enable_interrupts(wc); - /* Start DMA */ - t1xxp_start_dma(wc); + /* Misc. software stuff */ + t1xxp_software_init(wc); printk("Found a Wildcard: %s\n", wc->variety); res = 0; -- cgit v1.2.3