[zaptel-commits] mattf: branch mattf/bri-related r4144 - /team/mattf/bri-related/
SVN commits to the Zaptel project
zaptel-commits at lists.digium.com
Sat Apr 5 13:39:32 CDT 2008
Author: mattf
Date: Sat Apr 5 13:39:31 2008
New Revision: 4144
URL: http://svn.digium.com/view/zaptel?view=rev&rev=4144
Log: (empty)
Added:
team/mattf/bri-related/qozap.c (with props)
team/mattf/bri-related/qozap.h (with props)
Added: team/mattf/bri-related/qozap.c
URL: http://svn.digium.com/view/zaptel/team/mattf/bri-related/qozap.c?view=auto&rev=4144
==============================================================================
--- team/mattf/bri-related/qozap.c (added)
+++ team/mattf/bri-related/qozap.c Sat Apr 5 13:39:31 2008
@@ -1,0 +1,1998 @@
+/*
+ * qozap.c - Zaptel driver for the quadBRI PCI ISDN card
+ * and the octoBRI PCI ISDN card!
+ *
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Junghanns.NET GmbH
+ *
+ * Klaus-Peter Junghanns <kpj at junghanns.net>
+ *
+ * This program is free software and may be modified and
+ * distributed under the terms of the GNU Public License.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <zaptel.h>
+#include "qozap.h"
+
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+#if CONFIG_PCI
+
+static int doubleclock=0;
+static int ports=-1; /* autodetect */
+static int pcmslave=0;
+static int bloop=0;
+static int debug=0;
+static int dacs=1; /* 0 = no dacs, 1 = oncard dacs */
+static struct qoz_card *qoz_dev_list = NULL;
+static int qoz_dev_count = 0;
+static int totalBRIs = 0;
+static struct pci_dev *multi_qoz = NULL;
+static spinlock_t registerlock = SPIN_LOCK_UNLOCKED;
+static int sort=1;
+
+static int ztqoz_shutdown(struct zt_span *span);
+
+int qoz_waitbusy(struct qoz_card *qoztmp) {
+ int x=1000;
+ while (x-- && (qoz_inb(qoztmp,qoz_R_STATUS) & 1));
+ if (x < 0) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+void qoz_shutdownCard(struct qoz_card *qoztmp) {
+ int s=0;
+ unsigned long flags;
+
+ int stports=0;
+ if (qoztmp == NULL) {
+ printk(KERN_INFO "qozap: shutting down NULL card!\n");
+ return;
+ }
+
+ if ((qoztmp->pci_io == NULL) || (qoztmp->ioport == 0)) {
+ return;
+ }
+
+ if (debug)
+ printk(KERN_INFO "qozap: shutting down card %d (cardID %d) at io port %#x.\n",qoztmp->cardno,qoztmp->cardID,(u_int) qoztmp->ioport);
+
+
+ spin_lock_irqsave(&qoztmp->lock,flags);
+
+ // turn off irqs
+ qoz_outb(qoztmp,qoz_R_IRQMSK_MISC, 0);
+ qoz_outb(qoztmp,qoz_R_SCI_MSK, 0);
+ qoz_outb(qoztmp,qoz_R_IRQ_CTRL, 0);
+
+ spin_unlock_irqrestore(&qoztmp->lock,flags);
+
+ stports = qoztmp->stports;
+ for (s=0; s < stports; s++) {
+ if(qoztmp->spans[s].flags & ZT_FLAG_REGISTERED) {
+ zt_unregister(&(qoztmp->spans[s]));
+ if (debug > 2)
+ printk(KERN_INFO "qozap: unregistered card %d span %d.\n",qoztmp->cardno,s+1);
+ }
+ }
+
+
+ release_region(qoztmp->ioport, 8);
+ iounmap((void *) qoztmp->pci_io);
+ release_mem_region((unsigned long) qoztmp->pci_io_phys, 256);
+
+ spin_lock_irqsave(&qoztmp->lock,flags);
+
+ qoztmp->pci_io = NULL;
+ qoztmp->ioport = 0;
+
+ if (qoztmp->pcidev != NULL) {
+ pci_disable_device(qoztmp->pcidev);
+ }
+ pci_write_config_word(qoztmp->pcidev, PCI_COMMAND, 0);
+
+ free_irq(qoztmp->irq,qoztmp);
+ spin_unlock_irqrestore(&qoztmp->lock,flags);
+
+
+}
+
+void qoz_doLEDs(struct qoz_card *qoztmp) {
+ unsigned char leds = 0x0;
+ unsigned long ledw;
+ unsigned long flags;
+ spin_lock_irqsave(&qoztmp->lock,flags);
+
+ if ((qoztmp->type == 0xb520) && (qoztmp->stports == 4)){
+ qoz_outb(qoztmp,qoz_R_GPIO_SEL,0x20 | 0x10);
+ qoz_outb(qoztmp,qoz_R_GPIO_EN1,0xf);
+ qoz_outb(qoztmp,qoz_R_GPIO_OUT1,(qoztmp->leds[0] | (qoztmp->leds[1] << 1) | (qoztmp->leds[2] << 2) | (qoztmp->leds[3] << 3)));
+ } else if (((qoztmp->type == 0xb550) || (qoztmp->type == 0xb556)) && (qoztmp->stports == 4)){
+ qoz_outb(qoztmp,qoz_R_GPIO_SEL,0x80 | 0x40 | 0x20 | 0x10);
+ qoz_outb(qoztmp,qoz_R_GPIO_EN1,0xff);
+ leds = 0x10;
+ if (qoztmp->leds[0] == 1) {
+ leds |= 0x04;
+ }
+ if (qoztmp->leds[1] == 1) {
+ leds |= 0x20;
+ }
+ if (qoztmp->leds[2] == 1) {
+ leds |= 0x80;
+ }
+ if (qoztmp->leds[3] == 1) {
+ leds |= 0x40;
+ }
+
+ /*
+ 03
+ 12
+ 0x80 rr
+ rg
+ 0x40 rg
+ rr
+ 0x20 rr
+ gr
+ 0x04 gr
+ rr
+ */
+ qoz_outb(qoztmp,qoz_R_GPIO_OUT1, leds);
+
+ } else if ((qoztmp->type == 0xb556) && (qoztmp->stports == 2)){
+ qoz_outb(qoztmp,qoz_R_GPIO_SEL,0x80 | 0x40 | 0x20 | 0x10);
+ qoz_outb(qoztmp,qoz_R_GPIO_EN1,0xff);
+ leds = 0x0;
+ if (qoztmp->leds[0] == 1) {
+ leds |= 0x04;
+ }
+ if (qoztmp->leds[1] == 1) {
+ leds |= 0x08;
+ }
+ qoz_outb(qoztmp,qoz_R_GPIO_OUT1, leds);
+
+ } else if (qoztmp->type == 0xb558) {
+ qoz_outb(qoztmp,qoz_R_GPIO_SEL,0x80 | 0x40 | 0x20);
+ qoz_outb(qoztmp,qoz_R_GPIO_EN1,0x80 | 0x40 | 0x20 | 0x4);
+ if (qoztmp->leds[0] == 1) {
+ leds |= 0x04;
+ }
+ if (qoztmp->leds[1] == 1) {
+ leds |= 0x20;
+ }
+ if (qoztmp->leds[2] == 1) {
+ leds |= 0x40;
+ }
+ if (qoztmp->leds[3] == 1) {
+ leds |= 0x80;
+ }
+
+ qoz_outb(qoztmp,qoz_R_GPIO_OUT1, leds);
+ /*
+ gpio_10 0
+ gpio_13 1
+ gpio_15 2
+ gpio_14 3
+ */
+ } else if (qoztmp->type == 0xb55b) {
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x21);
+ /* 0x01 g1 st1
+ 0x02 g2 st2
+ 0x04 g3 st3
+ 0x08 g4 st4
+ 0x10 r8 st5
+ 0x20 r7 st6
+ 0x40 r6 st7
+ 0x80 r5 st8
+ */
+ if (qoztmp->leds[0] == 0) {
+ leds |= 0x01;
+ }
+ if (qoztmp->leds[1] == 0) {
+ leds |= 0x02;
+ }
+ if (qoztmp->leds[2] == 0) {
+ leds |= 0x04;
+ }
+ if (qoztmp->leds[3] == 0) {
+ leds |= 0x08;
+ }
+ if (qoztmp->leds[4] == 0) {
+ leds |= 0x10;
+ }
+ if (qoztmp->leds[5] == 0) {
+ leds |= 0x20;
+ }
+ if (qoztmp->leds[6] == 0) {
+ leds |= 0x40;
+ }
+ if (qoztmp->leds[7] == 0) {
+ leds |= 0x80;
+ }
+
+ ledw = leds << 24 | leds << 16 | leds << 8 | leds;
+
+ qoz_outdw_io(qoztmp,0x4000, ledw);
+
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x20);
+
+ }
+ spin_unlock_irqrestore(&qoztmp->lock,flags);
+}
+
+void qoz_doWD(struct qoz_card *qoztmp) {
+ unsigned long flags;
+ if (!qoztmp->wdp) {
+ return;
+ }
+ spin_lock_irqsave(&qoztmp->lock,flags);
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x21);
+ if (qoztmp->wdp == 1) {
+ qoz_outdw_io(qoztmp,0x4000, qoz_WD_P2);
+ qoztmp->wdp = 2;
+ } else {
+ qoz_outdw_io(qoztmp,0x4000, qoz_WD_P1);
+ qoztmp->wdp = 1;
+ }
+ qoz_inb_io(qoztmp,qoz_R_CHIP_ID);
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x20);
+ spin_unlock_irqrestore(&qoztmp->lock,flags);
+}
+
+void qoz_undoWD(struct qoz_card *qoztmp) {
+ unsigned long flags;
+
+ if (qoztmp->wdp) {
+ printk(KERN_INFO "qozap: Stopping hardware watchdog.\n");
+ spin_lock_irqsave(&qoztmp->lock,flags);
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x21);
+ qoz_outdw_io(qoztmp,0x4000, qoz_WD_P0);
+ qoztmp->wdp = 0;
+ qoz_inb_io(qoztmp,qoz_R_CHIP_ID);
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x20);
+ spin_unlock_irqrestore(&qoztmp->lock,flags);
+ }
+}
+
+void qoz_reset_pcm(struct qoz_card *qoztmp) {
+ qoz_outb(qoztmp,qoz_R_CIRM,0x20);
+ qoz_outb(qoztmp,qoz_R_CIRM,0x0);
+ qoz_waitbusy(qoztmp);
+
+ if (pcmslave) {
+ qoz_outb(qoztmp,qoz_R_PCM_MD0, 0x90);
+ qoz_outb(qoztmp,qoz_R_PCM_MD1, 0x20);
+ qoz_outb(qoztmp,qoz_R_PCM_MD0, 0xA0);
+ qoz_outb(qoztmp,qoz_R_PCM_MD2, 0x4 | 0x8);
+ } else {
+ qoz_outb(qoztmp,qoz_R_PCM_MD0, 0x91);
+ qoz_outb(qoztmp,qoz_R_PCM_MD1, 0x20);
+ }
+}
+
+void qoz_resetCard(struct qoz_card *qoztmp) {
+ unsigned long flags;
+ spin_lock_irqsave(&(qoztmp->lock),flags);
+ pci_write_config_word(qoztmp->pcidev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+ // soft reset
+ qoz_outb(qoztmp,qoz_R_CIRM,0x8);
+ qoz_outb(qoztmp,qoz_R_CIRM,0x0);
+ qoz_waitbusy(qoztmp);
+
+ qoz_reset_pcm(qoztmp);
+
+ // fifo reset
+ qoz_outb(qoztmp,qoz_R_CIRM,0x10);
+ qoz_outb(qoztmp,qoz_R_CIRM,0x0);
+ qoz_waitbusy(qoztmp);
+
+ // s/t reset
+ qoz_outb(qoztmp,qoz_R_CIRM,0x40);
+ qoz_outb(qoztmp,qoz_R_CIRM,0x0);
+ qoz_waitbusy(qoztmp);
+
+ /* set S0 amplitude */
+ qoz_outb(qoztmp,qoz_R_PWM_MD,0xa0);
+ if (qoztmp->type == 0xb552) {
+ qoz_outb(qoztmp,qoz_R_PWM0,0x19);
+ } else if (qoztmp->type == 0xb55b) {
+ qoz_outb(qoztmp,qoz_R_PWM0,0x19);
+ } else {
+ qoz_outb(qoztmp,qoz_R_PWM0,0x1E);
+ }
+
+ /* set up the timer */
+ qoz_outb(qoztmp,qoz_R_TI_WD, 0x2);
+ qoz_outb(qoztmp,qoz_R_IRQMSK_MISC, 0x2);
+
+
+ /* all state changes */
+ qoz_outb(qoztmp,qoz_R_SCI_MSK, 0xff);
+
+ if (qoztmp->type == 0xb552) {
+ qoz_outb(qoztmp,qoz_R_FIFO_MD,0x16);
+ } else if (qoztmp->type == 0xb55b) {
+ qoz_outb(qoztmp,qoz_R_FIFO_MD,0x16);
+ } else {
+ qoz_outb(qoztmp,qoz_R_FIFO_MD,0x26);
+ }
+
+ // double clock
+ if (doubleclock == 1) {
+ // hopefully you have set CLK_MODE correctly!
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x20);
+ } else {
+ if (qoztmp->type == 0x08b4) {
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x0);
+ } else if (qoztmp->type == 0xb550) {
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x20);
+ } else if (qoztmp->type == 0xb556) {
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x20);
+ } else if (qoztmp->type == 0xb557) {
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x20);
+ } else if (qoztmp->type == 0xb558) {
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x20);
+ } else if (qoztmp->type == 0xb520) {
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x20);
+ } else if (qoztmp->type == 0xb410) {
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x02);
+ } else {
+ /* you are on your own here! */
+ qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x20);
+ }
+ }
+ qoz_outb(qoztmp,qoz_R_CTRL,0x0);
+
+ /* R0 G1 */
+ qoztmp->leds[0] = 0x0;
+ qoztmp->leds[1] = 0x0;
+ qoztmp->leds[2] = 0x0;
+ qoztmp->leds[3] = 0x0;
+ qoztmp->leds[4] = 0x0;
+ qoztmp->leds[5] = 0x0;
+ qoztmp->leds[6] = 0x0;
+ qoztmp->leds[7] = 0x0;
+
+ if (qoztmp->type == 0xb552) {
+ qoztmp->stports = 8;
+ } else if (qoztmp->type == 0xb55b) {
+ qoztmp->stports = 8;
+ } else if (qoztmp->type == 0xb556) {
+ qoztmp->stports = 2;
+ } else if (qoztmp->type == 0xb557) {
+ qoztmp->stports = 2;
+ } else {
+ qoztmp->stports = 4;
+ }
+ qoztmp->ticks = 0;
+ qoztmp->clicks = 0;
+ if ((qoztmp->type == 0xb550) || (qoztmp->type == 0xb556)) {
+ printk(KERN_INFO "qozap: Starting hardware watchdog.\n");
+ qoztmp->wdp = 2;
+ } else {
+ qoztmp->wdp = 0;
+ }
+
+ qoz_outb(qoztmp,qoz_R_ST_SYNC,0x0);
+
+ /* IRQs off */
+ qoz_outb(qoztmp,qoz_R_IRQ_CTRL, 0);
+
+ spin_unlock_irqrestore(&(qoztmp->lock),flags);
+}
+
+void qoz_registerCard(struct qoz_card *qozcard) {
+ struct qoz_card *tmpcard = NULL;
+ spin_lock(®isterlock);
+
+ if (qozcard != NULL) {
+ if (!sort) {
+ tmpcard = qoz_dev_list;
+ if (tmpcard) {
+ while (tmpcard->next) {
+ tmpcard = tmpcard->next;
+ }
+ tmpcard->next = qozcard;
+ qozcard->prev = tmpcard;
+ } else {
+ qoz_dev_list = qozcard;
+ }
+ } else {
+ qozcard->prev = NULL;
+ qozcard->next = qoz_dev_list;
+ if (qoz_dev_list) {
+ qoz_dev_list->prev = qozcard;
+ }
+ qoz_dev_list = qozcard;
+ }
+ qozcard->cardno = ++qoz_dev_count;
+ } else {
+ printk(KERN_INFO "qozap: trying to register NULL card.\n");
+ }
+ spin_unlock(®isterlock);
+}
+
+static int qoz_dfifo_tx(struct qoz_card *qoztmp, int stport) {
+ int chan = 2;
+ int x=0;
+ char fifo = 0;
+ char offset = 0;
+ unsigned long flags;
+
+
+ if (qoztmp->type == 0xb552) {
+ offset = 24;
+ } else if (qoztmp->type == 0xb55b) {
+ offset = 24;
+ } else {
+ offset = 28;
+ }
+
+ fifo = stport + offset;
+
+ if (qoztmp->chans[stport][chan].bytes2transmit < 1) {
+ return 0;
+ } else {
+ spin_lock_irqsave(&qoztmp->lock,flags);
+ /* select fifo */
+ qoz_outb(qoztmp,qoz_R_FIFO,fifo << 1);
+ qoz_waitbusy(qoztmp);
+
+ if (debug > 1)
+ printk(KERN_INFO "qozap: card %d stport %d TX [ ", qoztmp->cardno, stport + 1);
+ /* copy frame to fifo */
+ for (x=0;x<qoztmp->chans[stport][chan].bytes2transmit;x++) {
+ if (debug > 1)
+ printk("%#x ",qoztmp->dtxbuf[stport][x]);
+ qoz_outb(qoztmp,qoz_A_FIFO_DATA0,qoztmp->dtxbuf[stport][x]);
+ }
+ if (debug > 1)
+ printk("] %d bytes\n",qoztmp->chans[stport][chan].bytes2transmit);
+
+ if (qoztmp->chans[stport][chan].eoftx == 1) {
+ /* transmit HDLC frame */
+ qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x1);
+ qoz_waitbusy(qoztmp);
+ }
+ spin_unlock_irqrestore(&qoztmp->lock,flags);
+ }
+ return 0;
+}
+
+static int qoz_fifo_tx(struct qoz_card *qoztmp, char fifo) {
+ int stport = fifo / 2;
+ int chan = fifo % 2;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qoztmp->lock,flags);
+ /* select fifo */
+ qoz_outb(qoztmp,qoz_R_FIFO,0x80 | (fifo << 1));
+ qoz_waitbusy(qoztmp);
+ /* transmit 8 bytes of transparent data */
+ qoz_outdw(qoztmp,qoz_A_FIFO_DATA0,*((unsigned int *) &qoztmp->txbuf[stport][chan][0]));
+ qoz_outdw(qoztmp,qoz_A_FIFO_DATA0,*((unsigned int *) &qoztmp->txbuf[stport][chan][4]));
+
+ spin_unlock_irqrestore(&qoztmp->lock,flags);
+ return 0;
+}
+
+static int qoz_dfifo_rx(struct qoz_card *qoztmp, int stport) {
+ unsigned char f1=1,f2=1,data,stat;
+ unsigned char of1=0,of2=0;
+ int len,i;
+ unsigned short z1=1,z2=1;
+ unsigned short oz1=0,oz2=0;
+ char fifo = 0;
+ char offset = 0;
+ unsigned long flags;
+
+ if (qoztmp->type == 0xb552) {
+ offset = 24;
+ } else if (qoztmp->type == 0xb55b) {
+ offset = 24;
+ } else {
+ offset = 28;
+ }
+
+ fifo = stport + offset;
+
+ spin_lock_irqsave(&qoztmp->lock,flags);
+ // select rx fifo
+ qoz_outb(qoztmp,qoz_R_FIFO,(fifo << 1) | 1);
+ qoz_waitbusy(qoztmp);
+
+ while ((of1 != f1) && (of2 != f2)) {
+ of1 = f1;
+ of2 = f2;
+ f1 = qoz_inb(qoztmp,qoz_A_F1) & 0xf;
+ f2 = qoz_inb(qoztmp,qoz_A_F2) & 0xf;
+ }
+
+ if (f1 == f2) {
+ /* no frame */
+ qoztmp->st[stport].drx--;
+ qoztmp->chans[stport][2].bytes2receive = 0;
+ spin_unlock_irqrestore(&qoztmp->lock,flags);
+ return 0;
+ }
+
+ while ((oz1 != z1) && (oz2 != z2)) {
+ oz1 = z1;
+ oz2 = z2;
+ if ((qoztmp->type != 0xb552) && (qoztmp->type != 0xb55b)){
+ z1 = qoz_inw(qoztmp,qoz_A_Z1) & 0x7ff;
+ z2 = qoz_inw(qoztmp,qoz_A_Z2) & 0x7ff;
+ } else {
+ z1 = qoz_inw(qoztmp,qoz_A_Z1) & 0x3ff;
+ z2 = qoz_inw(qoztmp,qoz_A_Z2) & 0x3ff;
+ }
+ }
+
+ if ((qoztmp->type == 0xb552)|| (qoztmp->type == 0xb55b)) {
+ len = z1 - z2;
+ if (len < 0) {
+ len += qoz_DFIFO_SIZE8;
+ }
+ } else {
+ len = z1 - z2;
+ if (len < 0) {
+ len += qoz_DFIFO_SIZE4;
+ }
+ }
+
+ if (len > qoz_DFIFO_SIZE4) {
+ printk(KERN_INFO "\nqozap: buffer overflow in D channel RX!\n");
+ qoztmp->chans[stport][2].bytes2receive = 0;
+ qoztmp->chans[stport][2].eofrx = 0;
+ } else {
+ if (debug > 1) printk(KERN_INFO "qozap: card %d span %d RX [ ", qoztmp->cardno, stport + 1);
+ for (i=0; i<len; i++) {
+ data = qoz_inb(qoztmp,qoz_A_FIFO_DATA0);
+ qoztmp->drxbuf[stport][i] = data;
+ if (debug > 1) printk("%#x ",data);
+ }
+ if (debug > 1) printk("] %d bytes\n", len);
+ qoztmp->chans[stport][2].bytes2receive = i;
+ qoztmp->chans[stport][2].eofrx = 1;
+ }
+
+ stat = qoz_inb(qoztmp,qoz_A_FIFO_DATA0);
+ if (stat != 0x0) {
+ // bad CRC, skip it
+ printk(KERN_INFO "qozap: CRC error for HDLC frame on card %d (cardID %d) S/T port %d\n",qoztmp->cardno, qoztmp->cardID, stport+1);
+ qoztmp->chans[stport][2].bytes2receive = 0;
+ qoztmp->chans[stport][2].eofrx = 0;
+// zt_qevent_nolock(&qoztmp->chans[stport][2], ZT_EVENT_BADFCS);
+ }
+ qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x1);
+ qoz_waitbusy(qoztmp);
+
+ /* frame recevived */
+ if (qoztmp->st[stport].drx > 0) {
+ qoztmp->st[stport].drx--;
+ } else {
+ printk(KERN_INFO "qozap: trying to receive too much (card %d span %d drx %d)\n", qoztmp->cardno, stport+1, qoztmp->st[stport].drx);
+ qoztmp->st[stport].drx = 0;
+ }
+ spin_unlock_irqrestore(&qoztmp->lock,flags);
+ return 0;
+}
+
+
+static int qoz_fifo_rx(struct qoz_card *qoztmp, char fifo) {
+ int stport = fifo / 2;
+ int chan = fifo % 2;
+ unsigned char data;
+ int len,i;
+ unsigned short z1=1,z2=1;
+ unsigned short oz1=0,oz2=0;
+ int mumbojumbo=0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qoztmp->lock,flags);
+
+ /* select rx fifo */
+ qoz_outb(qoztmp,qoz_R_FIFO,0x80 | (fifo << 1) | 1);
+ qoz_waitbusy(qoztmp);
+
+ while ((oz1 != z1) && (oz2 != z2)) {
+ oz1 = z1;
+ oz2 = z2;
+ z1 = qoz_inw(qoztmp,qoz_A_Z1) & 0x7f;
+ z2 = qoz_inw(qoztmp,qoz_A_Z2) & 0x7f;
+ }
+ len = z1 - z2;
+ if (len < 0) {
+ len += qoz_FIFO_SIZE;
+ }
+ if (len > 2 * ZT_CHUNKSIZE) {
+ mumbojumbo = len - (2 * ZT_CHUNKSIZE);
+ len = ZT_CHUNKSIZE;
+ for (i=0;i<mumbojumbo;i++) {
+ data = qoz_inb(qoztmp,qoz_A_FIFO_DATA0);
+ }
+ qoztmp->clicks++;
+ if (((qoztmp->clicks > 50) || (debug > 5)) && (mumbojumbo > 0)) {
+ printk(KERN_CRIT "qozap: dropped audio card %d cardid %d bytes %d z1 %d z2 %d fifo %d\n", qoztmp->cardno, qoztmp->cardID, mumbojumbo, z1, z2, fifo);
+ qoztmp->clicks = 0;
+ }
+ }
+
+
+ if (len < ZT_CHUNKSIZE) {
+// printk(KERN_INFO "qozap: not enough to receive (%d bytes)\n",len);
+ spin_unlock_irqrestore(&qoztmp->lock,flags);
+ return 0;
+ } else {
+ if (bloop) {
+ *((unsigned int *) &qoztmp->txbuf[stport][chan][0]) = qoz_indw(qoztmp,qoz_A_FIFO_DATA0);
+ *((unsigned int *) &qoztmp->txbuf[stport][chan][4]) = qoz_indw(qoztmp,qoz_A_FIFO_DATA0);
+ } else {
+ *((unsigned int *) &qoztmp->rxbuf[stport][chan][0]) = qoz_indw(qoztmp,qoz_A_FIFO_DATA0);
+ *((unsigned int *) &qoztmp->rxbuf[stport][chan][4]) = qoz_indw(qoztmp,qoz_A_FIFO_DATA0);
+ }
+ }
+
+ spin_unlock_irqrestore(&qoztmp->lock,flags);
+ if (bloop == 0)
+ zt_ec_chunk(&qoztmp->spans[stport].chans[chan], qoztmp->spans[stport].chans[chan].readchunk, qoztmp->spans[stport].chans[chan].writechunk);
+
+// printk(KERN_INFO "s/t port %d, channel %d, dbufi=%d, f1=%d, f2=%d, z1=%d, z2=%d => len = %d stat=%#x, hdlc=%d\n",stport,chan,qoztmp->st[stport].dbufi,f1,f2,z1,z2,len,stat,hdlc);
+ return 0;
+}
+
+static void qoz_assign(struct qoz_card *qoztmp, int src_span, int src_chan, int dst_span, int dst_chan, int timeslot, int use_pcm_bus) {
+ unsigned long flags;
+ int dst_fifo = dst_span * 2 + (dst_chan - 1);
+ int src_fifo = src_span * 2 + (src_chan - 1);
+ int src_hfc_chan = src_span * 4 + (src_chan - 1);
+ int dst_hfc_chan = dst_span * 4 + (dst_chan - 1);
+
+ spin_lock_irqsave(&qoztmp->lock, flags);
+
+ qoz_outb(qoztmp,qoz_R_FIFO,(src_fifo << 1) | 1);
+ qoz_waitbusy(qoztmp);
+ qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2);
+ qoz_waitbusy(qoztmp);
+ qoz_outb(qoztmp,qoz_A_CHANNEL,(src_hfc_chan << 1) | 1);
+ qoz_outb(qoztmp,qoz_A_CON_HDLC,0xDE); // was c2
+
+ qoz_outb(qoztmp,qoz_R_SLOT,timeslot << 1);
+ qoz_outb(qoztmp,qoz_A_SL_CFG, (src_hfc_chan << 1) | 0 | 0x40);
+
+ qoz_outb(qoztmp,qoz_R_FIFO, dst_fifo << 1);
+ qoz_waitbusy(qoztmp);
+ qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2);
+ qoz_waitbusy(qoztmp);
+ qoz_outb(qoztmp,qoz_A_CHANNEL,dst_hfc_chan << 1);
+ qoz_outb(qoztmp,qoz_A_CON_HDLC,0xDE); // was c2
+
+ qoz_outb(qoztmp,qoz_R_SLOT,(timeslot << 1) | 1);
+ qoz_outb(qoztmp,qoz_A_SL_CFG, (dst_hfc_chan << 1) | 1 | 0x40);
+
+ spin_unlock_irqrestore(&qoztmp->lock, flags);
+}
+
+static void qoz_unassign(struct qoz_card *qoztmp, int span, int chan, int timeslot) {
+ unsigned long flags;
+
+// int timeslot = span * 2 + (chan - 1);
+ int fifo = span * 2 + (chan - 1);
+ int hfc_chan = span * 4 + (chan - 1);
+
+ spin_lock_irqsave(&qoztmp->lock, flags);
+
+ qoz_outb(qoztmp,qoz_R_FIFO,(fifo << 1));
+ qoz_waitbusy(qoztmp);
+ qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2);
+ qoz_waitbusy(qoztmp);
+ qoz_outb(qoztmp,qoz_A_CON_HDLC,0x02);
+ qoz_outb(qoztmp,qoz_A_CHANNEL,(hfc_chan << 1));
+ qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x1);
+
+ qoz_outb(qoztmp,qoz_R_FIFO,(fifo << 1) | 1);
+ qoz_waitbusy(qoztmp);
+ qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2);
+ qoz_waitbusy(qoztmp);
+ qoz_outb(qoztmp,qoz_A_CON_HDLC,0x02);
+ qoz_outb(qoztmp,qoz_A_CHANNEL,(hfc_chan << 1) | 1);
+ qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x1);
+
+ qoz_outb(qoztmp,qoz_R_SLOT,(timeslot << 1) | 1);
+ qoz_outb(qoztmp,qoz_A_SL_CFG, 0x0);
+
+ qoz_outb(qoztmp,qoz_R_SLOT,timeslot << 1);
+ qoz_outb(qoztmp,qoz_A_SL_CFG, 0x0);
+
+ spin_unlock_irqrestore(&qoztmp->lock, flags);
+}
+
+
+static int ztqoz_dacs(struct zt_chan *dst, struct zt_chan *src)
+{
+ struct qoz_card *qoztmp = NULL;
+ int use_pcm_bus = 0;
+ int timeslot = 0;
+ if (!dacs) return -1;
+
+ if (src) {
+ qoztmp = src->pvt;
+
+ if (src->pvt != dst->pvt) {
+ if (dacs == 2) {
+ use_pcm_bus = 1;
+ timeslot = src->channo;
+ if (debug)
+ printk("qozap: Assigning channel %d/%d -> %d/%d, timeslot %d, different cards!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos, timeslot);
+ } else {
+ if (debug)
+ printk("qozap: Not Assigning %d/%d -> %d/%d, different cards!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos);
+ return -1;
+ }
+ } else {
+ use_pcm_bus = 0;
+// timeslot = src->span->offset * 2 + (src->chanpos);
+ timeslot = src->channo;
+ if (debug)
+ printk("qozap: Assigning channel %d/%d -> %d/%d, timeslot %d, same card!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos, timeslot);
+ }
+
+ if ((src->chanpos == 3) || (dst->chanpos == 3)) {
+ if (debug)
+ printk("qozap: Not Assigning D-channel %d/%d -> %d/%d!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos);
+ } else {
+ qoz_assign(qoztmp, src->span->offset, src->chanpos, dst->span->offset, dst->chanpos, timeslot, use_pcm_bus);
+ }
+ } else {
+ qoztmp = dst->pvt;
+ if (dst->chanpos == 3) {
+ if (debug)
+ printk("qozap: Not Unassigning D-channel %d/%d!\n", dst->span->offset, dst->chanpos);
+ } else {
+ timeslot = dst->channo;
+ qoz_unassign(qoztmp, dst->span->offset, dst->chanpos, timeslot);
+ if (debug)
+ printk("qozap: Unassigning channel %d/%d, timeslot %d!\n", dst->span->offset, dst->chanpos, timeslot);
+ }
+ }
+ return 0;
+}
+
+static void qoz_resync(struct qoz_card *qoztmp) {
+ int i=0;
+ int best=9999;
+ int src=-1;
+
+ if (pcmslave) return;
+
+ for (i=0; i<qoztmp->stports; i++){
+ if (qoztmp->st[i].l1up && (qoztmp->st_sync[i] > 0) && (qoztmp->st_sync[i] < best)) {
+ best = qoztmp->st_sync[i];
+ src = i;
+ }
+ }
+ if (src < 0) {
+ for (i=0; i<qoztmp->stports; i++){
+ if ((qoztmp->st_sync[i] > 0) && (qoztmp->st_sync[i] < best)) {
+ best = qoztmp->st_sync[i];
+ src = i;
+ }
+ }
+ }
+ if (src == qoztmp->syncsrc)
+ return;
+ if (src >= 0) {
+ qoztmp->syncsrc = src;
+ qoz_outb(qoztmp, qoz_R_ST_SYNC, src | 0x08);
+ if (debug > 2)
+ printk(KERN_INFO "qozap: card %d Sync source changed to span %d\n", qoztmp->cardno, src + 1);
+ }
+}
+
+static inline void qoz_run(struct qoz_card *qoztmp) {
+ int s=0;
+ unsigned long flags;
+
+ for (s=0;s<qoztmp->stports;s++) {
+ if (!bloop) {
+ if (qoztmp->spans[s].flags & ZT_FLAG_RUNNING) {
+ /* oh zaptel! tell us what to transmit... */
+ zt_transmit(&qoztmp->spans[s]);
+ /* B1 xmit */
+ qoz_fifo_tx(qoztmp, s * 2);
+ /* B2 xmit */
+ qoz_fifo_tx(qoztmp, (s * 2) + 1);
+
+ if ((qoztmp->st[s].layer1state != 7) && (qoztmp->chans[s][2].bytes2transmit > 0) && (qoztmp->st[s].nt_mode != 1)) {
+ if (qoztmp->st[s].t3 == -1) {
+ if (debug > 2)
+ printk(KERN_INFO "qozap: activating layer 1, span %d\n",s);
+ qoztmp->st[s].t3 = 0;
+ spin_lock_irqsave(&qoztmp->lock,flags);
+ qoz_outb(qoztmp,qoz_R_ST_SEL, s);
+ qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x60);
+ spin_unlock_irqrestore(&qoztmp->lock, flags);
+ } else {
+ }
+ }
+
+ /* D xmit */
+ if (qoztmp->spans[s].alarms != ZT_ALARM_RED) {
+ qoz_dfifo_tx(qoztmp, s);
+ } else {
+ if ((qoztmp->st[s].t3 == -1) && (qoztmp->st[s].t4 == -1) && (qoztmp->st[s].layer1state == 3) && (qoztmp->st[s].nt_mode != 1)) {
+ /* clear alarms */
+ if (debug > 2)
+ printk(KERN_INFO "qozap: clearing alarms on span %d\n",s);
+ qoztmp->spans[s].alarms = ZT_ALARM_NONE;
+ zt_alarm_notify_no_master_change(&qoztmp->spans[s]);
+ }
+ }
+
+ qoztmp->chans[s][2].bytes2receive = 0;
+ qoztmp->chans[s][2].bytes2transmit = 0;
+ qoztmp->chans[s][2].eofrx = 0;
+ qoztmp->chans[s][2].eoftx = 0;
+
+ }
+
+ /* B1 receive */
+ qoz_fifo_rx(qoztmp,(s*2));
+ /* B2 receive */
+ qoz_fifo_rx(qoztmp,(s*2)+1);
+ /* d-chan data */
+ if (qoztmp->st[s].drx > 0) {
+ if (debug > 2)
+ printk(KERN_CRIT "qozap: card %d st[%d].drx = %d\n", qoztmp->cardno, s, qoztmp->st[s].drx);
+ qoz_dfifo_rx(qoztmp, s);
+ }
+ if (qoztmp->spans[s].flags & ZT_FLAG_RUNNING) {
+ /* oh zaptel! thou shall receive! */
+ zt_receive(&(qoztmp->spans[s]));
+ }
+ } else {
+ // loop
+ /* B1 receive */
+ qoz_fifo_rx(qoztmp,(s*2));
+ /* B2 receive */
+ qoz_fifo_rx(qoztmp,(s*2)+1);
+ /* d-chan data */
+/* if (qoztmp->st[s].drx > 0) {
+ if (debug > 2)
+ printk(KERN_CRIT "qozap: card %d st[%d].drx = %d\n", qoztmp->cardno, s, qoztmp->st[s].drx);
+ qoz_dfifo_rx(qoztmp, s);
+ }
+ if (qoztmp->spans[s].flags & ZT_FLAG_RUNNING) {
+ zt_receive(&(qoztmp->spans[s]));
+ }
+*/
+ if (qoztmp->spans[s].flags & ZT_FLAG_RUNNING) {
+ /* oh zaptel! tell us what to transmit... */
+ // zt_transmit(&qoztmp->spans[s]);
+ /* B1 xmit */
+ qoz_fifo_tx(qoztmp, s * 2);
+ /* B2 xmit */
+ qoz_fifo_tx(qoztmp, (s * 2) + 1);
+ /* D xmit */
+// qoz_dfifo_tx(qoztmp, s);
+
+ qoztmp->chans[s][2].bytes2receive = 0;
+ qoztmp->chans[s][2].bytes2transmit = 0;
+ qoztmp->chans[s][2].eofrx = 0;
+ qoztmp->chans[s][2].eoftx = 0;
+
+ }
+ }
+ }
+}
+
+ZAP_IRQ_HANDLER(qoz_interrupt) {
+ struct qoz_card *qoztmp = dev_id;
+ unsigned long flags;
+ unsigned char irq_misc,irq_sci,status,l1state,irq_foview,fi;
+ int st=0,i=0,offset=0;
+ int j=0;
+
+ if (!qoztmp) {
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+ }
+
+ if ((!qoztmp->pci_io) || (!qoztmp->ioport)) {
+ printk(KERN_CRIT "qozap: no pci mem/io\n");
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+ }
+ if (qoztmp->dead) {
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#else
+ return;
+#endif
+ }
+
+
+ spin_lock_irqsave(&(qoztmp->lock), flags);
+ status = qoz_inb(qoztmp,qoz_R_STATUS);
+ irq_sci = qoz_inb(qoztmp,qoz_R_SCI);
+ spin_unlock_irqrestore(&(qoztmp->lock), flags);
+
+ if (!(status & 0x80) && !(status & 0x40) && (irq_sci == 0)) {
+// printk(KERN_CRIT "qozap: status %#x\n", status);
+ // it's not us!
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+ }
+ /* state machine irq */
+ if (irq_sci != 0) {
+ if (debug > 1) {
+ printk(KERN_INFO "qozap: card %d R_BERT_STA = %#x\n", qoztmp->cardno, qoz_inb(qoztmp, qoz_R_BERT_STA) & 7);
+ }
+ if (qoztmp->type == 0xb552) {
+ offset = 24;
+ } else if (qoztmp->type == 0xb55b) {
+ offset = 24;
+ } else {
+ offset = 28;
+ }
+ spin_lock_irqsave(&(qoztmp->lock), flags);
+ for (st=0;st<qoztmp->stports;st++) {
+ if (irq_sci & (1 << st)) {
+ qoz_outb(qoztmp,qoz_R_ST_SEL,st);
+ l1state = qoz_inb(qoztmp,qoz_A_ST_RD_STA) & 0xf;
+ if (debug > 1) {
+ printk(KERN_INFO "qozap: card %d span %d A_ST_RD_STA = %#x\n", qoztmp->cardno, st+1, qoz_inb(qoztmp, qoz_A_ST_RD_STA));
+ }
+ qoztmp->st[st].layer1state = l1state;
+ if (qoztmp->st[st].nt_mode == 1) {
+ if (debug)
+ printk(KERN_INFO "card %d span %d state G%d (A_ST_RD_STA = %#x)\n",qoztmp->cardno,st+1,l1state,qoz_inb(qoztmp,qoz_A_ST_RD_STA));
+ // NT state machine
+ if (l1state == 3) {
+ qoztmp->st[st].l1up = 1;
+ // keep layer1 up!
+ if (qoztmp->stports == 8) {
+ sprintf(qoztmp->spans[st].desc,"octoBRI PCI ISDN Card %d Span %d [NT] Layer 1 ACTIVATED (G%d)",qoztmp->cardno ,st + 1, l1state);
+ } else if (qoztmp->stports == 2) {
+ sprintf(qoztmp->spans[st].desc,"duoBRI PCI ISDN Card %d Span %d [NT] (cardID %d) Layer 1 ACTIVATED (G%d)",qoztmp->cardno ,st + 1,qoztmp->cardID, l1state);
+ } else{
+ sprintf(qoztmp->spans[st].desc,"quadBRI PCI ISDN Card %d Span %d [NT] (cardID %d) Layer 1 ACTIVATED (G%d)",qoztmp->cardno ,st + 1,qoztmp->cardID, l1state);
+ }
+ qoz_outb(qoztmp,qoz_A_ST_WR_STA,3 | 0x10 );
+ qoztmp->leds[st] = 1;
+ } else {
+ qoztmp->st[st].l1up = 0;
+ if (qoztmp->stports == 8) {
+ sprintf(qoztmp->spans[st].desc,"octoBRI PCI ISDN Card %d Span %d [NT] Layer 1 DEACTIVATED (G%d)",qoztmp->cardno ,st + 1, l1state);
+ } else if (qoztmp->stports == 2) {
+ sprintf(qoztmp->spans[st].desc,"duoBRI PCI ISDN Card %d Span %d [NT] (cardID %d) Layer 1 DEACTIVATED (G%d)",qoztmp->cardno ,st + 1,qoztmp->cardID, l1state);
+ } else {
+ sprintf(qoztmp->spans[st].desc,"quadBRI PCI ISDN Card %d Span %d [NT] (cardID %d) Layer 1 DEACTIVATED (G%d)",qoztmp->cardno ,st + 1,qoztmp->cardID, l1state);
+ }
+ qoztmp->leds[st] = 0;
+ }
+ } else {
+ if (debug)
+ printk(KERN_INFO "card %d span %d state F%d (A_ST_RD_STA = %#x)\n",qoztmp->cardno,st+1,l1state,qoz_inb(qoztmp,qoz_A_ST_RD_STA));
+ // TE state machine
+ if (l1state == 3) {
+ qoztmp->st[st].l1up = 0;
+ if (qoztmp->st[st].t3 > -1) {
+ /* keep layer1 up, if the span is started. */
+ if (qoztmp->spans[st].flags & ZT_FLAG_RUNNING) {
+ if (debug > 2)
+ printk("qozap: re-activating layer1 span %d\n", st);
+ qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x60);
+ }
+ } else {
+ if (debug > 2)
+ printk("qozap: not re-activating layer1 span %d\n", st);
+ qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x40);
+ /* if we tried to activate layer 1 and it failed make this an alarm */
+// qoztmp->spans[st].alarms = ZT_ALARM_RED;
+// zt_alarm_notify(&qoztmp->spans[st]);
+ /* if the network shuts us down in idle mode dont make this an alarm */
+ }
+ qoztmp->leds[st] = 0;
+ if (qoztmp->stports == 8) {
+ sprintf(qoztmp->spans[st].desc,"octoBRI PCI ISDN Card %d Span %d [TE] Layer 1 DEACTIVATED (F%d)",qoztmp->cardno ,st + 1, l1state);
+ } else if (qoztmp->stports == 2) {
+ sprintf(qoztmp->spans[st].desc,"duoBRI PCI ISDN Card %d Span %d [TE] (cardID %d) Layer 1 DEACTIVATED (F%d)",qoztmp->cardno ,st + 1,qoztmp->cardID, l1state);
+ } else {
+ sprintf(qoztmp->spans[st].desc,"quadBRI PCI ISDN Card %d Span %d [TE] (cardID %d) Layer 1 DEACTIVATED (F%d)",qoztmp->cardno ,st + 1,qoztmp->cardID, l1state);
+ }
+ } else if (l1state == 7) {
+ qoztmp->st[st].l1up = 1;
+ /* reset D RX fifo */
+ qoz_outb(qoztmp,qoz_R_FIFO,((st + offset) << 1) | 1);
+ qoz_waitbusy(qoztmp);
+ qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2);
+ qoz_waitbusy(qoztmp);
+ /* activation complete, stop timer t3 */
+ qoztmp->st[st].t3 = -1;
+ qoztmp->spans[st].alarms = ZT_ALARM_NONE;
+ zt_alarm_notify(&qoztmp->spans[st]);
+ qoztmp->leds[st] = 1;
+ if (qoztmp->stports == 8) {
+ sprintf(qoztmp->spans[st].desc,"octoBRI PCI ISDN Card %d Span %d [TE] Layer 1 ACTIVATED (F%d)",qoztmp->cardno ,st + 1, l1state);
+ } else if (qoztmp->stports == 2) {
+ sprintf(qoztmp->spans[st].desc,"duoBRI PCI ISDN Card %d Span %d [TE] (cardID %d) Layer 1 ACTIVATED (F%d)",qoztmp->cardno ,st + 1,qoztmp->cardID, l1state);
+ } else {
+ sprintf(qoztmp->spans[st].desc,"quadBRI PCI ISDN Card %d Span %d [TE] (cardID %d) Layer 1 ACTIVATED (F%d)",qoztmp->cardno ,st + 1,qoztmp->cardID, l1state);
+ }
+ } else if (l1state == 8) {
+ /* lost framing */
+ if (debug > 2)
+ printk(KERN_INFO "qozap: starting t4 for span %d\n", st);
+ qoztmp->st[st].t4 = 0;
+ } else {
+ qoztmp->st[st].l1up = 0;
+ qoztmp->leds[st] = 0;
+ if (qoztmp->stports == 8) {
+ sprintf(qoztmp->spans[st].desc,"octoBRI PCI ISDN Card %d Span %d [TE] Layer 1 DEACTIVATED (F%d)",qoztmp->cardno ,st + 1, l1state);
+ } else if (qoztmp->stports == 2) {
+ sprintf(qoztmp->spans[st].desc,"duoBRI PCI ISDN Card %d Span %d [TE] (cardID %d) Layer 1 DEACTIVATED (F%d)",qoztmp->cardno ,st + 1,qoztmp->cardID, l1state);
+ } else {
+ sprintf(qoztmp->spans[st].desc,"quadBRI PCI ISDN Card %d Span %d [TE] (cardID %d) Layer 1 DEACTIVATED (F%d)",qoztmp->cardno ,st + 1,qoztmp->cardID, l1state);
+ }
+ }
+ }
+
+ }
+ }
+ qoz_resync(qoztmp);
+ spin_unlock_irqrestore(&(qoztmp->lock), flags);
+ }
+
+
+ // misc irq
+ if (status & 0x40) {
+ spin_lock_irqsave(&(qoztmp->lock), flags);
+ irq_misc = qoz_inb(qoztmp,qoz_R_IRQ_MISC);
+ spin_unlock_irqrestore(&(qoztmp->lock), flags);
+ if (irq_misc & 0x2) {
+ // qozap timer
+ qoztmp->ticks++;
+ qoz_run(qoztmp);
+ if (qoztmp->ticks % 100) {
+ qoz_doLEDs(qoztmp);
+ }
+ if (qoztmp->ticks % 40) {
+ /* you thought that 42 was the answer.... */
+ qoz_doWD(qoztmp);
+ }
+ if (qoztmp->ticks > 1000) {
+ qoztmp->ticks = 0;
+ for (j=0;j<qoztmp->stports;j++) {
+ /* t3 */
+ if (qoztmp->st[j].t3 >= 0) {
+ qoztmp->st[j].t3++;
+ }
+ if (qoztmp->st[j].nt_mode != 1) {
+ if ((qoztmp->st[j].t3 > qoz_T3) && (qoztmp->st[j].layer1state != 7)) {
+ /* deactivate layer 1 */
+ if (debug > 2)
+ printk(KERN_INFO "qozap: t3 timer expired for span %d\n", j);
+ spin_lock_irqsave(&(qoztmp->lock), flags);
+ qoz_outb(qoztmp,qoz_R_ST_SEL, j);
+ qoz_outb(qoztmp,qoz_A_ST_WR_STA, 0x40 );
+ qoz_waitbusy(qoztmp);
+ qoztmp->st[j].t3 = -1;
+ qoztmp->spans[j].alarms = ZT_ALARM_RED;
+ spin_unlock_irqrestore(&(qoztmp->lock), flags);
+ zt_alarm_notify_no_master_change(&qoztmp->spans[j]);
+ }
+ }
+ /* t4 */
+ if (qoztmp->st[j].t4 >= 0) {
+ qoztmp->st[j].t4++;
+ }
+ if (qoztmp->st[j].nt_mode != 1) {
+ if ((qoztmp->st[j].t4 > qoz_T4) && (qoztmp->st[j].layer1state != 7)) {
+ /* deactivate layer 1 */
+ if (debug > 2)
+ printk(KERN_INFO "qozap: t4 timer expired for span %d\n", j);
+ spin_lock_irqsave(&(qoztmp->lock), flags);
+ qoz_outb(qoztmp,qoz_R_ST_SEL, j);
+ qoz_outb(qoztmp,qoz_A_ST_WR_STA, 0x40 );
+ qoztmp->st[j].t4 = -1;
+ qoztmp->st[st].l1up = 0;
+ qoztmp->spans[j].alarms = ZT_ALARM_RED;
+ qoz_waitbusy(qoztmp);
+ spin_unlock_irqrestore(&(qoztmp->lock), flags);
+ zt_alarm_notify_no_master_change(&qoztmp->spans[j]);
+ }
+ }
+ }
+ }
+ }
+ if (irq_misc & 0x4) {
+ // printk(KERN_INFO "qozap proc/nonproc irq\n");
+ }
+ }
+
+ if (status & 0x80) {
+ /* fifo irq */
+ spin_lock_irqsave(&(qoztmp->lock), flags);
+ irq_foview = qoz_inb(qoztmp,qoz_R_IRQ_OVIEW);
+ if ((qoztmp->type == 0xb552) || (qoztmp->type == 0xb55b)) {
+ if (irq_foview & 0x60) {
+ offset = 0;
+ fi = qoz_inb(qoztmp,qoz_R_IRQ_FIFO_BL6);
+ for (i=0; i < 8; i++) {
+ if (fi & (1 << i)) {
+ st = offset + (i / 2);
+ if (i % 2) {
+ if (debug > 2)
+ printk(KERN_CRIT "qozap: HDLC RX irq fifo %d span %d\n", i, st+1);
+ qoztmp->st[st].drx += 1;
+ } else {
+ if (debug > 2)
+ printk(KERN_CRIT "qozap: HDLC TX irq fifo %d span %d\n", i, st+1);
+ }
+ }
+ }
+ }
+ if (irq_foview & 0x80) {
+ offset = 4;
+ fi = qoz_inb(qoztmp,qoz_R_IRQ_FIFO_BL7);
+ for (i=0; i < 8; i++) {
+ if (fi & (1 << i)) {
+ st = offset + (i / 2);
+ if (i % 2) {
+ if (debug > 2)
+ printk(KERN_CRIT "qozap: HDLC RX irq fifo %d span %d\n", i, st+1);
+ qoztmp->st[st].drx += 1;
+ } else {
+ if (debug > 2)
+ printk(KERN_CRIT "qozap: HDLC TX irq fifo %d span %d\n", i, st+1);
+ }
+ }
+ }
+ }
+ } else {
+ if (irq_foview & 0x80) {
+ fi = qoz_inb(qoztmp,qoz_R_IRQ_FIFO_BL7);
+ for (i=0; i < 8; i++) {
+ if (fi & (1 << i)) {
+ st = i / 2;
+ if (i % 2) {
+ if (debug > 2)
+ printk(KERN_CRIT "qozap: HDLC RX irq fifo %d span %d\n", i, st+1);
+ qoztmp->st[st].drx += 1;
+ } else {
+ if (debug > 2)
+ printk(KERN_CRIT "qozap: HDLC TX irq fifo %d span %d\n", i, st+1);
+ }
+ }
+ }
+ }
+ }
+ spin_unlock_irqrestore(&(qoztmp->lock), flags);
+ }
+
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+}
+
+static int ztqoz_open(struct zt_chan *chan) {
+// printk(KERN_INFO "qozap: channel %d opened.\n",chan->channo);
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#else
+ try_module_get(THIS_MODULE);
+#endif
+ return 0;
+}
+
+static int ztqoz_close(struct zt_chan *chan) {
+// printk(KERN_INFO "qozap: channel %d closed.\n",chan->channo);
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#else
+ module_put(THIS_MODULE);
+#endif
+ return 0;
+}
+
+static int ztqoz_rbsbits(struct zt_chan *chan, int bits) {
+ return 0;
+}
+
+static int ztqoz_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) {
+ switch(cmd) {
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int ztqoz_startup(struct zt_span *span) {
+ struct qoz_card *qoztmp = span->pvt;
+ unsigned long flags;
+ int alreadyrunning;
+ int i=0;
+ int offset = 0;
+
+ if (qoztmp == NULL) {
+ printk(KERN_INFO "qozap: no card for span at startup!\n");
+ }
+
+ alreadyrunning = span->flags & ZT_FLAG_RUNNING;
+// printk(KERN_CRIT "already running %d flags %d\n", alreadyrunning, span->flags);
+
+ if (!alreadyrunning) {
+ span->chans[2].flags &= ~ZT_FLAG_HDLC;
+ span->chans[2].flags |= ZT_FLAG_BRIDCHAN;
+
+ /* setup B channel buffers (8 bytes each) */
+ for (i=0; i<2 ; i++) {
+ memset(qoztmp->rxbuf[span->offset][i],0x0,sizeof(qoztmp->rxbuf[span->offset][i]));
+ span->chans[i].readchunk = qoztmp->rxbuf[span->offset][i];
+ memset(qoztmp->txbuf[span->offset][i],0x0,sizeof(qoztmp->txbuf[span->offset][i]));
+ span->chans[i].writechunk = qoztmp->txbuf[span->offset][i];
+ }
+ /* setup D channel buffer */
+ memset(qoztmp->dtxbuf[span->offset],0x0,sizeof(qoztmp->dtxbuf[span->offset]));
+ span->chans[2].writechunk = qoztmp->dtxbuf[span->offset];
+ qoztmp->chans[span->offset][2].maxbytes2transmit = sizeof(qoztmp->dtxbuf[span->offset]);
+
+ memset(qoztmp->drxbuf[span->offset],0x0,sizeof(qoztmp->drxbuf[span->offset]));
+ span->chans[2].readchunk = qoztmp->drxbuf[span->offset];
+
+ span->flags |= ZT_FLAG_RUNNING;
+ } else {
+// printk(KERN_CRIT "already running\n");
+ return 0;
+ }
+
+ if (pcmslave && !span->offset) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((100 * HZ) / 1000);
+ }
+
+ spin_lock_irqsave(&qoztmp->lock,flags);
+ if (pcmslave && !span->offset) {
+ if (debug)
+ printk(KERN_INFO "qozap: resetting PCM interface to slave mode\n");
+ qoz_reset_pcm(qoztmp);
+ }
+
+ // irqs off
+ qoz_outb(qoztmp,qoz_R_IRQ_CTRL, 0);
+
+ if (qoztmp->type == 0xb552) {
+ offset = 24;
+ } else if (qoztmp->type == 0xb55b) {
+ offset = 24;
+ } else {
+ offset = 28;
+ }
+
+ /* setup D-FIFO TX */
+ qoz_outb(qoztmp,qoz_R_FIFO,(span->offset + offset) << 1);
+ qoz_waitbusy(qoztmp);
+ qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2);
+ qoz_waitbusy(qoztmp);
+ qoz_outb(qoztmp,qoz_A_CON_HDLC,0xD);
[... 970 lines stripped ...]
More information about the zaptel-commits
mailing list