summaryrefslogtreecommitdiff
path: root/tor2.c
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2001-11-01 23:37:15 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2001-11-01 23:37:15 +0000
commit9edf5e67c421257f00715425aee73e5b8ebfe1a9 (patch)
tree222fb2b6a0e90bdab16b1136065718f2296245c9 /tor2.c
parent28828383ce54fd705c0492a21b2cf7e86f8e4974 (diff)
Version 0.1.0 from FTP
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@20 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'tor2.c')
-rwxr-xr-xtor2.c983
1 files changed, 983 insertions, 0 deletions
diff --git a/tor2.c b/tor2.c
new file mode 100755
index 0000000..9f9f55b
--- /dev/null
+++ b/tor2.c
@@ -0,0 +1,983 @@
+/*
+ * Tormenta 2 Quad-T1 PCI Driver version 0.1, 8/29/01
+ *
+ * Written by Mark Spencer <markster@linux-support.net>
+ * Based on previous works, designs, and archetectures conceived and
+ * written by Jim Dixon <jim@lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001, Linux Support Services, Inc.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <linux/zaptel.h>
+#endif
+#define NEED_PCI_IDS
+#include "tor2-hw.h"
+#include "tor2fw.h"
+
+#define MAX_SPANS 16
+
+#define FLAG_STARTED (1 << 0)
+
+struct tor2_chan {
+ /* Private pointer for channel. We want to know our
+ channel and span */
+ struct tor2 *tor;
+ int span; /* Index from 0 */
+};
+
+struct tor2_span {
+ /* Private pointer for span. We want to know our
+ span number and pointer to the tor device */
+ struct tor2 *tor;
+ int span; /* Index from 0 */
+};
+
+struct tor2 {
+ /* This structure exists one per card */
+ struct pci_dev *pci; /* Pointer to PCI device */
+ int num; /* Which card we are */
+ int syncsrc; /* active sync source */
+ int syncs[4]; /* sync sources */
+ int alarmtimer[4]; /* Alarm timer */
+ char *type; /* Type of tormenta 2 card */
+ int irq; /* IRQ used by device */
+ int flags; /* Device flags */
+ unsigned long plx_region; /* phy addr of PCI9030 registers */
+ unsigned long plx_len; /* length of PLX window */
+ volatile unsigned short *plx; /* Virtual representation of local space */
+ unsigned long xilinx32_region; /* 32 bit Region allocated to Xilinx */
+ unsigned long xilinx32_len; /* Length of 32 bit Xilinx region */
+ volatile unsigned long *mem32; /* Virtual representation of 32 bit Xilinx memory area */
+ unsigned long xilinx8_region; /* 8 bit Region allocated to Xilinx */
+ unsigned long xilinx8_len; /* Length of 8 bit Xilinx region */
+ volatile unsigned char *mem8; /* Virtual representation of 8 bit Xilinx memory area */
+ struct zt_span spans[4]; /* Spans */
+ struct tor2_span tspans[4]; /* Span data */
+ struct zt_chan *chans[4]; /* Pointers to blocks of 24 contiguous zt_chans for each span */
+ struct tor2_chan tchans[24 * 4];/* Channel user data */
+ unsigned char txsigs[4][6]; /* Copy of tx sig registers */
+ int loopupcnt[4]; /* loop up code counter */
+ int loopdowncnt[4]; /* loop down code counter */
+ int spansstarted; /* number of spans started */
+ spinlock_t lock; /* lock context */
+ unsigned char leds; /* copy of LED register */
+ int taskletrun;
+ int taskletsched;
+ int taskletpending;
+ int taskletexec;
+ int txerrors;
+ struct tasklet_struct tor2_tlet;
+};
+
+#define t1out(tor,span,reg,val) tor->mem8[((span - 1) * 0x100) + reg] = val
+#define t1in(tor,span,reg) tor->mem8[((span - 1) * 0x100) + reg]
+
+static void tor2_tasklet(unsigned long data);
+
+#define GPIOC (PLX_LOC_GPIOC >> 1) /* word-oriented address for PLX GPIOC reg. (32 bit reg.) */
+#define INTCSR (0x4c >> 1) /* word-oriented address for PLX INTCSR reg. */
+#define PLX_INTENA 0x43 /* enable, hi-going, level trigger */
+
+#define SYNCREG 0x400
+#define CTLREG 0x401
+#define LEDREG 0x402
+#define STATREG 0x400
+
+#define INTENA (1 + ((loopback & 3) << 5))
+#define OUTBIT (2 + ((loopback & 3) << 5))
+#define INTACK (0x80 + ((loopback & 3) << 5))
+#define INTACTIVE 2
+
+#define SYNCSELF 0
+#define SYNC1 1
+#define SYNC2 2
+#define SYNC3 3
+#define SYNC4 4
+
+#define LEDRED 2
+#define LEDGREEN 1
+
+#define MAX_TOR_CARDS 64
+
+struct tor2 *cards[MAX_TOR_CARDS];
+
+/* signalling bits */
+#define TOR_ABIT 8
+#define TOR_BBIT 4
+
+static int debug;
+static int loopback;
+
+static void set_clear(struct tor2 *tor);
+static int tor2_startup(struct zt_span *span);
+static int tor2_shutdown(struct zt_span *span);
+static int tor2_rbsbits(struct zt_chan *chan, int bits);
+static int tor2_maint(struct zt_span *span, int cmd);
+static int tor2_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data);
+static void tor2_intr(int irq, void *dev_id, struct pt_regs *regs);
+
+
+/* translations of data channels for 24 channels in a 32 bit PCM highway */
+unsigned datxlt[] = {
+ 1 ,2 ,3 ,5 ,6 ,7 ,9 ,10,11,13,14,15,17,18,19,21,22,23,25,26,27,29,30,31 };
+
+static int tor2_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+ int i;
+ struct tor2_span *p = span->pvt;
+
+ if (debug)
+ printk("Tor2: Configuring span %d\n", span->spanno);
+ /* XXX We assume lineconfig is okay and shouldn't XXX */
+ span->lineconfig = lc->lineconfig;
+ span->txlevel = lc->lbo;
+ span->rxlevel = 0;
+ span->syncsrc = p->tor->syncsrc;
+
+ /* remove this span number from the current sync sources, if there */
+ for(i = 0; i < 3; i++) if (p->tor->syncs[i] == span->spanno) p->tor->syncs[i] = 0;
+ /* if a sync src, put it in proper place */
+ if (lc->sync) p->tor->syncs[lc->sync - 1] = span->spanno;
+
+ /* If we're already running, then go ahead and apply the changes */
+ if (span->flags & ZT_FLAG_RUNNING)
+ return tor2_startup(span);
+ return 0;
+}
+
+static int tor2_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ int alreadyrunning;
+ unsigned int flags;
+ struct tor2_chan *p = chan->pvt;
+
+ alreadyrunning = chan->span->flags & ZT_FLAG_RUNNING;
+ if (debug) {
+ if (alreadyrunning)
+ printk("Tor2: Reconfigured channel %d (%s) sigtype %d\n", chan->channo, chan->name, sigtype);
+ else
+ printk("Tor2: Configured channel %d (%s) sigtype %d\n", chan->channo, chan->name, sigtype);
+ }
+ spin_lock_irqsave(&p->tor->lock, flags);
+ if (alreadyrunning)
+ set_clear(p->tor);
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+ return 0;
+}
+
+static int tor2_open(struct zt_chan *chan)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int tor2_close(struct zt_chan *chan)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static void init_spans(struct tor2 *tor)
+{
+ int x,y,c;
+ for (x=0;x<4;x++) {
+ sprintf(tor->spans[x].name, "Tor2/%d/%d",
+ tor->num, x + 1);
+ sprintf(tor->spans[x].desc, "Tormenta 2 (PCI) Card %d Span %d", tor->num, x+1);
+ tor->spans[x].spanconfig = tor2_spanconfig;
+ tor->spans[x].chanconfig = tor2_chanconfig;
+ tor->spans[x].startup = tor2_startup;
+ tor->spans[x].shutdown = tor2_shutdown;
+ tor->spans[x].rbsbits = tor2_rbsbits;
+ tor->spans[x].maint = tor2_maint;
+ tor->spans[x].open = tor2_open;
+ tor->spans[x].close = tor2_close;
+ tor->spans[x].channels = 24;
+ tor->spans[x].chans = tor->chans[x];
+ tor->spans[x].flags = ZT_FLAG_RBS;
+ tor->spans[x].linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
+ tor->spans[x].ioctl = tor2_ioctl;
+ tor->spans[x].pvt = &tor->tspans[x];
+ tor->tspans[x].tor = tor;
+ tor->tspans[x].span = x;
+ init_waitqueue_head(&tor->spans[x].maintq);
+ for (y=0;y<24;y++) {
+ struct zt_chan *mychans = tor->chans[x] + y;
+ sprintf(mychans->name, "Tor2/%d/%d/%d", tor->num, x + 1, y + 1);
+ mychans->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;
+ c = (x * 24) + y;
+ mychans->pvt = &tor->tchans[c];
+ mychans->chanpos = y + 1;
+ tor->tchans[c].span = x;
+ tor->tchans[c].tor = tor;
+ }
+ }
+}
+
+static int __devinit tor2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int res,x;
+ struct tor2 *tor;
+ unsigned long endjif;
+ volatile unsigned long *gpioc_data;
+
+ res = pci_enable_device(pdev);
+ if (res)
+ return res;
+ tor = kmalloc(sizeof(struct tor2), GFP_KERNEL);
+ if (!tor)
+ return -ENOMEM;
+ memset(tor,0,sizeof(struct tor2));
+ for(x = 0; x < 4; x++) {
+ tor->chans[x] = kmalloc(sizeof(struct zt_chan) * 24,GFP_KERNEL);
+ if (!tor->chans[x])
+ return -ENOMEM;
+ memset(tor->chans[x],0,sizeof(struct zt_chan) * 24);
+ }
+ /* Load the resources */
+ tor->irq = pdev->irq;
+ if (tor->irq < 1) {
+ printk(KERN_ERR "No IRQ allocated for device\n");
+ goto err_out_free_tor;
+ }
+ tor->plx_region = pci_resource_start(pdev, 0);
+ tor->plx_len = pci_resource_len(pdev, 0);
+ tor->plx = ioremap(tor->plx_region, tor->plx_len);
+ /* We don't use the I/O space */
+ tor->xilinx32_region = pci_resource_start(pdev, 2);
+ tor->xilinx32_len = pci_resource_len(pdev, 2);
+ tor->mem32 = ioremap(tor->xilinx32_region, tor->xilinx32_len);
+ tor->xilinx8_region = pci_resource_start(pdev, 3);
+ tor->xilinx8_len = pci_resource_len(pdev, 3);
+ tor->mem8 = ioremap(tor->xilinx8_region, tor->xilinx8_len);
+ /* Record what type */
+ tor->type = (char *)ent->driver_data;
+ /* Verify existence and accuracy of resources */
+ if (!tor->plx_region || !tor->plx ||
+ (pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+ printk(KERN_ERR "Invalid PLX 9030 Base resource\n");
+ goto err_out_free_tor;
+ }
+ if (!tor->xilinx32_region || !tor->mem32 ||
+ (pci_resource_flags(pdev, 2) & IORESOURCE_IO)) {
+ printk(KERN_ERR "Invalid Xilinx 32 bit Base resource\n");
+ goto err_out_free_tor;
+ }
+ if (!tor->xilinx8_region || !tor->mem8 ||
+ (pci_resource_flags(pdev, 3) & IORESOURCE_IO)) {
+ printk(KERN_ERR "Invalid Xilinx 8 bit Base resource\n");
+ goto err_out_free_tor;
+ }
+ /* Request regions */
+ if (!request_mem_region(tor->plx_region, tor->plx_len, tor->type)) {
+ printk(KERN_ERR "Unable to reserve PLX memory %08lx window at %08lx\n",
+ tor->plx_len, tor->plx_region);
+ goto err_out_free_tor;
+ }
+ if (!request_mem_region(tor->xilinx32_region, tor->xilinx32_len, tor->type)) {
+ printk(KERN_ERR "Unable to reserve Xilinx 32 bit memory %08lx window at %08lx\n",
+ tor->xilinx32_len, tor->xilinx32_region);
+ goto err_out_release_plx_region;
+ }
+ if (!request_mem_region(tor->xilinx8_region, tor->xilinx8_len, tor->type)) {
+ printk(KERN_ERR "Unable to reserve Xilinx memory %08lx window at %08lx\n",
+ tor->xilinx8_len, tor->xilinx8_region);
+ goto err_out_release_plx_region;
+ }
+ pci_set_drvdata(pdev, tor);
+ printk("Detected %s at 0x%lx/0x%lx irq %d\n", tor->type,
+ tor->xilinx32_region, tor->xilinx8_region,tor->irq);
+
+ for(x = 0; x < MAX_TOR_CARDS; x++) {
+ if (!cards[x]) break;
+ }
+ if (x >= MAX_TOR_CARDS) {
+ printk("No cards[] slot available!!\n");
+ goto err_out_release_all;
+ }
+ tor->num = x;
+ cards[x] = tor;
+ /* start programming mode */
+ gpioc_data = (unsigned long *)&tor->plx[GPIOC];
+ *gpioc_data |= GPIO_WRITE; /* make sure WRITE is not asserted */
+ *gpioc_data &= ~GPIO_PROGRAM; /* activate the PROGRAM signal */
+ /* wait for INIT and DONE to go low */
+ while (*gpioc_data & (GPIO_INIT | GPIO_DONE));
+ if (debug) printk("fwload: Init and done gone to low\n");
+ *gpioc_data |= GPIO_PROGRAM; /* de-activate the PROGRAM signal */
+ /* wait for INIT to go high (clearing done */
+ while (!(*gpioc_data & GPIO_INIT));
+ if (debug) printk("fwload: Init went high (clearing done)\nNow loading...\n");
+ /* assert WRITE signal */
+ *gpioc_data &= ~GPIO_WRITE;
+ for(x = 0; x < sizeof(tor2fw); x++)
+ {
+ /* write the byte */
+ *tor->mem8 = tor2fw[x];
+ /* if DONE signal, we're done, exit */
+ if (*gpioc_data & GPIO_DONE) break;
+ /* if INIT drops, we're screwed, exit */
+ if (!(*gpioc_data & GPIO_INIT)) break;
+ }
+ if (debug) printk("fwload: Transferred %d bytes into chip\n",x);
+ /* Wait for FIFO to clear */
+ endjif = jiffies + 2;
+ while(jiffies < endjif); /* wait */
+ /* de-assert write signal */
+ *gpioc_data |= GPIO_WRITE;
+ if (debug) printk("fwload: Loading done!\n");
+ /* Wait for FIFO to clear */
+ endjif = jiffies + 2;
+ while(jiffies < endjif); /* wait */
+ if (!(*gpioc_data & GPIO_INIT))
+ {
+ printk("Drove Init low!! CRC Error!!!\n");
+ goto err_out_release_all;
+ }
+ if (!(*gpioc_data & GPIO_DONE))
+ {
+ printk("Did not get DONE signal. Short file maybe??\n");
+ goto err_out_release_all;
+ }
+ printk("Xilinx Chip successfully loaded, configured and started!!\n");
+
+ tor->mem8[SYNCREG] = 0;
+ tor->mem8[CTLREG] = 0;
+ tor->mem8[LEDREG] = 0;
+ for(x = 0; x < 256; x++) tor->mem32[x] = 0x7f7f7f7f;
+
+ if (request_irq(tor->irq, tor2_intr, SA_INTERRUPT, "tor2", tor)) {
+ printk(KERN_ERR "Unable to request tormenta IRQ %d\n", tor->irq);
+ goto err_out_release_all;
+ }
+
+ init_spans(tor);
+
+ if (zt_register(&tor->spans[0], 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", tor->spans[0].name);
+ goto err_out_release_all;
+ }
+ if (zt_register(&tor->spans[1], 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", tor->spans[1].name);
+ zt_unregister(&tor->spans[0]);
+ goto err_out_release_all;
+ }
+ if (zt_register(&tor->spans[2], 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", tor->spans[2].name);
+ zt_unregister(&tor->spans[0]);
+ zt_unregister(&tor->spans[1]);
+ goto err_out_release_all;
+ }
+ if (zt_register(&tor->spans[3], 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", tor->spans[3].name);
+ zt_unregister(&tor->spans[0]);
+ zt_unregister(&tor->spans[1]);
+ zt_unregister(&tor->spans[2]);
+ goto err_out_release_all;
+ }
+ tor->plx[INTCSR] = PLX_INTENA; /* enable PLX interrupt */
+ tasklet_init(&tor->tor2_tlet, tor2_tasklet, (unsigned long)tor);
+ return 0;
+
+err_out_release_all:
+ release_mem_region(tor->xilinx32_region, tor->xilinx32_len);
+ release_mem_region(tor->xilinx8_region, tor->xilinx8_len);
+err_out_release_plx_region:
+ release_mem_region(tor->plx_region, tor->plx_len);
+err_out_free_tor:
+ if (tor->plx) iounmap((void *)tor->plx);
+ if (tor->mem8) iounmap((void *)tor->mem8);
+ if (tor->mem32) iounmap((void *)tor->mem32);
+ if (tor) {
+ for(x = 0; x < 3; x++) kfree(tor->chans[x]);
+ kfree(tor);
+ }
+ return -NODEV;
+}
+
+static struct pci_driver tor2_driver;
+
+static void __devexit tor2_remove(struct pci_dev *pdev)
+{
+ int x;
+ struct tor2 *tor;
+ tor = pci_get_drvdata(pdev);
+ if (!tor)
+ BUG();
+ tor->mem8[SYNCREG] = 0;
+ tor->mem8[CTLREG] = 0;
+ tor->mem8[LEDREG] = 0;
+ tor->plx[INTCSR] = 0;
+ free_irq(tor->irq, tor);
+ if (tor->spans[0].flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&tor->spans[0]);
+ if (tor->spans[1].flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&tor->spans[1]);
+ if (tor->spans[2].flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&tor->spans[2]);
+ if (tor->spans[3].flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&tor->spans[3]);
+ release_mem_region(tor->plx_region, tor->plx_len);
+ release_mem_region(tor->xilinx32_region, tor->xilinx32_len);
+ release_mem_region(tor->xilinx8_region, tor->xilinx8_len);
+ if (tor->plx) iounmap((void *)tor->plx);
+ if (tor->mem8) iounmap((void *)tor->mem8);
+ if (tor->mem32) iounmap((void *)tor->mem32);
+
+ cards[tor->num] = 0;
+ pci_set_drvdata(pdev, NULL);
+ for(x = 0; x < 3; x++) kfree(tor->chans[x]);
+ kfree(tor);
+}
+
+static struct pci_driver tor2_driver = {
+ name: "tormenta2",
+ probe: tor2_probe,
+ remove: tor2_remove,
+ id_table: tor2_pci_ids,
+};
+
+static int __init tor2_init(void) {
+ int res;
+ res = pci_module_init(&tor2_driver);
+ printk("Registered Tormenta2 PCI\n");
+ return res;
+}
+
+static void __exit tor2_cleanup(void) {
+ pci_unregister_driver(&tor2_driver);
+ printk("Unregistered Tormenta2\n");
+}
+
+static void set_clear(struct tor2 *tor)
+{
+ int i,j,s;
+ unsigned short val=0;
+ for (s=0;s<4;s++) {
+ for (i=0;i<24;i++) {
+ j = (i/8);
+ if (tor->spans[s].chans[i].flags & ZT_FLAG_CLEAR)
+ val |= 1 << (i % 8);
+
+ if ((i % 8)==7) {
+#if 0
+ printk("Putting %d in register %02x on span %d\n",
+ val, 0x39 + j, 1 + s);
+#endif
+ t1out(tor,1 + s, 0x39 + j, val);
+ val = 0;
+ }
+ }
+ }
+
+}
+
+
+static int tor2_rbsbits(struct zt_chan *chan, int bits)
+{
+ u_char m,c;
+ int k,n,b;
+ struct tor2_chan *p = chan->pvt;
+ unsigned int flags;
+#if 0
+ printk("Setting bits to %d on channel %s\n", bits, chan->name);
+#endif
+ n = chan->chanpos - 1;
+ k = p->span;
+ b = (n / 8); /* get byte number */
+ m = 1 << (n & 7); /* get mask */
+ c = p->tor->txsigs[k][b];
+ c &= ~m; /* clear mask bit */
+ /* set mask bit, if bit is to be set */
+ if (bits & ZT_ABIT) c |= m;
+ p->tor->txsigs[k][b] = c;
+ spin_lock_irqsave(&p->tor->lock, flags);
+ t1out(p->tor,k + 1,0x70 + b,c);
+ t1out(p->tor,k + 1,0x76 + b,c);
+ b += 3; /* now points to b bit stuff */
+ /* get current signalling values */
+ c = p->tor->txsigs[k][b];
+ c &= ~m; /* clear mask bit */
+ /* set mask bit, if bit is to be set */
+ if (bits & ZT_BBIT) c |= m;
+ /* save new signalling values */
+ p->tor->txsigs[k][b] = c;
+ /* output them into the chip */
+ t1out(p->tor,k + 1,0x70 + b,c);
+ t1out(p->tor,k + 1,0x76 + b,c);
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+ return 0;
+}
+
+static int tor2_shutdown(struct zt_span *span)
+{
+ int i;
+ int tspan;
+ int wasrunning;
+ unsigned int flags;
+ struct tor2_span *p = span->pvt;
+
+ tspan = p->span + 1;
+ if (tspan < 0) {
+ printk("Tor2: Span '%d' isn't us?\n", span->spanno);
+ return -1;
+ }
+
+ spin_lock_irqsave(&p->tor->lock, flags);
+ wasrunning = span->flags & ZT_FLAG_RUNNING;
+
+ span->flags &= ~ZT_FLAG_RUNNING;
+ /* Zero out all registers */
+ for (i = 0; i < 160; i++)
+ t1out(p->tor,tspan, i, 0);
+ if (wasrunning)
+ p->tor->spansstarted--;
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+ if ((!p->tor->spans[0].flags & ZT_FLAG_RUNNING) &&
+ (!p->tor->spans[1].flags & ZT_FLAG_RUNNING) &&
+ (!p->tor->spans[2].flags & ZT_FLAG_RUNNING) &&
+ (!p->tor->spans[3].flags & ZT_FLAG_RUNNING))
+ /* No longer in use, disable interrupts */
+ p->tor->mem8[CTLREG] = 0;
+ if (debug)
+ printk("Span %d (%s) shutdown\n", span->spanno, span->name);
+ return 0;
+}
+
+
+static int tor2_startup(struct zt_span *span)
+{
+ unsigned long endjif;
+ int i;
+ int tspan;
+ unsigned int flags;
+ char *coding;
+ char *framing;
+ int alreadyrunning;
+ struct tor2_span *p = span->pvt;
+
+ tspan = p->span + 1;
+ if (tspan < 0) {
+ printk("Tor2: Span '%d' isn't us?\n", span->spanno);
+ return -1;
+ }
+
+
+ spin_lock_irqsave(&p->tor->lock, flags);
+
+ alreadyrunning = span->flags & ZT_FLAG_RUNNING;
+
+ if (!alreadyrunning) {
+ p->tor->mem8[SYNCREG] = SYNCSELF;
+ p->tor->mem8[CTLREG] = 0;
+ p->tor->mem8[LEDREG] = 0;
+ /* Zero out all registers */
+ for (i = 0; i < 160; i++)
+ t1out(p->tor,tspan, i, 0);
+
+ /* Set up for Interleaved Serial Bus operation in byte mode */
+ if (tspan == 1) t1out(p->tor,tspan,0x94,9);
+ else t1out(p->tor,tspan,0x94,8);
+ /* Full-on Sync required (RCR1) */
+ t1out(p->tor,tspan, 0x2b, 8);
+ /* RSYNC is an input (RCR2) */
+ t1out(p->tor,tspan, 0x2c, 8);
+ /* RBS enable (TCR1) */
+ t1out(p->tor,tspan, 0x35, 0x10);
+ /* TSYNC to be output (TCR2) */
+ t1out(p->tor,tspan, 0x36, 4);
+ /* Tx & Rx Elastic store, sysclk(s) = 2.048 mhz, loopback controls (CCR1) */
+ t1out(p->tor,tspan, 0x37, 0x9c);
+ /* Set up received loopup and loopdown codes */
+ t1out(p->tor,tspan, 0x12, 0x22);
+ t1out(p->tor,tspan, 0x14, 0x80);
+ t1out(p->tor,tspan, 0x15, 0x80);
+ }
+ /* Enable F bits pattern */
+ i = 0x20;
+ if (span->lineconfig & ZT_CONFIG_ESF)
+ i = 0x88;
+ if (span->lineconfig & ZT_CONFIG_B8ZS)
+ i |= 0x44;
+ t1out(p->tor,tspan, 0x38, i);
+ if (i & 0x80)
+ coding = "ESF";
+ else
+ coding = "SF";
+ if (i & 0x40)
+ framing = "B8ZS";
+ else {
+ framing = "AMI";
+ t1out(p->tor,tspan,0x7e,0x1c); /* F bits pattern (0x1c) into FDL register */
+ }
+ t1out(p->tor,tspan, 0x7c, span->txlevel << 5);
+
+ if (!alreadyrunning) {
+ /* LIRST to reset line interface */
+ t1out(p->tor,tspan, 0x0a, 0x80);
+
+ /* Wait 100 ms */
+ endjif = jiffies + 10;
+
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+
+ while(jiffies < endjif); /* wait 100 ms */
+
+ spin_lock_irqsave(&p->tor->lock, flags);
+
+ t1out(p->tor,tspan,0x0a,0x30); /* LIRST back to normal, Resetting elastic stores */
+
+ span->flags |= ZT_FLAG_RUNNING;
+ p->tor->spansstarted++;
+
+ /* enable interrupts */
+ p->tor->mem8[CTLREG] = INTENA;
+ }
+
+ set_clear(p->tor);
+
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+
+ if (debug) {
+ if (alreadyrunning)
+ printk("Tor2: Reconfigured span %d (%s/%s) LBO: %s\n", span->spanno, coding, framing, zt_lboname(span->txlevel));
+ else
+ printk("Tor2: Startup span %d (%s/%s) LBO: %s\n", span->spanno, coding, framing, zt_lboname(span->txlevel));
+ }
+ if (p->tor->syncs[0] == span->spanno) printk("SPAN %d: Primary Sync Source\n",span->spanno);
+ if (p->tor->syncs[1] == span->spanno) printk("SPAN %d: Secondary Sync Source\n",span->spanno);
+ if (p->tor->syncs[2] == span->spanno) printk("SPAN %d: Tertiary Sync Source\n",span->spanno);
+ if (p->tor->syncs[3] == span->spanno) printk("SPAN %d: Quaternary Sync Source\n",span->spanno);
+ return 0;
+}
+
+static int tor2_maint(struct zt_span *span, int cmd)
+{
+ struct tor2_span *p = span->pvt;
+
+ int tspan = p->span + 1;
+
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ t1out(p->tor,tspan,0x19,0); /* no local loop */
+ t1out(p->tor,tspan,0x0a,0); /* no remote loop */
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ t1out(p->tor,tspan,0x19,0x40); /* local loop */
+ t1out(p->tor,tspan,0x0a,0); /* no remote loop */
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ t1out(p->tor,tspan,0x1e,0); /* no local loop */
+ t1out(p->tor,tspan,0x0a,0x40); /* remote loop */
+ break;
+ case ZT_MAINT_LOOPUP:
+ t1out(p->tor,tspan,0x30,2); /* send loopup code */
+ t1out(p->tor,tspan,0x12,0x22); /* send loopup code */
+ t1out(p->tor,tspan,0x13,0x80); /* send loopup code */
+ break;
+ case ZT_MAINT_LOOPDOWN:
+ t1out(p->tor,tspan,0x30,2); /* send loopdown code */
+ t1out(p->tor,tspan,0x12,0x62); /* send loopdown code */
+ t1out(p->tor,tspan,0x13,0x90); /* send loopdown code */
+ break;
+ case ZT_MAINT_LOOPSTOP:
+ t1out(p->tor,tspan,0x30,0); /* stop sending loopup code */
+ break;
+ default:
+ printk("Tor2: Unknown maint command: %d\n", cmd);
+ break;
+ }
+ return 0;
+}
+
+static void tor2_tasklet(unsigned long data)
+{
+ struct tor2 *tor = (struct tor2 *)data;
+ int x;
+ tor->taskletrun++;
+ if (tor->taskletpending) {
+ tor->taskletexec++;
+ for (x=0;x<4;x++) {
+ if (tor->spans[x].flags & ZT_FLAG_RUNNING)
+ zt_receive(&tor->spans[x]);
+ }
+ for (x=0;x<4;x++) {
+ if (tor->spans[x].flags & ZT_FLAG_RUNNING)
+ zt_transmit(&tor->spans[x]);
+ }
+ }
+ tor->taskletpending = 0;
+}
+
+static void tor2_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ static unsigned int passno = 0;
+ int n, i, j, k;
+ static unsigned long rxword,txword;
+ unsigned char c, rxc;
+ unsigned char abits, bbits;
+ struct tor2 *tor = (struct tor2 *) dev_id;
+
+ /* make sure its a real interrupt for us */
+ if (!(tor->mem8[STATREG] & INTACTIVE)) /* if not, just return */
+ {
+ return;
+ }
+
+ /* set outbit, interrupt enable, and ack interrupt */
+ tor->mem8[CTLREG] = OUTBIT | INTENA | INTACK;
+
+#if 0
+ if (!passno)
+ printk("Interrupt handler\n");
+#endif
+
+ /* do the transmit output */
+ for(n = 0; n < 24; n++) {
+ for(i = 0; i < ZT_CHUNKSIZE; i++) {
+ /* span 1 */
+ txword = tor->spans[0].chans[n].writechunk[i] << 24;
+ /* span 2 */
+ txword |= tor->spans[1].chans[n].writechunk[i] << 16;
+ /* span 3 */
+ txword |= tor->spans[2].chans[n].writechunk[i] << 8;
+ /* span 4 */
+ txword |= tor->spans[3].chans[n].writechunk[i];
+ /* write to part */
+ tor->mem32[datxlt[n] + (32 * i)] = txword;
+ }
+ }
+
+ /* Do the receive input */
+ for(n = 0; n < 24; n++) {
+ for(i = 0; i < ZT_CHUNKSIZE; i++) {
+ /* read from */
+ rxword = tor->mem32[datxlt[n] + (32 * i)];
+ /* span 1 */
+ tor->spans[0].chans[n].readchunk[i] = rxword >> 24;
+ /* span 2 */
+ tor->spans[1].chans[n].readchunk[i] = (rxword & 0xff0000) >> 16;
+ /* span 3 */
+ tor->spans[2].chans[n].readchunk[i] = (rxword & 0xff00) >> 8;
+ /* span 4 */
+ tor->spans[3].chans[n].readchunk[i] = rxword & 0xff;
+ }
+ }
+
+ i = passno & 63;
+ if (i < 12) {
+ k = (i / 3); /* get span */
+ n = (i % 3); /* get base */
+ abits = t1in(tor,k + 1, 0x60 + n);
+ bbits = t1in(tor,k + 1, 0x63 + n);
+ for (j=0; j< 8; j++) {
+ /* Get channel number */
+ i = (n * 8) + j;
+ rxc = 0;
+ if (abits & (1 << j)) rxc |= ZT_ABIT;
+ if (bbits & (1 << j)) rxc |= ZT_BBIT;
+ if (tor->spans[k].chans[i].rxsig != rxc) {
+ /* Check for changes in received bits */
+ if (!(tor->spans[k].chans[i].sig & ZT_SIG_CLEAR))
+ zt_rbsbits(&tor->spans[k].chans[i], rxc);
+ }
+ }
+ }
+
+ for(i = 0; i < 4; i++) { /* Go thru all 4 spans */
+ /* if alarm timer, and it's timed out */
+ if (tor->alarmtimer[i]) {
+ if (!--tor->alarmtimer[i]) {
+ /* clear recover status */
+ tor->spans[i].alarms &= ~ZT_ALARM_RECOVER;
+ t1out(tor,i + 1,0x35,0x10); /* turn off yel */
+ zt_alarm_notify(&tor->spans[i]); /* let them know */
+ }
+ }
+ }
+
+ i = passno & 63;
+ if ((i >= 50) && (i <= 53))
+ {
+ j = 0; /* clear this alarm status */
+ i -= 50;
+ c = t1in(tor,i + 1,0x31); /* get RIR2 */
+ tor->spans[i].rxlevel = c >> 6; /* get rx level */
+ t1out(tor,i + 1,0x20,0xff);
+ c = t1in(tor,i + 1,0x20); /* get the status */
+ /* detect the code, only if we are not sending one */
+ if ((!tor->spans[i].mainttimer) && (c & 0x80)) /* if loop-up code detected */
+ {
+ /* set into remote loop, if not there already */
+ if ((tor->loopupcnt[i]++ > 80) &&
+ (tor->spans[i].maintstat != ZT_MAINT_REMOTELOOP))
+ {
+ t1out(tor,i + 1,0x1e,0); /* no local loop */
+ t1out(tor,i + 1,0x0a,0x40); /* remote loop */
+ tor->spans[i].maintstat = ZT_MAINT_REMOTELOOP;
+ }
+ } else tor->loopupcnt[i] = 0;
+ /* detect the code, only if we are not sending one */
+ if ((!tor->spans[i].mainttimer) && (c & 0x40)) /* if loop-down code detected */
+ {
+ /* if in remote loop, get out of it */
+ if ((tor->loopdowncnt[i]++ > 80) &&
+ (tor->spans[i].maintstat == ZT_MAINT_REMOTELOOP))
+ {
+ t1out(tor,i + 1,0x1e,0); /* no local loop */
+ t1out(tor,i + 1,0x0a,0); /* no remote loop */
+ tor->spans[i].maintstat = ZT_MAINT_NONE;
+ }
+ } else tor->loopdowncnt[i] = 0;
+ if (c & 3) /* if red alarm */
+ {
+ j |= ZT_ALARM_RED;
+ }
+ if (c & 8) /* if blue alarm */
+ {
+ j |= ZT_ALARM_BLUE;
+ }
+ /* only consider previous carrier alarm state */
+ tor->spans[i].alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN);
+ n = 1; /* set to 1 so will not be in yellow alarm if we dont
+ care about open channels */
+ /* if to have yellow alarm if nothing open */
+ if (tor->spans[i].lineconfig & ZT_CONFIG_NOTOPEN)
+ {
+ /* go thru all chans, and count # open */
+ for(n = 0,k = 0; k < 24; k++)
+ {
+ if (((tor->chans[i] + k)->flags & ZT_FLAG_OPEN) ||
+ ((tor->chans[i] + k)->flags & ZT_FLAG_NETDEV)) n++;
+ }
+ /* if none open, set alarm condition */
+ if (!n) j |= ZT_ALARM_NOTOPEN;
+ }
+ /* if no more alarms, and we had some */
+ if ((!j) && tor->spans[i].alarms)
+ {
+ tor->alarmtimer[i] = ZT_ALARMSETTLE_TIME;
+ }
+ if (tor->alarmtimer[i]) j |= ZT_ALARM_RECOVER;
+ /* if going into alarm state, set yellow alarm */
+ if ((j) && (!tor->spans[i].alarms)) t1out(tor,i + 1,0x35,0x11);
+ if (c & 4) /* if yellow alarm */
+ j |= ZT_ALARM_YELLOW;
+ if (tor->spans[i].maintstat || tor->spans[i].mainttimer) j |= ZT_ALARM_LOOPBACK;
+ tor->spans[i].alarms = j;
+ c = (LEDRED | LEDGREEN) << (2 * i);
+ tor->leds &= ~c; /* mask out bits for this span */
+ if (j & ZT_ALARM_RED) tor->leds |= LEDRED << (2 * i);
+ else if (j & ZT_ALARM_YELLOW) tor->leds |= (LEDRED | LEDGREEN) << (2 * i);
+ else tor->leds |= LEDGREEN << (2 * i);
+ tor->mem8[LEDREG] = tor->leds;
+ zt_alarm_notify(&tor->spans[i]);
+ }
+ if (!(passno % 1000)) /* even second boundary */
+ {
+ /* do all spans */
+ for(i = 1; i <= 4; i++)
+ {
+ /* add this second's BPV count to total one */
+ tor->spans[i - 1].bpvcount += t1in(tor,i,0x24) + (t1in(tor,i,0x23) << 8);
+ }
+ }
+ /* re-evaluate active sync src */
+ tor->syncsrc = 0;
+ /* if primary sync specified, see if we can use it */
+ if (tor->syncs[0])
+ {
+ /* if no alarms, use it */
+ if (!(tor->spans[tor->syncs[0] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE |
+ ZT_ALARM_LOOPBACK))) tor->syncsrc = tor->syncs[0];
+ }
+ /* if any others specified, see if we can use them */
+ for(i = 1; i < 4; i++) {
+ /* if we dont have one yet, and there is one specified at this level, see if we can use it */
+ if ((!tor->syncsrc) && (tor->syncs[i])) {
+ /* if no alarms, use it */
+ if (!(tor->spans[tor->syncs[i] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE |
+ ZT_ALARM_LOOPBACK))) tor->syncsrc = tor->syncs[i];
+ }
+ }
+ /* update sync src info */
+ for(i = 0; i < 4; i++) tor->spans[i].syncsrc = tor->syncsrc;
+
+ if (!tor->taskletpending) {
+ tor->taskletpending = 1;
+ tor->taskletsched++;
+ tasklet_hi_schedule(&tor->tor2_tlet);
+ } else {
+ tor->txerrors++;
+ }
+
+#if 0
+ for(i = 3; i >= 0; i--) {
+ /* Process receive for this span */
+ if (tor->spans[i].flags & ZT_FLAG_RUNNING)
+ zt_receive(&tor->spans[i]);
+ }
+
+ for(i = 3; i >= 0; i--) {
+ /* Prepare next set for transmission */
+ if (tor->spans[i].flags & ZT_FLAG_RUNNING)
+ zt_transmit(&tor->spans[i]);
+ }
+#endif
+
+ passno++;
+ /* clear OUTBIT and enable interrupts */
+ tor->mem8[CTLREG] = INTENA;
+}
+
+
+static int tor2_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
+{
+ switch(cmd) {
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+MODULE_AUTHOR("Mark Spencer");
+MODULE_DESCRIPTION("Tormenta 2 PCI Driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(loopback, "i");
+
+MODULE_DEVICE_TABLE(pci, tor2_pci_ids);
+
+module_init(tor2_init);
+module_exit(tor2_cleanup);
+
+
+