summaryrefslogtreecommitdiff
path: root/drivers/dahdi/tor2.c
diff options
context:
space:
mode:
authorKevin P. Fleming <kpfleming@digium.com>2008-05-21 15:11:48 +0000
committerKevin P. Fleming <kpfleming@digium.com>2008-05-21 15:11:48 +0000
commit802b567e6c7ba7803a950324cbed13f7d57944cb (patch)
tree6b90ca3119aaa2e4073d3b651ac965dea5d3430e /drivers/dahdi/tor2.c
parentec5ce88e015b41c2f46f6c9b783339b945f9502a (diff)
start copying kernel bits
git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@4315 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi/tor2.c')
-rw-r--r--drivers/dahdi/tor2.c1521
1 files changed, 1521 insertions, 0 deletions
diff --git a/drivers/dahdi/tor2.c b/drivers/dahdi/tor2.c
new file mode 100644
index 0000000..cbff7a2
--- /dev/null
+++ b/drivers/dahdi/tor2.c
@@ -0,0 +1,1521 @@
+/*
+ * Tormenta 2 Quad-T1 PCI Driver
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * 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>
+#include "zaptel.h"
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+#define NEED_PCI_IDS
+#include "tor2-hw.h"
+#include "tor2fw.h"
+
+/*
+ * Tasklets provide better system interactive response at the cost of the
+ * possibility of losing a frame of data at very infrequent intervals. If
+ * you are more concerned with the performance of your machine, enable the
+ * tasklets. If you are strict about absolutely no drops, then do not enable
+ * tasklets.
+ */
+
+/* #define ENABLE_TASKLETS */
+
+/* this stuff needs to work for 64 bit systems, however using the macro causes
+ it to take twice as long */
+/* #define FIXTHISFOR64 */ /* as of now, un-comment for 32 bit only system */
+
+#define SPANS_PER_CARD 4
+#define MAX_SPANS 16
+
+#define FLAG_STARTED (1 << 0)
+
+#define TYPE_T1 1 /* is a T1 card */
+#define TYPE_E1 2 /* is an E1 card */
+
+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[SPANS_PER_CARD]; /* sync sources */
+ int psyncs[SPANS_PER_CARD]; /* span-relative sync sources */
+ int alarmtimer[SPANS_PER_CARD]; /* Alarm timer */
+ char *type; /* Type of tormenta 2 card */
+ int irq; /* IRQ used by device */
+ int order; /* Order */
+ int flags; /* Device flags */
+ int syncpos[SPANS_PER_CARD]; /* span-relative sync sources */
+ int master; /* Are we master */
+ 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 int *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[SPANS_PER_CARD]; /* Spans */
+ struct tor2_span tspans[SPANS_PER_CARD]; /* Span data */
+ struct zt_chan *chans[SPANS_PER_CARD]; /* Pointers to blocks of 24(30/31) contiguous zt_chans for each span */
+ struct tor2_chan tchans[32 * SPANS_PER_CARD]; /* Channel user data */
+ unsigned char txsigs[SPANS_PER_CARD][16]; /* Copy of tx sig registers */
+ int loopupcnt[SPANS_PER_CARD]; /* loop up code counter */
+ int loopdowncnt[SPANS_PER_CARD];/* loop down code counter */
+ int spansstarted; /* number of spans started */
+ spinlock_t lock; /* lock context */
+ unsigned char leds; /* copy of LED register */
+ unsigned char ec_chunk1[SPANS_PER_CARD][32][ZT_CHUNKSIZE]; /* first EC chunk buffer */
+ unsigned char ec_chunk2[SPANS_PER_CARD][32][ZT_CHUNKSIZE]; /* second EC chunk buffer */
+#ifdef ENABLE_TASKLETS
+ int taskletrun;
+ int taskletsched;
+ int taskletpending;
+ int taskletexec;
+ int txerrors;
+ struct tasklet_struct tor2_tlet;
+#endif
+ int cardtype; /* card type, T1 or E1 */
+ unsigned int *datxlt; /* pointer to datxlt structure */
+ unsigned int passno; /* number of interrupt passes */
+};
+
+#define t1out(tor,span,reg,val) tor->mem8[((span - 1) * 0x100) + reg] = val
+#define t1in(tor,span,reg) tor->mem8[((span - 1) * 0x100) + reg]
+
+#ifdef ENABLE_TASKLETS
+static void tor2_tasklet(unsigned long data);
+#endif
+
+#define GPIOC (PLX_LOC_GPIOC >> 1) /* word-oriented address for PLX GPIOC reg. (32 bit reg.) */
+#define LAS2BRD (0x30 >> 1)
+#define LAS3BRD (0x34 >> 1)
+#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 SWREG 0x401
+#define CTLREG1 0x404
+
+#define INTENA (1 + ((loopback & 3) << 5))
+#define OUTBIT (2 + ((loopback & 3) << 5))
+#define E1DIV 0x10
+#define INTACK (0x80 + ((loopback & 3) << 5))
+#define INTACTIVE 2
+#define MASTER (1 << 3)
+
+/* un-define this if you dont want NON-REV A hardware support */
+/* #define NONREVA 1 */
+
+#define SYNCSELF 0
+#define SYNC1 1
+#define SYNC2 2
+#define SYNC3 3
+#define SYNC4 4
+#define SYNCEXTERN 5
+
+#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 japan;
+static int loopback;
+static int highestorder;
+static int timingcable;
+
+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);
+ZAP_IRQ_HANDLER(tor2_intr);
+
+/* translations of data channels for 24 channels in a 32 bit PCM highway */
+unsigned datxlt_t1[] = {
+ 1 ,2 ,3 ,5 ,6 ,7 ,9 ,10,11,13,14,15,17,18,19,21,22,23,25,26,27,29,30,31 };
+
+/* translations of data channels for 30/31 channels in a 32 bit PCM highway */
+unsigned datxlt_e1[] = {
+ 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
+ 25,26,27,28,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);
+
+ span->syncsrc = p->tor->syncsrc;
+
+ /* remove this span number from the current sync sources, if there */
+ for (i = 0; i < SPANS_PER_CARD; i++) {
+ if (p->tor->syncs[i] == span->spanno) {
+ p->tor->syncs[i] = 0;
+ p->tor->psyncs[i] = 0;
+ }
+ }
+ p->tor->syncpos[p->span] = lc->sync;
+ /* if a sync src, put it in the proper place */
+ if (lc->sync) {
+ p->tor->syncs[lc->sync - 1] = span->spanno;
+ p->tor->psyncs[lc->sync - 1] = p->span + 1;
+ }
+ /* 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 long 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);
+ }
+ /* nothing more to do if an E1 */
+ if (p->tor->cardtype == TYPE_E1) return 0;
+ 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)
+{
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static int tor2_close(struct zt_chan *chan)
+{
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static void init_spans(struct tor2 *tor)
+{
+ int x, y, c;
+ for (x = 0; x < SPANS_PER_CARD; x++) {
+ sprintf(tor->spans[x].name, "Tor2/%d/%d", tor->num, x + 1);
+ snprintf(tor->spans[x].desc, sizeof(tor->spans[x].desc) - 1,
+ "Tormenta 2 (PCI) Quad %s Card %d Span %d",
+ (tor->cardtype == TYPE_T1) ? "T1" : "E1", tor->num, x + 1);
+ tor->spans[x].manufacturer = "Digium";
+ zap_copy_string(tor->spans[x].devicetype, tor->type, sizeof(tor->spans[x].devicetype));
+ snprintf(tor->spans[x].location, sizeof(tor->spans[x].location) - 1,
+ "PCI Bus %02d Slot %02d", tor->pci->bus->number, PCI_SLOT(tor->pci->devfn) + 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;
+ if (tor->cardtype == TYPE_T1) {
+ tor->spans[x].channels = 24;
+ tor->spans[x].deflaw = ZT_LAW_MULAW;
+ tor->spans[x].linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
+ tor->spans[x].spantype = "T1";
+ } else {
+ tor->spans[x].channels = 31;
+ tor->spans[x].deflaw = ZT_LAW_ALAW;
+ tor->spans[x].linecompat = ZT_CONFIG_HDB3 | ZT_CONFIG_CCS | ZT_CONFIG_CRC4;
+ tor->spans[x].spantype = "E1";
+ }
+ tor->spans[x].chans = tor->chans[x];
+ tor->spans[x].flags = ZT_FLAG_RBS;
+ 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<tor->spans[x].channels;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 | ZT_SIG_CAS | ZT_SIG_SF | ZT_SIG_EM_E1;
+ c = (x * tor->spans[x].channels) + y;
+ mychans->pvt = &tor->tchans[c];
+ mychans->chanpos = y + 1;
+ tor->tchans[c].span = x;
+ tor->tchans[c].tor = tor;
+ }
+ }
+}
+
+static int __devinit tor2_launch(struct tor2 *tor)
+{
+ if (tor->spans[0].flags & ZT_FLAG_REGISTERED)
+ return 0;
+ printk("Tor2: Launching card: %d\n", tor->order);
+ if (zt_register(&tor->spans[0], 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", tor->spans[0].name);
+ return -1;
+ }
+ 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]);
+ return -1;
+ }
+ 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]);
+ return -1;
+ }
+ 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]);
+ return -1;
+ }
+ tor->plx[INTCSR] = cpu_to_le16(PLX_INTENA); /* enable PLX interrupt */
+#ifdef ENABLE_TASKLETS
+ tasklet_init(&tor->tor2_tlet, tor2_tasklet, (unsigned long)tor);
+#endif
+ return 0;
+}
+
+static int __devinit tor2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int res,x,f;
+ struct tor2 *tor;
+ unsigned long endjif;
+ volatile unsigned long *gpdata_io,*lasdata_io;
+ unsigned long gpdata,lasdata;
+
+ 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));
+ spin_lock_init(&tor->lock);
+ for (x = 0; x < SPANS_PER_CARD; x++) {
+ tor->chans[x] = kmalloc(sizeof(struct zt_chan) * 31,GFP_KERNEL);
+ if (!tor->chans[x])
+ return -ENOMEM;
+ memset(tor->chans[x],0,sizeof(struct zt_chan) * 31);
+ }
+ /* Load the resources */
+ tor->pci = pdev;
+ 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, so we dont do anything with section 1 */
+ 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 */
+ gpdata_io = (unsigned long *)&tor->plx[GPIOC];
+ gpdata = le32_to_cpu(*gpdata_io);
+
+ gpdata |= GPIO_WRITE; /* make sure WRITE is not asserted */
+ *gpdata_io = cpu_to_le32(gpdata);
+
+ gpdata &= ~GPIO_PROGRAM; /* activate the PROGRAM signal */
+ *gpdata_io = cpu_to_le32(gpdata);
+
+ /* wait for INIT and DONE to go low */
+ endjif = jiffies + 10;
+ while (le32_to_cpu(*gpdata_io) & (GPIO_INIT | GPIO_DONE) && (jiffies <= endjif));
+
+ if (endjif < jiffies) {
+ printk("Timeout waiting for INIT and DONE to go low\n");
+ goto err_out_release_all;
+ }
+ if (debug) printk("fwload: Init and done gone to low\n");
+ gpdata |= GPIO_PROGRAM;
+ *gpdata_io = cpu_to_le32(gpdata); /* de-activate the PROGRAM signal */
+ /* wait for INIT to go high (clearing done */
+ endjif = jiffies + 10;
+ while (!(le32_to_cpu(*gpdata_io) & GPIO_INIT) && (jiffies <= endjif));
+ if (endjif < jiffies) {
+ printk("Timeout waiting for INIT to go high\n");
+ goto err_out_release_all;
+ }
+
+ if (debug) printk("fwload: Init went high (clearing done)\nNow loading...\n");
+ /* assert WRITE signal */
+ gpdata &= ~GPIO_WRITE;
+ *gpdata_io = cpu_to_le32(gpdata);
+ for (x = 0; x < sizeof(tor2fw); x++)
+ {
+ /* write the byte */
+ *tor->mem8 = tor2fw[x];
+ /* if DONE signal, we're done, exit */
+ if (le32_to_cpu(*gpdata_io) & GPIO_DONE) break;
+ /* if INIT drops, we're screwed, exit */
+ if (!(le32_to_cpu(*gpdata_io) & 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 */
+ gpdata |= GPIO_WRITE;
+ *gpdata_io = cpu_to_le32(gpdata);
+ if (debug) printk("fwload: Loading done!\n");
+
+ /* Wait for FIFO to clear */
+ endjif = jiffies + 2;
+ while (jiffies < endjif); /* wait */
+ if (!(le32_to_cpu(*gpdata_io) & GPIO_INIT))
+ {
+ printk("Drove Init low!! CRC Error!!!\n");
+ goto err_out_release_all;
+ }
+ if (!(le32_to_cpu(*gpdata_io) & 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[CTLREG1] = 0;
+ tor->mem8[LEDREG] = 0;
+
+ /* set the LA2BRD register so that we enable block transfer, read
+ pre-fetch, and set to maximum read pre-fetch size */
+ lasdata_io = (unsigned long *)&tor->plx[LAS2BRD];
+ lasdata = *lasdata_io;
+ lasdata |= 0x39;
+ *lasdata_io = lasdata;
+
+ /* set the LA3BRD register so that we enable block transfer */
+ lasdata_io = (unsigned long *)&tor->plx[LAS3BRD];
+ lasdata = *lasdata_io;
+ lasdata |= 1;
+ *lasdata_io = lasdata;
+
+ /* check part revision data */
+ x = t1in(tor,1,0xf) & 15;
+#ifdef NONREVA
+ if (x > 3)
+ {
+ tor->mem8[CTLREG1] = NONREVA;
+ }
+#endif
+ for (x = 0; x < 256; x++) tor->mem32[x] = 0x7f7f7f7f;
+
+
+ if (request_irq(tor->irq, tor2_intr, ZAP_IRQ_SHARED_DISABLED, "tor2", tor)) {
+ printk(KERN_ERR "Unable to request tormenta IRQ %d\n", tor->irq);
+ goto err_out_release_all;
+ }
+
+ if (t1in(tor,1,0xf) & 0x80) {
+ printk("Tormenta 2 Quad E1/PRA Card\n");
+ tor->cardtype = TYPE_E1;
+ tor->datxlt = datxlt_e1;
+ } else {
+ printk("Tormenta 2 Quad T1/PRI Card\n");
+ tor->cardtype = TYPE_T1;
+ tor->datxlt = datxlt_t1;
+ }
+ init_spans(tor);
+
+ tor->order = tor->mem8[SWREG];
+ printk("Detected Card number: %d\n", tor->order);
+
+ /* Launch cards as appropriate */
+ x = 0;
+ for (;;) {
+ /* Find a card to activate */
+ f = 0;
+ for (x=0;cards[x];x++) {
+ if (cards[x]->order <= highestorder) {
+ tor2_launch(cards[x]);
+ if (cards[x]->order == highestorder)
+ f = 1;
+ }
+ }
+ /* If we found at least one, increment the highest order and search again, otherwise stop */
+ if (f)
+ highestorder++;
+ else
+ break;
+ }
+
+ 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 -ENODEV;
+}
+
+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] = cpu_to_le16(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++)
+ if (tor->chans[x])
+ kfree(tor->chans[x]);
+ kfree(tor);
+}
+
+static struct pci_driver tor2_driver = {
+ name: "tormenta2",
+ probe: tor2_probe,
+#ifdef LINUX26
+ remove: __devexit_p(tor2_remove),
+#else
+ remove: tor2_remove,
+#endif
+ id_table: tor2_pci_ids,
+};
+
+static int __init tor2_init(void) {
+ int res;
+ res = zap_pci_module(&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 < SPANS_PER_CARD; 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 long flags;
+#if 0
+ printk("Setting bits to %d on channel %s\n", bits, chan->name);
+#endif
+ if (p->tor->cardtype == TYPE_E1) { /* do it E1 way */
+ if (chan->chanpos == 16) return 0;
+ n = chan->chanpos - 1;
+ if (chan->chanpos > 16) n--;
+ k = p->span;
+ b = (n % 15) + 1;
+ c = p->tor->txsigs[k][b];
+ m = (n / 15) * 4; /* nibble selector */
+ c &= (15 << m); /* keep the other nibble */
+ c |= (bits & 15) << (4 - m); /* put our new nibble here */
+ p->tor->txsigs[k][b] = c;
+ /* output them to the chip */
+ t1out(p->tor,k + 1,0x40 + b,c);
+ return 0;
+ }
+ 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);
+ 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);
+ b += 3; /* now points to c 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_CBIT) 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);
+ b += 3; /* now points to d 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_DBIT) 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);
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+ return 0;
+}
+
+static int tor2_shutdown(struct zt_span *span)
+{
+ int i;
+ int tspan;
+ int wasrunning;
+ unsigned long 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 */
+ if (p->tor->cardtype == TYPE_E1) {
+ for (i = 0; i < 192; i++)
+ t1out(p->tor,tspan, i, 0);
+ } else {
+ 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 long flags;
+ char *coding;
+ char *framing;
+ char *crcing;
+ 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;
+
+ /* initialize the start value for the entire chunk of last ec buffer */
+ for (i = 0; i < span->channels; i++)
+ {
+ memset(p->tor->ec_chunk1[p->span][i],
+ ZT_LIN2X(0,&span->chans[i]),ZT_CHUNKSIZE);
+ memset(p->tor->ec_chunk2[p->span][i],
+ ZT_LIN2X(0,&span->chans[i]),ZT_CHUNKSIZE);
+ }
+ /* Force re-evaluation of the timing source */
+ if (timingcable)
+ p->tor->syncsrc = -1;
+
+ if (p->tor->cardtype == TYPE_E1) { /* if this is an E1 card */
+ unsigned char tcr1,ccr1,tcr2;
+ if (!alreadyrunning) {
+ p->tor->mem8[SYNCREG] = SYNCSELF;
+ p->tor->mem8[CTLREG] = E1DIV;
+ p->tor->mem8[LEDREG] = 0;
+ /* Force re-evaluation of sync src */
+ /* Zero out all registers */
+ for (i = 0; i < 192; i++)
+ t1out(p->tor,tspan, i, 0);
+
+ /* Set up for Interleaved Serial Bus operation in byte mode */
+ /* Set up all the spans every time, so we are sure they are
+ in a consistent state. If we don't, a card without all
+ its spans configured misbehaves in strange ways. */
+ t1out(p->tor,1,0xb5,9);
+ t1out(p->tor,2,0xb5,8);
+ t1out(p->tor,3,0xb5,8);
+ t1out(p->tor,4,0xb5,8);
+
+ t1out(p->tor,tspan,0x1a,4); /* CCR2: set LOTCMC */
+ for (i = 0; i <= 8; i++) t1out(p->tor,tspan,i,0);
+ for (i = 0x10; i <= 0x4f; i++) if (i != 0x1a) t1out(p->tor,tspan,i,0);
+ t1out(p->tor,tspan,0x10,0x20); /* RCR1: Rsync as input */
+ t1out(p->tor,tspan,0x11,6); /* RCR2: Sysclk=2.048 Mhz */
+ t1out(p->tor,tspan,0x12,9); /* TCR1: TSiS mode */
+ }
+ ccr1 = 0;
+ crcing = "";
+ tcr1 = 9; /* base TCR1 value: TSis mode */
+ tcr2 = 0;
+ if (span->lineconfig & ZT_CONFIG_CCS) {
+ ccr1 |= 8; /* CCR1: Rx Sig mode: CCS */
+ coding = "CCS";
+ } else {
+ tcr1 |= 0x20;
+ coding = "CAS";
+ }
+ if (span->lineconfig & ZT_CONFIG_HDB3) {
+ ccr1 |= 0x44; /* CCR1: TX and RX HDB3 */
+ framing = "HDB3";
+ } else framing = "AMI";
+ if (span->lineconfig & ZT_CONFIG_CRC4) {
+ ccr1 |= 0x11; /* CCR1: TX and TX CRC4 */
+ tcr2 |= 0x02; /* TCR2: CRC4 bit auto */
+ crcing = "/CRC4";
+ }
+ t1out(p->tor,tspan,0x12,tcr1);
+ t1out(p->tor,tspan,0x13,tcr2);
+ t1out(p->tor,tspan,0x14,ccr1);
+ t1out(p->tor,tspan, 0x18, 0x20); /* 120 Ohm, normal */
+
+ if (!alreadyrunning) {
+ t1out(p->tor,tspan,0x1b,0x8a); /* CCR3: LIRST & TSCLKM */
+ t1out(p->tor,tspan,0x20,0x1b); /* TAFR */
+ t1out(p->tor,tspan,0x21,0x5f); /* TNAFR */
+ t1out(p->tor,tspan,0x40,0xb); /* TSR1 */
+ for (i = 0x41; i <= 0x4f; i++) t1out(p->tor,tspan,i,0x55);
+ for (i = 0x22; i <= 0x25; i++) t1out(p->tor,tspan,i,0xff);
+ /* 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,0x1b,0x9a); /* CCR3: set also ESR */
+ t1out(p->tor,tspan,0x1b,0x82); /* CCR3: TSCLKM only now */
+
+ span->flags |= ZT_FLAG_RUNNING;
+ p->tor->spansstarted++;
+
+ /* enable interrupts */
+ p->tor->mem8[CTLREG] = INTENA | E1DIV;
+ }
+
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+
+ if (debug) {
+ if (alreadyrunning)
+ printk("Tor2: Reconfigured span %d (%s/%s%s) 120 Ohms\n", span->spanno, coding, framing, crcing);
+ else
+ printk("Tor2: Startup span %d (%s/%s%s) 120 Ohms\n", span->spanno, coding, framing, crcing);
+ }
+ } else { /* is a T1 card */
+
+ 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 */
+ /* Set up all the spans every time, so we are sure they are
+ in a consistent state. If we don't, a card without all
+ its spans configured misbehaves in strange ways. */
+ t1out(p->tor,1,0x94,9);
+ t1out(p->tor,2,0x94,8);
+ t1out(p->tor,3,0x94,8);
+ t1out(p->tor,4,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);
+ /* Setup japanese mode if appropriate */
+ t1out(p->tor,tspan,0x19,(japan ? 0x80 : 0x00)); /* no local loop */
+ t1out(p->tor,tspan,0x1e,(japan ? 0x80 : 0x00)); /* no local loop */
+ }
+ /* 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;
+
+ if (p->tor->cardtype == TYPE_E1)
+ {
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ t1out(p->tor,tspan,0xa8,0); /* no loops */
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ t1out(p->tor,tspan,0xa8,0x40); /* local loop */
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ t1out(p->tor,tspan,0xa8,0x80); /* remote loop */
+ break;
+ case ZT_MAINT_LOOPUP:
+ case ZT_MAINT_LOOPDOWN:
+ case ZT_MAINT_LOOPSTOP:
+ return -ENOSYS;
+ default:
+ printk("Tor2: Unknown maint command: %d\n", cmd);
+ break;
+ }
+ return 0;
+ }
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ t1out(p->tor,tspan,0x19,(japan ? 0x80 : 0x00)); /* no local loop */
+ t1out(p->tor,tspan,0x0a,0); /* no remote loop */
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ t1out(p->tor,tspan,0x19,0x40 | (japan ? 0x80 : 0x00)); /* local loop */
+ t1out(p->tor,tspan,0x0a,0); /* no remote loop */
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ t1out(p->tor,tspan,0x1e,(japan ? 0x80 : 0x00)); /* 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 inline void tor2_run(struct tor2 *tor)
+{
+ int x,y;
+ for (x = 0; x < SPANS_PER_CARD; x++) {
+ if (tor->spans[x].flags & ZT_FLAG_RUNNING) {
+ /* since the Tormenta 2 PCI is double-buffered, you
+ need to delay the transmit data 2 entire chunks so
+ that the transmit will be in sync with the receive */
+ for (y=0;y<tor->spans[x].channels;y++) {
+ zt_ec_chunk(&tor->spans[x].chans[y],
+ tor->spans[x].chans[y].readchunk,
+ tor->ec_chunk2[x][y]);
+ memcpy(tor->ec_chunk2[x][y],tor->ec_chunk1[x][y],
+ ZT_CHUNKSIZE);
+ memcpy(tor->ec_chunk1[x][y],
+ tor->spans[x].chans[y].writechunk,
+ ZT_CHUNKSIZE);
+ }
+ zt_receive(&tor->spans[x]);
+ }
+ }
+ for (x = 0; x < SPANS_PER_CARD; x++) {
+ if (tor->spans[x].flags & ZT_FLAG_RUNNING)
+ zt_transmit(&tor->spans[x]);
+ }
+}
+
+#ifdef ENABLE_TASKLETS
+static void tor2_tasklet(unsigned long data)
+{
+ struct tor2 *tor = (struct tor2 *)data;
+ tor->taskletrun++;
+ if (tor->taskletpending) {
+ tor->taskletexec++;
+ tor2_run(tor);
+ }
+ tor->taskletpending = 0;
+}
+#endif
+
+static int syncsrc = 0;
+static int syncnum = 0 /* -1 */;
+static int syncspan = 0;
+#ifdef DEFINE_SPINLOCK
+static DEFINE_SPINLOCK(synclock);
+#else
+static spinlock_t synclock = SPIN_LOCK_UNLOCKED;
+#endif
+
+static int tor2_findsync(struct tor2 *tor)
+{
+ int i;
+ int x;
+ unsigned long flags;
+ int p;
+ int nonzero;
+ int newsyncsrc = 0; /* Zaptel span number */
+ int newsyncnum = 0; /* tor2 card number */
+ int newsyncspan = 0; /* span on given tor2 card */
+ spin_lock_irqsave(&synclock, flags);
+#if 1
+ if (!tor->num) {
+ /* If we're the first card, go through all the motions, up to 8 levels
+ of sync source */
+ p = 1;
+ while (p < 8) {
+ nonzero = 0;
+ for (x=0;cards[x];x++) {
+ for (i = 0; i < SPANS_PER_CARD; i++) {
+ if (cards[x]->syncpos[i]) {
+ nonzero = 1;
+ if ((cards[x]->syncpos[i] == p) &&
+ !(cards[x]->spans[i].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_LOOPBACK)) &&
+ (cards[x]->spans[i].flags & ZT_FLAG_RUNNING)) {
+ /* This makes a good sync source */
+ newsyncsrc = cards[x]->spans[i].spanno;
+ newsyncnum = x;
+ newsyncspan = i + 1;
+ /* Jump out */
+ goto found;
+ }
+ }
+ }
+ }
+ if (nonzero)
+ p++;
+ else
+ break;
+ }
+found:
+ if ((syncnum != newsyncnum) || (syncsrc != newsyncsrc) || (newsyncspan != syncspan)) {
+ syncnum = newsyncnum;
+ syncsrc = newsyncsrc;
+ syncspan = newsyncspan;
+ if (debug) printk("New syncnum: %d, syncsrc: %d, syncspan: %d\n", syncnum, syncsrc, syncspan);
+ }
+ }
+#endif
+ /* update sync src info */
+ if (tor->syncsrc != syncsrc) {
+ tor->syncsrc = syncsrc;
+ /* Update sync sources */
+ for (i = 0; i < SPANS_PER_CARD; i++) {
+ tor->spans[i].syncsrc = tor->syncsrc;
+ }
+ if (syncnum == tor->num) {
+#if 1
+ /* actually set the sync register */
+ tor->mem8[SYNCREG] = syncspan;
+#endif
+ if (debug) printk("Card %d, using sync span %d, master\n", tor->num, syncspan);
+ tor->master = MASTER;
+ } else {
+#if 1
+ /* time from the timing cable */
+ tor->mem8[SYNCREG] = SYNCEXTERN;
+#endif
+ tor->master = 0;
+ if (debug) printk("Card %d, using Timing Bus, NOT master\n", tor->num);
+ }
+ }
+ spin_unlock_irqrestore(&synclock, flags);
+ return 0;
+}
+
+ZAP_IRQ_HANDLER(tor2_intr)
+{
+ int n, i, j, k, syncsrc;
+ unsigned int 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 */
+ {
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+ }
+
+ if (tor->cardtype == TYPE_E1)
+ /* set outbit, interrupt enable, and ack interrupt */
+ tor->mem8[CTLREG] = OUTBIT | INTENA | INTACK | E1DIV | tor->master;
+ else
+ /* set outbit, interrupt enable, and ack interrupt */
+ tor->mem8[CTLREG] = OUTBIT | INTENA | INTACK | tor->master;
+
+#if 0
+ if (!tor->passno)
+ printk("Interrupt handler\n");
+#endif
+
+ /* do the transmit output */
+ for (n = 0; n < tor->spans[0].channels; 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 */
+#ifdef FIXTHISFOR64
+ tor->mem32[tor->datxlt[n] + (32 * i)] = txword;
+#else
+ tor->mem32[tor->datxlt[n] + (32 * i)] = cpu_to_le32(txword);
+#endif
+ }
+ }
+
+ /* Do the receive input */
+ for (n = 0; n < tor->spans[0].channels; n++) {
+ for (i = 0; i < ZT_CHUNKSIZE; i++) {
+ /* read from */
+#ifdef FIXTHISFOR64
+ rxword = tor->mem32[tor->datxlt[n] + (32 * i)];
+#else
+ rxword = le32_to_cpu(tor->mem32[tor->datxlt[n] + (32 * i)]);
+#endif
+ /* 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 = tor->passno & 15;
+ /* if an E1 card, do rx signalling for it */
+ if ((i < 3) && (tor->cardtype == TYPE_E1)) { /* if an E1 card */
+ for (j = (i * 5); j < (i * 5) + 5; j++) {
+ for (k = 1; k <= SPANS_PER_CARD; k++) {
+ c = t1in(tor,k,0x31 + j);
+ rxc = c & 15;
+ if (rxc != tor->spans[k - 1].chans[j + 16].rxsig) {
+ /* Check for changes in received bits */
+ if (!(tor->spans[k - 1].chans[j + 16].sig & ZT_SIG_CLEAR))
+ zt_rbsbits(&tor->spans[k - 1].chans[j + 16], rxc);
+ }
+ rxc = c >> 4;
+ if (rxc != tor->spans[k - 1].chans[j].rxsig) {
+ /* Check for changes in received bits */
+ if (!(tor->spans[k - 1].chans[j].sig & ZT_SIG_CLEAR))
+ zt_rbsbits(&tor->spans[k - 1].chans[j], rxc);
+ }
+ }
+ }
+ }
+
+ /* if a T1, do the signalling */
+ if ((i < 12) && (tor->cardtype == TYPE_T1)) {
+ 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 < SPANS_PER_CARD; i++) { /* Go thru all the 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;
+ if (tor->cardtype == TYPE_E1)
+ t1out(tor,i + 1,0x21,0x5f); /* turn off yel */
+ else
+ t1out(tor,i + 1,0x35,0x10); /* turn off yel */
+ zt_alarm_notify(&tor->spans[i]); /* let them know */
+ }
+ }
+ }
+
+ i = tor->passno & 15;
+ if ((i >= 10) && (i <= 13) && !(tor->passno & 0x30))
+ {
+ j = 0; /* clear this alarm status */
+ i -= 10;
+ if (tor->cardtype == TYPE_T1) {
+ 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,(japan ? 0x80 : 0x00)); /* 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,(japan ? 0x80 : 0x00)); /* 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;
+ }
+ } else { /* its an E1 card */
+ t1out(tor,i + 1,6,0xff);
+ c = t1in(tor,i + 1,6); /* get the status */
+ if (c & 9) /* if red alarm */
+ {
+ j |= ZT_ALARM_RED;
+ }
+ if (c & 2) /* 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 < tor->spans[i].channels; 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)) {
+ if (tor->cardtype == TYPE_E1)
+ t1out(tor,i + 1,0x21,0x7f);
+ else
+ 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 */
+ /* light LED's if span configured and running */
+ if (tor->spans[i].flags & ZT_FLAG_RUNNING) {
+ 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 (!(tor->passno % 1000)) /* even second boundary */
+ {
+ /* do all spans */
+ for (i = 1; i <= SPANS_PER_CARD; i++)
+ {
+ if (tor->cardtype == TYPE_E1)
+ {
+ /* add this second's BPV count to total one */
+ tor->spans[i - 1].bpvcount += t1in(tor,i,1) + (t1in(tor,i,0) << 8);
+ if (tor->spans[i - 1].lineconfig & ZT_CONFIG_CRC4)
+ {
+ tor->spans[i - 1].crc4count += t1in(tor,i,3) + ((t1in(tor,i,2) & 3) << 8);
+ tor->spans[i - 1].ebitcount += t1in(tor,i,5) + ((t1in(tor,i,4) & 3) << 8);
+ }
+ tor->spans[i - 1].fascount += (t1in(tor,i,4) >> 2) + ((t1in(tor,i,2) & 0x3F) << 6);
+ }
+ else
+ {
+ /* add this second's BPV count to total one */
+ tor->spans[i - 1].bpvcount += t1in(tor,i,0x24) + (t1in(tor,i,0x23) << 8);
+ }
+ }
+ }
+ if (!timingcable) {
+ /* re-evaluate active sync src (no cable version) */
+ tor->syncsrc = 0;
+ syncsrc = 0;
+ /* if primary sync specified, see if we can use it */
+ if (tor->psyncs[0])
+ {
+ /* if no alarms, use it */
+ if (!(tor->spans[tor->psyncs[0] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE |
+ ZT_ALARM_LOOPBACK))) {
+ tor->syncsrc = tor->psyncs[0];
+ syncsrc = tor->syncs[0];
+ }
+ }
+ /* if any others specified, see if we can use them */
+ for (i = 1; i < SPANS_PER_CARD; 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->psyncs[i])) {
+ /* if no alarms, use it */
+ if (!(tor->spans[tor->psyncs[i] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE |
+ ZT_ALARM_LOOPBACK))) {
+ tor->syncsrc = tor->psyncs[i];
+ syncsrc = tor->syncs[i];
+ }
+ }
+ }
+ /* update sync src info */
+ for (i = 0; i < SPANS_PER_CARD; i++) tor->spans[i].syncsrc = syncsrc;
+
+ /* actually set the sync register */
+ tor->mem8[SYNCREG] = tor->syncsrc;
+ } else /* Timing cable version */
+ tor2_findsync(tor);
+
+ tor->passno++;
+
+#ifdef ENABLE_TASKLETS
+ if (!tor->taskletpending) {
+ tor->taskletpending = 1;
+ tor->taskletsched++;
+ tasklet_hi_schedule(&tor->tor2_tlet);
+ } else {
+ tor->txerrors++;
+ }
+#else
+ tor2_run(tor);
+#endif
+ /* We are not the timing bus master */
+ if (tor->cardtype == TYPE_E1)
+ /* clear OUTBIT and enable interrupts */
+ tor->mem8[CTLREG] = INTENA | E1DIV | tor->master;
+ else
+ /* clear OUTBIT and enable interrupts */
+ tor->mem8[CTLREG] = INTENA | tor->master;
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+}
+
+
+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 Quad T1 or E1 Zaptel Driver");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+#ifdef LINUX26
+module_param(debug, int, 0600);
+module_param(loopback, int, 0600);
+module_param(timingcable, int, 0600);
+module_param(japan, int, 0600);
+#else
+MODULE_PARM(debug, "i");
+MODULE_PARM(loopback, "i");
+MODULE_PARM(timingcable, "i");
+MODULE_PARM(japan, "i");
+#endif
+
+MODULE_DEVICE_TABLE(pci, tor2_pci_ids);
+
+module_init(tor2_init);
+module_exit(tor2_cleanup);