[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(&registerlock);
+
+    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(&registerlock);
+}
+
+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