[Pkg-voip-commits] r1247 - zaptel/trunk/debian/patches

Tzafrir Cohen tzafrir-guest at costa.debian.org
Tue Feb 7 16:35:54 UTC 2006


Author: tzafrir-guest
Date: 2006-02-07 16:35:46 +0000 (Tue, 07 Feb 2006)
New Revision: 1247

Added:
   zaptel/trunk/debian/patches/bristuff.dpatch
Modified:
   zaptel/trunk/debian/patches/00list
Log:
the missing bristuff from last commit

Modified: zaptel/trunk/debian/patches/00list
===================================================================
--- zaptel/trunk/debian/patches/00list	2006-02-07 15:16:11 UTC (rev 1246)
+++ zaptel/trunk/debian/patches/00list	2006-02-07 16:35:46 UTC (rev 1247)
@@ -10,4 +10,4 @@
 ukcid
 xpp
 dot_version
-bristuff-0.3.0-PRE1h
+bristuff

Added: zaptel/trunk/debian/patches/bristuff.dpatch
===================================================================
--- zaptel/trunk/debian/patches/bristuff.dpatch	2006-02-07 15:16:11 UTC (rev 1246)
+++ zaptel/trunk/debian/patches/bristuff.dpatch	2006-02-07 16:35:46 UTC (rev 1247)
@@ -0,0 +1,6690 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## bristuff.dpatch by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: The zapbri modules (cwain, qozap, zaphfc) and zaptel patch from the 
+## DP: bristuff patch by Klaus-Peter Junghanns. Version 0.3.0-PRE1k
+
+ at DPATCH@
+diff -urNad zaptel-1.2.3/cwain/cwain.c /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/cwain.c
+--- zaptel-1.2.3/cwain/cwain.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/cwain.c	2006-01-27 05:39:03.000000000 +0200
+@@ -0,0 +1,1492 @@
++/*
++ * cwain.c - Zaptel driver for the Junghanns.NET E1 card
++ *
++ * c.w.a.i.n. == card without an interesting name
++ *
++ * single/double E1 board
++ *
++ * Copyright (C) 2004, 2005 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 "cwain.h"
++
++#if CONFIG_PCI
++
++static int ports=-1; /* autodetect */
++static int debug=0;
++static struct zt_cwain *cwain_span_list = NULL;
++static int cwain_span_count = 0;
++static struct zt_cwain_card *cwain_card_list = NULL;
++static int cwain_card_count = 0;
++static struct pci_dev *multi_cwain = NULL;
++static spinlock_t cwain_span_registerlock = SPIN_LOCK_UNLOCKED;
++static spinlock_t cwain_card_registerlock = SPIN_LOCK_UNLOCKED;
++
++static int ztcwain_shutdown(struct zt_span *span);
++
++int cwain_waitbusy(struct zt_cwain *cwaintmp) {
++    int x=1000;
++    while (x-- && (cwain_inb(cwaintmp,cwain_R_STATUS) & 1));
++    if (x < 0) {
++	printk(KERN_CRIT "cwain: really busy waiting!\n");
++	return -1;
++    } else {
++	if ((x < 990) && (cwaintmp->ticks > 500)) {
++	    printk(KERN_CRIT "cwain: waited %d\n", 1000 - x);
++	}
++	return 0;
++    }
++}
++
++void cwain_unregister_zap_span(struct zt_cwain *cwainspan) {
++    if (!cwainspan) {
++	printk(KERN_INFO "cwain: shutting down NULL span!\n");
++	return;
++    }
++    if(cwainspan->span.flags & ZT_FLAG_RUNNING) {
++        ztcwain_shutdown(&cwainspan->span);
++        if (debug)
++            printk(KERN_INFO "cwain: shutdown span %d.\n",cwainspan->cardno);
++    }
++    if(cwainspan->span.flags & ZT_FLAG_REGISTERED) {
++        zt_unregister(&cwainspan->span);
++        if (debug)
++    	printk(KERN_INFO "cwain: unregistered span %d.\n",cwainspan->cardno);
++    }
++}
++
++void cwain_shutdown_span(struct zt_cwain *cwainspan) {
++    
++    if (!cwainspan) {
++	printk(KERN_INFO "cwain: shutting down NULL span!\n");
++	return;
++    }
++
++    if (cwainspan->pci_io == NULL) {
++	return;
++    }
++
++    if (debug)
++	printk(KERN_INFO "cwain: shutting down span %d (cardID %d) at %p.\n",cwainspan->cardno,cwainspan->cardID,cwainspan->pci_io);
++
++    // turn off irqs
++
++    // softreset
++    cwain_outb(cwainspan,cwain_R_CIRM,0x8);
++    cwain_outb(cwainspan,cwain_R_CIRM,0x0); 
++    cwain_waitbusy(cwainspan);
++
++    cwain_outb(cwainspan,cwain_R_IRQMSK_MISC, 0); 
++    cwain_outb(cwainspan,cwain_R_IRQ_CTRL, 0); 
++
++    pci_write_config_word(cwainspan->pcidev, PCI_COMMAND, 0);	// disable memio
++
++    if (cwainspan->pcidev != NULL) {
++        pci_disable_device(cwainspan->pcidev);
++	cwainspan->pcidev = NULL;
++    }
++
++//    iounmap((void *) cwainspan->pci_io);
++//    cwainspan->pci_io = NULL;
++}
++
++void cwain_shutdown_card(struct zt_cwain_card *cwaintmp) {
++    unsigned long flags = 0;
++    int i = 0;
++    
++    if (!cwaintmp) {
++	printk(KERN_INFO "cwain: shutting down NULL card!\n");
++	return;
++    }
++
++    for (i=0;i<cwaintmp->spans;i++) {
++	cwain_unregister_zap_span(cwaintmp->span[i]);
++    }
++
++    spin_lock_irqsave(&cwaintmp->lock,flags);
++
++    // turn off irqs
++    cwain_outb(cwaintmp->span[0],cwain_R_IRQ_CTRL, 0); 
++    cwain_outb(cwaintmp->span[0],cwain_R_IRQMSK_MISC, 0); 
++
++    for (i=0;i<cwaintmp->spans;i++) {
++	cwain_shutdown_span(cwaintmp->span[i]);
++    }
++    spin_unlock_irqrestore(&cwaintmp->lock,flags);
++
++    for (i=0;i<cwaintmp->spans;i++) {
++	iounmap((void *) cwaintmp->span[i]->pci_io);
++	cwaintmp->span[i]->pci_io = NULL;
++    }
++
++    free_irq(cwaintmp->irq,cwaintmp);
++}
++
++void cwain_doLEDs(struct zt_cwain *cwaintmp) {
++    /*
++     O1 O3 (red)
++     O2 O4 (green)
++    */
++    if (!(cwaintmp->span.flags & ZT_FLAG_RUNNING)) {
++	return;
++    }
++    if ((cwaintmp->type == 0xb553) || (cwaintmp->type == 0xb554)) {
++	/* sync status */
++	if (((cwaintmp->sync_sta & 0x07) == 0x07) && cwaintmp->sync) {
++	    cwaintmp->leds[0] = 1;    
++	    cwaintmp->leds[1] = 0;    
++	} else {
++	    cwaintmp->leds[0] = 0;    
++	    cwaintmp->leds[1] = 1;    
++	}
++	/* multiframe alignment */
++	if ((cwaintmp->sync_sta & 0x20) == 0x20) {
++    	    cwaintmp->leds[2] = 1;    
++	    cwaintmp->leds[3] = 0;    
++	} else {
++	    if ((cwaintmp->span.lineconfig & ZT_CONFIG_CRC4) && cwaintmp->sync) {
++		/* CRC4 requested */
++		cwaintmp->leds[2] = 0;    
++		cwaintmp->leds[3] = 1;    
++	    } else {
++		/* no CRC4, disable 3 and 4 */
++		cwaintmp->leds[2] = 1;    
++		cwaintmp->leds[3] = 1;    
++	    }
++	}
++	cwain_outb(cwaintmp,cwain_R_GPIO_OUT1,(cwaintmp->leds[0] | (cwaintmp->leds[1] << 1) | (cwaintmp->leds[2] << 2) | (cwaintmp->leds[3] << 3)));
++    }
++}
++
++void cwain_reset_span(struct zt_cwain *cwaintmp) {
++    int i = 0;
++    pci_write_config_word(cwaintmp->pcidev, PCI_COMMAND, PCI_COMMAND_MEMORY);	// enable memio
++
++    /* FIFO, HDLC reset */
++    cwain_outb(cwaintmp,cwain_R_CIRM,0x10);
++    cwain_outb(cwaintmp,cwain_R_CIRM,0x0); 
++    cwain_waitbusy(cwaintmp);
++
++    /* PCM reset */
++    cwain_outb(cwaintmp,cwain_R_CIRM,0x20);
++    cwain_outb(cwaintmp,cwain_R_CIRM,0x0); 
++    cwain_waitbusy(cwaintmp);
++
++    for (i=0; i<128; i++) {
++	cwain_outb(cwaintmp,cwain_R_SLOT, i);
++	cwain_outb(cwaintmp,cwain_A_SL_CFG, 0x0);
++    }
++    
++    /* E1 reset */
++    cwain_outb(cwaintmp,cwain_R_CIRM,0x40);
++    cwain_outb(cwaintmp,cwain_R_CIRM,0x0); 
++    cwain_waitbusy(cwaintmp);
++
++    /* 128 byte B chans, 4096 byte D chans */
++    cwain_outb(cwaintmp,cwain_R_FIFO_MD,0x36);
++    cwain_outb(cwaintmp,cwain_R_BRG_PCM_CFG,0x0); 
++    cwain_outb(cwaintmp,cwain_R_CTRL,0x0); 
++
++    /* no blinky blink */
++    cwain_outb(cwaintmp,cwain_R_GPIO_SEL,0x20 | 0x10);
++    cwain_outb(cwaintmp,cwain_R_GPIO_EN1,0x0f);
++    cwain_outb(cwaintmp,cwain_R_GPIO_OUT1,0x0f);
++
++    /* IRQs off */
++    cwain_outb(cwaintmp,cwain_R_IRQ_CTRL,0x0); 
++
++    cwaintmp->leds[0] = 1;    
++    cwaintmp->leds[1] = 1;    
++    cwaintmp->leds[2] = 1;    
++    cwaintmp->leds[3] = 1;    
++    
++    cwaintmp->ticks = 0;
++    cwaintmp->clicks = 0;
++}
++
++struct zt_cwain_card *cwain_get_card(unsigned int pcibus) {
++    struct zt_cwain_card *cwaintmp = cwain_card_list;
++    spin_lock(&cwain_card_registerlock);
++    while (cwaintmp) {
++	if (cwaintmp->pcibus == pcibus) {
++	    break;
++	}
++	cwaintmp = cwaintmp->next;
++    }
++    spin_unlock(&cwain_card_registerlock);
++    return cwaintmp;
++}
++
++
++void cwain_register_card(struct zt_cwain_card *cwaincard) {
++    spin_lock(&cwain_card_registerlock);
++    if (cwaincard != NULL) {
++	cwaincard->prev = NULL;
++	cwaincard->next = cwain_card_list;
++	if (cwain_card_list) {
++	    cwain_card_list->prev = cwaincard;
++	}
++	cwain_card_list = cwaincard;
++	cwain_card_count++;
++    } else {
++	printk(KERN_INFO "cwain: trying to register NULL card.\n");
++    }
++    spin_unlock(&cwain_card_registerlock);
++}
++
++int cwain_register_span(struct zt_cwain *cwainspan) {
++    struct zt_cwain_card *cwaintmp;
++    spin_lock(&cwain_span_registerlock);
++    if (cwainspan != NULL) {
++	cwainspan->prev = NULL;
++	cwainspan->next = cwain_span_list;
++	if (cwain_span_list) {
++	    cwain_span_list->prev = cwainspan;
++	}
++	cwain_span_list = cwainspan;
++	cwainspan->cardno = ++cwain_span_count;
++    } else {
++	printk(KERN_INFO "cwain: trying to register NULL span.\n");
++    }
++    spin_unlock(&cwain_span_registerlock);
++
++    if (cwainspan->type == 0xb553) {
++	cwaintmp = kmalloc(sizeof(struct zt_cwain_card),GFP_KERNEL);
++	if (!cwaintmp) {
++	    printk(KERN_WARNING "cwain: unable to kmalloc!\n");
++	    return -1;
++	}
++	memset(cwaintmp, 0x0, sizeof(struct zt_cwain_card));
++	
++	spin_lock_init(&cwaintmp->lock);
++	cwaintmp->pcibus = cwainspan->pcibus;
++	cwaintmp->span[0] = cwainspan;
++	cwaintmp->syncs[0] = -1;
++	cwaintmp->spans = 1;
++	cwaintmp->cardID = cwainspan->cardID;
++	cwain_register_card(cwaintmp);
++	printk(KERN_INFO
++	        "cwain: Junghanns.NET singleE1 PCI ISDN card configured at mem %#x IRQ %d HZ %d CardID %d\n",
++	          (u_int) cwainspan->pci_io,
++	        cwaintmp->span[0]->irq, HZ, cwainspan->cardID);
++    } else {
++	cwaintmp = cwain_get_card(cwainspan->pcibus);
++	if (!cwaintmp) {
++	    cwaintmp = kmalloc(sizeof(struct zt_cwain_card),GFP_KERNEL);
++	    if (!cwaintmp) {
++		printk(KERN_WARNING "cwain: unable to kmalloc!\n");
++	        return -1;
++	    }
++	    memset(cwaintmp, 0x0, sizeof(struct zt_cwain_card));
++	
++	    spin_lock_init(&cwaintmp->lock);
++	    cwaintmp->pcibus = cwainspan->pcibus;
++	    cwaintmp->spans = cwainspan->type - 46419;
++	    cwaintmp->span[0] = cwainspan;
++	    cwaintmp->cardID = cwainspan->cardID;
++	    cwaintmp->syncs[0] = -1;
++	    cwain_register_card(cwaintmp);
++	} else {
++	    cwaintmp->spans = cwainspan->type - 46418;
++	    if (cwainspan->cardID < cwaintmp->cardID) {
++		cwaintmp->cardID = cwainspan->cardID;
++		cwaintmp->span[1] = cwaintmp->span[0];
++		cwaintmp->syncs[1] = cwaintmp->syncs[0];
++	        cwaintmp->span[0] = cwainspan;
++	    } else {
++	        cwaintmp->span[1] = cwainspan;
++		cwaintmp->syncs[1] = -1;
++	    }
++	    printk(KERN_INFO
++	        "cwain: Junghanns.NET doubleE1 PCI ISDN card configured at mem (%#x / %#x) IRQ %d HZ %d CardID (%d / %d) bus %#x\n",
++	          (u_int) cwaintmp->span[0]->pci_io, (u_int) cwaintmp->span[1]->pci_io,
++	        cwaintmp->span[0]->irq, HZ, cwaintmp->span[0]->cardID, cwaintmp->span[1]->cardID, cwaintmp->pcibus);
++	}
++    }
++    return 0;
++}
++
++static int cwain_dfifo_tx(struct zt_cwain *cwaintmp) {
++    int chan = 15;
++    int x=0;
++    char fifo = 0;
++
++    fifo = 0x1F;
++
++    if (cwaintmp->chans[chan].bytes2transmit < 1) {
++	return 0;
++    } else {
++	/* select fifo */
++	cwain_outb(cwaintmp,cwain_R_FIFO,fifo << 1);    
++	cwain_waitbusy(cwaintmp);
++    
++	if (debug)
++	    printk(KERN_INFO "cwain: card %d TX [ ", cwaintmp->cardno);
++	/* copy frame to fifo */
++    	for (x=0;x<cwaintmp->chans[chan].bytes2transmit;x++) {
++	    if (debug)
++	        printk("%#x ",cwaintmp->dtxbuf[x]);
++    	    cwain_outb(cwaintmp,cwain_A_FIFO_DATA0,cwaintmp->dtxbuf[x]);
++	}
++	if (debug)
++	    printk("]\n");
++	if (debug)
++    	    printk(KERN_INFO "ztx %d bytes\n",cwaintmp->chans[chan].bytes2transmit);
++
++	if (cwaintmp->chans[chan].eoftx == 1) {
++	    /* transmit HDLC frame */
++    	    cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x1);    
++    	    cwain_waitbusy(cwaintmp);
++	}
++    }
++    return 0;
++}
++
++static int cwain_fifo_tx(struct zt_cwain *cwaintmp, char fifo) {
++    int chan;
++    if (fifo >= 15) {
++	chan = fifo;
++    } else {
++	chan = fifo;
++    }
++    /* select fifo */
++    cwain_outb(cwaintmp,cwain_R_FIFO,0x80 | (fifo << 1));    
++    cwain_waitbusy(cwaintmp);
++    /* transmit 8 bytes of transparent data */
++    cwain_outdw(cwaintmp,cwain_A_FIFO_DATA0,*((unsigned int *) &cwaintmp->txbuf[chan][0]));
++    cwain_outdw(cwaintmp,cwain_A_FIFO_DATA0,*((unsigned int *) &cwaintmp->txbuf[chan][4]));
++	    
++    return 0;
++}
++
++static int cwain_dfifo_rx(struct zt_cwain *cwaintmp) {
++    int chan = 15;
++    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;
++
++    fifo = 0x1F;
++    
++    /* select fifo */
++    cwain_outb(cwaintmp,cwain_R_FIFO,(fifo << 1) | 1);    
++    cwain_waitbusy(cwaintmp);
++    
++    while ((oz1 != z1) && (oz2 != z2)) {
++        oz1 = z1;
++        oz2 = z2;
++    	z1 = cwain_inw(cwaintmp,cwain_A_Z1) & 0xfff;
++	z2 = cwain_inw(cwaintmp,cwain_A_Z2) & 0xfff;
++    }
++    
++    len = z1-(z2 & 0xfff);
++    if (len < 0) {
++        len += cwain_DFIFO_SIZE;
++    }
++
++    while ((of1 != f1) && (of2 != f2)) {
++        of1 = f1;
++        of2 = f2;
++        f1 = cwain_inb(cwaintmp,cwain_A_F1) & 0xf;
++        f2 = cwain_inb(cwaintmp,cwain_A_F2) & 0xf;
++    }
++
++    if (len > cwain_DFIFO_SIZE) {
++	printk(KERN_INFO "\ncwain: buffer overflow in D channel RX!\n");
++	cwaintmp->chans[chan].bytes2receive = 0;
++	cwaintmp->chans[chan].eofrx = 0;
++    } else {
++	if (debug) printk(KERN_INFO "cwain: card %d RX [ ", cwaintmp->cardno);
++	for (i=0; i<len; i++) {
++    	    data = cwain_inb(cwaintmp,cwain_A_FIFO_DATA0);
++	    cwaintmp->drxbuf[i] = data;
++	    if (debug) printk("%#x ",data);
++	}
++	if (debug) printk("] %d bytes\n", i);
++	cwaintmp->chans[chan].bytes2receive = i;
++	cwaintmp->chans[chan].eofrx = 1;
++    }
++
++    stat = cwain_inb(cwaintmp,cwain_A_FIFO_DATA0);
++    if (stat != 0x0) {
++	// bad CRC, skip it
++	if (cwaintmp->sync) {
++	    printk(KERN_INFO "cwain: BAD CRC for hdlc frame on card %d (cardID %d) stat %#x\n",cwaintmp->cardno, cwaintmp->cardID, stat);
++	}
++	cwaintmp->chans[chan].bytes2receive = 0;
++	cwaintmp->chans[chan].eofrx = 0;
++//	    zt_qevent_nolock(&cwaintmp->spans[stport].chans[chan], ZT_EVENT_BADFCS);
++    }
++    cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x1);    
++    cwain_waitbusy(cwaintmp);
++
++    /* frame received */
++    cwaintmp->drx--;
++    return 0;
++}
++
++
++static int cwain_fifo_rx(struct zt_cwain *cwaintmp, char fifo) {
++    int chan;
++    unsigned char data;
++    int len,i;
++    unsigned short z1=1,z2=1;
++    unsigned short oz1=0,oz2=0;
++    int mumbojumbo=0;
++    int x = 1000;
++
++    if (fifo >= 15) {
++	chan = fifo; /* +1 */
++    } else {
++	chan = fifo;
++    }
++
++    // select rx fifo
++    
++	// no hdlc, transparent data
++	cwain_outb(cwaintmp,cwain_R_FIFO,0x80 | (fifo << 1) | 1);    
++        cwain_waitbusy(cwaintmp);
++    
++	while (x-- && ((oz1 != z1) && (oz2 != z2))) {
++	    oz1 = z1;
++	    oz2 = z2;
++	    z1 = cwain_inw(cwaintmp,cwain_A_Z1) & 0x1ff;
++    	    z2 = cwain_inw(cwaintmp,cwain_A_Z2) & 0x1ff;
++	}
++	if (x < 500) {
++	    printk(KERN_CRIT "cwain: prevented endless loop\n");
++	}
++    
++	len = z1-(z2 & 0x1ff);
++	if (len < 0) {
++	    len += cwain_FIFO_SIZE;
++	}
++//	if (len > 2 * ZT_CHUNKSIZE) {
++	if (len > cwain_FIFO_HW) {
++//	    mumbojumbo = len - (2 * ZT_CHUNKSIZE);
++	    mumbojumbo = len - (cwain_FIFO_HW);
++	    len = ZT_CHUNKSIZE;
++	    for (i=0;i<mumbojumbo;i++) {
++    		data = cwain_inb(cwaintmp,cwain_A_FIFO_DATA0);
++	    }
++	    cwaintmp->clicks++;
++	}
++	if (len < ZT_CHUNKSIZE) {
++	    if (cwaintmp->clicks > 501) {
++		printk(KERN_INFO "cwain: not enough to receive (%d bytes)\n",len);
++	    }
++	    return 0;
++	} else {
++	    *((unsigned int *) &cwaintmp->rxbuf[chan][0]) = cwain_indw(cwaintmp,cwain_A_FIFO_DATA0);
++	    *((unsigned int *) &cwaintmp->rxbuf[chan][4]) = cwain_indw(cwaintmp,cwain_A_FIFO_DATA0);
++	}
++
++	zt_ec_chunk(&cwaintmp->span.chans[chan], cwaintmp->span.chans[chan].readchunk, cwaintmp->span.chans[chan].writechunk);
++
++	if (cwaintmp->clicks > 500) {
++	    printk(KERN_INFO "cwain: span %d dropped audio fifo %d mj %d\n", cwaintmp->cardID, fifo, mumbojumbo);
++	    cwaintmp->clicks = 0;
++	}
++//    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,cwaintmp->st[stport].dbufi,f1,f2,z1,z2,len,stat,hdlc);    
++    return 0;
++}
++
++void cwain_set_master(struct zt_cwain_card *cwaintmp, int span) {
++    int i=0;
++
++    if (cwaintmp->syncsrc == span) return;
++    
++    for (i=0; i < cwaintmp->spans; i++) {
++	if (i != span) {
++	    if (cwaintmp->syncs[i] > 0) {
++		/* enable PCM slave mode, PCM32, synced to E1 receive */
++    		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD0, 0x90);
++		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD1, 0x0);
++		cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0xA0);
++		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD2, 0x00);
++	    } else {
++		/* enable PCM slave mode, PCM32 */
++    		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD0, 0x90);
++		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD1, 0x0);
++		cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0xA0);
++		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD2, 0x00);
++	    }
++	    cwaintmp->master[i] = 0;
++	    cwaintmp->span[i]->span.syncsrc = 0;
++	}
++    }
++
++    if (cwaintmp->syncs[span] > 0) {
++        /* enable PCM master mode, PCM32, synced to E1 receive */
++	if (debug)
++	    printk(KERN_INFO "cwain: cardID %d span %d, PCM master E1 sync\n", cwaintmp->cardID, span);
++	cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0x91);
++        cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD1, 0x0);
++	cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0xA1);
++        cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD2, 0x00);
++	cwaintmp->span[span]->span.syncsrc = 1;
++    } else {
++        /* enable PCM master mode, PCM32, free running */
++	if (debug)
++	    printk(KERN_INFO "cwain: cardID %d span %d, PCM master\n", cwaintmp->cardID, span);
++	cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0x91);
++        cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD1, 0x0);
++	cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0xA1);
++        cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD2, 0x04);
++	cwaintmp->span[span]->span.syncsrc = 0;
++    }
++    
++    cwaintmp->master[span] = 1;
++    cwaintmp->syncsrc = span;
++}
++
++void cwain_check_timing(struct zt_cwain_card *cwaintmp) {
++    int i=0;
++    int bestsync = 42;
++
++    for (i=0; i < cwaintmp->spans; i++) {
++        if ((cwaintmp->syncs[i] > 0) && ((cwaintmp->span[i]->sync_sta & 0x7) == 0x7)) {
++    	    if (bestsync < cwaintmp->spans) {
++		if (cwaintmp->syncs[i] < cwaintmp->syncs[bestsync]) {
++	    	    bestsync = i;
++		}
++	    } else {
++	        bestsync = i;
++	    }
++	}
++    }
++
++    if (cwaintmp->syncsrc >= 0) {
++	if (debug > 3)
++	    printk(KERN_INFO "cwain: bestsync %d cwaintmp->syncsrc %d\n", bestsync, cwaintmp->syncsrc);
++	
++	if (bestsync == cwaintmp->syncsrc) {
++	    if (debug > 3)
++		printk(KERN_INFO "cwain: already on best syncsrc %d\n", bestsync);
++	    return;
++	}
++
++	/* if we have a better syncsrc */
++	if (bestsync < cwaintmp->spans) {
++	    if (debug)
++		printk(KERN_INFO "cwain: found better syncsrc %d\n", bestsync);
++	    cwain_set_master(cwaintmp, bestsync);
++	    return;		    
++	}
++    }
++
++    /* if reelection failed, find internal sync source */
++    if (cwaintmp->syncsrc == -1) {
++	/* no master yet */
++	if (debug > 3)
++	    printk(KERN_INFO "cwain: no clocksource found cardID %d\n", cwaintmp->cardID);
++	for (i=0; i < cwaintmp->spans; i++) {
++	    /* find the first internal source */
++	    if (debug > 3)
++	        printk(KERN_INFO "cwain: cwaintmp->syncs[%d] = %d\n", i, cwaintmp->syncs[i]);
++	    if (cwaintmp->syncs[i] == 0) {
++		if (debug)
++		    printk(KERN_INFO "cwain: using internal clock of span %d\n", i);
++		cwain_set_master(cwaintmp, i);
++		return;
++	    }
++	}
++    }
++
++    /* if we have no internal sync source the only thing we can do is to enable any of the possible sync sources*/
++    if (cwaintmp->syncsrc == -1) {
++	/* find the first possible sync source with framing */
++        for (i=0; i < cwaintmp->spans; i++) {
++	    if (cwaintmp->syncs[i] > 0) {
++		if (debug)
++		    printk(KERN_INFO "cwain: desperately using clock of span %d\n", i);
++		cwain_set_master(cwaintmp, i);
++		break;
++	    }
++	}
++    }
++}
++
++static inline void cwain_isr_run(struct zt_cwain *cwaintmp) {
++    int fifo=0;
++    if (cwaintmp->span.flags & ZT_FLAG_RUNNING) {
++        /* oh zaptel! tell us what to transmit... */
++        zt_transmit(&cwaintmp->span);
++	/* B chans 1-15 mapped to fifos 0-14 */
++	/* B chans 17-31 mapped to fifos 15-29 */
++	for (fifo=0; fifo < 30; fifo++) {
++	    /* B xmit */
++	    cwain_fifo_tx(cwaintmp, fifo);
++	}
++	if (cwaintmp->sync) {
++	    cwain_dfifo_tx(cwaintmp);
++	}
++
++        cwaintmp->chans[15].bytes2receive = 0;
++	cwaintmp->chans[15].bytes2transmit = 0;
++	cwaintmp->chans[15].eofrx = 0;
++	cwaintmp->chans[15].eoftx = 0;
++
++	for (fifo=0; fifo < 30; fifo++) {
++	    /* B rx */
++	    cwain_fifo_rx(cwaintmp, fifo);
++	}
++
++	/* d-chan data */
++	if ((cwaintmp->drx > 0) && cwaintmp->sync){
++	    if (debug > 2)
++	    	printk(KERN_CRIT "drx = %d\n", cwaintmp->drx);
++	    cwain_dfifo_rx(cwaintmp);
++	}
++	/* oh zaptel! thou shall receive! */
++	zt_receive(&(cwaintmp->span));
++    }
++}
++
++void cwain_isr_sync(struct zt_cwain *cwainspan) {
++    unsigned char sync_sta;
++    unsigned char sync_ok = 0;
++    unsigned char jatt_sta = 0;
++
++    if (!cwainspan->span.flags & ZT_FLAG_RUNNING) {
++	return;
++    }
++
++    sync_sta = cwain_inb(cwainspan, cwain_R_SYNC_STA);
++
++if ((!cwainspan->sync) || (sync_sta != cwainspan->sync_sta)) {
++
++    if (debug > 2)
++	printk(KERN_CRIT "cwain: cardID %d R_SYNC_STA =%#x\n", cwainspan->cardID, sync_sta);
++
++    if (cwainspan->span.lineconfig & ZT_CONFIG_CRC4) {
++	if ((sync_sta & 0x80) == 0x80) {
++	    /* reset MFA detection */
++	    cwain_outb(cwainspan ,cwain_R_RX_SL0_CFG1,0x41);
++	} else if ((sync_sta & 0x27) == 0x27) {
++	    if ((cwainspan->sync_sta & 0x27) != 0x27) {
++		/* sync achieved, restart JATT */
++		if (debug)
++		    printk(KERN_INFO "cwain: %d starting jitter attenuator\n", cwainspan->cardID);
++		cwain_outb(cwainspan, cwain_R_JATT_CFG,0x9c);
++	    }
++	    sync_ok = 0x27;
++	} else {
++	    sync_ok = 0x00;
++	}
++    } else {
++	if ((sync_sta & 0x07) == 0x07) {
++	    if ((cwainspan->sync_sta & 0x7) != 0x7) {
++		/* sync achieved, restart JATT */
++		if (debug)
++		    printk(KERN_INFO "cwain: %d starting jitter attenuator\n", cwainspan->cardID);
++		cwain_outb(cwainspan, cwain_R_JATT_CFG,0x9c);
++	    }
++	    sync_ok = 0x07;
++	} else {
++	    sync_ok = 0x00;
++	}
++    }
++
++    cwainspan->sync_sta = sync_sta;
++
++    jatt_sta = cwain_inb(cwainspan, cwain_R_JATT_STA);
++    if ((jatt_sta & 0x60) != 0x60) {
++	if (debug > 2)
++	    printk(KERN_INFO "cwain: %d jitter attenuator %#x\n", cwainspan->cardID, (jatt_sta & 0x60) >> 5);
++	sync_ok = 0x00;
++    } else if (!cwainspan->sync && sync_ok) {
++	if (debug)
++	    printk(KERN_CRIT "cwain: %d jitter attenuator %#x ok!\n", cwainspan->cardID, (jatt_sta & 0x60) >> 5);
++    }
++
++    if (sync_ok && (!cwainspan->sync)) {
++	/* elastic buffer offsets */
++	cwain_outb(cwainspan,cwain_R_RX_OFFS,0x06);
++	cwain_outb(cwainspan,cwain_R_TX_OFFS,0x06);
++
++	if (debug > 2)
++	    printk(KERN_INFO "cwain: enabling D channel fifos\n");
++	cwain_outb(cwainspan,cwain_R_FIFO,0x1F << 1);
++	cwain_waitbusy(cwainspan);
++	cwain_outb(cwainspan,cwain_A_CON_HDLC,0xd);
++	cwain_outb(cwainspan,cwain_A_IRQ_MSK,0x1);
++	
++	cwain_outb(cwainspan,cwain_R_FIFO,(0x1F << 1) | 1);
++	cwain_waitbusy(cwainspan);
++	cwain_outb(cwainspan,cwain_A_CON_HDLC,0xd);
++	cwain_outb(cwainspan,cwain_A_IRQ_MSK,0x1);
++	cwainspan->span.alarms = ZT_ALARM_NONE;
++	zt_alarm_notify(&cwainspan->span);
++    }
++    if (!sync_ok && cwainspan->sync) {
++	if (debug > 2)
++	    printk(KERN_INFO "cwain: disabling D channel fifos\n");
++	cwain_outb(cwainspan,cwain_R_FIFO,0x1F << 1);
++	cwain_waitbusy(cwainspan);
++	cwain_outb(cwainspan,cwain_A_CON_HDLC,0x1);
++	cwain_outb(cwainspan,cwain_A_IRQ_MSK,0x0);
++	cwain_outb(cwainspan,cwain_R_FIFO,(0x1F << 1) | 1);
++	cwain_waitbusy(cwainspan);
++	cwain_outb(cwainspan,cwain_A_CON_HDLC,0x1);
++	cwain_outb(cwainspan,cwain_A_IRQ_MSK,0x0);
++	cwainspan->span.alarms = ZT_ALARM_RED;
++	zt_alarm_notify(&cwainspan->span);
++    }
++
++    cwainspan->sync = sync_ok;
++    if (sync_ok) {
++	switch (cwainspan->type) {
++	    case 0xb553:
++		sprintf(cwainspan->span.desc,"Junghanns.NET singleE1 PCI ISDN Card %d (cardID %d) SYNCED",cwainspan->cardno,cwainspan->cardID);
++		break;
++    	    case 0xb554:
++		sprintf(cwainspan->span.desc,"Junghanns.NET doubleE1 PCI ISDN Card %d (cardID %d) (1 E1 port) SYNCED",cwainspan->cardno,cwainspan->cardID);
++	        break;
++	}
++    } else {
++	switch (cwainspan->type) {
++	    case 0xb553:
++		sprintf(cwainspan->span.desc,"Junghanns.NET singleE1 PCI ISDN Card %d (cardID %d) NO SYNC (sync_sta = %#x)",cwainspan->cardno,cwainspan->cardID, sync_sta);
++		break;
++    	    case 0xb554:
++		sprintf(cwainspan->span.desc,"Junghanns.NET doubleE1 PCI ISDN Card %d (cardID %d) (1 E1 port) NO SYNC (sync_sta = %#x)",cwainspan->cardno,cwainspan->cardID, sync_sta);
++	        break;
++	}
++    }
++    cwain_doLEDs(cwainspan);
++}
++}
++
++int cwain_isr_fifo(struct zt_cwain *cwainspan, unsigned char status) {
++    unsigned char irq_foview,fi;
++
++    if (status & 0x80) {
++	/* fifo irq */
++	irq_foview = cwain_inb(cwainspan,cwain_R_IRQ_OVIEW);
++	if (irq_foview & 0x80) {
++	    fi = cwain_inb(cwainspan,cwain_R_IRQ_FIFO_BL7);
++	    if (fi & 0x80) {
++		if (debug > 2)
++		    printk(KERN_CRIT "cwain: fifo 31 RX irq for D channel\n");
++		cwainspan->drx += 1;		
++	    }
++	}
++	return 1;
++    }
++    return 0;
++}
++
++#ifdef LINUX26
++static irqreturn_t cwain_interrupt(int irq, void *dev_id, struct pt_regs *regs) {
++#else
++static void cwain_interrupt(int irq, void *dev_id, struct pt_regs *regs) {
++#endif
++    struct zt_cwain_card *cwaintmp = dev_id;
++    unsigned char status, status2, status_tmp, irq_misc, irq_misc2;
++    unsigned long flags;
++    int i = 0;
++    int l1event = 0;
++    
++    if (!cwaintmp || cwaintmp->dead) {
++#ifdef LINUX26
++		return IRQ_NONE;
++#else
++		return;
++#endif		
++    }
++    
++    
++    spin_lock_irqsave(&(cwaintmp->lock),flags);
++    status = cwain_inb(cwaintmp->span[0],cwain_R_STATUS);
++
++    status2 = 0;
++
++    for (i=0;i<cwaintmp->spans;i++) {
++	if (i == 0) {
++	    status_tmp = status;
++	} else {
++	    status_tmp = cwain_inb(cwaintmp->span[i],cwain_R_STATUS);
++	    status2 = status_tmp;
++	}
++	cwain_isr_fifo(cwaintmp->span[i], status_tmp);
++    }
++
++    if (!(status & 0x80) && !(status & 0x40)) {
++	// it's not us!
++	spin_unlock_irqrestore(&(cwaintmp->lock),flags);
++#ifdef LINUX26
++		return IRQ_NONE;
++#else
++		return;
++#endif		
++    }
++
++    // misc irq
++    if (status & 0x40) {
++	irq_misc = cwain_inb(cwaintmp->span[0],cwain_R_IRQ_MISC);
++	if (irq_misc & 0x2)  {
++	    /* cwain timer */
++	    cwaintmp->ticks++;
++	    for (i=0;i<cwaintmp->spans;i++) {
++		cwain_isr_run(cwaintmp->span[i]);
++	    }
++	    if (cwaintmp->ticks == 500) {
++		cwaintmp->ticks = 0;
++	    }
++	} 
++	if (irq_misc & 0x1) {
++	    /* state machine */
++	    if (debug > 4)
++		printk(KERN_INFO "cwain: state machine irq\n");
++	    l1event++;
++	}
++	if (irq_misc & 0x10) {
++    	    for (i=0;i<cwaintmp->spans;i++) {
++    	        cwain_isr_sync(cwaintmp->span[i]);
++    	    }
++	}
++    }
++
++    // misc irq
++    if (status2 & 0x40) {
++	if (cwaintmp->spans == 2) {
++	    irq_misc2 = cwain_inb(cwaintmp->span[1],cwain_R_IRQ_MISC);
++	}
++	if (irq_misc2 & 0x1) {
++	    /* state machine 2 */
++	    if (debug > 4)
++		printk(KERN_INFO "cwain: state machine 2 irq\n");
++	    l1event++;
++	}
++    }
++
++    if (l1event > 0) {
++//	printk(KERN_INFO "cwain: l1event %d\n", l1event);
++        if (cwaintmp->spans == 2) {
++    	    cwain_check_timing(cwaintmp);
++        }
++    	for (i=0;i<cwaintmp->spans;i++) {
++    	    cwain_isr_sync(cwaintmp->span[i]);
++    	}
++    }
++
++    spin_unlock_irqrestore(&(cwaintmp->lock),flags);
++#ifdef LINUX26
++	return IRQ_RETVAL(1);
++#endif		
++}
++
++static int ztcwain_open(struct zt_chan *chan) {
++//    printk(KERN_INFO "cwain: channel %d opened.\n",chan->channo);
++#ifndef LINUX26
++    MOD_INC_USE_COUNT;
++#else
++    try_module_get(THIS_MODULE);
++#endif
++    return 0;
++}
++
++static int ztcwain_close(struct zt_chan *chan) {
++//    printk(KERN_INFO "cwain: channel %d closed.\n",chan->channo);
++#ifndef LINUX26
++    MOD_DEC_USE_COUNT;
++#else
++    module_put(THIS_MODULE);
++#endif
++    return 0;
++}
++
++static int ztcwain_rbsbits(struct zt_chan *chan, int bits) {
++    return 0;
++}
++
++static int ztcwain_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) {
++        switch(cmd) {
++        default:
++                return -ENOTTY;
++        }
++        return 0;
++}
++
++static int ztcwain_startup(struct zt_span *span) {
++    struct zt_cwain_card *cwaincard = span->pvt;
++    struct zt_cwain *cwaintmp;
++    unsigned long flags;
++    int alreadyrunning;
++    int i=0;
++
++//    printk(KERN_INFO "cwain: startup spanno %d offset %d\n", span->spanno, span->offset);
++
++    if (cwaincard == NULL) {
++	printk(KERN_CRIT "cwain: cwaincard == NULL!\n");
++	return 0;
++    }
++
++    cwaintmp = cwaincard->span[span->offset];
++    if (cwaintmp == NULL) {
++	printk(KERN_CRIT "cwain: cwaintmp == NULL!\n");
++	return 0;
++    }
++
++    
++    alreadyrunning = span->flags & ZT_FLAG_RUNNING;
++//    printk(KERN_CRIT "already running %d flags %d\n", alreadyrunning, span->flags);
++
++    if (!alreadyrunning) {
++	span->chans[15].flags &= ~ZT_FLAG_HDLC;
++	span->chans[15].flags |= ZT_FLAG_BRIDCHAN; /* yes! */
++    
++	/* setup B channel buffers (8 bytes each) */
++	for (i=0; i<15 ; i++) {
++	    memset(cwaintmp->rxbuf[i],0x0,sizeof(cwaintmp->rxbuf[i]));
++    	    memset(cwaintmp->txbuf[i],0x0,sizeof(cwaintmp->txbuf[i]));
++
++    	    span->chans[i].readchunk = cwaintmp->rxbuf[i];
++	    span->chans[i].writechunk = cwaintmp->txbuf[i];
++	}
++	for (i=16; i<31 ; i++) {
++	    memset(cwaintmp->rxbuf[i-1],0x0,sizeof(cwaintmp->rxbuf[i-1]));
++    	    memset(cwaintmp->txbuf[i-1],0x0,sizeof(cwaintmp->txbuf[i-1]));
++    	    span->chans[i].readchunk = cwaintmp->rxbuf[i-1];
++	    span->chans[i].writechunk = cwaintmp->txbuf[i-1];
++	}
++	/* setup D channel buffer */
++    	memset(cwaintmp->dtxbuf,0x0,sizeof(cwaintmp->dtxbuf));
++	span->chans[15].writechunk = cwaintmp->dtxbuf;
++	cwaintmp->chans[15].maxbytes2transmit = sizeof(cwaintmp->dtxbuf);
++
++	memset(cwaintmp->drxbuf,0x0,sizeof(cwaintmp->drxbuf));
++    	span->chans[15].readchunk = cwaintmp->drxbuf;
++
++	span->flags |= ZT_FLAG_RUNNING;
++    } else {
++	printk(KERN_CRIT "already running\n");
++	return 0;
++    }
++
++    spin_lock_irqsave(&cwaintmp->lock,flags);
++    // irqs off
++    cwain_outb(cwaintmp,cwain_R_IRQ_CTRL, 0); 
++
++    /* setup D-FIFO TX */
++    cwain_outb(cwaintmp,cwain_R_FIFO,0x1F << 1);
++    cwain_waitbusy(cwaintmp);
++    cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
++    cwain_waitbusy(cwaintmp);
++    cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x1);
++    cwain_outb(cwaintmp,cwain_A_SUBCH_CFG,0x0);
++    cwain_outb(cwaintmp,cwain_A_CHANNEL,0x10 << 1);
++    cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
++
++    /* setup D-FIFO RX */
++    cwain_outb(cwaintmp,cwain_R_FIFO,(0x1F << 1) | 1);
++    cwain_waitbusy(cwaintmp);
++    cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
++    cwain_waitbusy(cwaintmp);
++    cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x1);
++    cwain_outb(cwaintmp,cwain_A_SUBCH_CFG,0x0);
++    cwain_outb(cwaintmp,cwain_A_CHANNEL,(0x10 << 1) | 1);
++    cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
++
++    /* setup B-FIFOs TX */
++    /* map ts 1 to 15 to fifos 0 to 14 */
++    for (i=1; i<16 ; i++) {
++	cwain_outb(cwaintmp,cwain_R_FIFO,(i - 1) << 1);
++	cwain_waitbusy(cwaintmp);
++    	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
++	cwain_waitbusy(cwaintmp);
++	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
++	cwain_outb(cwaintmp,cwain_A_CHANNEL,i << 1);
++	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x1);
++    }
++    /* map ts 17 to 31 to fifos 15 to 29 */
++    for (i=17; i<32 ; i++) {
++	cwain_outb(cwaintmp,cwain_R_FIFO,(i - 2) << 1);
++	cwain_waitbusy(cwaintmp);
++    	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
++	cwain_waitbusy(cwaintmp);
++	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
++	cwain_outb(cwaintmp,cwain_A_CHANNEL,i << 1);
++	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x1);
++    }
++
++    /* setup B-FIFOs RX */
++    /* map ts 1 to 15 to fifos 0 to 14 */
++    for (i=1; i<16 ; i++) {
++	cwain_outb(cwaintmp,cwain_R_FIFO,((i-1) << 1) | 1);
++    	cwain_waitbusy(cwaintmp);
++    	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
++    	cwain_waitbusy(cwaintmp);
++    	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
++    	cwain_outb(cwaintmp,cwain_A_CHANNEL,(i << 1) | 1);
++    	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x1);
++    }
++    /* map ts 17 to 31 to fifos 15 to 29 */
++    for (i=17; i<32 ; i++) {
++	cwain_outb(cwaintmp,cwain_R_FIFO,((i-2) << 1) | 1);
++    	cwain_waitbusy(cwaintmp);
++    	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
++    	cwain_waitbusy(cwaintmp);
++    	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
++    	cwain_outb(cwaintmp,cwain_A_CHANNEL,(i << 1) | 1);
++    	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x1);
++    }
++
++    if (debug)
++        printk(KERN_INFO "cwain: starting card %d span %d/%d.\n",cwaintmp->cardno,span->spanno,span->offset);
++
++    if (cwaincard->spans == 1) {
++	cwain_set_master(cwaincard, 0);
++    }
++    
++    /* setup E1 amplitude */
++    cwain_outb(cwaintmp,cwain_R_PWM_MD,0x20);
++    cwain_outb(cwaintmp,cwain_R_PWM0,0x50);
++    cwain_outb(cwaintmp,cwain_R_PWM1,0xff);
++
++    /* setup E1 transceiver */
++    cwain_outb(cwaintmp,cwain_R_TX_SL0,0xf8);  // R_TX_FR1
++    cwain_outb(cwaintmp,cwain_R_TX_SL0_CFG0,0x00); /* semiautomatic mode */
++
++    cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG0,0x6); /* 0x26 */
++
++    if (cwaintmp->span.lineconfig & ZT_CONFIG_AMI) {
++	cwain_outb(cwaintmp,cwain_R_TX0,0x82);
++	cwain_outb(cwaintmp,cwain_R_RX0,0x02);
++    } else if (cwaintmp->span.lineconfig & ZT_CONFIG_HDB3) {
++	cwain_outb(cwaintmp,cwain_R_TX0,0x81);
++	cwain_outb(cwaintmp,cwain_R_RX0,0x01);
++    }
++
++    /* transmitter mode */
++    cwain_outb(cwaintmp,cwain_R_TX1,0x60); 
++
++    cwain_outb(cwaintmp,cwain_R_LOS0,0x10);
++    cwain_outb(cwaintmp,cwain_R_LOS1,0x10);
++
++    if (cwaintmp->span.lineconfig & ZT_CONFIG_CRC4) {
++	/* crc4 multiframe */
++	cwain_outb(cwaintmp,cwain_R_TX_SL0_CFG1,0x31);
++//	cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG1,0x41);
++	cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG1,0x03);
++    } else {
++	/* doubleframe */
++	cwain_outb(cwaintmp,cwain_R_TX_SL0_CFG1,0x0);
++//	cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG1,0x40);
++	cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG1,0x02);
++    }
++
++    
++    /* setup sync mode */    
++    if (cwaincard->syncs[span->offset] > 0) {
++	cwain_outb(cwaintmp,cwain_R_SYNC_CTRL,0x2);
++	cwain_outb(cwaintmp,cwain_R_SYNC_OUT,0x1);    
++	/* layer 1, here we go! */
++	cwain_outb(cwaintmp,cwain_R_E1_WR_STA,0x00);
++    } else {
++//	cwain_outb(cwaintmp,cwain_R_SYNC_CTRL,0x5);
++	cwain_outb(cwaintmp,cwain_R_SYNC_CTRL,0x7);
++	cwain_outb(cwaintmp,cwain_R_SYNC_OUT,0x0);
++	/* layer 1, up! */
++	cwain_outb(cwaintmp,cwain_R_E1_WR_STA,0x11);
++    }
++    
++    cwaintmp->sync = 0;
++    cwaintmp->sync_sta = 0;
++    
++    /* enable irqs */
++    cwain_outb(cwaintmp,cwain_R_IRQ_CTRL, 8 | 1); 
++    spin_unlock_irqrestore(&cwaintmp->lock,flags);
++
++    return 0;
++}
++
++static int ztcwain_shutdown(struct zt_span *span) {
++    struct zt_cwain_card *cwaincard = span->pvt;
++    struct zt_cwain *cwaintmp;
++    unsigned long flags;
++    int alreadyrunning;
++    int i=0;
++    
++    if (cwaincard == NULL) {
++	printk(KERN_CRIT "cwain: cwaincard == NULL!\n");
++	return 0;
++    }
++
++    cwaintmp = cwaincard->span[span->offset];
++    if (cwaintmp == NULL) {
++	printk(KERN_CRIT "cwain: cwaintmp == NULL!\n");
++	return 0;
++    }
++
++    alreadyrunning = span->flags & ZT_FLAG_RUNNING;
++    
++    if (!alreadyrunning) {
++	return 0;
++    }
++    spin_lock_irqsave(&cwaintmp->lock,flags);
++
++//    printk(KERN_CRIT "cwain: stopping card %d span %d/%d.\n",cwaintmp->cardno,span->spanno,span->offset);
++
++    // turn off irqs for all fifos
++
++    /* disable FIFO TX */
++    for (i=0; i<0x20 ; i++) {
++	cwain_outb(cwaintmp,cwain_R_FIFO,i << 1);
++	cwain_waitbusy(cwaintmp);
++	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
++    }
++
++    /* disable FIFO RX */
++    for (i=0; i<0x20 ; i++) {
++	cwain_outb(cwaintmp,cwain_R_FIFO,(i << 1) | 1);
++    	cwain_waitbusy(cwaintmp);
++    	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
++    }
++
++
++    /* Deactivate Layer 1 */
++    cwain_outb(cwaintmp,cwain_R_E1_WR_STA,0x10);
++
++    cwain_outb(cwaintmp,cwain_R_IRQ_CTRL, 0); 
++//    cwain_outb(cwaintmp,cwain_R_IRQMSK_MISC, 0); 
++    cwain_inb(cwaintmp,cwain_R_STATUS);
++
++
++    span->flags &= ~ZT_FLAG_RUNNING;
++
++
++    spin_unlock_irqrestore(&cwaintmp->lock,flags);
++
++//    printk(KERN_CRIT "cwain: card %d span %d/%d down.\n",cwaintmp->cardno,span->spanno,span->offset);
++    return 0;
++}
++
++static int ztcwain_maint(struct zt_span *span, int cmd) {
++    return 0;
++}
++
++static int ztcwain_chanconfig(struct zt_chan *chan,int sigtype) {
++//    printk(KERN_INFO "chan_config sigtype=%d\n", sigtype);
++    return 0;
++}
++
++static int ztcwain_spanconfig(struct zt_span *span,struct zt_lineconfig *lc) {
++    struct zt_cwain_card *cwaincard = span->pvt;
++    span->lineconfig = lc->lineconfig;
++    span->syncsrc = lc->sync;
++
++    cwaincard->syncs[span->offset] = lc->sync;
++    cwaincard->syncsrc = -1;
++//    printk(KERN_INFO "span_config %d lineconfig=%d syncsrc=%d\n", span->spanno, lc->lineconfig, lc->sync);
++//    cwain_check_timing(cwaincard);
++    return 0;
++}
++
++static int ztcwain_initialize(struct zt_cwain *cwaintmp, struct zt_cwain_card *cwaincard, int offset) {
++    int i=0;
++    
++	memset(&cwaintmp->span,0,sizeof(struct zt_span)); // you never can tell...
++	sprintf(cwaintmp->span.name,"cwain/%d",cwaintmp->cardno);
++	switch (cwaintmp->type) {
++	    case 0xb553:
++		sprintf(cwaintmp->span.desc,"Junghanns.NET singleE1 PCI ISDN Card %d (cardID %d)",cwaintmp->cardno,cwaintmp->cardID);
++		break;
++	    case 0xb554:
++		sprintf(cwaintmp->span.desc,"Junghanns.NET doubleE1 PCI ISDN Card %d (cardID %d) (1 E1 port)",cwaintmp->cardno,cwaintmp->cardID);
++		break;
++	    default:
++		return -1;
++	}
++        cwaintmp->span.spanconfig = ztcwain_spanconfig;
++        cwaintmp->span.chanconfig = ztcwain_chanconfig;
++        cwaintmp->span.startup = ztcwain_startup;
++        cwaintmp->span.shutdown = ztcwain_shutdown;
++        cwaintmp->span.maint = ztcwain_maint;
++        cwaintmp->span.rbsbits = ztcwain_rbsbits;
++        cwaintmp->span.open = ztcwain_open;
++        cwaintmp->span.close = ztcwain_close;
++        cwaintmp->span.ioctl = ztcwain_ioctl;
++
++        cwaintmp->span.chans = cwaintmp->chans;
++        cwaintmp->span.channels = 31;
++        cwaintmp->span.deflaw = ZT_LAW_ALAW;
++        cwaintmp->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_HDB3 | ZT_CONFIG_CCS; 
++        init_waitqueue_head(&cwaintmp->span.maintq);
++        cwaintmp->span.pvt = cwaincard;
++        cwaintmp->span.offset = offset;
++
++	for (i=0; i < cwaintmp->span.channels; i++) {
++	    memset(&(cwaintmp->chans[i]),0x0,sizeof(struct zt_chan));
++	    sprintf(cwaintmp->chans[i].name,"cwain%d/%d",cwain_span_count + 1,i + 1);
++	    cwaintmp->chans[i].pvt = cwaintmp;
++	    cwaintmp->chans[i].sigcap =  ZT_SIG_CLEAR;
++	    cwaintmp->chans[i].chanpos = i + 1; 
++	}
++
++	if (zt_register(&cwaintmp->span,0)) {
++	    printk(KERN_INFO "cwain: unable to register zaptel span!\n");
++	    return -1;
++	}
++//	 printk(KERN_INFO "cwain: registered zaptel span %d.\n",s+1);
++
++    return 0;
++}
++
++int cwain_reset_card(struct zt_cwain_card *cwaintmp) {
++    unsigned long flags;
++    int i = 0;
++
++    cwaintmp->irq = cwaintmp->span[0]->irq;
++    
++    if (cwaintmp->spans == 2) {
++	if (request_irq(cwaintmp->irq, cwain_interrupt, SA_INTERRUPT | SA_SHIRQ, "cwain2", cwaintmp)) {
++    	    printk(KERN_WARNING "cwain: unable to register irq\n");
++	    return -1;
++	}
++    } else {
++	if (request_irq(cwaintmp->irq, cwain_interrupt, SA_INTERRUPT | SA_SHIRQ, "cwain", cwaintmp)) {
++    	    printk(KERN_WARNING "cwain: unable to register irq\n");
++	    return -1;
++	}
++    }
++
++    spin_lock_irqsave(&(cwaintmp->lock),flags);
++
++    for (i=0;i<cwaintmp->spans;i++) {
++	cwain_reset_span(cwaintmp->span[i]);
++    }
++
++    /* no master yet, force reelection */
++    cwaintmp->syncsrc = -1;
++    
++    /* set up the timer 1 khz, zaptel timing */
++    cwain_outb(cwaintmp->span[0],cwain_R_TI_WD, 0x2);
++
++    if (cwaintmp->spans == 2) {
++	cwain_outb(cwaintmp->span[1],cwain_R_IRQMSK_MISC, 0x1); 
++    }
++    /* enable timer interrupts */
++    cwain_outb(cwaintmp->span[0],cwain_R_IRQMSK_MISC, 0x13); 
++
++    /* Finally enable IRQ output */
++    cwain_outb(cwaintmp->span[0],cwain_R_IRQ_CTRL, 0x8 | 0x1); 
++
++    spin_unlock_irqrestore(&(cwaintmp->lock),flags);
++    return 0;
++}
++
++int cwain_find_spans(unsigned int pcidid) {
++    struct pci_dev *tmp;
++    struct zt_cwain *cwaintmp = NULL;
++    int i=0;
++    unsigned char dips=0;
++    int cid=0;
++    int modes=0;
++    tmp = pci_find_device(PCI_VENDOR_ID_CCD,pcidid,multi_cwain);
++    while (tmp != NULL) {
++	multi_cwain = tmp;	// skip this next time.
++
++	if (pci_enable_device(tmp)) {
++	    multi_cwain = NULL;
++	    return -1;
++	}
++
++	cwaintmp = kmalloc(sizeof(struct zt_cwain),GFP_KERNEL);
++	if (!cwaintmp) {
++	    printk(KERN_WARNING "cwain: unable to kmalloc!\n");
++	    pci_disable_device(tmp);
++	    multi_cwain = NULL;
++	    return -ENOMEM;
++	}
++	memset(cwaintmp, 0x0, sizeof(struct zt_cwain));
++	
++	spin_lock_init(&cwaintmp->lock);
++	cwaintmp->pcidev = tmp;
++	cwaintmp->pcibus = tmp->bus->number;
++	cwaintmp->pcidevfn = tmp->devfn; 
++
++
++	cwaintmp->pci_io = (char *) tmp->resource[1].start;
++	if (!cwaintmp->pci_io) {
++	    printk(KERN_WARNING "cwain: no iomem!\n");
++	    pci_disable_device(tmp);
++	    multi_cwain = NULL;
++	    return -EIO;
++	}
++
++	if (!tmp->irq) {
++	    printk(KERN_WARNING "cwain: PCI device has no irq!\n");
++	    pci_disable_device(tmp);
++	    multi_cwain = NULL;
++	    return -EIO;
++	}
++
++        cwaintmp->irq = tmp->irq;
++
++	cwaintmp->pci_io = ioremap((ulong) cwaintmp->pci_io, 256);
++			       
++	/* enable memio */
++	pci_write_config_word(cwaintmp->pcidev, PCI_COMMAND, PCI_COMMAND_MEMORY);	
++
++	/* disable interrupts */
++	cwain_outb(cwaintmp,cwain_R_IRQ_CTRL, 0); 
++
++        if (((tmp->subsystem_device==0xb553) || (tmp->subsystem_device==0xb554))&& (pcidid == PCI_DEVICE_ID_CCD_E)) {
++	    dips = (cwain_inb(cwaintmp,cwain_R_GPI_IN0) >> 5);
++	    cid = 7;
++	    for (i=0;i<3;i++) {
++	        if ((dips & (1 << i)) != 0) {
++	    	cid -= (1 << (2-i));
++	        }
++	    }
++//		printk(KERN_INFO "DIPS = %#x CID= %#x\n",dips,cid);
++        } else {
++	    cid = 0xff;
++        }
++
++	if (ports == -1) {
++    	    if ((tmp->subsystem_device==0xb520) && (pcidid == PCI_DEVICE_ID_CCD_E)) {
++		modes = (cwain_inb(cwaintmp,cwain_R_GPI_IN0) >> 4) & 0x01;
++	    } else {
++		modes = 0; // assume TE mode
++	    }
++	} else {
++	    modes = ports >> cwain_span_count;
++	}
++
++
++	cwaintmp->cardID = cid;
++	cwaintmp->type = tmp->subsystem_device;
++
++	if ((modes & 1) != 0) {
++	    cwaintmp->nt_mode = 1;
++	} else {
++	    cwaintmp->nt_mode = 0;
++	}
++
++	cwain_register_span(cwaintmp);
++
++	tmp = pci_find_device(PCI_VENDOR_ID_CCD,pcidid,multi_cwain);
++    }
++    return 0;
++}
++
++
++int cwain_sort_cards(void) {
++    int changed=0,tmpcardno;
++    struct zt_cwain_card *tmpcard,*tmpcard2;
++    spin_lock(&cwain_card_registerlock);
++    do {
++	changed = 0;
++	tmpcard = cwain_card_list;
++	while (tmpcard != NULL) {
++	    if (tmpcard->prev) {
++		if (tmpcard->prev->cardID > tmpcard->cardID) {
++		    tmpcardno = tmpcard->prev->cardno;
++		    tmpcard->prev->cardno = tmpcard->cardno; 
++		    tmpcard->cardno = tmpcardno;
++		
++		    tmpcard2 = tmpcard->prev;
++		    if (tmpcard2->prev) {
++			tmpcard2->prev->next = tmpcard;
++		    } else {
++			cwain_card_list = tmpcard;
++		    }
++		    if (tmpcard->next) {
++			tmpcard->next->prev = tmpcard2;
++		    } 
++		    tmpcard2->next = tmpcard->next;
++		    tmpcard->prev = tmpcard2->prev;
++		    tmpcard->next = tmpcard2;
++		    tmpcard2->prev = tmpcard;
++		    changed = 1;
++		    tmpcard = tmpcard2;
++		}
++	    }
++	    tmpcard = tmpcard->next;
++	}
++    } while (changed == 1);
++    spin_unlock(&cwain_card_registerlock);
++    return 0;
++}
++
++int cwain_zap_cards(void) {
++    struct zt_cwain_card *tmpcard = cwain_card_list;
++    int i=0;
++    int res=0;
++    while (tmpcard != NULL) {
++	for (i=0; i<tmpcard->spans; i++) {
++	    ztcwain_initialize(tmpcard->span[i], tmpcard, i);
++	}
++	res = cwain_reset_card(tmpcard);
++	tmpcard = tmpcard->next;
++    }
++    return res;
++}
++
++
++int init_module(void) {
++    multi_cwain = NULL;
++    cwain_find_spans(PCI_DEVICE_ID_CCD_E);
++    cwain_sort_cards();
++    cwain_zap_cards();
++    if (cwain_card_count == 0) {
++	printk(KERN_INFO "cwain: no cwain cards found.\n");
++    } else {
++	printk(KERN_INFO "cwain: %d cwain card(s) in this box, %d E1 ports total.\n", cwain_card_count, cwain_span_count);
++    }
++    return 0;
++}
++
++void cleanup_module(void) {
++    struct zt_cwain_card *tmpcard,*tmplist;
++    struct zt_cwain *tmpspan,*spanlist;
++    int i=0;
++    int j=0;
++    
++    tmplist = cwain_card_list;
++    tmpcard = NULL;
++    while (tmplist) {
++	tmpcard = tmplist;
++	tmplist = tmplist->next;
++
++	tmpcard->dead = 1;
++	cwain_shutdown_card(tmpcard);
++	kfree(tmpcard);
++	i++;
++    }
++
++    spanlist = cwain_span_list;
++    tmpspan = NULL;
++    while (spanlist) {
++	tmpspan = spanlist;
++	spanlist = spanlist->next;
++	kfree(tmpspan);
++	j++;
++    }
++    printk(KERN_INFO "cwain: shutdown %d spans, %d cwain cards.\n", j, i);
++}
++#endif
++
++MODULE_PARM(ports,"i");
++MODULE_PARM(debug,"i");
++MODULE_DESCRIPTION("cwain zaptel driver");
++MODULE_AUTHOR("Klaus-Peter Junghanns <kpj at junghanns.net>");
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("GPL");
++#endif	
+diff -urNad zaptel-1.2.3/cwain/cwain.h /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/cwain.h
+--- zaptel-1.2.3/cwain/cwain.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/cwain.h	2005-09-26 09:59:05.000000000 +0300
+@@ -0,0 +1,238 @@
++#define cwain_FIFO_SIZE	128
++#define cwain_DFIFO_SIZE	4096
++#define cwain_FIFO_HW	13
++
++typedef struct zt_cwain {
++    /* pci resources */
++    unsigned int irq;
++    unsigned int iomem;
++    unsigned char *pci_io;
++    unsigned int pcibus;
++    unsigned int pcidevfn;
++    struct pci_dev *pcidev;
++    unsigned int type;
++
++    /* lock to protect the structure */
++    spinlock_t lock;
++    int cardID;
++    unsigned char cardno;
++    
++    /* ticks and clicks, fish and chips */
++    unsigned int ticks;
++    unsigned int clicks;
++    unsigned char nt_mode;
++    unsigned char sync_sta;
++    unsigned char sync;
++    int syncmode;
++    
++    /* blinky blink */
++    unsigned char leds[4];
++
++    /* B chan buffers */
++    unsigned char rxbuf[30][ZT_CHUNKSIZE];
++    unsigned char txbuf[30][ZT_CHUNKSIZE];
++    
++    /* number of RXed dchan frames */
++    unsigned char drx;
++    /* D chan buffer */
++    unsigned char drxbuf[cwain_DFIFO_SIZE];
++    unsigned char dtxbuf[cwain_DFIFO_SIZE];
++
++
++    /* zaptel resources */
++    struct zt_span span;
++    struct zt_chan chans[31];
++
++    /* more zaptel stuff */
++    unsigned int usecount;
++    int spantype;
++    int spanflags;
++
++    /* linked list */
++    struct zt_cwain *next;
++    struct zt_cwain *prev;
++
++} zt_cwain;
++
++typedef struct zt_cwain_card {
++    /* lock to protect the structure */
++    spinlock_t lock;
++
++    unsigned int spans;
++    unsigned int dead;
++    int cardID;
++    unsigned char cardno;
++    unsigned int ticks;
++
++    struct zt_cwain *span[2];
++    int syncsrc;
++    int syncs[2];
++    int master[2];
++    
++    unsigned int irq;   
++    unsigned int pcibus;
++
++    /* linked list */
++    struct zt_cwain_card *next;
++    struct zt_cwain_card *prev;
++} zt_cwain_card;
++
++#define cwain_outb(a,b,c) (writeb((c),(a)->pci_io+(b)))
++#define cwain_inb(a,b) (readb((a)->pci_io+(b)))
++
++#define cwain_outw(a,b,c) (writew((c),(a)->pci_io+(b)))
++#define cwain_inw(a,b) (readw((a)->pci_io+(b)))
++
++#define cwain_outdw(a,b,c) (writel((c),(a)->pci_io+(b)))
++#define cwain_indw(a,b) (readl((a)->pci_io+(b)))
++
++
++/* Write only registers */
++#define cwain_A_CH_MSK		0xF4
++#define cwain_A_CHANNEL 	0xFC
++#define cwain_A_CON_HDLC	0xFA
++#define cwain_A_CONF		0xD1
++#define cwain_A_FIFO_SEQ	0xFD
++#define cwain_R_INC_RES_FIFO	0x0E
++#define cwain_A_IRQ_MSK		0xFF
++#define cwain_A_SL_CFG		0xD0
++#define cwain_A_SUBCH_CFG	0xFB
++#define cwain_R_BERT_WD_MD	0x1B
++#define cwain_R_BRG_PCM_CFG	0x02
++#define cwain_R_CIRM		0x00
++#define cwain_R_CONF_EN		0x18
++#define cwain_R_CTRL		0x01
++#define cwain_R_DTMF		0x1C
++#define cwain_R_DTMF_N		0x1D
++#define cwain_R_E1_WR_STA	0x20
++#define cwain_R_FIFO_MD		0x0D
++#define cwain_R_FIFO		0x0F
++#define cwain_R_FIRST_FIFO	0x0B
++#define cwain_R_FSM_IDX		0x0F
++#define cwain_R_GPIO_EN0	0x42
++#define cwain_R_GPIO_EN1	0x43
++#define cwain_R_GPIO_OUT0	0x40
++#define cwain_R_GPIO_OUT1	0x41
++#define cwain_R_GPIO_SEL	0x44
++#define cwain_R_IRQ_CTRL	0x13
++#define cwain_R_IRQMSK_MISC	0x11
++#define cwain_R_JATT_CFG	0x2F
++#define cwain_R_LOS0		0x22
++#define cwain_R_LOS1		0x23
++#define cwain_R_PCM_MD0		0x14
++#define cwain_R_PCM_MD1		0x15
++#define cwain_R_PCM_MD2		0x15
++#define cwain_R_PWM_MD		0x46
++#define cwain_R_PWM0		0x38
++#define cwain_R_PWM1		0x39
++#define cwain_R_RAM_ADDR0	0x08
++#define cwain_R_RAM_ADDR1	0x09
++#define cwain_R_RAM_ADDR2	0x0A
++#define cwain_R_RAM_MISC	0x0C
++#define cwain_R_RX_OFFS		0x30
++#define cwain_R_RX_SL0_CFG0	0x25
++#define cwain_R_RX_SL0_CFG1	0x26
++#define cwain_R_RX0		0x24
++#define cwain_R_SH0H		0x15
++#define cwain_R_SH0L		0x15
++#define cwain_R_SH1H		0x15
++#define cwain_R_SH1L		0x15
++#define cwain_R_SL_SEL0		0x15
++#define cwain_R_SL_SEL1		0x15
++#define cwain_R_SL_SEL2		0x15
++#define cwain_R_SL_SEL3		0x15
++#define cwain_R_SL_SEL4		0x15
++#define cwain_R_SL_SEL5		0x15
++#define cwain_R_SL_SEL6		0x15
++#define cwain_R_SL_SEL7		0x15
++#define cwain_R_SLOT		0x10
++#define cwain_R_SYNC_CTRL	0x35
++#define cwain_R_SYNC_OUT	0x31
++#define cwain_R_TI_WD		0x1A
++#define cwain_R_TX_OFFS		0x34
++#define cwain_R_TX_SL0_CFG0	0x2C
++#define cwain_R_TX_SL0_CFG1	0x2E
++#define cwain_R_TX_SL0		0x2D
++#define cwain_R_TX0		0x28
++#define cwain_R_TX1		0x29
++
++#define cwain_R_TX_FR0		0x2C
++#define cwain_R_TX_FR1		0x2D
++#define cwain_R_TX_FR2		0x2E
++
++#define cwain_R_RX_FR0		0x25
++#define cwain_R_RX_FR1		0x26
++
++/* Read only registers */
++#define cwain_A_F1		0x0C
++#define cwain_A_F12		0x0C
++#define cwain_A_F2		0x0D
++#define cwain_A_Z1		0x04
++#define cwain_A_Z12		0x04
++#define cwain_A_Z1H		0x05
++#define cwain_A_Z1L		0x04
++#define cwain_A_Z2		0x06
++#define cwain_A_Z2H		0x07
++#define cwain_A_Z2L		0x06
++#define cwain_R_BERT_ECH	0x1B
++#define cwain_R_BERT_ECL	0x1A
++#define cwain_R_BERT_STA	0x17
++#define cwain_R_CHIP_ID		0x16
++#define cwain_R_CHIP_RV		0x1F
++#define cwain_R_CONF_OFLOW	0x14
++#define cwain_R_CRC_ECH		0x35
++#define cwain_R_CRC_ECL		0x34
++#define cwain_R_E_ECH		0x37
++#define cwain_R_E_ECL		0x36
++#define cwain_R_E1_RD_STA	0x20
++#define cwain_R_F0_CNTH		0x19
++#define cwain_R_F0_CNTL		0x18
++#define cwain_R_FAS_ECH		0x31
++#define cwain_R_FAS_ECL		0x30
++#define cwain_R_GPI_IN0		0x44
++#define cwain_R_GPI_IN1		0x45
++#define cwain_R_GPI_IN2		0x46
++#define cwain_R_GPI_IN3		0x47
++#define cwain_R_GPIO_IN0	0x40
++#define cwain_R_GPIO_IN1	0x41
++#define cwain_R_INT_DATA	0x88
++#define cwain_R_IRQ_FIFO_BL0	0xC8
++#define cwain_R_IRQ_FIFO_BL1	0xC9
++#define cwain_R_IRQ_FIFO_BL2	0xCA
++#define cwain_R_IRQ_FIFO_BL3	0xCB
++#define cwain_R_IRQ_FIFO_BL4	0xCC
++#define cwain_R_IRQ_FIFO_BL5	0xCD
++#define cwain_R_IRQ_FIFO_BL6	0xCE
++#define cwain_R_IRQ_FIFO_BL7	0xCF
++#define cwain_R_IRQ_MISC	0x11
++#define cwain_R_IRQ_OVIEW	0x10
++#define cwain_R_JATT_STA	0x2B
++#define cwain_R_RAM_USE		0x15
++#define cwain_R_RX_SL0_0	0x25
++#define cwain_R_RX_SL0_1	0x26
++#define cwain_R_RX_SL0_2	0x27
++#define cwain_R_SA6_VAL13_ECH	0x39
++#define cwain_R_SA6_VAL13_ECL	0x38
++#define cwain_R_SA6_VAL23_ECH	0x3B
++#define cwain_R_SA6_VAL23_ECL	0x3A
++#define cwain_R_SLIP		0x2C
++#define cwain_R_STATUS		0x1C
++#define cwain_R_SYNC_STA	0x24
++#define cwain_R_VIO_ECH		0x33
++#define cwain_R_VIO_ECL		0x32
++
++
++/* Read/Write registers */
++#define cwain_A_FIFO_DATA0_NOINC	0x84
++#define cwain_A_FIFO_DATA0	0x80
++#define cwain_A_FIFO_DATA1_NOINC	0x84
++#define cwain_A_FIFO_DATA1	0x80
++#define cwain_A_FIFO_DATA2_NOINC	0x84
++#define cwain_A_FIFO_DATA2	0x80
++#define cwain_R_RAM_DATA	0xC0
++
++#define PCI_DEVICE_ID_CCD_E	0x30b1
++
++#define CLKDEL_TE	0xe	/* CLKDEL in TE mode */
++#define CLKDEL_NT	0xc	/* CLKDEL in NT mode */
++
+diff -urNad zaptel-1.2.3/cwain/LICENSE /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/LICENSE
+--- zaptel-1.2.3/cwain/LICENSE	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/LICENSE	2005-09-26 09:59:05.000000000 +0300
+@@ -0,0 +1,341 @@
++
++		    GNU GENERAL PUBLIC LICENSE
++		       Version 2, June 1991
++
++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
++                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++			    Preamble
++
++  The licenses for most software are designed to take away your
++freedom to share and change it.  By contrast, the GNU General Public
++License is intended to guarantee your freedom to share and change free
++software--to make sure the software is free for all its users.  This
++General Public License applies to most of the Free Software
++Foundation's software and to any other program whose authors commit to
++using it.  (Some other Free Software Foundation software is covered by
++the GNU Library General Public License instead.)  You can apply it to
++your programs, too.
++
++  When we speak of free software, we are referring to freedom, not
++price.  Our General Public Licenses are designed to make sure that you
++have the freedom to distribute copies of free software (and charge for
++this service if you wish), that you receive source code or can get it
++if you want it, that you can change the software or use pieces of it
++in new free programs; and that you know you can do these things.
++
++  To protect your rights, we need to make restrictions that forbid
++anyone to deny you these rights or to ask you to surrender the rights.
++These restrictions translate to certain responsibilities for you if you
++distribute copies of the software, or if you modify it.
++
++  For example, if you distribute copies of such a program, whether
++gratis or for a fee, you must give the recipients all the rights that
++you have.  You must make sure that they, too, receive or can get the
++source code.  And you must show them these terms so they know their
++rights.
++
++  We protect your rights with two steps: (1) copyright the software, and
++(2) offer you this license which gives you legal permission to copy,
++distribute and/or modify the software.
++
++  Also, for each author's protection and ours, we want to make certain
++that everyone understands that there is no warranty for this free
++software.  If the software is modified by someone else and passed on, we
++want its recipients to know that what they have is not the original, so
++that any problems introduced by others will not reflect on the original
++authors' reputations.
++
++  Finally, any free program is threatened constantly by software
++patents.  We wish to avoid the danger that redistributors of a free
++program will individually obtain patent licenses, in effect making the
++program proprietary.  To prevent this, we have made it clear that any
++patent must be licensed for everyone's free use or not licensed at all.
++
++  The precise terms and conditions for copying, distribution and
++modification follow.
++
++		    GNU GENERAL PUBLIC LICENSE
++   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++
++  0. This License applies to any program or other work which contains
++a notice placed by the copyright holder saying it may be distributed
++under the terms of this General Public License.  The "Program", below,
++refers to any such program or work, and a "work based on the Program"
++means either the Program or any derivative work under copyright law:
++that is to say, a work containing the Program or a portion of it,
++either verbatim or with modifications and/or translated into another
++language.  (Hereinafter, translation is included without limitation in
++the term "modification".)  Each licensee is addressed as "you".
++
++Activities other than copying, distribution and modification are not
++covered by this License; they are outside its scope.  The act of
++running the Program is not restricted, and the output from the Program
++is covered only if its contents constitute a work based on the
++Program (independent of having been made by running the Program).
++Whether that is true depends on what the Program does.
++
++  1. You may copy and distribute verbatim copies of the Program's
++source code as you receive it, in any medium, provided that you
++conspicuously and appropriately publish on each copy an appropriate
++copyright notice and disclaimer of warranty; keep intact all the
++notices that refer to this License and to the absence of any warranty;
++and give any other recipients of the Program a copy of this License
++along with the Program.
++
++You may charge a fee for the physical act of transferring a copy, and
++you may at your option offer warranty protection in exchange for a fee.
++
++  2. You may modify your copy or copies of the Program or any portion
++of it, thus forming a work based on the Program, and copy and
++distribute such modifications or work under the terms of Section 1
++above, provided that you also meet all of these conditions:
++
++    a) You must cause the modified files to carry prominent notices
++    stating that you changed the files and the date of any change.
++
++    b) You must cause any work that you distribute or publish, that in
++    whole or in part contains or is derived from the Program or any
++    part thereof, to be licensed as a whole at no charge to all third
++    parties under the terms of this License.
++
++    c) If the modified program normally reads commands interactively
++    when run, you must cause it, when started running for such
++    interactive use in the most ordinary way, to print or display an
++    announcement including an appropriate copyright notice and a
++    notice that there is no warranty (or else, saying that you provide
++    a warranty) and that users may redistribute the program under
++    these conditions, and telling the user how to view a copy of this
++    License.  (Exception: if the Program itself is interactive but
++    does not normally print such an announcement, your work based on
++    the Program is not required to print an announcement.)
++
++These requirements apply to the modified work as a whole.  If
++identifiable sections of that work are not derived from the Program,
++and can be reasonably considered independent and separate works in
++themselves, then this License, and its terms, do not apply to those
++sections when you distribute them as separate works.  But when you
++distribute the same sections as part of a whole which is a work based
++on the Program, the distribution of the whole must be on the terms of
++this License, whose permissions for other licensees extend to the
++entire whole, and thus to each and every part regardless of who wrote it.
++
++Thus, it is not the intent of this section to claim rights or contest
++your rights to work written entirely by you; rather, the intent is to
++exercise the right to control the distribution of derivative or
++collective works based on the Program.
++
++In addition, mere aggregation of another work not based on the Program
++with the Program (or with a work based on the Program) on a volume of
++a storage or distribution medium does not bring the other work under
++the scope of this License.
++
++  3. You may copy and distribute the Program (or a work based on it,
++under Section 2) in object code or executable form under the terms of
++Sections 1 and 2 above provided that you also do one of the following:
++
++    a) Accompany it with the complete corresponding machine-readable
++    source code, which must be distributed under the terms of Sections
++    1 and 2 above on a medium customarily used for software interchange; or,
++
++    b) Accompany it with a written offer, valid for at least three
++    years, to give any third party, for a charge no more than your
++    cost of physically performing source distribution, a complete
++    machine-readable copy of the corresponding source code, to be
++    distributed under the terms of Sections 1 and 2 above on a medium
++    customarily used for software interchange; or,
++
++    c) Accompany it with the information you received as to the offer
++    to distribute corresponding source code.  (This alternative is
++    allowed only for noncommercial distribution and only if you
++    received the program in object code or executable form with such
++    an offer, in accord with Subsection b above.)
++
++The source code for a work means the preferred form of the work for
++making modifications to it.  For an executable work, complete source
++code means all the source code for all modules it contains, plus any
++associated interface definition files, plus the scripts used to
++control compilation and installation of the executable.  However, as a
++special exception, the source code distributed need not include
++anything that is normally distributed (in either source or binary
++form) with the major components (compiler, kernel, and so on) of the
++operating system on which the executable runs, unless that component
++itself accompanies the executable.
++
++If distribution of executable or object code is made by offering
++access to copy from a designated place, then offering equivalent
++access to copy the source code from the same place counts as
++distribution of the source code, even though third parties are not
++compelled to copy the source along with the object code.
++
++  4. You may not copy, modify, sublicense, or distribute the Program
++except as expressly provided under this License.  Any attempt
++otherwise to copy, modify, sublicense or distribute the Program is
++void, and will automatically terminate your rights under this License.
++However, parties who have received copies, or rights, from you under
++this License will not have their licenses terminated so long as such
++parties remain in full compliance.
++
++  5. You are not required to accept this License, since you have not
++signed it.  However, nothing else grants you permission to modify or
++distribute the Program or its derivative works.  These actions are
++prohibited by law if you do not accept this License.  Therefore, by
++modifying or distributing the Program (or any work based on the
++Program), you indicate your acceptance of this License to do so, and
++all its terms and conditions for copying, distributing or modifying
++the Program or works based on it.
++
++  6. Each time you redistribute the Program (or any work based on the
++Program), the recipient automatically receives a license from the
++original licensor to copy, distribute or modify the Program subject to
++these terms and conditions.  You may not impose any further
++restrictions on the recipients' exercise of the rights granted herein.
++You are not responsible for enforcing compliance by third parties to
++this License.
++
++  7. If, as a consequence of a court judgment or allegation of patent
++infringement or for any other reason (not limited to patent issues),
++conditions are imposed on you (whether by court order, agreement or
++otherwise) that contradict the conditions of this License, they do not
++excuse you from the conditions of this License.  If you cannot
++distribute so as to satisfy simultaneously your obligations under this
++License and any other pertinent obligations, then as a consequence you
++may not distribute the Program at all.  For example, if a patent
++license would not permit royalty-free redistribution of the Program by
++all those who receive copies directly or indirectly through you, then
++the only way you could satisfy both it and this License would be to
++refrain entirely from distribution of the Program.
++
++If any portion of this section is held invalid or unenforceable under
++any particular circumstance, the balance of the section is intended to
++apply and the section as a whole is intended to apply in other
++circumstances.
++
++It is not the purpose of this section to induce you to infringe any
++patents or other property right claims or to contest validity of any
++such claims; this section has the sole purpose of protecting the
++integrity of the free software distribution system, which is
++implemented by public license practices.  Many people have made
++generous contributions to the wide range of software distributed
++through that system in reliance on consistent application of that
++system; it is up to the author/donor to decide if he or she is willing
++to distribute software through any other system and a licensee cannot
++impose that choice.
++
++This section is intended to make thoroughly clear what is believed to
++be a consequence of the rest of this License.
++
++  8. If the distribution and/or use of the Program is restricted in
++certain countries either by patents or by copyrighted interfaces, the
++original copyright holder who places the Program under this License
++may add an explicit geographical distribution limitation excluding
++those countries, so that distribution is permitted only in or among
++countries not thus excluded.  In such case, this License incorporates
++the limitation as if written in the body of this License.
++
++  9. The Free Software Foundation may publish revised and/or new versions
++of the General Public License from time to time.  Such new versions will
++be similar in spirit to the present version, but may differ in detail to
++address new problems or concerns.
++
++Each version is given a distinguishing version number.  If the Program
++specifies a version number of this License which applies to it and "any
++later version", you have the option of following the terms and conditions
++either of that version or of any later version published by the Free
++Software Foundation.  If the Program does not specify a version number of
++this License, you may choose any version ever published by the Free Software
++Foundation.
++
++  10. If you wish to incorporate parts of the Program into other free
++programs whose distribution conditions are different, write to the author
++to ask for permission.  For software which is copyrighted by the Free
++Software Foundation, write to the Free Software Foundation; we sometimes
++make exceptions for this.  Our decision will be guided by the two goals
++of preserving the free status of all derivatives of our free software and
++of promoting the sharing and reuse of software generally.
++
++			    NO WARRANTY
++
++  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
++REPAIR OR CORRECTION.
++
++  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
++POSSIBILITY OF SUCH DAMAGES.
++
++		     END OF TERMS AND CONDITIONS
++
++	    How to Apply These Terms to Your New Programs
++
++  If you develop a new program, and you want it to be of the greatest
++possible use to the public, the best way to achieve this is to make it
++free software which everyone can redistribute and change under these terms.
++
++  To do so, attach the following notices to the program.  It is safest
++to attach them to the start of each source file to most effectively
++convey the exclusion of warranty; and each file should have at least
++the "copyright" line and a pointer to where the full notice is found.
++
++    <one line to give the program's name and a brief idea of what it does.>
++    Copyright (C) 19yy  <name of author>
++
++    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++
++
++Also add information on how to contact you by electronic and paper mail.
++
++If the program is interactive, make it output a short notice like this
++when it starts in an interactive mode:
++
++    Gnomovision version 69, Copyright (C) 19yy name of author
++    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
++    This is free software, and you are welcome to redistribute it
++    under certain conditions; type `show c' for details.
++
++The hypothetical commands `show w' and `show c' should show the appropriate
++parts of the General Public License.  Of course, the commands you use may
++be called something other than `show w' and `show c'; they could even be
++mouse-clicks or menu items--whatever suits your program.
++
++You should also get your employer (if you work as a programmer) or your
++school, if any, to sign a "copyright disclaimer" for the program, if
++necessary.  Here is a sample; alter the names:
++
++  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
++  `Gnomovision' (which makes passes at compilers) written by James Hacker.
++
++  <signature of Ty Coon>, 1 April 1989
++  Ty Coon, President of Vice
++
++This General Public License does not permit incorporating your program into
++proprietary programs.  If your program is a subroutine library, you may
++consider it more useful to permit linking proprietary applications with the
++library.  If this is what you want to do, use the GNU Library General
++Public License instead of this License.
+diff -urNad zaptel-1.2.3/cwain/Makefile /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/Makefile
+--- zaptel-1.2.3/cwain/Makefile	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/Makefile	2006-02-02 18:48:02.000000000 +0200
+@@ -0,0 +1,90 @@
++KINCLUDES = /usr/src/linux/include
++BRISTUFFBASE = $(shell dirname `pwd`)
++
++ZAP = $(shell [ -f $(BRISTUFFBASE)/zaptel-1.2.3/zaptel.h ] && echo "-I$(BRISTUFFBASE)/zaptel-1.2.3")
++
++HOSTCC=gcc
++
++CFLAGS+=-I. $(ZAP) -O4 -g -Wall #-DBLINKYBLINK
++CFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi)
++
++KFLAGS=-D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -fomit-frame-pointer -O2 -Wall -I$(KINCLUDES) $(ZAP)
++KFLAGS+=$(shell [ -f $(KINCLUDES)/linux/modversions.h ] && echo "-DMODVERSIONS -include $(KINCLUDES)/linux/modversions.h")
++KFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-msoft-float -fsigned-char"; fi)
++
++OBJS=cwain.o
++
++BUILDVER=$(shell if uname -r | grep -q ^2.6; then echo "linux26"; else echo "linux24"; fi)
++
++MODCONF=$(shell if [ -d $(INSTALL_PREFIX)/etc/modprobe.d ]; then echo "$(INSTALL_PREFIX)/etc/modprobe.d/zaptel"; elif [ -d $(INSTALL_PREFIX)/etc/modutils ]; then echo "$(INSTALL_PREFIX)/etc/modutils/zaptel"; elif [ -f $(INSTALL_PREFIX)/etc/modprobe.conf ]; then echo "$(INSTALL_PREFIX)/modprobe.conf"; elif [ -f $(INSTALL_PREFIX)/etc/modules.conf ]; then echo "$(INSTALL_PREFIX)/etc/modules.conf"; else echo $(INSTALL_PREFIX)/etc/conf.modules ; fi)
++
++MODULES=cwain
++
++MODULESO=$(shell for x in $(MODULES); do echo "$$x.o "; done )
++MODULESKO=$(shell for x in $(MODULES); do echo "$$x.ko "; done )
++
++PWD=$(shell pwd)
++
++obj-m := $(MODULESO)
++
++all: $(BUILDVER)
++
++linux24: $(OBJS)
++	sync
++
++linux26:
++	@if ! [ -d /usr/src/linux-2.6 ]; then echo "Link /usr/src/linux-2.6 to your kernel sources first!"; exit 1 ; fi
++	make -C /usr/src/linux-2.6 SUBDIRS=$(PWD) ZAP=$(ZAP) modules
++obj-m := $(OBJS)
++
++cwain.o: cwain.c cwain.h 
++	$(CC) -c cwain.c $(KFLAGS)
++
++clean:	
++	rm -f $(OBJS) *.ko *.mod.c *.mod.o .*o.cmd *~
++	
++testlinux24: all
++	modprobe zaptel
++	insmod ./cwain.o
++	ztcfg -v
++	cat /proc/interrupts
++	sleep 1
++	cat /proc/interrupts
++	rmmod cwain zaptel
++
++testlinux26: all
++	modprobe zaptel
++	insmod ./cwain.ko
++	ztcfg -v
++	cat /proc/interrupts
++	sleep 5
++	cat /proc/interrupts
++	rmmod cwain zaptel
++
++reload:	unload load
++load:	load$(BUILDVER)
++
++test:	test$(BUILDVER)
++
++
++loadlinux24: linux24
++	modprobe zaptel
++	insmod ./cwain.o
++	ztcfg -v
++
++loadlinux26: linux26
++	sync
++	modprobe zaptel
++	insmod ./cwain.ko debug=1
++	ztcfg -v
++
++install:	install$(BUILDVER)
++
++installlinux26:
++	install -D -m 644 cwain.ko $(INSTALL_PREFIX)/lib/modules/`uname -r`/misc/cwain.ko
++
++installlinux24:
++	install -D -m 644 cwain.o $(INSTALL_PREFIX)/lib/modules/`uname -r`/misc/cwain.o
++
++unload: 
++	rmmod cwain zaptel
+diff -urNad zaptel-1.2.3/cwain/TODO /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/TODO
+--- zaptel-1.2.3/cwain/TODO	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/TODO	2005-09-26 09:59:05.000000000 +0300
+@@ -0,0 +1 @@
++
+diff -urNad zaptel-1.2.3/cwain/zaptel.conf /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/zaptel.conf
+--- zaptel-1.2.3/cwain/zaptel.conf	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/cwain/zaptel.conf	2005-10-27 11:26:41.000000000 +0200
+@@ -0,0 +1,11 @@
++loadzone=nl
++defaultzone=nl
++span=1,2,3,ccs,hdb3,crc4
++
++alaw=1-31
++
++bchan=1-15
++dchan=16
++bchan=17-31
++
++
+diff -urNad zaptel-1.2.3/qozap/LICENSE /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/LICENSE
+--- zaptel-1.2.3/qozap/LICENSE	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/LICENSE	2005-06-13 10:03:36.000000000 +0300
+@@ -0,0 +1,341 @@
++
++		    GNU GENERAL PUBLIC LICENSE
++		       Version 2, June 1991
++
++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
++                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++			    Preamble
++
++  The licenses for most software are designed to take away your
++freedom to share and change it.  By contrast, the GNU General Public
++License is intended to guarantee your freedom to share and change free
++software--to make sure the software is free for all its users.  This
++General Public License applies to most of the Free Software
++Foundation's software and to any other program whose authors commit to
++using it.  (Some other Free Software Foundation software is covered by
++the GNU Library General Public License instead.)  You can apply it to
++your programs, too.
++
++  When we speak of free software, we are referring to freedom, not
++price.  Our General Public Licenses are designed to make sure that you
++have the freedom to distribute copies of free software (and charge for
++this service if you wish), that you receive source code or can get it
++if you want it, that you can change the software or use pieces of it
++in new free programs; and that you know you can do these things.
++
++  To protect your rights, we need to make restrictions that forbid
++anyone to deny you these rights or to ask you to surrender the rights.
++These restrictions translate to certain responsibilities for you if you
++distribute copies of the software, or if you modify it.
++
++  For example, if you distribute copies of such a program, whether
++gratis or for a fee, you must give the recipients all the rights that
++you have.  You must make sure that they, too, receive or can get the
++source code.  And you must show them these terms so they know their
++rights.
++
++  We protect your rights with two steps: (1) copyright the software, and
++(2) offer you this license which gives you legal permission to copy,
++distribute and/or modify the software.
++
++  Also, for each author's protection and ours, we want to make certain
++that everyone understands that there is no warranty for this free
++software.  If the software is modified by someone else and passed on, we
++want its recipients to know that what they have is not the original, so
++that any problems introduced by others will not reflect on the original
++authors' reputations.
++
++  Finally, any free program is threatened constantly by software
++patents.  We wish to avoid the danger that redistributors of a free
++program will individually obtain patent licenses, in effect making the
++program proprietary.  To prevent this, we have made it clear that any
++patent must be licensed for everyone's free use or not licensed at all.
++
++  The precise terms and conditions for copying, distribution and
++modification follow.
++
++		    GNU GENERAL PUBLIC LICENSE
++   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++
++  0. This License applies to any program or other work which contains
++a notice placed by the copyright holder saying it may be distributed
++under the terms of this General Public License.  The "Program", below,
++refers to any such program or work, and a "work based on the Program"
++means either the Program or any derivative work under copyright law:
++that is to say, a work containing the Program or a portion of it,
++either verbatim or with modifications and/or translated into another
++language.  (Hereinafter, translation is included without limitation in
++the term "modification".)  Each licensee is addressed as "you".
++
++Activities other than copying, distribution and modification are not
++covered by this License; they are outside its scope.  The act of
++running the Program is not restricted, and the output from the Program
++is covered only if its contents constitute a work based on the
++Program (independent of having been made by running the Program).
++Whether that is true depends on what the Program does.
++
++  1. You may copy and distribute verbatim copies of the Program's
++source code as you receive it, in any medium, provided that you
++conspicuously and appropriately publish on each copy an appropriate
++copyright notice and disclaimer of warranty; keep intact all the
++notices that refer to this License and to the absence of any warranty;
++and give any other recipients of the Program a copy of this License
++along with the Program.
++
++You may charge a fee for the physical act of transferring a copy, and
++you may at your option offer warranty protection in exchange for a fee.
++
++  2. You may modify your copy or copies of the Program or any portion
++of it, thus forming a work based on the Program, and copy and
++distribute such modifications or work under the terms of Section 1
++above, provided that you also meet all of these conditions:
++
++    a) You must cause the modified files to carry prominent notices
++    stating that you changed the files and the date of any change.
++
++    b) You must cause any work that you distribute or publish, that in
++    whole or in part contains or is derived from the Program or any
++    part thereof, to be licensed as a whole at no charge to all third
++    parties under the terms of this License.
++
++    c) If the modified program normally reads commands interactively
++    when run, you must cause it, when started running for such
++    interactive use in the most ordinary way, to print or display an
++    announcement including an appropriate copyright notice and a
++    notice that there is no warranty (or else, saying that you provide
++    a warranty) and that users may redistribute the program under
++    these conditions, and telling the user how to view a copy of this
++    License.  (Exception: if the Program itself is interactive but
++    does not normally print such an announcement, your work based on
++    the Program is not required to print an announcement.)
++
++These requirements apply to the modified work as a whole.  If
++identifiable sections of that work are not derived from the Program,
++and can be reasonably considered independent and separate works in
++themselves, then this License, and its terms, do not apply to those
++sections when you distribute them as separate works.  But when you
++distribute the same sections as part of a whole which is a work based
++on the Program, the distribution of the whole must be on the terms of
++this License, whose permissions for other licensees extend to the
++entire whole, and thus to each and every part regardless of who wrote it.
++
++Thus, it is not the intent of this section to claim rights or contest
++your rights to work written entirely by you; rather, the intent is to
++exercise the right to control the distribution of derivative or
++collective works based on the Program.
++
++In addition, mere aggregation of another work not based on the Program
++with the Program (or with a work based on the Program) on a volume of
++a storage or distribution medium does not bring the other work under
++the scope of this License.
++
++  3. You may copy and distribute the Program (or a work based on it,
++under Section 2) in object code or executable form under the terms of
++Sections 1 and 2 above provided that you also do one of the following:
++
++    a) Accompany it with the complete corresponding machine-readable
++    source code, which must be distributed under the terms of Sections
++    1 and 2 above on a medium customarily used for software interchange; or,
++
++    b) Accompany it with a written offer, valid for at least three
++    years, to give any third party, for a charge no more than your
++    cost of physically performing source distribution, a complete
++    machine-readable copy of the corresponding source code, to be
++    distributed under the terms of Sections 1 and 2 above on a medium
++    customarily used for software interchange; or,
++
++    c) Accompany it with the information you received as to the offer
++    to distribute corresponding source code.  (This alternative is
++    allowed only for noncommercial distribution and only if you
++    received the program in object code or executable form with such
++    an offer, in accord with Subsection b above.)
++
++The source code for a work means the preferred form of the work for
++making modifications to it.  For an executable work, complete source
++code means all the source code for all modules it contains, plus any
++associated interface definition files, plus the scripts used to
++control compilation and installation of the executable.  However, as a
++special exception, the source code distributed need not include
++anything that is normally distributed (in either source or binary
++form) with the major components (compiler, kernel, and so on) of the
++operating system on which the executable runs, unless that component
++itself accompanies the executable.
++
++If distribution of executable or object code is made by offering
++access to copy from a designated place, then offering equivalent
++access to copy the source code from the same place counts as
++distribution of the source code, even though third parties are not
++compelled to copy the source along with the object code.
++
++  4. You may not copy, modify, sublicense, or distribute the Program
++except as expressly provided under this License.  Any attempt
++otherwise to copy, modify, sublicense or distribute the Program is
++void, and will automatically terminate your rights under this License.
++However, parties who have received copies, or rights, from you under
++this License will not have their licenses terminated so long as such
++parties remain in full compliance.
++
++  5. You are not required to accept this License, since you have not
++signed it.  However, nothing else grants you permission to modify or
++distribute the Program or its derivative works.  These actions are
++prohibited by law if you do not accept this License.  Therefore, by
++modifying or distributing the Program (or any work based on the
++Program), you indicate your acceptance of this License to do so, and
++all its terms and conditions for copying, distributing or modifying
++the Program or works based on it.
++
++  6. Each time you redistribute the Program (or any work based on the
++Program), the recipient automatically receives a license from the
++original licensor to copy, distribute or modify the Program subject to
++these terms and conditions.  You may not impose any further
++restrictions on the recipients' exercise of the rights granted herein.
++You are not responsible for enforcing compliance by third parties to
++this License.
++
++  7. If, as a consequence of a court judgment or allegation of patent
++infringement or for any other reason (not limited to patent issues),
++conditions are imposed on you (whether by court order, agreement or
++otherwise) that contradict the conditions of this License, they do not
++excuse you from the conditions of this License.  If you cannot
++distribute so as to satisfy simultaneously your obligations under this
++License and any other pertinent obligations, then as a consequence you
++may not distribute the Program at all.  For example, if a patent
++license would not permit royalty-free redistribution of the Program by
++all those who receive copies directly or indirectly through you, then
++the only way you could satisfy both it and this License would be to
++refrain entirely from distribution of the Program.
++
++If any portion of this section is held invalid or unenforceable under
++any particular circumstance, the balance of the section is intended to
++apply and the section as a whole is intended to apply in other
++circumstances.
++
++It is not the purpose of this section to induce you to infringe any
++patents or other property right claims or to contest validity of any
++such claims; this section has the sole purpose of protecting the
++integrity of the free software distribution system, which is
++implemented by public license practices.  Many people have made
++generous contributions to the wide range of software distributed
++through that system in reliance on consistent application of that
++system; it is up to the author/donor to decide if he or she is willing
++to distribute software through any other system and a licensee cannot
++impose that choice.
++
++This section is intended to make thoroughly clear what is believed to
++be a consequence of the rest of this License.
++
++  8. If the distribution and/or use of the Program is restricted in
++certain countries either by patents or by copyrighted interfaces, the
++original copyright holder who places the Program under this License
++may add an explicit geographical distribution limitation excluding
++those countries, so that distribution is permitted only in or among
++countries not thus excluded.  In such case, this License incorporates
++the limitation as if written in the body of this License.
++
++  9. The Free Software Foundation may publish revised and/or new versions
++of the General Public License from time to time.  Such new versions will
++be similar in spirit to the present version, but may differ in detail to
++address new problems or concerns.
++
++Each version is given a distinguishing version number.  If the Program
++specifies a version number of this License which applies to it and "any
++later version", you have the option of following the terms and conditions
++either of that version or of any later version published by the Free
++Software Foundation.  If the Program does not specify a version number of
++this License, you may choose any version ever published by the Free Software
++Foundation.
++
++  10. If you wish to incorporate parts of the Program into other free
++programs whose distribution conditions are different, write to the author
++to ask for permission.  For software which is copyrighted by the Free
++Software Foundation, write to the Free Software Foundation; we sometimes
++make exceptions for this.  Our decision will be guided by the two goals
++of preserving the free status of all derivatives of our free software and
++of promoting the sharing and reuse of software generally.
++
++			    NO WARRANTY
++
++  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
++REPAIR OR CORRECTION.
++
++  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
++POSSIBILITY OF SUCH DAMAGES.
++
++		     END OF TERMS AND CONDITIONS
++
++	    How to Apply These Terms to Your New Programs
++
++  If you develop a new program, and you want it to be of the greatest
++possible use to the public, the best way to achieve this is to make it
++free software which everyone can redistribute and change under these terms.
++
++  To do so, attach the following notices to the program.  It is safest
++to attach them to the start of each source file to most effectively
++convey the exclusion of warranty; and each file should have at least
++the "copyright" line and a pointer to where the full notice is found.
++
++    <one line to give the program's name and a brief idea of what it does.>
++    Copyright (C) 19yy  <name of author>
++
++    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++
++
++Also add information on how to contact you by electronic and paper mail.
++
++If the program is interactive, make it output a short notice like this
++when it starts in an interactive mode:
++
++    Gnomovision version 69, Copyright (C) 19yy name of author
++    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
++    This is free software, and you are welcome to redistribute it
++    under certain conditions; type `show c' for details.
++
++The hypothetical commands `show w' and `show c' should show the appropriate
++parts of the General Public License.  Of course, the commands you use may
++be called something other than `show w' and `show c'; they could even be
++mouse-clicks or menu items--whatever suits your program.
++
++You should also get your employer (if you work as a programmer) or your
++school, if any, to sign a "copyright disclaimer" for the program, if
++necessary.  Here is a sample; alter the names:
++
++  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
++  `Gnomovision' (which makes passes at compilers) written by James Hacker.
++
++  <signature of Ty Coon>, 1 April 1989
++  Ty Coon, President of Vice
++
++This General Public License does not permit incorporating your program into
++proprietary programs.  If your program is a subroutine library, you may
++consider it more useful to permit linking proprietary applications with the
++library.  If this is what you want to do, use the GNU Library General
++Public License instead of this License.
+diff -urNad zaptel-1.2.3/qozap/Makefile /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/Makefile
+--- zaptel-1.2.3/qozap/Makefile	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/Makefile	2006-02-02 18:47:49.000000000 +0200
+@@ -0,0 +1,91 @@
++KINCLUDES = /usr/src/linux/include
++BRISTUFFBASE = $(shell dirname `pwd`)
++
++ZAP = $(shell [ -f $(BRISTUFFBASE)/zaptel-1.2.3/zaptel.h ] && echo "-I$(BRISTUFFBASE)/zaptel-1.2.3")
++
++HOSTCC=gcc
++
++CFLAGS+=-I. $(ZAP) -O4 -g -Wall -DBUILDING_TONEZONE  #-DTONEZONE_DRIVER
++CFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi)
++
++KFLAGS=-D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -fomit-frame-pointer -O2 -Wall -I$(KINCLUDES) $(ZAP)
++KFLAGS+=$(shell [ -f $(KINCLUDES)/linux/modversions.h ] && echo "-DMODVERSIONS -include $(KINCLUDES)/linux/modversions.h")
++KFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-msoft-float -fsigned-char"; fi)
++
++OBJS=qozap.o
++
++BUILDVER=$(shell if uname -r | grep -q ^2.6; then echo "linux26"; else echo "linux24"; fi)
++
++MODCONF=$(shell if [ -d $(INSTALL_PREFIX)/etc/modprobe.d ]; then echo "$(INSTALL_PREFIX)/etc/modprobe.d/zaptel"; elif [ -d $(INSTALL_PREFIX)/etc/modutils ]; then echo "$(INSTALL_PREFIX)/etc/modutils/zaptel"; elif [ -f $(INSTALL_PREFIX)/etc/modprobe.conf ]; then echo "$(INSTALL_PREFIX)/modprobe.conf"; elif [ -f $(INSTALL_PREFIX)/etc/modules.conf ]; then echo "$(INSTALL_PREFIX)/etc/modules.conf"; else echo $(INSTALL_PREFIX)/etc/conf.modules ; fi)
++
++MODULES=qozap
++
++MODULESO=$(shell for x in $(MODULES); do echo "$$x.o "; done )
++MODULESKO=$(shell for x in $(MODULES); do echo "$$x.ko "; done )
++
++PWD=$(shell pwd)
++
++obj-m := $(MODULESO)
++
++all: $(BUILDVER)
++
++linux24: $(OBJS)
++	sync
++
++linux26:
++	@if ! [ -d /usr/src/linux-2.6 ]; then echo "Link /usr/src/linux-2.6 to your kernel sources first!"; exit 1 ; fi
++	make -C /usr/src/linux-2.6 SUBDIRS=$(PWD) ZAP=$(ZAP) modules
++obj-m := $(OBJS)
++
++qozap.o: qozap.c qozap.h 
++	$(CC) -c qozap.c $(KFLAGS)
++
++clean:	
++	rm -f $(OBJS) *.ko *.mod.c *.mod.o .*o.cmd *~
++	rm -rf .tmp_versions
++
++testlinux24: all
++	modprobe zaptel
++	insmod ./qozap.o
++	ztcfg -v
++	cat /proc/interrupts
++	sleep 1
++	cat /proc/interrupts
++	rmmod qozap zaptel
++
++testlinux26: all
++	modprobe zaptel
++	insmod ./qozap.ko
++	ztcfg -v
++	cat /proc/interrupts
++	sleep 1
++	cat /proc/interrupts
++	rmmod qozap zaptel
++
++reload:	unload load
++load:	load$(BUILDVER)
++
++test:	test$(BUILDVER)
++
++
++loadlinux24: linux24
++	modprobe zaptel
++	insmod ./qozap.o
++	ztcfg -v
++
++loadlinux26: linux26
++	sync
++	modprobe zaptel
++	insmod ./qozap.ko
++	ztcfg -v
++
++unload: 
++	rmmod qozap zaptel
++
++install:	install$(BUILDVER)
++
++installlinux26:
++	install -D -m 644 qozap.ko $(INSTALL_PREFIX)/lib/modules/`uname -r`/misc/qozap.ko
++
++installlinux24:
++	install -D -m 644 qozap.o $(INSTALL_PREFIX)/lib/modules/`uname -r`/misc/qozap.o
+diff -urNad zaptel-1.2.3/qozap/qozap.c /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/qozap.c
+--- zaptel-1.2.3/qozap/qozap.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/qozap.c	2005-08-01 09:58:20.000000000 +0300
+@@ -0,0 +1,1493 @@
++/*
++ * qozap.c - Zaptel driver for the quadBRI PCI ISDN card
++ * and the octoBRI PCI ISDN card!
++ *
++ * Copyright (C) 2003, 2004, 2005 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"
++
++#if CONFIG_PCI
++
++static int doubleclock=0;
++static int ports=-1; /* autodetect */
++static int bloop=0;
++static int debug=0;
++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 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);
++
++    if (qoztmp->ztdev != NULL) {
++	stports = qoztmp->stports;
++	for (s=0; s < stports; s++) {
++	    if(qoztmp->ztdev->spans[s].flags & ZT_FLAG_RUNNING) {
++		ztqoz_shutdown(&qoztmp->ztdev->spans[s]);
++		if (debug)
++		    printk(KERN_INFO "qozap: shutdown card %d span %d.\n",qoztmp->cardno,s+1);
++	    }
++	}
++    }
++
++    spin_lock_irqsave(&qoztmp->lock,flags);
++
++    // turn off irqs
++    qoz_outb(qoztmp,qoz_R_IRQ_CTRL, 0); 
++    qoz_outb(qoztmp,qoz_R_IRQMSK_MISC, 0); 
++    qoz_outb(qoztmp,qoz_R_SCI_MSK, 0); 
++
++    free_irq(qoztmp->irq,qoztmp);
++
++    // softreset
++    qoz_outb(qoztmp,qoz_R_CIRM,0x8);
++    qoz_outb(qoztmp,qoz_R_CIRM,0x0); 
++    qoz_waitbusy(qoztmp);
++
++    qoz_outb(qoztmp,qoz_R_IRQMSK_MISC, 0); 
++    qoz_outb(qoztmp,qoz_R_SCI_MSK, 0); 
++    qoz_outb(qoztmp,qoz_R_IRQ_CTRL, 0); 
++
++    release_region(qoztmp->ioport, 7);
++    iounmap((void *) qoztmp->pci_io);
++
++    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);	
++    
++    spin_unlock_irqrestore(&qoztmp->lock,flags);
++
++    if (qoztmp->ztdev != NULL) {
++	stports = qoztmp->stports;
++	for (s=0; s < stports; s++) {
++	    if(qoztmp->ztdev->spans[s].flags & ZT_FLAG_REGISTERED) {
++		zt_unregister(&qoztmp->ztdev->spans[s]);
++		if (debug)
++		    printk(KERN_INFO "qozap: unregistered card %d span %d.\n",qoztmp->cardno,s+1);
++	    }
++	}
++	kfree(qoztmp->ztdev);
++	qoztmp->ztdev = NULL;
++    }
++}
++
++void qoz_doLEDs(struct qoz_card *qoztmp) {
++    unsigned char leds = 0x0;
++    if ((qoztmp->type == 0xb520) && (qoztmp->stports == 4)){
++//	if ((qoztmp->ticks > 0) && (qoztmp->ticks <= 300)) {
++	    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)));
++/*	}
++	if ((qoztmp->ticks > 300) && (qoztmp->ticks <= 600)) {
++    	    qoz_outb(qoztmp,qoz_R_GPIO_EN1,0x0);
++	} */
++    } else if ((qoztmp->type == 0xb550) && (qoztmp->stports == 4)){
++	    qoz_outb(qoztmp,qoz_R_GPIO_SEL,0x80 | 0x40 | 0x20 | 0x10);
++    	    qoz_outb(qoztmp,qoz_R_GPIO_EN1,0xff);
++	    if (qoztmp->leds[0] == 0) {
++		leds |= 0x80;
++	    } else {
++		leds |= 0x40;
++	    }
++	    if (qoztmp->leds[1] == 0) {
++		leds |= 0x10;
++	    } else {
++		leds |= 0x20;
++	    }
++	    if (qoztmp->leds[2] == 0) {
++		leds |= 0x04;
++	    } else {
++		leds |= 0x08;
++	    }
++	    if (qoztmp->leds[3] == 0) {
++		leds |= 0x02;
++	    } else {
++		leds |= 0x01;
++	    }
++    /* 	0x80 st1g
++	0x40 st1r
++	0x20 st2r
++	0x10 st2g	
++	0x08 st3r
++	0x04 st3g
++	0x02 st4g
++	0x01 st4r
++    */
++	    qoz_outb(qoztmp,qoz_R_GPIO_OUT1, leds);
++    }
++}
++
++void qoz_doWD(struct qoz_card *qoztmp) {
++    if (!qoztmp->wdp) {
++	return;
++    }
++    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);    
++}
++
++void qoz_undoWD(struct qoz_card *qoztmp) {
++    printk(KERN_INFO "qozap: Stopping hardware watchdog.\n");
++    qoz_outdw_io(qoztmp,0x4000, qoz_WD_P0);
++    qoztmp->wdp = 0;
++    qoz_inb_io(qoztmp,qoz_R_CHIP_ID);    
++}
++
++void qoz_resetCard(struct qoz_card *qoztmp) {
++    unsigned long flags;
++    unsigned char i=0;
++    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);
++
++    // 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 {
++	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); 
++    qoz_outb(qoztmp,qoz_R_PCM_MD0, 0x1);
++
++    /* all state changes */
++    qoz_outb(qoztmp,qoz_R_SCI_MSK, 0xff); 
++
++    if (qoztmp->type == 0xb552) {
++        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,0x23); 
++	} else if (qoztmp->type == 0xb520) {
++	    qoz_outb(qoztmp,qoz_R_BRG_PCM_CFG,0x20); 
++	} 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;
++
++    /* Finally enable IRQ output */
++    qoz_outb(qoztmp,qoz_R_IRQ_CTRL, 0x8 | 0x1); 
++    if (qoztmp->type == 0xb552) {
++	qoztmp->stports = 8;
++    } else {
++	qoztmp->stports = 4;
++    }
++    qoztmp->ticks = 0;
++    qoztmp->clicks = 0;
++    if (qoztmp->type == 0xb550) {
++	printk(KERN_INFO "qozap: Starting hardware watchdog.\n");
++	qoztmp->wdp = 2;
++    } else {
++	qoztmp->wdp = 0;
++    }
++
++    for (i=0;i<qoztmp->stports;i++) {
++	if (qoztmp->st[i].nt_mode) {
++	    qoz_outb(qoztmp,qoz_R_ST_SYNC,0x8 | i);
++	    if (debug)
++		printk(KERN_INFO "qoztmp: using NT port %d for sync\n", i);
++	    break;
++	}
++    }
++    if (i == qoztmp->stports) {
++	qoz_outb(qoztmp,qoz_R_ST_SYNC,0x0);
++    }
++    spin_unlock_irqrestore(&(qoztmp->lock),flags);
++}
++
++void qoz_registerCard(struct qoz_card *qozcard) {
++    spin_lock(&registerlock);
++    if (qozcard != NULL) {
++	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;
++
++    if (qoztmp->type == 0xb552) {
++	offset = 24;
++    } else {
++	offset = 28;
++    }
++
++    fifo = stport + offset;
++
++    if (qoztmp->ztdev->chans[stport][chan].bytes2transmit < 1) {
++	return 0;
++    } else {
++	/* 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->ztdev->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->ztdev->chans[stport][chan].bytes2transmit);
++
++	if (qoztmp->ztdev->chans[stport][chan].eoftx == 1) {
++	    /* transmit HDLC frame */
++    	    qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x1);    
++    	    qoz_waitbusy(qoztmp);
++	}
++    }
++    return 0;
++}
++
++static int qoz_fifo_tx(struct qoz_card *qoztmp, char fifo) {
++    int stport = fifo / 2;
++    int chan = fifo % 2;
++
++    /* 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]));
++	    
++    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;
++
++    if (qoztmp->type == 0xb552) {
++	offset = 24;
++    } else {
++	offset = 28;
++    }
++
++    fifo = stport + offset;
++    // 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->ztdev->chans[stport][2].bytes2receive = 0;
++	return 0;
++    }
++    
++    while ((oz1 != z1) && (oz2 != z2)) {
++        oz1 = z1;
++        oz2 = z2;
++	if (qoztmp->type != 0xb552) {
++    	    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) {
++	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->ztdev->chans[stport][2].bytes2receive = 0;
++	qoztmp->ztdev->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->ztdev->chans[stport][2].bytes2receive = i;
++	qoztmp->ztdev->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->ztdev->chans[stport][2].bytes2receive = 0;
++	qoztmp->ztdev->chans[stport][2].eofrx = 0;
++//        zt_qevent_nolock(&qoztmp->ztdev->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;
++    }
++    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;
++
++        /* 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 > 1) || (debug == 4)) {
++		printk(KERN_CRIT "qozap: dropped audio card %d cardid %d bytes %d z1 %d z2 %d\n", qoztmp->cardno, qoztmp->cardID, mumbojumbo, z1, z2);
++		qoztmp->clicks = 0;
++	    }
++	}
++	if (len < ZT_CHUNKSIZE) {
++//	    printk(KERN_INFO "qozap: not enough to receive (%d bytes)\n",len);
++	    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);
++	    }
++	}
++	if (bloop == 0)
++	    zt_ec_chunk(&qoztmp->ztdev->spans[stport].chans[chan], qoztmp->ztdev->spans[stport].chans[chan].readchunk, qoztmp->ztdev->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 inline void qoz_run(struct qoz_card *qoztmp) {
++    int s=0;
++    if (qoztmp->ztdev != NULL) {
++	for (s=0;s<qoztmp->stports;s++) {
++	if (!bloop) {
++	    if (qoztmp->ztdev->spans[s].flags & ZT_FLAG_RUNNING) {
++		/* oh zaptel! tell us what to transmit... */
++    		zt_transmit(&qoztmp->ztdev->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->ztdev->chans[s][2].bytes2transmit > 0) && (qoztmp->st[s].nt_mode != 1)) {
++		    if (qoztmp->st[s].t3 == -1) {
++			printk(KERN_INFO "qozap: activating layer 1, span %d\n",s);
++			qoztmp->st[s].t3 = 0;
++			qoz_outb(qoztmp,qoz_R_ST_SEL, s);
++			qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x60); 
++		    } else {
++		    }
++		}
++		
++		/* D xmit */
++		if (qoztmp->ztdev->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 */
++			printk(KERN_INFO "qozap: clearing alarms on span %d\n",s);
++			qoztmp->ztdev->spans[s].alarms = ZT_ALARM_NONE;
++			zt_alarm_notify(&qoztmp->ztdev->spans[s]);
++		    }
++		}
++
++		qoztmp->ztdev->chans[s][2].bytes2receive = 0;
++		qoztmp->ztdev->chans[s][2].bytes2transmit = 0;
++		qoztmp->ztdev->chans[s][2].eofrx = 0;
++		qoztmp->ztdev->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->ztdev->spans[s].flags & ZT_FLAG_RUNNING) {
++	        /* oh zaptel! thou shall receive! */
++		zt_receive(&(qoztmp->ztdev->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->ztdev->spans[s].flags & ZT_FLAG_RUNNING) {
++		zt_receive(&(qoztmp->ztdev->spans[s]));
++	    }
++*/
++	    if (qoztmp->ztdev->spans[s].flags & ZT_FLAG_RUNNING) {
++		/* oh zaptel! tell us what to transmit... */
++    	//	zt_transmit(&qoztmp->ztdev->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->ztdev->chans[s][2].bytes2receive = 0;
++		qoztmp->ztdev->chans[s][2].bytes2transmit = 0;
++		qoztmp->ztdev->chans[s][2].eofrx = 0;
++		qoztmp->ztdev->chans[s][2].eoftx = 0;
++
++	    }
++	}
++	} 
++    }
++}
++
++#ifdef LINUX26
++static irqreturn_t qoz_interrupt(int irq, void *dev_id, struct pt_regs *regs) {
++#else
++static void qoz_interrupt(int irq, void *dev_id, struct pt_regs *regs) {
++#endif
++    struct qoz_card *qoztmp = dev_id;
++    struct zt_qoz *ztqoz = qoztmp->ztdev;
++    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		
++    }
++    
++    spin_lock_irqsave(&(qoztmp->lock),flags);
++    status = qoz_inb(qoztmp,qoz_R_STATUS);
++    irq_sci = qoz_inb(qoztmp,qoz_R_SCI);
++
++    if (!(status & 0x80) && !(status & 0x40) && (irq_sci == 0)) {
++//	printk(KERN_CRIT "qozap: status %#x\n", status);
++	// it's not us!
++	spin_unlock_irqrestore(&(qoztmp->lock),flags);
++#ifdef LINUX26
++		return IRQ_NONE;
++#else
++		return;
++#endif		
++    }
++    /* state machine irq */
++    if (irq_sci != 0) {
++	if (debug > 1) {
++	    printk(KERN_INFO "R_BERT_STA = %#x\n", qoz_inb(qoztmp, qoz_R_BERT_STA) & 7);
++	}
++	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 "A_ST_RD_STA = %#x\n", 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) {
++			// keep layer1 up!
++			if (qoztmp->stports == 8) {
++			    sprintf(ztqoz->spans[st].desc,"octoBRI PCI ISDN Card %d Span %d [NT] Layer 1 ACTIVATED (G%d)",qoztmp->cardno ,st + 1, l1state);
++			} else {
++			    sprintf(ztqoz->spans[st].desc,"quadBRI PCI ISDN Card %d Span %d [NT] (cardID %d) Layer 1 ACTIVATED (G%d)",qoztmp->cardno ,st + 1,ztqoz->card->cardID, l1state);
++			}
++			qoz_outb(qoztmp,qoz_A_ST_WR_STA,3 | 0x10 );
++			qoztmp->leds[st] = 1;
++		    } else {
++			if (qoztmp->stports == 8) {
++			    sprintf(ztqoz->spans[st].desc,"octoBRI PCI ISDN Card %d Span %d [NT] Layer 1 DEACTIVATED (G%d)",qoztmp->cardno ,st + 1, l1state);
++			} else {
++			    sprintf(ztqoz->spans[st].desc,"quadBRI PCI ISDN Card %d Span %d [NT] (cardID %d) Layer 1 DEACTIVATED (G%d)",qoztmp->cardno ,st + 1,ztqoz->card->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) {
++			if (qoztmp->st[st].t3 > -1)  {
++			    /* keep layer1 up, if the span is started. */
++			    if (qoztmp->ztdev->spans[st].flags & ZT_FLAG_RUNNING) {
++printk("qozap: re-activating layer1 span %d\n", st);
++    				qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x60);
++			    }
++			} else {
++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->ztdev->spans[st].alarms = ZT_ALARM_RED;
++//			    zt_alarm_notify(&qoztmp->ztdev->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(ztqoz->spans[st].desc,"octoBRI PCI ISDN Card %d Span %d [TE] Layer 1 DEACTIVATED (F%d)",qoztmp->cardno ,st + 1, l1state);
++			} else {
++			    sprintf(ztqoz->spans[st].desc,"quadBRI PCI ISDN Card %d Span %d [TE] (cardID %d) Layer 1 DEACTIVATED (F%d)",qoztmp->cardno ,st + 1,ztqoz->card->cardID, l1state);
++			}
++		    } else if (l1state == 7) {
++			/* activation complete, stop timer t3 */
++			qoztmp->st[st].t3 = -1;
++			qoztmp->ztdev->spans[st].alarms = ZT_ALARM_NONE;
++			zt_alarm_notify(&qoztmp->ztdev->spans[st]);
++			qoztmp->leds[st] = 1;
++			if (qoztmp->stports == 8) {
++			    sprintf(ztqoz->spans[st].desc,"octoBRI PCI ISDN Card %d Span %d [TE] Layer 1 ACTIVATED (F%d)",qoztmp->cardno ,st + 1, l1state);
++			} else {
++			    sprintf(ztqoz->spans[st].desc,"quadBRI PCI ISDN Card %d Span %d [TE] (cardID %d) Layer 1 ACTIVATED (F%d)",qoztmp->cardno ,st + 1,ztqoz->card->cardID, l1state);
++			}
++		    } else if (l1state == 8) {
++			/* lost framing */
++			printk(KERN_INFO "qozap: starting t4 for span %d\n", st);
++			qoztmp->st[st].t4 = 0;
++		    } else {
++			if (qoztmp->stports == 8) {
++			    sprintf(ztqoz->spans[st].desc,"octoBRI PCI ISDN Card %d Span %d [TE] Layer 1 DEACTIVATED (F%d)",qoztmp->cardno ,st + 1, l1state);
++			} else {
++			    sprintf(ztqoz->spans[st].desc,"quadBRI PCI ISDN Card %d Span %d [TE] (cardID %d) Layer 1 DEACTIVATED (F%d)",qoztmp->cardno ,st + 1,ztqoz->card->cardID, l1state);
++			}    
++		    }
++		}
++		
++	    }
++	}
++    }
++
++
++    // misc irq
++    if (status & 0x40) {
++	irq_misc = qoz_inb(qoztmp,qoz_R_IRQ_MISC);
++	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 */
++			    printk(KERN_INFO "qozap: t3 timer expired for span %d\n", j);
++			    qoz_outb(qoztmp,qoz_R_ST_SEL, j);
++			    qoz_outb(qoztmp,qoz_A_ST_WR_STA, 0x40 );
++			    qoztmp->st[j].t3 = -1;
++			    qoztmp->ztdev->spans[j].alarms = ZT_ALARM_RED;
++			    zt_alarm_notify(&qoztmp->ztdev->spans[j]);
++			    qoz_waitbusy(qoztmp);
++			}
++		    }
++		    /* 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 */
++			    printk(KERN_INFO "qozap: t4 timer expired for span %d\n", j);
++			    qoz_outb(qoztmp,qoz_R_ST_SEL, j);
++			    qoz_outb(qoztmp,qoz_A_ST_WR_STA, 0x40 );
++			    qoztmp->st[j].t4 = -1;
++			    qoztmp->ztdev->spans[j].alarms = ZT_ALARM_RED;
++			    zt_alarm_notify(&qoztmp->ztdev->spans[j]);
++			    qoz_waitbusy(qoztmp);
++			}
++		    }
++		}
++	    }
++	}
++	if (irq_misc & 0x4) {
++	//    printk(KERN_INFO "qozap proc/nonproc irq\n");
++	}
++    }
++    if (status & 0x80) {
++	/* fifo irq */
++	irq_foview = qoz_inb(qoztmp,qoz_R_IRQ_OVIEW);
++        if (qoztmp->type == 0xb552) {
++	    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 zt_qoz *qozt = span->pvt;
++    struct qoz_card *qoztmp = qozt->card;
++    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->ztdev->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;
++    }
++
++    spin_lock_irqsave(&qoztmp->lock,flags);
++    // irqs off
++    qoz_outb(qoztmp,qoz_R_IRQ_CTRL, 0); 
++
++    if (qoztmp->type == 0xb552) {
++	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);
++    qoz_outb(qoztmp,qoz_A_SUBCH_CFG,0x2);
++    qoz_outb(qoztmp,qoz_A_CHANNEL,((span->offset * 4) + 2) << 1);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x1);
++
++    /* setup D-FIFO RX */
++    qoz_outb(qoztmp,qoz_R_FIFO,((span->offset + offset) << 1) | 1);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_A_CON_HDLC,0xD);
++    qoz_outb(qoztmp,qoz_A_SUBCH_CFG,0x2);
++    qoz_outb(qoztmp,qoz_A_CHANNEL,(((span->offset * 4) + 2) << 1) | 1);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x1);
++
++    /* setup B1-FIFO TX */
++    qoz_outb(qoztmp,qoz_R_FIFO,(span->offset * 2) << 1);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_A_CON_HDLC,0x2);
++    qoz_outb(qoztmp,qoz_A_CHANNEL,(span->offset * 4) << 1);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x1);
++
++    /* setup B1-FIFO RX */
++    qoz_outb(qoztmp,qoz_R_FIFO,((span->offset * 2) << 1) | 1);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_A_CON_HDLC,0x2);
++    qoz_outb(qoztmp,qoz_A_CHANNEL,((span->offset * 4) << 1) | 1);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x1);
++
++    /* setup B2-FIFO TX */
++    qoz_outb(qoztmp,qoz_R_FIFO,((span->offset * 2) + 1) << 1);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_A_CON_HDLC,0x2);
++    qoz_outb(qoztmp,qoz_A_CHANNEL,((span->offset * 4) + 1) << 1);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x1);
++
++    /* setup B2-FIFO RX */
++    qoz_outb(qoztmp,qoz_R_FIFO,(((span->offset * 2) + 1) << 1) | 1);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_A_CON_HDLC,0x2);
++    qoz_outb(qoztmp,qoz_A_CHANNEL,((((span->offset) * 4) + 1) << 1) | 1);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x1);
++
++    if (debug)
++        printk(KERN_INFO "qozap: starting card %d span %d/%d.\n",qoztmp->cardno,span->spanno,span->offset);
++    
++    /* activate layer 1 */
++    qoz_outb(qoztmp,qoz_R_ST_SEL,span->offset);
++    if (qoztmp->st[span->offset].nt_mode == 1) {
++	// NT mode
++	qoz_outb(qoztmp,qoz_A_ST_CTRL0,0x7);
++	qoz_outb(qoztmp,qoz_A_ST_CTRL1,0x0);
++	qoz_outb(qoztmp,qoz_A_ST_CTRL2,0x3);
++	qoz_outb(qoztmp,qoz_A_ST_CLK_DLY,0x60 | CLKDEL_NT);
++    } else {
++	// TE mode
++	qoz_outb(qoztmp,qoz_A_ST_CTRL0,0x3);
++	qoz_outb(qoztmp,qoz_A_ST_CTRL1,0x0);
++	qoz_outb(qoztmp,qoz_A_ST_CTRL2,0x3);
++	if (qoztmp->type == 0xb550) {
++	    qoz_outb(qoztmp,qoz_A_ST_CLK_DLY,CLKDEL_TE);
++	} else {
++	    qoz_outb(qoztmp,qoz_A_ST_CLK_DLY,CLKDEL_TE + 1);
++	}
++    }
++    qoztmp->st[span->offset].t3 = 0;
++    qoztmp->st[span->offset].t4 = -1;
++    
++    qoz_outb(qoztmp,qoz_R_ST_SEL,span->offset);
++    if (qoztmp->st[span->offset].nt_mode == 1) {
++	qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x80); 
++    } else {
++	qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x0); 
++    }
++    /* enable irqs */
++    qoz_outb(qoztmp,qoz_R_IRQ_CTRL, 8 | 1); 
++    spin_unlock_irqrestore(&qoztmp->lock,flags);
++
++    qoz_outb(qoztmp,qoz_R_ST_SEL,span->offset);
++    if (qoztmp->st[span->offset].nt_mode == 1) {
++	qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x60 | 0x80); // ACT, G2->G3 EN
++    } else {
++	qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x60); // start Activation
++    }
++
++    return 0;
++}
++
++static int ztqoz_shutdown(struct zt_span *span) {
++    struct zt_qoz *ztqoz = span->pvt;
++    struct qoz_card *qoztmp = ztqoz->card;
++    int alreadyrunning;
++    int offset = 0;
++    
++    if (qoztmp == NULL) {
++	printk(KERN_CRIT "qozap: qoztmp == NULL!\n");
++	return 0;
++	
++    }
++
++    alreadyrunning = span->flags & ZT_FLAG_RUNNING;
++    
++    if (!alreadyrunning) {
++	return 0;
++    }
++
++//    printk(KERN_CRIT "qozap: stopping card %d port %d.\n",qoztmp->cardno, span->offset + 1);
++
++    // turn off irqs for all fifos
++    if (qoztmp->type == 0xb552) {
++	offset = 24;
++    } else {
++	offset = 28;
++    }
++
++    /* disable D TX fifo */
++    qoz_outb(qoztmp,qoz_R_FIFO,(span->offset + offset) << 1);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_A_CON_HDLC,0x1);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x0);
++
++    /* disable D RX fifo */
++    qoz_outb(qoztmp,qoz_R_FIFO,((span->offset + offset) << 1) | 1);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_A_CON_HDLC,0x1);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x0);
++
++    /* disable B1 TX fifo */
++    qoz_outb(qoztmp,qoz_R_FIFO,(span->offset * 2) << 1);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_A_CON_HDLC,0x2);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x0);
++
++    /* disable B1 RX fifo */
++    qoz_outb(qoztmp,qoz_R_FIFO,((span->offset * 2) << 1) | 1);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_A_CON_HDLC,0x2);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x0);
++
++    /* disable B2 TX fifo */
++    qoz_outb(qoztmp,qoz_R_FIFO,(((span->offset) * 2) + 1) << 1);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_A_CON_HDLC,0x2);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x0);
++
++    /* disable B2 RX fifo */
++    qoz_outb(qoztmp,qoz_R_FIFO,((((span->offset) * 2) + 1) << 1) | 1);
++    qoz_waitbusy(qoztmp);
++    qoz_outb(qoztmp,qoz_A_CON_HDLC,0x2);
++    qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x0); 
++
++    span->flags &= ~ZT_FLAG_RUNNING;
++
++    /* Deactivate Layer 1 */
++    qoz_outb(qoztmp,qoz_R_ST_SEL,span->offset);
++    if (qoztmp->st[span->offset].nt_mode == 1) {
++	qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x40); 
++    } else {
++	qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x40);
++    }
++
++
++//    printk(KERN_CRIT "qozap: card %d span %d/%d down.\n",qoztmp->cardno,span->spanno,span->offset);
++    return 0;
++}
++
++static int ztqoz_maint(struct zt_span *span, int cmd) {
++    return 0;
++}
++
++static int ztqoz_chanconfig(struct zt_chan *chan,int sigtype) {
++//    printk(KERN_INFO "chan_config sigtype=%d\n",sigtype);
++    return 0;
++}
++
++static int ztqoz_spanconfig(struct zt_span *span,struct zt_lineconfig *lc) {
++//    span->lineconfig = lc->lineconfig;
++    return 0;
++}
++
++static int ztqoz_initialize(struct zt_qoz *ztqoz) {
++    struct qoz_card *qoztmp = ztqoz->card;
++    int i=0,s=0;
++    
++    for (s=0; s < ztqoz->card->stports; s++) {
++	memset(&ztqoz->spans[s],0,sizeof(struct zt_span)); // you never can tell...
++	sprintf(ztqoz->spans[s].name,"ztqoz/%d/%d",qoz_dev_count + 1,s + 1);
++	if (ztqoz->card->stports == 8) {
++	    if (qoztmp->st[s].nt_mode == 1){
++		sprintf(ztqoz->spans[s].desc,"octoBRI PCI ISDN Card %d Span %d [NT]",qoztmp->cardno,s + 1);
++	    } else {
++		sprintf(ztqoz->spans[s].desc,"octoBRI PCI ISDN Card %d Span %d [TE]",qoztmp->cardno,s + 1);
++	    }
++	} else {
++	    if (ztqoz->card->cardID < 0xff) {
++		if (qoztmp->st[s].nt_mode == 1){
++		    sprintf(ztqoz->spans[s].desc,"quadBRI PCI ISDN Card %d Span %d [NT] (cardID %d)",qoztmp->cardno,s + 1,ztqoz->card->cardID);
++		} else {
++		    sprintf(ztqoz->spans[s].desc,"quadBRI PCI ISDN Card %d Span %d [TE] (cardID %d)",qoztmp->cardno,s + 1,ztqoz->card->cardID);
++		}
++	    } else {
++		if (qoztmp->st[s].nt_mode == 1){
++		    sprintf(ztqoz->spans[s].desc,"quadBRI PCI ISDN Card %d Span %d [NT]",qoztmp->cardno,s + 1);
++		} else {
++		    sprintf(ztqoz->spans[s].desc,"quadBRI PCI ISDN Card %d Span %d [TE]",qoztmp->cardno,s + 1);
++		}
++	    }
++	}
++
++        ztqoz->spans[s].spanconfig = ztqoz_spanconfig;
++        ztqoz->spans[s].chanconfig = ztqoz_chanconfig;
++        ztqoz->spans[s].startup = ztqoz_startup;
++        ztqoz->spans[s].shutdown = ztqoz_shutdown;
++        ztqoz->spans[s].maint = ztqoz_maint;
++        ztqoz->spans[s].rbsbits = ztqoz_rbsbits;
++        ztqoz->spans[s].open = ztqoz_open;
++        ztqoz->spans[s].close = ztqoz_close;
++        ztqoz->spans[s].ioctl = ztqoz_ioctl;
++
++        ztqoz->spans[s].chans = ztqoz->chans[s];
++        ztqoz->spans[s].channels = 3;
++        ztqoz->spans[s].deflaw = ZT_LAW_ALAW;
++        ztqoz->spans[s].linecompat = ZT_CONFIG_AMI | ZT_CONFIG_CCS; // <--- this is really BS
++        init_waitqueue_head(&ztqoz->spans[s].maintq);
++        ztqoz->spans[s].pvt = ztqoz;
++        ztqoz->spans[s].offset = s;
++
++	for (i=0; i < ztqoz->spans[s].channels; i++) {
++	    memset(&(ztqoz->chans[s][i]),0x0,sizeof(struct zt_chan));
++	    sprintf(ztqoz->chans[s][i].name,"ztqoz%d/%d/%d",qoz_dev_count + 1,s + 1,i + 1);
++	    ztqoz->chans[s][i].pvt = ztqoz;
++	    ztqoz->chans[s][i].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;
++	    ztqoz->chans[s][i].chanpos = i + 1; 
++	}
++
++	if (zt_register(&ztqoz->spans[s],0)) {
++	    printk(KERN_INFO "qozap: unable to register zaptel span %d!\n",s+1);
++	    return -1;
++	}
++//	 printk(KERN_INFO "qozap: registered zaptel span %d.\n",s+1);
++    }
++
++    return 0;
++}
++
++int qoz_findCards(unsigned int pcidid) {
++    struct pci_dev *tmp;
++    struct qoz_card *qoztmp = NULL;
++    struct zt_qoz *ztqoz = NULL;
++    int i=0;
++    unsigned char dips=0;
++    int cid=0;
++    int modes=0;
++    tmp = pci_find_device(PCI_VENDOR_ID_CCD,pcidid,multi_qoz);
++    while (tmp != NULL) {
++	multi_qoz = tmp;	// skip this next time.
++
++	if (pci_enable_device(tmp)) {
++	    multi_qoz = NULL;
++	    return -1;
++	}
++
++	qoztmp = kmalloc(sizeof(struct qoz_card),GFP_KERNEL);
++	if (!qoztmp) {
++	    printk(KERN_WARNING "qozap: unable to kmalloc!\n");
++	    pci_disable_device(tmp);
++	    multi_qoz = NULL;
++	    return -ENOMEM;
++	}
++	memset(qoztmp, 0x0, sizeof(struct qoz_card));
++	
++	spin_lock_init(&qoztmp->lock);
++	qoztmp->pcidev = tmp;
++	qoztmp->pcibus = tmp->bus->number;
++	qoztmp->pcidevfn = tmp->devfn; 
++
++	if (!tmp->irq) {
++	    printk(KERN_WARNING "qozap: no irq!\n");
++	} else {
++	    qoztmp->irq = tmp->irq;
++	}
++
++	qoztmp->pci_io = (char *) tmp->resource[1].start;
++	if (!qoztmp->pci_io) {
++	    printk(KERN_WARNING "qozap: no iomem!\n");
++	    pci_disable_device(tmp);
++	    multi_qoz = NULL;
++	    return -EIO;
++	}
++
++	qoztmp->ioport = tmp->resource[0].start;
++	if (!qoztmp->ioport) {
++	    printk(KERN_WARNING "qozap: no ioport!\n");
++	    pci_disable_device(tmp);
++	    multi_qoz = NULL;
++	    return -EIO;
++	}
++	if (!request_region(qoztmp->ioport, 7, "qozap")) {
++	    printk(KERN_WARNING "qozap: couldnt request io range!\n");
++	    pci_disable_device(tmp);
++	    multi_qoz = NULL;
++	    return -EIO;
++	}
++	
++	if (request_irq(qoztmp->irq, qoz_interrupt, SA_INTERRUPT | SA_SHIRQ, "qozap", qoztmp)) {
++	    printk(KERN_WARNING "qozap: unable to register irq\n");
++	    kfree(qoztmp);
++	    pci_disable_device(tmp);
++	    multi_qoz = NULL;
++	    return -EIO;
++	}
++
++	qoztmp->pci_io = ioremap((ulong) qoztmp->pci_io, 256);
++	
++	pci_write_config_word(qoztmp->pcidev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
++
++	// disable ints
++	qoz_outb(qoztmp,qoz_R_IRQ_CTRL, 0); 
++
++	ztqoz = kmalloc(sizeof(struct zt_qoz),GFP_KERNEL);
++	if (!ztqoz) {
++	    printk(KERN_INFO "qozap: unable to kmalloc!\n");
++	    qoz_shutdownCard(qoztmp);
++	    kfree(qoztmp);
++	    multi_qoz = NULL;
++	    return -ENOMEM;
++	}
++	memset(ztqoz, 0x0, sizeof(struct zt_qoz));
++
++	if (pcidid == PCI_DEVICE_ID_CCD_M) {
++	    qoztmp->stports = 8;
++	} else {
++	    qoztmp->stports = 4;
++	}
++	
++
++        if ((tmp->subsystem_device==0xb520) && (pcidid == PCI_DEVICE_ID_CCD_M4)) {
++	//    printk(KERN_INFO "MODES = %#x.\n",modes);
++	    qoz_outb(qoztmp,qoz_R_GPIO_SEL,0x80 | 0x40);
++	    dips = (qoz_inb(qoztmp,qoz_R_GPIO_IN1) >> 5);
++	    cid = 7;
++	    for (i=0;i<3;i++) {
++	        if ((dips & (1 << i)) != 0) {
++	    	cid -= (1 << (2-i));
++	        }
++	    }
++	//	printk(KERN_INFO "DIPS = %#x CID= %#x\n",dips,cid);
++        } else if ((tmp->subsystem_device==0xb550) && (pcidid == PCI_DEVICE_ID_CCD_M4)) {
++	//    printk(KERN_INFO "MODES = %#x.\n",modes);
++	    dips = ~(qoz_inb(qoztmp,qoz_R_GPI_IN3) & 7);
++	    cid = 0;
++	    for (i=0;i<3;i++) {
++	        if ((dips & (1 << i)) != 0) {
++	    	cid += (1 << i);
++	        }
++	    }
++	printk(KERN_INFO "DIPS = %#x CID= %#x\n",dips,cid);
++        } else {
++	    cid = 0xff;
++        }
++
++	if (ports == -1) {
++    	    if ((tmp->subsystem_device==0xb520) && (pcidid == PCI_DEVICE_ID_CCD_M4)) {
++		modes = qoz_inb(qoztmp,qoz_R_GPI_IN3) >> 4;
++    	    } else if ((tmp->subsystem_device==0xb550) && (pcidid == PCI_DEVICE_ID_CCD_M4)) {
++		qoz_outb(qoztmp,qoz_R_GPIO_SEL,0xff);
++		qoz_outb(qoztmp,qoz_R_GPIO_EN0,0x00);
++		printk(KERN_CRIT "gpio_in0 %#x \n", qoz_inb(qoztmp,qoz_R_GPIO_IN0));
++		printk(KERN_CRIT "gpio_in1 %#x \n", qoz_inb(qoztmp,qoz_R_GPIO_IN1));
++		printk(KERN_CRIT "gpi_in1 %#x \n", qoz_inb(qoztmp,qoz_R_GPI_IN1));
++		printk(KERN_CRIT "gpi_in2 %#x \n", qoz_inb(qoztmp,qoz_R_GPI_IN2));
++		printk(KERN_CRIT "gpi_in3 %#x \n", qoz_inb(qoztmp,qoz_R_GPI_IN3));
++		modes = qoz_inb(qoztmp,qoz_R_GPI_IN3) >> 4;	    
++	    } else {
++		modes = 0; // assume TE mode
++	    }
++	} else {
++	    modes = ports >> totalBRIs;
++	}
++
++	if (pcidid == PCI_DEVICE_ID_CCD_M4) {
++	    switch (tmp->subsystem_device) {
++		case 0x08b4:
++			if (ports == -1) ports = 0; /* assume TE mode if no ports param */
++			printk(KERN_INFO
++		        "qozap: CologneChip HFC-4S evaluation board configured at io port %#x IRQ %d HZ %d\n",
++		          (u_int) qoztmp->ioport,
++		        qoztmp->irq, HZ);
++		    break;
++		case 0xb520:
++			printk(KERN_INFO
++		        "qozap: Junghanns.NET quadBRI card configured at io port %#x IRQ %d HZ %d CardID %d\n",
++		          (u_int) qoztmp->ioport,
++		        qoztmp->irq, HZ, cid);
++		    break;
++		case 0xb550:
++			printk(KERN_INFO
++		        "qozap: Junghanns.NET quadBRI (Version 2.0) card configured at io port %#x IRQ %d HZ %d CardID %d\n",
++		          (u_int) qoztmp->ioport,
++		        qoztmp->irq, HZ, cid);
++		    break;
++	    } 
++	    totalBRIs += 4;
++	} else {
++	    switch (tmp->subsystem_device) {
++		case 0xb552:
++		    printk(KERN_INFO
++		       "qozap: Junghanns.NET octoBRI card configured at io port %#x IRQ %d HZ %d\n",
++		       (u_int) qoztmp->ioport,
++		       qoztmp->irq, HZ);
++	        break;
++		default:
++		    if (qoztmp->pcidev != NULL) {
++    			pci_disable_device(qoztmp->pcidev);
++		    }
++		    pci_write_config_word(qoztmp->pcidev, PCI_COMMAND, 0);	
++		    free_irq(qoztmp->irq,qoztmp);
++		    kfree(qoztmp);
++		    qoztmp = NULL;
++		    tmp = pci_find_device(PCI_VENDOR_ID_CCD,pcidid,multi_qoz);
++		    continue;
++		break;		
++	    } 
++	    totalBRIs += 8;
++	}
++
++	qoztmp->cardID = cid;
++	qoztmp->type = tmp->subsystem_device;
++
++	printk(KERN_INFO "qozap: S/T ports: %d [",qoztmp->stports);
++	for (i=0;i<qoztmp->stports;i++) {
++	    if ((modes & (1 << i)) != 0) {
++	        qoztmp->st[i].nt_mode = 1;
++	        printk(" NT");
++	    } else {
++	        qoztmp->st[i].nt_mode = 0;
++	        printk(" TE");
++	    }
++	}
++	printk(" ]\n");
++	
++	ztqoz->card = qoztmp;
++	qoztmp->ztdev = ztqoz;
++
++	qoz_registerCard(qoztmp);
++	tmp = pci_find_device(PCI_VENDOR_ID_CCD,pcidid,multi_qoz);
++    }
++    return 0;
++}
++
++
++int qoz_sortCards(void) {
++    int changed=0,tmpcardno;
++    struct qoz_card *tmpcard,*tmpcard2;
++    spin_lock(&registerlock);
++    do {
++	changed = 0;
++	tmpcard = qoz_dev_list;
++	while (tmpcard != NULL) {
++	    if (tmpcard->prev) {
++		if (tmpcard->prev->cardID > tmpcard->cardID) {
++		    tmpcardno = tmpcard->prev->cardno;
++		    tmpcard->prev->cardno = tmpcard->cardno; 
++		    tmpcard->cardno = tmpcardno;
++		
++		    tmpcard2 = tmpcard->prev;
++		    if (tmpcard2->prev) {
++			tmpcard2->prev->next = tmpcard;
++		    } else {
++			qoz_dev_list = tmpcard;
++		    }
++		    if (tmpcard->next) {
++			tmpcard->next->prev = tmpcard2;
++		    } 
++		    tmpcard2->next = tmpcard->next;
++		    tmpcard->prev = tmpcard2->prev;
++		    tmpcard->next = tmpcard2;
++		    tmpcard2->prev = tmpcard;
++		    changed = 1;
++		    tmpcard = tmpcard2;
++		}
++	    }
++	    tmpcard = tmpcard->next;
++	}
++    } while (changed == 1);
++    spin_unlock(&registerlock);
++    return 0;
++}
++
++int qoz_zapCards(void) {
++    struct qoz_card *tmpcard;
++    tmpcard = qoz_dev_list;
++    while (tmpcard != NULL) {
++	ztqoz_initialize(tmpcard->ztdev);
++	qoz_resetCard(tmpcard);
++	tmpcard = tmpcard->next;
++    }
++    return 0;
++}
++
++
++int init_module(void) {
++    multi_qoz = NULL;
++    qoz_findCards(PCI_DEVICE_ID_CCD_M4);
++    qoz_findCards(PCI_DEVICE_ID_CCD_M);
++    qoz_sortCards();
++    qoz_zapCards();
++    if (qoz_dev_count == 0) {
++	printk(KERN_INFO "qozap: no multiBRI cards found.\n");
++    } else {
++	printk(KERN_INFO "qozap: %d multiBRI card(s) in this box, %d BRI ports total, bloop %d.\n",qoz_dev_count, totalBRIs, bloop);
++    }
++    return 0;
++}
++
++void cleanup_module(void) {
++    struct qoz_card *tmpcard,*tmplist;
++    int i=0;
++    tmplist = qoz_dev_list;
++    while (tmplist != NULL) {
++	qoz_undoWD(tmplist);
++	qoz_shutdownCard(tmplist);
++	tmplist = tmplist->next;
++    }
++    tmplist = qoz_dev_list;
++    spin_lock(&registerlock);
++    while (tmplist != NULL) {
++	tmpcard = tmplist->next;
++	kfree(tmplist);
++	i++;
++	tmplist = tmpcard;
++    }
++    spin_unlock(&registerlock);
++    printk(KERN_INFO "qozap: shutdown %d multiBRI cards.\n", i);
++}
++#endif
++
++MODULE_PARM(doubleclock,"i");
++MODULE_PARM(ports,"i");
++MODULE_PARM(bloop,"i");
++MODULE_PARM(debug,"i");
++MODULE_DESCRIPTION("quad/octo BRI zaptel driver");
++MODULE_AUTHOR("Klaus-Peter Junghanns <kpj at junghanns.net>");
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("GPL");
++#endif	
+diff -urNad zaptel-1.2.3/qozap/qozap.h /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/qozap.h
+--- zaptel-1.2.3/qozap/qozap.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/qozap.h	2005-06-13 11:56:43.000000000 +0300
+@@ -0,0 +1,237 @@
++#define qoz_SPANS 8	
++#define qoz_FIFO_SIZE	128
++#define qoz_DFIFO_SIZE4	2048
++#define qoz_DFIFO_SIZE8	1024
++
++typedef struct qoz_span {
++    unsigned char nt_mode;
++    unsigned char btx;
++    unsigned char bswapped;
++    unsigned char drx;
++    int t3;
++    int t4;
++    unsigned char layer1state;
++} qoz_span;
++
++typedef struct qoz_regs {
++    unsigned char fifo_en;
++    unsigned char ctmt;
++    unsigned char int_m1;
++    unsigned char int_m2;
++    unsigned char sctrl;
++    unsigned char sctrl_e;
++    unsigned char sctrl_r;
++    unsigned char connect;
++    unsigned char trm;
++    unsigned char mst_mode;
++} qoz_regs;
++
++typedef struct qoz_card {
++    spinlock_t lock;
++    int cardID;
++    unsigned char leds[8];
++    unsigned char cardno;
++    unsigned int irq;
++    unsigned int iomem;
++    unsigned char *pci_io;
++    unsigned long ioport;
++    struct qoz_span st[qoz_SPANS];
++    unsigned int pcibus;
++    unsigned int pcidevfn;
++    struct pci_dev *pcidev;
++    struct zt_qoz *ztdev;
++    unsigned char rxbuf[qoz_SPANS][2][ZT_CHUNKSIZE];
++    unsigned char txbuf[qoz_SPANS][2][ZT_CHUNKSIZE];
++    unsigned char drxbuf[qoz_SPANS][qoz_DFIFO_SIZE4];
++    unsigned char dtxbuf[qoz_SPANS][qoz_DFIFO_SIZE4];
++    unsigned char stports;
++    unsigned int ticks;
++    unsigned int clicks;
++    unsigned int type;
++    unsigned int wdp;
++    struct qoz_card *next;
++    struct qoz_card *prev;
++} qoz_card;
++
++
++typedef struct zt_qoz {
++    unsigned int usecount;
++    struct zt_span spans[qoz_SPANS];
++    struct zt_chan chans[qoz_SPANS][3];
++    struct qoz_card *card;
++} zt_qoz;
++
++#define qoz_outb_io(a,b,c) \
++    outw((b), ((a)->ioport+4)); \
++    outb((c), ((a)->ioport));
++
++#define qoz_inb_io(a,b) ({ outw((b), (a)->ioport+4); inb((a)->ioport); })
++
++#define qoz_outw_io(a,b,c) \
++    outw((b), ((a)->ioport+4)); \
++    outw((c), ((a)->ioport));
++
++#define qoz_inw_io(a,b) ({ outw((b), (a)->ioport+4); inw((a)->ioport); })
++
++#define qoz_outdw_io(a,b,c) \
++    outw((b), ((a)->ioport+4)); \
++    outl((c), ((a)->ioport));
++
++#define qoz_indw_io(a,b) ({ outw((b), (a)->ioport+4); inl((a)->ioport); })
++
++#define qoz_outb(a,b,c) (writeb((c),(a)->pci_io+(b)))
++#define qoz_inb(a,b) (readb((a)->pci_io+(b)))
++
++#define qoz_outw(a,b,c) (writew((c),(a)->pci_io+(b)))
++#define qoz_inw(a,b) (readw((a)->pci_io+(b)))
++
++#define qoz_outdw(a,b,c) (writel((c),(a)->pci_io+(b)))
++#define qoz_indw(a,b) (readl((a)->pci_io+(b)))
++
++
++/* Write only registers */
++#define qoz_A_CH_MSK	0xF4
++#define qoz_A_CHANNEL 	0xFC
++#define qoz_A_CON_HDLC	0xFA
++#define qoz_A_CONF	0xD1
++#define qoz_A_FIFO_SEQ	0xFD
++#define qoz_R_INC_RES_FIFO	0x0E
++#define qoz_A_IRQ_MSK	0xFF
++#define qoz_A_SL_CFG	0xD0
++#define qoz_A_ST_B1_TX	0x3C
++#define qoz_A_ST_B2_TX	0x3D
++#define qoz_A_ST_CLK_DLY	0x37
++#define qoz_A_ST_CTRL0	0x31
++#define qoz_A_ST_CTRL1	0x32
++#define qoz_A_ST_CTRL2	0x33
++#define qoz_A_ST_D_TX	0x3E
++#define qoz_A_ST_SQ_WR	0x34
++#define qoz_A_ST_WR_STA	0x30
++#define qoz_A_SUBCH_CFG	0xFB
++#define qoz_R_BERT_WD_MD	0x1B
++#define qoz_R_BRG_CTRL	0x45
++#define qoz_R_BRG_MD	0x47
++#define qoz_R_BRG_PCM_CFG	0x02
++#define qoz_R_BRG_TIM_SEL01	0x4C
++#define qoz_R_BRG_TIM_SEL23	0x4D
++#define qoz_R_BRG_TIM_SEL45	0x4E
++#define qoz_R_BRG_TIM_SEL67	0x4F
++#define qoz_R_BRG_TIM0	0x48
++#define qoz_R_BRG_TIM1	0x49
++#define qoz_R_BRG_TIM2	0x4A
++#define qoz_R_BRG_TIM3	0x4B
++#define qoz_R_CIRM	0x00
++#define qoz_R_CONF_EN	0x18
++#define qoz_R_CTRL	0x01
++#define qoz_R_DTMF0	0x1C
++#define qoz_R_DTMF1	0x1D
++#define qoz_R_FIFO_MD	0x0D
++#define qoz_R_FIFO	0x0F
++#define qoz_R_FIRST_FIFO	0x0B
++#define qoz_R_FSM_IDX	0x0F
++#define qoz_R_GPIO_EN0	0x42
++#define qoz_R_GPIO_EN1	0x43
++#define qoz_R_GPIO_OUT0	0x40
++#define qoz_R_GPIO_OUT1	0x41
++#define qoz_R_GPIO_SEL	0x44
++#define qoz_R_IRQ_CTRL	0x13
++#define qoz_R_IRQMSK_MISC	0x11
++#define qoz_R_PCM_MD0	0x14
++#define qoz_R_PCM_MD1	0x15
++#define qoz_R_PCM_MD2	0x15
++#define qoz_R_PWM_MD	0x46
++#define qoz_R_PWM0	0x38
++#define qoz_R_PWM1	0x39
++#define qoz_R_RAM_ADDR0	0x08
++#define qoz_R_RAM_ADDR1	0x09
++#define qoz_R_RAM_ADDR2	0x0A
++#define qoz_R_RAM_MISC	0x0C
++#define qoz_R_SCI_MSK	0x12
++#define qoz_R_SH0H	0x15
++#define qoz_R_SH0L	0x15
++#define qoz_R_SH1H	0x15
++#define qoz_R_SH1L	0x15
++#define qoz_R_SL_SEL0	0x15
++#define qoz_R_SL_SEL1	0x15
++#define qoz_R_SL_SEL2	0x15
++#define qoz_R_SL_SEL3	0x15
++#define qoz_R_SL_SEL4	0x15
++#define qoz_R_SL_SEL5	0x15
++#define qoz_R_SL_SEL6	0x15
++#define qoz_R_SL_SEL7	0x15
++#define qoz_R_SLOT	0x10
++#define qoz_R_ST_SEL	0x16
++#define qoz_R_ST_SYNC	0x17
++#define qoz_R_TI_WD	0x1A
++
++/* Read only registers */
++#define qoz_A_F1	0x0C
++#define qoz_A_F12	0x0C
++#define qoz_A_F2	0x0D
++#define qoz_A_ST_B1_RX	0x3C
++#define qoz_A_ST_B2_TX	0x3D
++#define qoz_A_ST_D_RX	0x3E
++#define qoz_A_ST_E_RX	0x3F
++#define qoz_A_ST_RD_STA	0x30
++#define qoz_A_ST_SQ_RD	0x34
++#define qoz_A_Z1	0x04
++#define qoz_A_Z12	0x04
++#define qoz_A_Z1H	0x05
++#define qoz_A_Z1L	0x04
++#define qoz_A_Z2	0x06
++#define qoz_A_Z2H	0x07
++#define qoz_A_Z2L	0x06
++#define qoz_R_BERT_ECH	0x1B
++#define qoz_R_BERT_ECL	0x1A
++#define qoz_R_BERT_STA	0x17
++#define qoz_R_CHIP_ID	0x16
++#define qoz_R_CHIP_RV	0x1F
++#define qoz_R_CONF_OFLOW	0x14
++#define qoz_R_F0_CNTH	0x19
++#define qoz_R_F0_CNTL	0x18
++#define qoz_R_GPI_IN0	0x44
++#define qoz_R_GPI_IN1	0x45
++#define qoz_R_GPI_IN2	0x46
++#define qoz_R_GPI_IN3	0x47
++#define qoz_R_GPIO_IN0	0x40
++#define qoz_R_GPIO_IN1	0x41
++#define qoz_R_INT_DATA	0x88
++#define qoz_R_IRQ_FIFO_BL0	0xC8
++#define qoz_R_IRQ_FIFO_BL1	0xC9
++#define qoz_R_IRQ_FIFO_BL2	0xCA
++#define qoz_R_IRQ_FIFO_BL3	0xCB
++#define qoz_R_IRQ_FIFO_BL4	0xCC
++#define qoz_R_IRQ_FIFO_BL5	0xCD
++#define qoz_R_IRQ_FIFO_BL6	0xCE
++#define qoz_R_IRQ_FIFO_BL7	0xCF
++#define qoz_R_IRQ_MISC	0x11
++#define qoz_R_IRQ_OVIEW	0x10
++#define qoz_R_RAM_USE	0x15
++#define qoz_R_SCI	0x12
++#define qoz_R_STATUS	0x1C
++
++/* Read/Write registers */
++#define qoz_A_FIFO_DATA0_NOINC	0x84
++#define qoz_A_FIFO_DATA0	0x80
++#define qoz_A_FIFO_DATA1_NOINC	0x84
++#define qoz_A_FIFO_DATA1	0x80
++#define qoz_A_FIFO_DATA2_NOINC	0x84
++#define qoz_A_FIFO_DATA2	0x80
++#define qoz_R_RAM_DATA	0xC0
++
++#define PCI_DEVICE_ID_CCD_M	0x16b8
++#define PCI_DEVICE_ID_CCD_M4	0x08b4
++#define CLKDEL_TE	0xe	/* CLKDEL in TE mode */
++#define CLKDEL_NT	0xc	/* CLKDEL in NT mode */
++
++#define HFC8S_CHIP_ID	0x80
++#define HFC4S_CHIP_ID	0xC0
++
++#define qoz_WD_P0	0x000000
++#define qoz_WD_P1	0x808080
++#define qoz_WD_P2	0x404040
++
++#define qoz_T3		3
++#define qoz_T4		1
++
++
+diff -urNad zaptel-1.2.3/qozap/TODO /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/TODO
+--- zaptel-1.2.3/qozap/TODO	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/TODO	2005-06-13 10:03:36.000000000 +0300
+@@ -0,0 +1,9 @@
++- native-native bridging
++- onchip dtmf
++- E channel support for full debug
++
++
++t3 (5ms max)
++
++t4 (500ms) layer 1 down/up
++
+diff -urNad zaptel-1.2.3/qozap/zapata.conf /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/zapata.conf
+--- zaptel-1.2.3/qozap/zapata.conf	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/zapata.conf	2005-06-13 10:03:36.000000000 +0300
+@@ -0,0 +1,49 @@
++;
++; Zapata telephony interface
++;
++; Configuration file
++
++[channels]
++;
++; Default language
++;
++;language=en
++;
++; Default context
++;
++;
++switchtype = euroisdn
++
++; p2mp TE mode (for connecting ISDN lines in point-to-multipoint mode)
++signalling = bri_cpe_ptmp
++; p2p TE mode (for connecting ISDN lines in point-to-point mode)
++;signalling = bri_cpe
++; p2mp NT mode (for connecting ISDN phones in point-to-multipoint mode)
++;signalling = bri_net_ptmp
++; p2p NT mode (for connecting an ISDN pbx in point-to-point mode)
++;signalling = bri_net
++
++pridialplan = local
++prilocaldialplan = local
++nationalprefix = 0
++internationalprefix = 00
++
++echocancel = yes
++
++context=demo
++group = 1
++; S/T port 1
++channel => 1-2
++
++group = 2
++; S/T port 2
++channel => 4-5
++
++group = 3
++; S/T port 3
++channel => 7-8
++
++group = 4
++; S/T port 4
++channel => 10-11
++
+diff -urNad zaptel-1.2.3/qozap/zapata.conf.octoBRI /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/zapata.conf.octoBRI
+--- zaptel-1.2.3/qozap/zapata.conf.octoBRI	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/zapata.conf.octoBRI	2005-06-13 10:03:36.000000000 +0300
+@@ -0,0 +1,65 @@
++;
++; Zapata telephony interface
++;
++; Configuration file
++
++[channels]
++;
++; Default language
++;
++;language=en
++;
++; Default context
++;
++;
++switchtype = euroisdn
++
++; p2mp TE mode (for connecting ISDN lines in point-to-multipoint mode)
++signalling = bri_cpe_ptmp
++; p2p TE mode (for connecting ISDN lines in point-to-point mode)
++;signalling = bri_cpe
++; p2mp NT mode (for connecting ISDN phones in point-to-multipoint mode)
++;signalling = bri_net_ptmp
++; p2p NT mode (for connecting an ISDN pbx in point-to-point mode)
++;signalling = bri_net
++
++pridialplan = local
++prilocaldialplan = local
++nationalprefix = 0
++internationalprefix = 00
++
++echocancel = yes
++
++context=demo
++group = 1
++; S/T port 1
++channel => 1-2
++
++group = 2
++; S/T port 2
++channel => 4-5
++
++group = 3
++; S/T port 3
++channel => 7-8
++
++group = 4
++; S/T port 4
++channel => 10-11
++
++group = 5
++; S/T port 5
++channel => 13-14
++
++group = 6
++; S/T port 6
++channel => 16-17
++
++group = 7
++; S/T port 7
++channel => 19-20
++
++group = 8
++; S/T port 8
++channel => 22-23
++
+diff -urNad zaptel-1.2.3/qozap/zaptel.conf /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/zaptel.conf
+--- zaptel-1.2.3/qozap/zaptel.conf	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/zaptel.conf	2005-11-20 16:35:32.000000000 +0200
+@@ -0,0 +1,18 @@
++loadzone=nl
++defaultzone=nl
++# qozap span definitions
++# most of the values should be bogus because we are not really zaptel
++span=1,1,3,ccs,ami
++span=2,2,3,ccs,ami
++span=3,0,3,ccs,ami
++span=4,0,3,ccs,ami
++
++bchan=1,2
++dchan=3
++bchan=4,5
++dchan=6
++bchan=7,8
++dchan=9
++bchan=10,11
++dchan=12
++
+diff -urNad zaptel-1.2.3/qozap/zaptel.conf.octoBRI /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/zaptel.conf.octoBRI
+--- zaptel-1.2.3/qozap/zaptel.conf.octoBRI	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/qozap/zaptel.conf.octoBRI	2005-06-13 10:03:36.000000000 +0300
+@@ -0,0 +1,30 @@
++loadzone=nl
++defaultzone=nl
++# qozap span definitions
++# most of the values should be bogus because we are not really zaptel
++span=1,1,3,ccs,ami
++span=2,0,3,ccs,ami
++span=3,0,3,ccs,ami
++span=4,0,3,ccs,ami
++span=5,1,3,ccs,ami
++span=6,0,3,ccs,ami
++span=7,0,3,ccs,ami
++span=8,0,3,ccs,ami
++
++bchan=1,2
++dchan=3
++bchan=4,5
++dchan=6
++bchan=7,8
++dchan=9
++bchan=10,11
++dchan=12
++bchan=13,14
++dchan=15
++bchan=16,17
++dchan=18
++bchan=19,20
++dchan=21
++bchan=22,23
++dchan=24
++
+diff -urNad zaptel-1.2.3/zaphfc/LICENSE /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/LICENSE
+--- zaptel-1.2.3/zaphfc/LICENSE	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/LICENSE	2003-08-19 04:24:43.000000000 +0300
+@@ -0,0 +1,341 @@
++
++		    GNU GENERAL PUBLIC LICENSE
++		       Version 2, June 1991
++
++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
++                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++			    Preamble
++
++  The licenses for most software are designed to take away your
++freedom to share and change it.  By contrast, the GNU General Public
++License is intended to guarantee your freedom to share and change free
++software--to make sure the software is free for all its users.  This
++General Public License applies to most of the Free Software
++Foundation's software and to any other program whose authors commit to
++using it.  (Some other Free Software Foundation software is covered by
++the GNU Library General Public License instead.)  You can apply it to
++your programs, too.
++
++  When we speak of free software, we are referring to freedom, not
++price.  Our General Public Licenses are designed to make sure that you
++have the freedom to distribute copies of free software (and charge for
++this service if you wish), that you receive source code or can get it
++if you want it, that you can change the software or use pieces of it
++in new free programs; and that you know you can do these things.
++
++  To protect your rights, we need to make restrictions that forbid
++anyone to deny you these rights or to ask you to surrender the rights.
++These restrictions translate to certain responsibilities for you if you
++distribute copies of the software, or if you modify it.
++
++  For example, if you distribute copies of such a program, whether
++gratis or for a fee, you must give the recipients all the rights that
++you have.  You must make sure that they, too, receive or can get the
++source code.  And you must show them these terms so they know their
++rights.
++
++  We protect your rights with two steps: (1) copyright the software, and
++(2) offer you this license which gives you legal permission to copy,
++distribute and/or modify the software.
++
++  Also, for each author's protection and ours, we want to make certain
++that everyone understands that there is no warranty for this free
++software.  If the software is modified by someone else and passed on, we
++want its recipients to know that what they have is not the original, so
++that any problems introduced by others will not reflect on the original
++authors' reputations.
++
++  Finally, any free program is threatened constantly by software
++patents.  We wish to avoid the danger that redistributors of a free
++program will individually obtain patent licenses, in effect making the
++program proprietary.  To prevent this, we have made it clear that any
++patent must be licensed for everyone's free use or not licensed at all.
++
++  The precise terms and conditions for copying, distribution and
++modification follow.
++
++		    GNU GENERAL PUBLIC LICENSE
++   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++
++  0. This License applies to any program or other work which contains
++a notice placed by the copyright holder saying it may be distributed
++under the terms of this General Public License.  The "Program", below,
++refers to any such program or work, and a "work based on the Program"
++means either the Program or any derivative work under copyright law:
++that is to say, a work containing the Program or a portion of it,
++either verbatim or with modifications and/or translated into another
++language.  (Hereinafter, translation is included without limitation in
++the term "modification".)  Each licensee is addressed as "you".
++
++Activities other than copying, distribution and modification are not
++covered by this License; they are outside its scope.  The act of
++running the Program is not restricted, and the output from the Program
++is covered only if its contents constitute a work based on the
++Program (independent of having been made by running the Program).
++Whether that is true depends on what the Program does.
++
++  1. You may copy and distribute verbatim copies of the Program's
++source code as you receive it, in any medium, provided that you
++conspicuously and appropriately publish on each copy an appropriate
++copyright notice and disclaimer of warranty; keep intact all the
++notices that refer to this License and to the absence of any warranty;
++and give any other recipients of the Program a copy of this License
++along with the Program.
++
++You may charge a fee for the physical act of transferring a copy, and
++you may at your option offer warranty protection in exchange for a fee.
++
++  2. You may modify your copy or copies of the Program or any portion
++of it, thus forming a work based on the Program, and copy and
++distribute such modifications or work under the terms of Section 1
++above, provided that you also meet all of these conditions:
++
++    a) You must cause the modified files to carry prominent notices
++    stating that you changed the files and the date of any change.
++
++    b) You must cause any work that you distribute or publish, that in
++    whole or in part contains or is derived from the Program or any
++    part thereof, to be licensed as a whole at no charge to all third
++    parties under the terms of this License.
++
++    c) If the modified program normally reads commands interactively
++    when run, you must cause it, when started running for such
++    interactive use in the most ordinary way, to print or display an
++    announcement including an appropriate copyright notice and a
++    notice that there is no warranty (or else, saying that you provide
++    a warranty) and that users may redistribute the program under
++    these conditions, and telling the user how to view a copy of this
++    License.  (Exception: if the Program itself is interactive but
++    does not normally print such an announcement, your work based on
++    the Program is not required to print an announcement.)
++
++These requirements apply to the modified work as a whole.  If
++identifiable sections of that work are not derived from the Program,
++and can be reasonably considered independent and separate works in
++themselves, then this License, and its terms, do not apply to those
++sections when you distribute them as separate works.  But when you
++distribute the same sections as part of a whole which is a work based
++on the Program, the distribution of the whole must be on the terms of
++this License, whose permissions for other licensees extend to the
++entire whole, and thus to each and every part regardless of who wrote it.
++
++Thus, it is not the intent of this section to claim rights or contest
++your rights to work written entirely by you; rather, the intent is to
++exercise the right to control the distribution of derivative or
++collective works based on the Program.
++
++In addition, mere aggregation of another work not based on the Program
++with the Program (or with a work based on the Program) on a volume of
++a storage or distribution medium does not bring the other work under
++the scope of this License.
++
++  3. You may copy and distribute the Program (or a work based on it,
++under Section 2) in object code or executable form under the terms of
++Sections 1 and 2 above provided that you also do one of the following:
++
++    a) Accompany it with the complete corresponding machine-readable
++    source code, which must be distributed under the terms of Sections
++    1 and 2 above on a medium customarily used for software interchange; or,
++
++    b) Accompany it with a written offer, valid for at least three
++    years, to give any third party, for a charge no more than your
++    cost of physically performing source distribution, a complete
++    machine-readable copy of the corresponding source code, to be
++    distributed under the terms of Sections 1 and 2 above on a medium
++    customarily used for software interchange; or,
++
++    c) Accompany it with the information you received as to the offer
++    to distribute corresponding source code.  (This alternative is
++    allowed only for noncommercial distribution and only if you
++    received the program in object code or executable form with such
++    an offer, in accord with Subsection b above.)
++
++The source code for a work means the preferred form of the work for
++making modifications to it.  For an executable work, complete source
++code means all the source code for all modules it contains, plus any
++associated interface definition files, plus the scripts used to
++control compilation and installation of the executable.  However, as a
++special exception, the source code distributed need not include
++anything that is normally distributed (in either source or binary
++form) with the major components (compiler, kernel, and so on) of the
++operating system on which the executable runs, unless that component
++itself accompanies the executable.
++
++If distribution of executable or object code is made by offering
++access to copy from a designated place, then offering equivalent
++access to copy the source code from the same place counts as
++distribution of the source code, even though third parties are not
++compelled to copy the source along with the object code.
++
++  4. You may not copy, modify, sublicense, or distribute the Program
++except as expressly provided under this License.  Any attempt
++otherwise to copy, modify, sublicense or distribute the Program is
++void, and will automatically terminate your rights under this License.
++However, parties who have received copies, or rights, from you under
++this License will not have their licenses terminated so long as such
++parties remain in full compliance.
++
++  5. You are not required to accept this License, since you have not
++signed it.  However, nothing else grants you permission to modify or
++distribute the Program or its derivative works.  These actions are
++prohibited by law if you do not accept this License.  Therefore, by
++modifying or distributing the Program (or any work based on the
++Program), you indicate your acceptance of this License to do so, and
++all its terms and conditions for copying, distributing or modifying
++the Program or works based on it.
++
++  6. Each time you redistribute the Program (or any work based on the
++Program), the recipient automatically receives a license from the
++original licensor to copy, distribute or modify the Program subject to
++these terms and conditions.  You may not impose any further
++restrictions on the recipients' exercise of the rights granted herein.
++You are not responsible for enforcing compliance by third parties to
++this License.
++
++  7. If, as a consequence of a court judgment or allegation of patent
++infringement or for any other reason (not limited to patent issues),
++conditions are imposed on you (whether by court order, agreement or
++otherwise) that contradict the conditions of this License, they do not
++excuse you from the conditions of this License.  If you cannot
++distribute so as to satisfy simultaneously your obligations under this
++License and any other pertinent obligations, then as a consequence you
++may not distribute the Program at all.  For example, if a patent
++license would not permit royalty-free redistribution of the Program by
++all those who receive copies directly or indirectly through you, then
++the only way you could satisfy both it and this License would be to
++refrain entirely from distribution of the Program.
++
++If any portion of this section is held invalid or unenforceable under
++any particular circumstance, the balance of the section is intended to
++apply and the section as a whole is intended to apply in other
++circumstances.
++
++It is not the purpose of this section to induce you to infringe any
++patents or other property right claims or to contest validity of any
++such claims; this section has the sole purpose of protecting the
++integrity of the free software distribution system, which is
++implemented by public license practices.  Many people have made
++generous contributions to the wide range of software distributed
++through that system in reliance on consistent application of that
++system; it is up to the author/donor to decide if he or she is willing
++to distribute software through any other system and a licensee cannot
++impose that choice.
++
++This section is intended to make thoroughly clear what is believed to
++be a consequence of the rest of this License.
++
++  8. If the distribution and/or use of the Program is restricted in
++certain countries either by patents or by copyrighted interfaces, the
++original copyright holder who places the Program under this License
++may add an explicit geographical distribution limitation excluding
++those countries, so that distribution is permitted only in or among
++countries not thus excluded.  In such case, this License incorporates
++the limitation as if written in the body of this License.
++
++  9. The Free Software Foundation may publish revised and/or new versions
++of the General Public License from time to time.  Such new versions will
++be similar in spirit to the present version, but may differ in detail to
++address new problems or concerns.
++
++Each version is given a distinguishing version number.  If the Program
++specifies a version number of this License which applies to it and "any
++later version", you have the option of following the terms and conditions
++either of that version or of any later version published by the Free
++Software Foundation.  If the Program does not specify a version number of
++this License, you may choose any version ever published by the Free Software
++Foundation.
++
++  10. If you wish to incorporate parts of the Program into other free
++programs whose distribution conditions are different, write to the author
++to ask for permission.  For software which is copyrighted by the Free
++Software Foundation, write to the Free Software Foundation; we sometimes
++make exceptions for this.  Our decision will be guided by the two goals
++of preserving the free status of all derivatives of our free software and
++of promoting the sharing and reuse of software generally.
++
++			    NO WARRANTY
++
++  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
++REPAIR OR CORRECTION.
++
++  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
++POSSIBILITY OF SUCH DAMAGES.
++
++		     END OF TERMS AND CONDITIONS
++
++	    How to Apply These Terms to Your New Programs
++
++  If you develop a new program, and you want it to be of the greatest
++possible use to the public, the best way to achieve this is to make it
++free software which everyone can redistribute and change under these terms.
++
++  To do so, attach the following notices to the program.  It is safest
++to attach them to the start of each source file to most effectively
++convey the exclusion of warranty; and each file should have at least
++the "copyright" line and a pointer to where the full notice is found.
++
++    <one line to give the program's name and a brief idea of what it does.>
++    Copyright (C) 19yy  <name of author>
++
++    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++
++
++Also add information on how to contact you by electronic and paper mail.
++
++If the program is interactive, make it output a short notice like this
++when it starts in an interactive mode:
++
++    Gnomovision version 69, Copyright (C) 19yy name of author
++    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
++    This is free software, and you are welcome to redistribute it
++    under certain conditions; type `show c' for details.
++
++The hypothetical commands `show w' and `show c' should show the appropriate
++parts of the General Public License.  Of course, the commands you use may
++be called something other than `show w' and `show c'; they could even be
++mouse-clicks or menu items--whatever suits your program.
++
++You should also get your employer (if you work as a programmer) or your
++school, if any, to sign a "copyright disclaimer" for the program, if
++necessary.  Here is a sample; alter the names:
++
++  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
++  `Gnomovision' (which makes passes at compilers) written by James Hacker.
++
++  <signature of Ty Coon>, 1 April 1989
++  Ty Coon, President of Vice
++
++This General Public License does not permit incorporating your program into
++proprietary programs.  If your program is a subroutine library, you may
++consider it more useful to permit linking proprietary applications with the
++library.  If this is what you want to do, use the GNU Library General
++Public License instead of this License.
+diff -urNad zaptel-1.2.3/zaphfc/Makefile /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/Makefile
+--- zaptel-1.2.3/zaphfc/Makefile	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/Makefile	2006-02-02 18:48:12.000000000 +0200
+@@ -0,0 +1,118 @@
++KINCLUDES = /usr/src/linux/include
++BRISTUFFBASE = $(shell dirname `pwd`)
++
++ZAP = $(shell [ -f $(BRISTUFFBASE)/zaptel-1.2.3/zaptel.h ] && echo "-I$(BRISTUFFBASE)/zaptel-1.2.3")
++RTAI = $(shell [ -f /usr/realtime/include/rtai.h ] && echo "-DRTAITIMING -I/usr/realtime/include")
++
++HOSTCC=gcc
++
++CFLAGS+=-I. $(ZAP) $(RTAI) -O2 -g -Wall -DBUILDING_TONEZONE 
++CFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi)
++
++KFLAGS=-D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -fomit-frame-pointer -O2 -Wall -I$(KINCLUDES) $(ZAP) $(RTAI) -Wall
++KFLAGS+=$(shell [ -f $(KINCLUDES)/linux/modversions.h ] && echo "-DMODVERSIONS -include $(KINCLUDES)/linux/modversions.h")
++KFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-msoft-float -fsigned-char"; fi)
++
++
++BUILDVER=$(shell if uname -r | grep -q ^2.6; then echo "linux26"; else echo "linux24"; fi)
++
++MODCONF=$(shell if [ -d $(INSTALL_PREFIX)/etc/modprobe.d ]; then echo "$(INSTALL_PREFIX)/etc/modprobe.d/zaptel"; elif [ -d $(INSTALL_PREFIX)/etc/modutils ]; then echo "$(INSTALL_PREFIX)/etc/modutils/zaptel"; elif [ -f $(INSTALL_PREFIX)/etc/modprobe.conf ]; then echo "$(INSTALL_PREFIX)/modprobe.conf"; elif [ -f $(INSTALL_PREFIX)/etc/modules.conf ]; then echo "$(INSTALL_PREFIX)/etc/modules.conf"; else echo $(INSTALL_PREFIX)/etc/conf.modules ; fi)
++
++OBJS=zaphfc.o
++
++MODULES=zaphfc
++
++MODULESO=$(shell for x in $(MODULES); do echo "$$x.o "; done )
++MODULESKO=$(shell for x in $(MODULES); do echo "$$x.ko "; done )
++
++PWD=$(shell pwd)
++
++obj-m := $(MODULESO)
++
++all: $(BUILDVER)
++
++linux24: $(OBJS)
++	sync
++
++
++zaphfc.o: zaphfc.c zaphfc.h
++	$(CC) -c zaphfc.c $(KFLAGS)
++
++clean:	
++	rm -f $(OBJS) *.ko *.mod.c *.mod.o .*o.cmd *~
++	rm -rf .tmp_versions
++
++test: all
++	modprobe zaptel
++	insmod ./zaphfc.o
++	cat /proc/interrupts
++	sleep 1
++	cat /proc/interrupts
++	rmmod zaphfc
++	rmmod zaptel
++
++load:	load$(BUILDVER)
++
++loadNT:	load$(BUILDVER)NT
++
++load-debug:	load$(BUILDVER)-debug
++
++loadNT-debug:	load$(BUILDVER)NT-debug
++
++loadlinux24: all
++	modprobe zaptel
++	insmod ./zaphfc.o
++	ztcfg -v
++
++loadlinux24-debug: all
++	modprobe zaptel
++	insmod ./zaphfc.o debug=1
++	ztcfg -v
++
++loadlinux26: linux26
++	modprobe zaptel
++	insmod ./zaphfc.ko
++	ztcfg -v
++
++loadlinux26-debug: linux26
++	modprobe zaptel
++	insmod ./zaphfc.ko debug=1
++	ztcfg -v
++
++loadlinux24NT: all
++	modprobe zaptel
++	insmod ./zaphfc.o modes=1
++	ztcfg -v
++
++loadlinux24NT-debug: all
++	modprobe zaptel
++	insmod ./zaphfc.o modes=1 debug=1
++	ztcfg -v
++
++loadlinux26NT: linux26
++	modprobe zaptel
++	insmod ./zaphfc.ko modes=1
++	ztcfg -v
++
++loadlinux26NT-debug: linux26
++	modprobe zaptel
++	insmod ./zaphfc.ko modes=1 debug=1
++	ztcfg -v
++
++unload: 
++	-rmmod zaphfc zaptel
++
++zaphfc.ko: zaphfc.c zaphfc.h
++
++linux26: 
++	@if ! [ -d /usr/src/linux-2.6 ]; then echo "Link /usr/src/linux-2.6 to your kernel sources first!"; exit 1 ; fi
++	make -C /usr/src/linux-2.6 SUBDIRS=$(PWD) ZAP=$(ZAP) modules
++
++install:	install$(BUILDVER)
++
++installlinux26:
++	install -D -m 644 zaphfc.ko $(INSTALL_PREFIX)/lib/modules/`uname -r`/misc/zaphfc.ko
++
++installlinux24:
++	install -D -m 644 zaphfc.o $(INSTALL_PREFIX)/lib/modules/`uname -r`/misc/zaphfc.o
++
+diff -urNad zaptel-1.2.3/zaphfc/zapata.conf /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/zapata.conf
+--- zaptel-1.2.3/zaphfc/zapata.conf	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/zapata.conf	2005-02-26 19:24:32.000000000 +0200
+@@ -0,0 +1,38 @@
++;
++; Zapata telephony interface
++;
++; Configuration file
++
++[channels]
++;
++; Default language
++;
++;language=en
++;
++; Default context
++;
++;
++switchtype = euroisdn
++; p2mp TE mode
++signalling = bri_cpe_ptmp
++
++; p2p TE mode
++;signalling = bri_cpe
++; p2mp NT mode
++;signalling = bri_net_ptmp
++; p2p NT mode
++;signalling = bri_net
++
++pridialplan = dynamic
++prilocaldialplan = local
++nationalprefix = 0
++internationalprefix = 00
++
++echocancel=yes
++echotraining = 100
++echocancelwhenbridged=yes
++
++immediate=yes
++group = 1
++context=demo
++channel => 1-2
+diff -urNad zaptel-1.2.3/zaphfc/zaphfc.c /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/zaphfc.c
+--- zaptel-1.2.3/zaphfc/zaphfc.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/zaphfc.c	2005-11-20 19:58:16.000000000 +0200
+@@ -0,0 +1,1149 @@
++/*
++ * zaphfc.c - Zaptel driver for HFC-S PCI A based ISDN BRI cards
++ *
++ * kernel module inspired by HFC PCI ISDN4Linux and Zaptel drivers
++ *
++ * Copyright (C) 2002, 2003, 2004, 2005 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>
++#ifdef RTAITIMING
++#include <asm/io.h>
++#include <rtai.h>
++#include <rtai_sched.h>
++#include <rtai_fifos.h>
++#endif
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <zaptel.h>
++#include "zaphfc.h"
++
++#if CONFIG_PCI
++
++#define CLKDEL_TE	0x0f	/* CLKDEL in TE mode */
++#define CLKDEL_NT	0x6c	/* CLKDEL in NT mode */
++
++typedef struct {
++        int vendor_id;
++        int device_id;
++        char *vendor_name;
++        char *card_name;
++} PCI_ENTRY;
++
++static const PCI_ENTRY id_list[] =
++{
++        {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, "CCD/Billion/Asuscom", "2BD0"},
++        {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, "Billion", "B000"},
++        {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, "Billion", "B006"},
++        {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, "Billion", "B007"},
++        {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, "Billion", "B008"},
++        {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, "Billion", "B009"},
++        {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, "Billion", "B00A"},
++        {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, "Billion", "B00B"},
++        {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, "Billion", "B00C"},
++        {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, "Seyeon", "B100"},
++        {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, "Abocom/Magitek", "2BD1"},
++        {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, "Asuscom/Askey", "675"},
++        {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, "German telekom", "T-Concept"},
++        {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, "German telekom", "A1T"},
++        {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, "Motorola MC145575", "MC145575"},
++        {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, "Zoltrix", "2BD0"},
++        {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E,"Digi International", "Digi DataFire Micro V IOM2 (Europe)"},
++        {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,"Digi International", "Digi DataFire Micro V (Europe)"},
++        {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,"Digi International", "Digi DataFire Micro V IOM2 (North America)"},
++        {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,"Digi International", "Digi DataFire Micro V (North America)"},
++	{0x182d, 0x3069,"Sitecom","Isdn 128 PCI"},
++        {0, 0, NULL, NULL},
++};
++
++static struct hfc_card *hfc_dev_list = NULL;
++static int hfc_dev_count = 0;
++static int modes = 0; // all TE
++static int debug = 0;
++static struct pci_dev *multi_hfc = NULL;
++static spinlock_t registerlock = SPIN_LOCK_UNLOCKED;
++
++void hfc_shutdownCard(struct hfc_card *hfctmp) {
++    unsigned long flags;
++
++    if (hfctmp == NULL) {
++	return;
++    }
++
++    if (hfctmp->pci_io == NULL) {
++	return;
++    }
++    
++    spin_lock_irqsave(&hfctmp->lock,flags);
++
++    printk(KERN_INFO "zaphfc: shutting down card at %p.\n",hfctmp->pci_io);
++
++    /* Clear interrupt mask */
++    hfctmp->regs.int_m2 = 0;
++    hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
++
++    /* Reset pending interrupts */
++    hfc_inb(hfctmp, hfc_INT_S1);
++
++    /* Wait for interrupts that might still be pending */
++    spin_unlock_irqrestore(&hfctmp->lock, flags);
++    set_current_state(TASK_UNINTERRUPTIBLE);
++    schedule_timeout((30 * HZ) / 1000);	// wait 30 ms
++    spin_lock_irqsave(&hfctmp->lock,flags);
++
++    /* Remove interrupt handler */
++    if (hfctmp->irq) {
++	free_irq(hfctmp->irq, hfctmp);
++    }
++
++    /* Soft-reset the card */
++    hfc_outb(hfctmp, hfc_CIRM, hfc_CIRM_RESET); // softreset on
++
++    spin_unlock_irqrestore(&hfctmp->lock, flags);
++    set_current_state(TASK_UNINTERRUPTIBLE);
++    schedule_timeout((30 * HZ) / 1000);	// wait 30 ms
++    spin_lock_irqsave(&hfctmp->lock,flags);
++
++    hfc_outb(hfctmp,hfc_CIRM,0);	// softreset off
++
++    pci_write_config_word(hfctmp->pcidev, PCI_COMMAND, 0);	// disable memio and bustmaster
++
++    if (hfctmp->fifomem != NULL) {
++        kfree(hfctmp->fifomem);
++    }
++    iounmap((void *) hfctmp->pci_io);
++    hfctmp->pci_io = NULL;
++    if (hfctmp->pcidev != NULL) {
++        pci_disable_device(hfctmp->pcidev);
++    }
++    spin_unlock_irqrestore(&hfctmp->lock,flags);
++    if (hfctmp->ztdev != NULL) {
++	zt_unregister(&hfctmp->ztdev->span);
++	kfree(hfctmp->ztdev);
++	printk(KERN_INFO "unregistered from zaptel.\n");
++    }
++}
++
++void hfc_resetCard(struct hfc_card *hfctmp) {
++    unsigned long flags;
++
++    spin_lock_irqsave(&hfctmp->lock,flags);
++    pci_write_config_word(hfctmp->pcidev, PCI_COMMAND, PCI_COMMAND_MEMORY);	// enable memio
++    hfctmp->regs.int_m2 = 0;
++    hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
++
++//    printk(KERN_INFO "zaphfc: resetting card.\n");
++    pci_set_master(hfctmp->pcidev);
++    hfc_outb(hfctmp, hfc_CIRM, hfc_CIRM_RESET);	// softreset on
++    spin_unlock_irqrestore(&hfctmp->lock, flags);
++
++    set_current_state(TASK_UNINTERRUPTIBLE);
++    schedule_timeout((30 * HZ) / 1000);	// wait 30 ms
++    hfc_outb(hfctmp, hfc_CIRM, 0);	// softreset off
++
++    set_current_state(TASK_UNINTERRUPTIBLE);
++    schedule_timeout((20 * HZ) / 1000);	// wait 20 ms
++    if (hfc_inb(hfctmp,hfc_STATUS) & hfc_STATUS_PCI_PROC) {
++	printk(KERN_WARNING "zaphfc: hfc busy.\n");
++    }
++
++//    hfctmp->regs.fifo_en = hfc_FIFOEN_D | hfc_FIFOEN_B1 | hfc_FIFOEN_B2;
++//    hfctmp->regs.fifo_en = hfc_FIFOEN_D;	/* only D fifos enabled */
++    hfctmp->regs.fifo_en = 0;	/* no fifos enabled */
++    hfc_outb(hfctmp, hfc_FIFO_EN, hfctmp->regs.fifo_en);
++
++    hfctmp->regs.trm = 2;
++    hfc_outb(hfctmp, hfc_TRM, hfctmp->regs.trm);
++
++    if (hfctmp->regs.nt_mode == 1) {
++	hfc_outb(hfctmp, hfc_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */
++    } else {
++	hfc_outb(hfctmp, hfc_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */
++    }
++    hfctmp->regs.sctrl_e = hfc_SCTRL_E_AUTO_AWAKE;
++    hfc_outb(hfctmp, hfc_SCTRL_E, hfctmp->regs.sctrl_e);	/* S/T Auto awake */
++    hfctmp->regs.bswapped = 0;	/* no exchange */
++
++    hfctmp->regs.ctmt = hfc_CTMT_TRANSB1 | hfc_CTMT_TRANSB2; // all bchans are transparent , no freaking hdlc
++    hfc_outb(hfctmp, hfc_CTMT, hfctmp->regs.ctmt);
++
++    hfctmp->regs.int_m1 = 0;
++    hfc_outb(hfctmp, hfc_INT_M1, hfctmp->regs.int_m1);
++
++#ifdef RTAITIMING
++    hfctmp->regs.int_m2 = 0;
++#else
++    hfctmp->regs.int_m2 = hfc_M2_PROC_TRANS;
++#endif
++    hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
++
++    /* Clear already pending ints */
++    hfc_inb(hfctmp, hfc_INT_S1);
++
++    if (hfctmp->regs.nt_mode == 1) {
++	hfctmp->regs.sctrl = 3 | hfc_SCTRL_NONE_CAP | hfc_SCTRL_MODE_NT;	/* set tx_lo mode, error in datasheet ! */
++    } else {
++	hfctmp->regs.sctrl = 3 | hfc_SCTRL_NONE_CAP | hfc_SCTRL_MODE_TE;	/* set tx_lo mode, error in datasheet ! */
++    }
++
++    hfctmp->regs.mst_mode = hfc_MST_MODE_MASTER;	/* HFC Master Mode */
++    hfc_outb(hfctmp, hfc_MST_MODE, hfctmp->regs.mst_mode);
++
++    hfc_outb(hfctmp, hfc_SCTRL, hfctmp->regs.sctrl);
++    hfctmp->regs.sctrl_r = 3;
++    hfc_outb(hfctmp, hfc_SCTRL_R, hfctmp->regs.sctrl_r);
++
++    hfctmp->regs.connect = 0;
++    hfc_outb(hfctmp, hfc_CONNECT, hfctmp->regs.connect);
++
++    hfc_outb(hfctmp, hfc_CIRM, 0x80 | 0x40);	// bit order
++
++    /* Finally enable IRQ output */
++#ifndef RTAITIMING
++    hfctmp->regs.int_m2 |= hfc_M2_IRQ_ENABLE;
++    hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
++#endif
++
++    /* clear pending ints */
++    hfc_inb(hfctmp, hfc_INT_S1); 
++    hfc_inb(hfctmp, hfc_INT_S2);
++}
++
++void hfc_registerCard(struct hfc_card *hfccard) {
++    spin_lock(&registerlock);
++    if (hfccard != NULL) {
++	hfccard->cardno = hfc_dev_count++;
++	hfccard->next = hfc_dev_list;
++	hfc_dev_list = hfccard;
++    }
++    spin_unlock(&registerlock);
++}
++
++static void hfc_btrans(struct hfc_card *hfctmp, char whichB) {
++    // we are called with irqs disabled from the irq handler
++    int count, maxlen, total;
++    unsigned char *f1, *f2;
++    unsigned short *z1, *z2, newz1;
++    int freebytes;
++
++    if (whichB == 1) {
++	f1 = (char *)(hfctmp->fifos + hfc_FIFO_B1TX_F1);
++        f2 = (char *)(hfctmp->fifos + hfc_FIFO_B1TX_F2);
++	z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1TX_Z1 + (*f1 * 4));
++	z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1TX_Z2 + (*f1 * 4));
++    } else {
++	f1 = (char *)(hfctmp->fifos + hfc_FIFO_B2TX_F1);
++        f2 = (char *)(hfctmp->fifos + hfc_FIFO_B2TX_F2);
++	z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2TX_Z1 + (*f1 * 4));
++	z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2TX_Z2 + (*f1 * 4));
++    }
++
++    freebytes = *z2 - *z1;
++    if (freebytes <= 0) {
++	freebytes += hfc_B_FIFO_SIZE;
++    }
++    count = ZT_CHUNKSIZE;
++
++    total = count;
++    if (freebytes < count) {
++	hfctmp->clicks++;
++	/* only spit out this warning once per second to not make things worse! */
++	if (hfctmp->clicks > 100) {
++	    printk(KERN_CRIT "zaphfc: bchan tx fifo full, dropping audio! (z1=%d, z2=%d)\n",*z1,*z2);
++	    hfctmp->clicks = 0;
++	}
++	return;
++    }
++    
++    maxlen = (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL) - *z1;
++    if (maxlen > count) {
++        maxlen = count;
++    }
++    newz1 = *z1 + total;
++    if (newz1 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) { newz1 -= hfc_B_FIFO_SIZE; }
++
++	if (whichB == 1) {
++	    memcpy((char *)(hfctmp->fifos + hfc_FIFO_B1TX_ZOFF + *z1),hfctmp->ztdev->chans[0].writechunk, maxlen);
++	} else {
++	    memcpy((char *)(hfctmp->fifos + hfc_FIFO_B2TX_ZOFF + *z1),hfctmp->ztdev->chans[1].writechunk, maxlen);
++	}
++	
++	count -= maxlen;
++	if (count > 0) {
++	// Buffer wrap
++	    if (whichB == 1) {
++	        memcpy((char *)(hfctmp->fifos + hfc_FIFO_B1TX_ZOFF + hfc_B_SUB_VAL),hfctmp->ztdev->chans[0].writechunk+maxlen, count);
++	    } else {
++	        memcpy((char *)(hfctmp->fifos + hfc_FIFO_B2TX_ZOFF + hfc_B_SUB_VAL),hfctmp->ztdev->chans[1].writechunk+maxlen, count);
++	    }
++	}
++
++    *z1 = newz1;	/* send it now */
++
++//    if (count > 0) printk(KERN_CRIT "zaphfc: bchan tx fifo (f1=%d, f2=%d, z1=%d, z2=%d)\n",(*f1) & hfc_FMASK,(*f2) & hfc_FMASK, *z1, *z2);
++    return;    
++}
++
++static void hfc_brec(struct hfc_card *hfctmp, char whichB) {
++    // we are called with irqs disabled from the irq handler
++    int count, maxlen, drop;
++    volatile unsigned char *f1, *f2;
++    volatile unsigned short *z1, *z2, newz2;
++    int bytes = 0;
++
++    if (whichB == 1) {
++	f1 = (char *)(hfctmp->fifos + hfc_FIFO_B1RX_F1);
++        f2 = (char *)(hfctmp->fifos + hfc_FIFO_B1RX_F2);
++	z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z1 + (*f1 * 4));
++	z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z2 + (*f1 * 4));
++    } else {
++	f1 = (char *)(hfctmp->fifos + hfc_FIFO_B2RX_F1);
++        f2 = (char *)(hfctmp->fifos + hfc_FIFO_B2RX_F2);
++	z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z1 + (*f1 * 4));
++	z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z2 + (*f1 * 4));
++    }
++
++    bytes = *z1 - *z2;
++    if (bytes < 0) {
++	bytes += hfc_B_FIFO_SIZE;
++    }
++    count = ZT_CHUNKSIZE;
++    
++    if (bytes < ZT_CHUNKSIZE) {
++#ifndef RTAITIMING
++	printk(KERN_CRIT "zaphfc: bchan rx fifo not enough bytes to receive! (z1=%d, z2=%d, wanted %d got %d), probably a buffer overrun.\n",*z1,*z2,ZT_CHUNKSIZE,bytes);
++#endif
++	return;
++    }
++
++    /* allowing the buffering of hfc_BCHAN_BUFFER bytes of audio data works around irq jitter */
++    if (bytes > hfc_BCHAN_BUFFER + ZT_CHUNKSIZE) {
++	/* if the system is too slow to handle it, we will have to drop it all (except 1 zaptel chunk) */
++	drop = bytes - ZT_CHUNKSIZE;
++	hfctmp->clicks++;
++	/* only spit out this warning once per second to not make things worse! */
++	if (hfctmp->clicks > 100) {
++	    printk(KERN_CRIT "zaphfc: dropped audio (z1=%d, z2=%d, wanted %d got %d, dropped %d).\n",*z1,*z2,count,bytes,drop);
++	    hfctmp->clicks = 0;
++	}
++	/* hm, we are processing the b chan data tooooo slowly... let's drop the lost audio */
++	newz2 = *z2 + drop;
++	if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) { 
++	    newz2 -= hfc_B_FIFO_SIZE; 
++	}
++	*z2 = newz2;
++    }
++
++    
++    maxlen = (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL) - *z2;
++    if (maxlen > count) {
++        maxlen = count;
++    }
++    if (whichB == 1) {
++        memcpy(hfctmp->ztdev->chans[0].readchunk,(char *)(hfctmp->fifos + hfc_FIFO_B1RX_ZOFF + *z2), maxlen);
++    } else {
++        memcpy(hfctmp->ztdev->chans[1].readchunk,(char *)(hfctmp->fifos + hfc_FIFO_B2RX_ZOFF + *z2), maxlen);
++    }
++    newz2 = *z2 + count;
++    if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) { 
++        newz2 -= hfc_B_FIFO_SIZE; 
++    }
++    *z2 = newz2;
++	
++    count -= maxlen;
++    if (count > 0) {
++    // Buffer wrap
++        if (whichB == 1) {
++	    z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z2 + (*f1 * 4));
++    	    memcpy(hfctmp->ztdev->chans[0].readchunk + maxlen,(char *)(hfctmp->fifos + hfc_FIFO_B1RX_ZOFF + hfc_B_SUB_VAL), count);
++	} else {
++	    z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z2 + (*f1 * 4));
++	    memcpy(hfctmp->ztdev->chans[1].readchunk + maxlen,(char *)(hfctmp->fifos + hfc_FIFO_B2RX_ZOFF + hfc_B_SUB_VAL), count);
++	}
++	newz2 = *z2 + count;
++	if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) { 
++	    newz2 -= hfc_B_FIFO_SIZE; 
++	}
++    }
++
++
++    if (whichB == 1) {
++	zt_ec_chunk(&hfctmp->ztdev->chans[0], hfctmp->ztdev->chans[0].readchunk, hfctmp->ztdev->chans[0].writechunk);
++    } else {
++	zt_ec_chunk(&hfctmp->ztdev->chans[1], hfctmp->ztdev->chans[1].readchunk, hfctmp->ztdev->chans[1].writechunk);
++    }
++    return;    
++}
++
++
++static void hfc_dtrans(struct hfc_card *hfctmp) {
++    // we are called with irqs disabled from the irq handler
++    int x;
++    int count, maxlen, total;
++    unsigned char *f1, *f2, newf1;
++    unsigned short *z1, *z2, newz1;
++    int frames, freebytes;
++
++    if (hfctmp->ztdev->chans[2].bytes2transmit == 0) {
++	return;
++    }
++
++    f1 = (char *)(hfctmp->fifos + hfc_FIFO_DTX_F1);
++    f2 = (char *)(hfctmp->fifos + hfc_FIFO_DTX_F2);
++    z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z1 + (*f1 * 4));
++    z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z2 + (*f1 * 4));
++
++    frames = (*f1 - *f2) & hfc_FMASK;
++    if (frames < 0) {
++	frames += hfc_MAX_DFRAMES + 1;
++    }
++
++    if (frames >= hfc_MAX_DFRAMES) {
++	printk(KERN_CRIT "zaphfc: dchan tx fifo total number of frames exceeded!\n");
++	return;
++    }
++
++    freebytes = *z2 - *z1;
++    if (freebytes <= 0) {
++	freebytes += hfc_D_FIFO_SIZE;
++    }
++    count = hfctmp->ztdev->chans[2].bytes2transmit;
++
++    total = count;
++    if (freebytes < count) {
++	printk(KERN_CRIT "zaphfc: dchan tx fifo not enough free bytes! (z1=%d, z2=%d)\n",*z1,*z2);
++	return;
++    }
++    
++    newz1 = (*z1 + count) & hfc_ZMASK;
++    newf1 = ((*f1 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1);	// next frame
++    
++    if (count > 0) {
++	if (debug) {
++    	    printk(KERN_CRIT "zaphfc: card %d TX [ ", hfctmp->cardno);
++	    for (x=0; x<count; x++) {
++		printk("%#2x ",hfctmp->dtransbuf[x]);
++	    }
++	    if (hfctmp->ztdev->chans[2].eoftx == 1) {
++		printk("] %d bytes\n", count);
++	    } else {
++		printk("..] %d bytes\n", count);
++	    }
++	}
++	maxlen = hfc_D_FIFO_SIZE - *z1;
++	if (maxlen > count) {
++	    maxlen = count;
++	}
++	memcpy((char *)(hfctmp->fifos + hfc_FIFO_DTX_ZOFF + *z1),hfctmp->ztdev->chans[2].writechunk, maxlen);
++	count -= maxlen;
++	if (count > 0) {
++	    memcpy((char *)(hfctmp->fifos + hfc_FIFO_DTX_ZOFF),(char *)(hfctmp->ztdev->chans[2].writechunk + maxlen), count);
++	}
++    }
++
++    *z1 = newz1;
++
++    if (hfctmp->ztdev->chans[2].eoftx == 1) {
++	*f1 = newf1;
++	z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z1 + (*f1 * 4));
++	*z1 = newz1;
++	hfctmp->ztdev->chans[2].eoftx = 0;
++    }
++//    printk(KERN_CRIT "zaphfc: dchan tx fifo (f1=%d, f2=%d, z1=%d, z2=%d)\n",(*f1) & hfc_FMASK,(*f2) & hfc_FMASK, *z1, *z2);
++    return;    
++}
++
++/* receive a complete hdlc frame, skip broken or short frames */
++static void hfc_drec(struct hfc_card *hfctmp) {
++    int count=0, maxlen=0, framelen=0;
++    unsigned char *f1, *f2, *crcstat;
++    unsigned short *z1, *z2, oldz2, newz2;
++
++    hfctmp->ztdev->chans[2].bytes2receive=0;
++    hfctmp->ztdev->chans[2].eofrx = 0;
++
++    /* put the received data into the zaptel buffer
++       we'll call zt_receive() later when the timer fires. */
++    f1 = (char *)(hfctmp->fifos + hfc_FIFO_DRX_F1);
++    f2 = (char *)(hfctmp->fifos + hfc_FIFO_DRX_F2);
++
++    if (*f1 == *f2) return; /* nothing received, strange eh? */
++
++    z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z1 + (*f2 * 4));
++    z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
++    
++    /* calculate length of frame, including 2 bytes CRC and 1 byte STAT */
++    count = *z1 - *z2;
++    
++    if (count < 0) { 
++	count += hfc_D_FIFO_SIZE; /* ring buffer wrapped */
++    }
++    count++;
++    framelen = count;
++
++    crcstat = (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF + *z1);
++
++    if ((framelen < 4) || (*crcstat != 0x0)) {
++	/* the frame is too short for a valid HDLC frame or the CRC is borked */
++	printk(KERN_CRIT "zaphfc: empty HDLC frame or bad CRC received (framelen = %d, stat = %#x, card = %d).\n", framelen, *crcstat, hfctmp->cardno);
++	oldz2 = *z2;
++	*f2 = ((*f2 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1);	/* NEXT!!! */
++        // recalculate z2, because Z2 is a function of F2 Z2(F2) and we INCed F2!!!
++	z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
++	*z2 = (oldz2 + framelen) & hfc_ZMASK;
++	hfctmp->drecinframe = 0;
++	hfctmp->regs.int_drec--;
++	/* skip short or broken frames */
++        hfctmp->ztdev->chans[2].bytes2receive = 0; 
++	return;
++    }
++
++    count -= 1;	/* strip STAT */
++    hfctmp->ztdev->chans[2].eofrx = 1;
++
++    if (count + *z2 <= hfc_D_FIFO_SIZE) {
++	maxlen = count;
++    } else {
++	maxlen = hfc_D_FIFO_SIZE - *z2;
++    }
++
++    /* copy first part */
++    memcpy(hfctmp->drecbuf, (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF + *z2), maxlen);
++    hfctmp->ztdev->chans[2].bytes2receive += maxlen; 
++    
++    count -= maxlen;
++    if (count > 0) {
++	/* ring buffer wrapped, copy rest from start of d fifo */
++	memcpy(hfctmp->drecbuf + maxlen, (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF), count);
++	hfctmp->ztdev->chans[2].bytes2receive += count; 
++    }
++
++    /* frame read */
++    oldz2 = *z2;
++    newz2 = (oldz2 + framelen) & hfc_ZMASK;
++    *f2 = ((*f2 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1);	/* NEXT!!! */
++    /* recalculate z2, because Z2 is a function of F2 Z2(F2) and we INCed F2!!! */
++    z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
++    *z2 = newz2;
++    hfctmp->drecinframe = 0;
++    hfctmp->regs.int_drec--; 
++}
++
++#ifndef RTAITIMING
++#ifdef LINUX26
++static irqreturn_t hfc_interrupt(int irq, void *dev_id, struct pt_regs *regs) {
++#else
++static void hfc_interrupt(int irq, void *dev_id, struct pt_regs *regs) {
++#endif
++    struct hfc_card *hfctmp = dev_id;
++    unsigned long flags = 0;
++    unsigned char stat;
++#else
++static void hfc_service(struct hfc_card *hfctmp) {
++#endif
++    struct zt_hfc *zthfc;
++    unsigned char s1, s2, l1state;
++    int x;
++
++    if (!hfctmp) {
++#ifndef RTAITIMING
++#ifdef LINUX26
++		return IRQ_NONE;
++#else
++		return;
++#endif		
++#else
++	/* rtai */
++	return;
++#endif
++    }
++
++    if (!hfctmp->pci_io) {
++	    printk(KERN_WARNING "%s: IO-mem disabled, cannot handle interrupt\n",
++		   __FUNCTION__);
++#ifndef RTAITIMING
++#ifdef LINUX26
++	    return IRQ_NONE;
++#else
++	    return;
++#endif		
++#else
++	/* rtai */
++	return;
++#endif
++    }
++    
++    /*	we assume a few things in this irq handler:
++	- the hfc-pci will only generate "timer" irqs (proc/non-proc)
++	- we need to use every 8th IRQ (to generate 1khz timing)
++	OR
++	- if we use rtai for timing the hfc-pci will not generate ANY irq,
++	  instead rtai will call this "fake" irq with a 1khz realtime timer. :)
++	- rtai will directly service the card, not like it used to by triggering
++	  the linux irq
++    */
++
++#ifndef RTAITIMING
++    spin_lock_irqsave(&hfctmp->lock, flags);
++    stat = hfc_inb(hfctmp, hfc_STATUS);
++
++    if ((stat & hfc_STATUS_ANYINT) == 0) {
++        // maybe we are sharing the irq
++	spin_unlock_irqrestore(&hfctmp->lock,flags);
++#ifdef LINUX26
++	return IRQ_NONE;
++#else
++	return;
++#endif		
++    }
++#endif
++
++    s1 = hfc_inb(hfctmp, hfc_INT_S1);
++    s2 = hfc_inb(hfctmp, hfc_INT_S2); 
++    if (s1 != 0) {
++	if (s1 & hfc_INTS_TIMER) {
++	    // timer (bit 7)
++	    // printk(KERN_CRIT "timer %d %d %d.\n", stat, s1, s2);
++	}
++	if (s1 & hfc_INTS_L1STATE) {
++	    // state machine (bit 6)
++	    // printk(KERN_CRIT "zaphfc: layer 1 state machine interrupt\n");
++	    zthfc = hfctmp->ztdev;
++	    l1state = hfc_inb(hfctmp,hfc_STATES)  & hfc_STATES_STATE_MASK;
++	    if (hfctmp->regs.nt_mode == 1) {
++		if (debug) {
++	    	    printk(KERN_CRIT "zaphfc: card %d layer 1 state = G%d\n", hfctmp->cardno, l1state);
++		}
++		switch (l1state) {
++		    case 3:
++#ifdef RTAITIMING
++			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 ACTIVATED (G%d) [realtime]", hfctmp->cardno, l1state);
++#else
++			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 ACTIVATED (G%d)", hfctmp->cardno, l1state);
++#endif
++			break;
++		    default:
++#ifdef RTAITIMING
++			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 DEACTIVATED (G%d) [realtime]", hfctmp->cardno, l1state);
++#else
++			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 DEACTIVATED (G%d)", hfctmp->cardno, l1state);
++#endif
++		}
++		if (l1state == 2) {
++		    hfc_outb(hfctmp, hfc_STATES, hfc_STATES_ACTIVATE | hfc_STATES_DO_ACTION | hfc_STATES_NT_G2_G3);
++		} else if (l1state == 3) {
++		    // fix to G3 state (see specs)
++		    hfc_outb(hfctmp, hfc_STATES, hfc_STATES_LOAD_STATE | 3);
++		}
++	    } else {
++		if (debug) {
++	    	    printk(KERN_CRIT "zaphfc: card %d layer 1 state = F%d\n", hfctmp->cardno, l1state);
++		}
++		switch (l1state) {
++		    case 7:
++#ifdef RTAITIMING
++			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 ACTIVATED (F%d) [realtime]", hfctmp->cardno, l1state);
++#else
++			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 ACTIVATED (F%d)", hfctmp->cardno, l1state);
++#endif
++			break;
++		    default:
++#ifdef RTAITIMING
++			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 DEACTIVATED (F%d) [realtime]", hfctmp->cardno, l1state);
++#else
++			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 DEACTIVATED (F%d)", hfctmp->cardno, l1state);
++#endif
++		}
++		if (l1state == 3) {
++		    hfc_outb(hfctmp, hfc_STATES, hfc_STATES_DO_ACTION | hfc_STATES_ACTIVATE);
++		}
++	    }
++	    
++	}
++	if (s1 & hfc_INTS_DREC) {
++	    // D chan RX (bit 5)
++	    hfctmp->regs.int_drec++;
++	    // mr. zapata there is something for you!
++	//    printk(KERN_CRIT "d chan rx\n");		    
++	}
++	if (s1 & hfc_INTS_B2REC) {
++	    // B2 chan RX (bit 4)
++	}
++	if (s1 & hfc_INTS_B1REC) {
++	    // B1 chan RX (bit 3)
++	}
++	if (s1 & hfc_INTS_DTRANS) {
++	    // D chan TX (bit 2)
++//	    printk(KERN_CRIT "zaphfc: dchan frame transmitted.\n");
++	}
++	if (s1 & hfc_INTS_B2TRANS) {
++	    // B2 chan TX (bit 1)
++	}
++	if (s1 & hfc_INTS_B1TRANS) {
++	    // B1 chan TX (bit 0)
++	}
++    }
++#ifdef RTAITIMING
++    /* fake an irq */
++    s2 |= hfc_M2_PROC_TRANS;
++#endif
++    if (s2 != 0) {
++	if (s2 & hfc_M2_PMESEL) {
++	    // kaboom irq (bit 7)
++	    printk(KERN_CRIT "zaphfc: sync lost, pci performance too low. you might have some cpu throtteling enabled.\n");
++	}
++	if (s2 & hfc_M2_GCI_MON_REC) {
++	    // RxR monitor channel (bit 2)
++	}
++	if (s2 & hfc_M2_GCI_I_CHG) {
++	    // GCI I-change  (bit 1)
++	}
++	if (s2 & hfc_M2_PROC_TRANS) {
++	    // processing/non-processing transition  (bit 0)
++	    hfctmp->ticks++;
++#ifndef RTAITIMING
++	    if (hfctmp->ticks > 7) {
++		// welcome to zaptel timing :)
++#endif
++	    	hfctmp->ticks = 0;
++
++		if (hfctmp->ztdev->span.flags & ZT_FLAG_RUNNING) {
++		    // clear dchan buffer
++		    hfctmp->ztdev->chans[2].bytes2transmit = 0;
++		    hfctmp->ztdev->chans[2].maxbytes2transmit = hfc_D_FIFO_SIZE;
++
++		    zt_transmit(&(hfctmp->ztdev->span));
++
++		    hfc_btrans(hfctmp,1);
++		    hfc_btrans(hfctmp,2);
++		    hfc_dtrans(hfctmp);
++		}
++
++		hfc_brec(hfctmp,1);
++		hfc_brec(hfctmp,2);
++		if (hfctmp->regs.int_drec > 0) {
++		    // dchan data to read
++		    hfc_drec(hfctmp);
++		    if (hfctmp->ztdev->chans[2].bytes2receive > 0) {
++			    if (debug) {
++    				printk(KERN_CRIT "zaphfc: card %d RX [ ", hfctmp->cardno);
++				if (hfctmp->ztdev->chans[2].eofrx) {
++				    /* dont output CRC == less user confusion */
++				    for (x=0; x < hfctmp->ztdev->chans[2].bytes2receive - 2; x++) {
++					printk("%#2x ", hfctmp->drecbuf[x]);
++				    }
++				    printk("] %d bytes\n", hfctmp->ztdev->chans[2].bytes2receive - 2);
++				} else {
++				    for (x=0; x < hfctmp->ztdev->chans[2].bytes2receive; x++) {
++					printk("%#2x ", hfctmp->drecbuf[x]);
++				    }
++				    printk("..] %d bytes\n", hfctmp->ztdev->chans[2].bytes2receive);
++				}
++			    }
++		    }
++		} else {
++			// hmm....ok, let zaptel receive nothing
++		    hfctmp->ztdev->chans[2].bytes2receive = 0;
++		}
++		if (hfctmp->ztdev->span.flags & ZT_FLAG_RUNNING) {
++		    zt_receive(&(hfctmp->ztdev->span));
++		}
++		
++#ifndef RTAITIMING
++	    }
++#endif
++	}
++
++    }
++#ifndef RTAITIMING
++    spin_unlock_irqrestore(&hfctmp->lock,flags);
++#ifdef LINUX26
++	return IRQ_RETVAL(1);
++#endif		
++#endif
++}
++
++
++static int zthfc_open(struct zt_chan *chan) {
++    struct zt_hfc *zthfc = chan->pvt;
++    struct hfc_card *hfctmp = zthfc->card;
++    
++    if (!hfctmp) {
++    return 0;
++    }
++#ifndef LINUX26  
++    MOD_INC_USE_COUNT;
++#else
++    try_module_get(THIS_MODULE);
++#endif
++    return 0;
++}
++
++static int zthfc_close(struct zt_chan *chan) {
++    struct zt_hfc *zthfc = chan->pvt;
++    struct hfc_card *hfctmp = zthfc->card;
++
++    if (!hfctmp) {
++	return 0;
++    }
++
++#ifndef LINUX26  
++    MOD_DEC_USE_COUNT;
++#else
++    module_put(THIS_MODULE);
++#endif
++    return 0;
++}
++
++static int zthfc_rbsbits(struct zt_chan *chan, int bits) {
++    return 0;
++}
++
++static int zthfc_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) {
++        switch(cmd) {
++        default:
++                return -ENOTTY;
++        }
++        return 0;
++}
++
++static int zthfc_startup(struct zt_span *span) {
++    struct zt_hfc *zthfc = span->pvt;
++    struct hfc_card *hfctmp = zthfc->card;
++    int alreadyrunning;
++    
++    if (hfctmp == NULL) {
++	printk(KERN_INFO "zaphfc: no card for span at startup!\n");
++    }
++    alreadyrunning = span->flags & ZT_FLAG_RUNNING;
++    
++    if (!alreadyrunning) {
++	span->chans[2].flags &= ~ZT_FLAG_HDLC;
++	span->chans[2].flags |= ZT_FLAG_BRIDCHAN;
++	
++	span->flags |= ZT_FLAG_RUNNING;
++
++	hfctmp->ticks = -2;
++	hfctmp->clicks = 0;
++	hfctmp->regs.fifo_en = hfc_FIFOEN_D | hfc_FIFOEN_B1 | hfc_FIFOEN_B2;
++        hfc_outb(hfctmp, hfc_FIFO_EN, hfctmp->regs.fifo_en);
++    } else {
++	return 0;
++    }
++
++    // drivers, start engines!
++    hfc_outb(hfctmp, hfc_STATES, hfc_STATES_DO_ACTION | hfc_STATES_ACTIVATE);
++    return 0;
++}
++
++static int zthfc_shutdown(struct zt_span *span) {
++    return 0;
++}
++
++static int zthfc_maint(struct zt_span *span, int cmd) {
++    return 0;
++}
++
++static int zthfc_chanconfig(struct zt_chan *chan, int sigtype) {
++//    printk(KERN_CRIT "chan_config sigtype=%d\n", sigtype);
++    return 0;
++}
++
++static int zthfc_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) {
++    span->lineconfig = lc->lineconfig;
++    return 0;
++}
++
++static int zthfc_initialize(struct zt_hfc *zthfc) {
++    struct hfc_card *hfctmp = zthfc->card;
++    int i;
++
++    memset(&zthfc->span, 0x0, sizeof(struct zt_span)); // you never can tell...
++
++    sprintf(zthfc->span.name, "ZTHFC%d", hfc_dev_count + 1);
++    if (hfctmp->regs.nt_mode == 1) {
++#ifdef RTAITIMING
++	sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] [realtime]", hfc_dev_count + 1);
++#else
++	sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT]", hfc_dev_count + 1);
++#endif
++    } else {
++#ifdef RTAITIMING
++	sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] [realtime]", hfc_dev_count + 1);
++#else
++	sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE]", hfc_dev_count + 1);
++#endif
++    }
++
++    zthfc->span.spanconfig = zthfc_spanconfig;
++    zthfc->span.chanconfig = zthfc_chanconfig;
++    zthfc->span.startup = zthfc_startup;
++    zthfc->span.shutdown = zthfc_shutdown;
++    zthfc->span.maint = zthfc_maint;
++    zthfc->span.rbsbits = zthfc_rbsbits;
++    zthfc->span.open = zthfc_open;
++    zthfc->span.close = zthfc_close;
++    zthfc->span.ioctl = zthfc_ioctl;
++
++    zthfc->span.chans = zthfc->chans;
++    zthfc->span.channels = 3;
++    zthfc->span.deflaw = ZT_LAW_ALAW;
++    zthfc->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_CCS; // <--- this is really BS
++    zthfc->span.offset = 0;
++    init_waitqueue_head(&zthfc->span.maintq);
++    zthfc->span.pvt = zthfc;
++
++    for (i = 0; i < zthfc->span.channels; i++) {
++	memset(&(zthfc->chans[i]), 0x0, sizeof(struct zt_chan));
++	sprintf(zthfc->chans[i].name, "ZTHFC%d/%d/%d", hfc_dev_count + 1,0,i + 1);
++	zthfc->chans[i].pvt = zthfc;
++	zthfc->chans[i].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;
++	zthfc->chans[i].chanpos = i + 1; 
++    }
++
++    if (zt_register(&zthfc->span,0)) {
++	printk(KERN_CRIT "unable to register zaptel device!\n");
++	return -1;
++    }
++//    printk(KERN_CRIT "zaphfc: registered zaptel device!\n");
++    return 0;
++}
++
++#ifdef RTAITIMING
++#define TICK_PERIOD  1000000
++#define TICK_PERIOD2 1000000000
++#define TASK_PRIORITY 1
++#define STACK_SIZE 10000
++
++static RT_TASK rt_task;
++static struct hfc_card *rtai_hfc_list[hfc_MAX_CARDS];
++static unsigned char rtai_hfc_counter = 0;
++
++static void rtai_register_hfc(struct hfc_card *hfctmp) {
++    rtai_hfc_list[rtai_hfc_counter++] = hfctmp;
++}
++
++static void rtai_loop(int t) {
++    int i=0;
++    for (;;) {
++	for (i=0; i < rtai_hfc_counter; i++) {
++	    if (rtai_hfc_list[i] != NULL)
++		hfc_service(rtai_hfc_list[i]);
++	}
++        rt_task_wait_period();
++    }
++}
++#endif
++
++int hfc_findCards(int pcivendor, int pcidevice, char *vendor_name, char *card_name) {
++    struct pci_dev *tmp;
++    struct hfc_card *hfctmp = NULL;
++    struct zt_hfc *zthfc = NULL;
++
++    tmp = pci_find_device(pcivendor, pcidevice, multi_hfc);
++    while (tmp != NULL) {
++	multi_hfc = tmp;	// skip this next time.
++
++	if (pci_enable_device(tmp)) {
++	    multi_hfc = NULL;
++	    return -1;
++	}
++	pci_set_master(tmp);
++
++	hfctmp = kmalloc(sizeof(struct hfc_card), GFP_KERNEL);
++	if (!hfctmp) {
++	    printk(KERN_WARNING "zaphfc: unable to kmalloc!\n");
++	    pci_disable_device(tmp);
++	    multi_hfc = NULL;
++	    return -ENOMEM;
++	}
++	memset(hfctmp, 0x0, sizeof(struct hfc_card));
++	spin_lock_init(&hfctmp->lock);
++	
++	hfctmp->pcidev = tmp;
++	hfctmp->pcibus = tmp->bus->number;
++	hfctmp->pcidevfn = tmp->devfn; 
++
++	if (!tmp->irq) {
++	    printk(KERN_WARNING "zaphfc: no irq!\n");
++	} else {
++	    hfctmp->irq = tmp->irq;
++	}
++
++	hfctmp->pci_io = (char *) tmp->resource[1].start;
++	if (!hfctmp->pci_io) {
++	    printk(KERN_WARNING "zaphfc: no iomem!\n");
++	    kfree(hfctmp);
++	    pci_disable_device(tmp);
++	    multi_hfc = NULL;
++	    return -1;
++	}
++	
++	hfctmp->fifomem = kmalloc(65536, GFP_KERNEL);
++	if (!hfctmp->fifomem) {
++	    printk(KERN_WARNING "zaphfc: unable to kmalloc fifomem!\n");
++	    kfree(hfctmp);
++	    pci_disable_device(tmp);
++	    multi_hfc = NULL;
++	    return -ENOMEM;
++	} else {
++	    memset(hfctmp->fifomem, 0x0, 65536);
++	    hfctmp->fifos = (((ulong) hfctmp->fifomem) & ~0x7FFF) + 0x8000;
++	    pci_write_config_dword(hfctmp->pcidev, 0x80, (u_int) virt_to_bus(hfctmp->fifos));
++	    hfctmp->pci_io = ioremap((ulong) hfctmp->pci_io, 256);
++	}
++
++#ifdef RTAITIMING
++	/* we need no stinking irq */
++	hfctmp->irq = 0;
++#else
++	if (request_irq(hfctmp->irq, &hfc_interrupt, SA_INTERRUPT | SA_SHIRQ, "zaphfc", hfctmp)) {
++	    printk(KERN_WARNING "zaphfc: unable to register irq\n");
++	    kfree(hfctmp->fifomem);
++	    kfree(hfctmp);
++	    iounmap((void *) hfctmp->pci_io);
++	    pci_disable_device(tmp);
++	    multi_hfc = NULL;
++	    return -EIO;
++	}
++#endif
++
++#ifdef RTAITIMING
++	rtai_register_hfc(hfctmp);
++#endif
++	printk(KERN_INFO
++		       "zaphfc: %s %s configured at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
++			vendor_name, card_name,
++		       (u_int) hfctmp->pci_io,
++		       (u_int) hfctmp->fifos,
++		       (u_int) virt_to_bus(hfctmp->fifos),
++		       hfctmp->irq, HZ); 
++	pci_write_config_word(hfctmp->pcidev, PCI_COMMAND, PCI_COMMAND_MEMORY);	// enable memio
++	hfctmp->regs.int_m1 = 0;	// no ints
++	hfctmp->regs.int_m2 = 0;	// not at all
++	hfc_outb(hfctmp,hfc_INT_M1,hfctmp->regs.int_m1);
++	hfc_outb(hfctmp,hfc_INT_M2,hfctmp->regs.int_m2);
++
++	if ((modes & (1 << hfc_dev_count)) != 0) {
++	    printk(KERN_INFO "zaphfc: Card %d configured for NT mode\n",hfc_dev_count);
++	    hfctmp->regs.nt_mode = 1;
++	} else {
++	    printk(KERN_INFO "zaphfc: Card %d configured for TE mode\n",hfc_dev_count);
++	    hfctmp->regs.nt_mode = 0;
++	}
++
++	zthfc = kmalloc(sizeof(struct zt_hfc),GFP_KERNEL);
++	if (!zthfc) {
++	    printk(KERN_CRIT "zaphfc: unable to kmalloc!\n");
++	    hfc_shutdownCard(hfctmp);
++	    kfree(hfctmp);
++	    multi_hfc = NULL;
++	    return -ENOMEM;
++	}
++	memset(zthfc, 0x0, sizeof(struct zt_hfc));
++
++	zthfc->card = hfctmp;
++	zthfc_initialize(zthfc);
++	hfctmp->ztdev = zthfc;
++
++	memset(hfctmp->drecbuf, 0x0, sizeof(hfctmp->drecbuf));
++	hfctmp->ztdev->chans[2].readchunk = hfctmp->drecbuf;
++
++	memset(hfctmp->dtransbuf, 0x0, sizeof(hfctmp->dtransbuf));
++	hfctmp->ztdev->chans[2].writechunk = hfctmp->dtransbuf;
++
++	memset(hfctmp->brecbuf[0], 0x0, sizeof(hfctmp->brecbuf[0]));
++	hfctmp->ztdev->chans[0].readchunk = hfctmp->brecbuf[0];
++	memset(hfctmp->btransbuf[0], 0x0, sizeof(hfctmp->btransbuf[0]));
++	hfctmp->ztdev->chans[0].writechunk = hfctmp->btransbuf[0];
++
++	memset(hfctmp->brecbuf[1], 0x0, sizeof(hfctmp->brecbuf[1]));
++	hfctmp->ztdev->chans[1].readchunk = hfctmp->brecbuf[1];
++	memset(hfctmp->btransbuf[1], 0x0, sizeof(hfctmp->btransbuf[1]));
++	hfctmp->ztdev->chans[1].writechunk = hfctmp->btransbuf[1];
++
++
++	hfc_registerCard(hfctmp);
++	hfc_resetCard(hfctmp);
++	tmp = pci_find_device(pcivendor, pcidevice, multi_hfc);
++    }
++    return 0;
++}
++
++
++
++int init_module(void) {
++    int i = 0;
++#ifdef RTAITIMING
++    RTIME tick_period;
++    for (i=0; i < hfc_MAX_CARDS; i++) {
++	rtai_hfc_list[i] = NULL;
++    }
++    rt_set_periodic_mode();
++#endif
++    i = 0;
++    while (id_list[i].vendor_id) {
++	multi_hfc = NULL;
++	hfc_findCards(id_list[i].vendor_id, id_list[i].device_id, id_list[i].vendor_name, id_list[i].card_name);
++	i++;
++    }
++#ifdef RTAITIMING
++    for (i=0; i < hfc_MAX_CARDS; i++) {
++        if (rtai_hfc_list[i]) {
++	    printk(KERN_INFO
++		       "zaphfc: configured %d at mem %#x fifo %#x(%#x) for realtime servicing\n",
++			rtai_hfc_list[i]->cardno,
++		       (u_int) rtai_hfc_list[i]->pci_io,
++		       (u_int) rtai_hfc_list[i]->fifos,
++		       (u_int) virt_to_bus(rtai_hfc_list[i]->fifos));
++
++	}
++    }
++    rt_task_init(&rt_task, rtai_loop, 1, STACK_SIZE, TASK_PRIORITY, 0, 0);
++    tick_period = start_rt_timer(nano2count(TICK_PERIOD));
++    rt_task_make_periodic(&rt_task, rt_get_time() + tick_period, tick_period);
++#endif
++    printk(KERN_INFO "zaphfc: %d hfc-pci card(s) in this box.\n", hfc_dev_count);
++    return 0;
++}
++
++void cleanup_module(void) {
++    struct hfc_card *tmpcard;
++#ifdef RTAITIMING
++    stop_rt_timer();
++    rt_task_delete(&rt_task);
++#endif
++    printk(KERN_INFO "zaphfc: stop\n");
++//    spin_lock(&registerlock);
++    while (hfc_dev_list != NULL) {
++	if (hfc_dev_list == NULL) break;
++	hfc_shutdownCard(hfc_dev_list);
++	tmpcard = hfc_dev_list;
++	hfc_dev_list = hfc_dev_list->next;
++	if (tmpcard != NULL) {
++	    kfree(tmpcard);
++	    tmpcard = NULL;
++	    printk(KERN_INFO "zaphfc: freed one card.\n");
++	}
++    }
++//    spin_unlock(&registerlock);
++}
++#endif
++
++
++MODULE_DESCRIPTION("HFC-S PCI A Zaptel Driver");
++MODULE_AUTHOR("Klaus-Peter Junghanns <kpj at junghanns.net>");
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("GPL");
++#endif	
++MODULE_PARM(modes,"i");
++MODULE_PARM(debug,"i");
+diff -urNad zaptel-1.2.3/zaphfc/zaphfc.h /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/zaphfc.h
+--- zaptel-1.2.3/zaphfc/zaphfc.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/zaphfc.h	2005-02-27 00:30:32.000000000 +0200
+@@ -0,0 +1,289 @@
++/*
++ * zaphfc.h - Zaptel driver for HFC-S PCI A based ISDN BRI cards
++ *
++ * kernel module based on HFC PCI ISDN4Linux and Zaptel drivers
++ *
++ * Copyright (C) 2002, 2003, 2004, 2005 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.
++ *
++ */
++
++/* HFC register addresses - accessed using memory mapped I/O */
++/* For a list, see datasheet section 3.2.1 at page 21 */
++
++#define hfc_outb(a,b,c) (writeb((c),(a)->pci_io+(b)))
++#define hfc_inb(a,b) (readb((a)->pci_io+(b)))
++
++/* GCI/IOM bus monitor registers */
++
++#define hfc_C_I       0x08
++#define hfc_TRxR      0x0C
++#define hfc_MON1_D    0x28
++#define hfc_MON2_D    0x2C
++
++
++/* GCI/IOM bus timeslot registers */
++
++#define hfc_B1_SSL    0x80
++#define hfc_B2_SSL    0x84
++#define hfc_AUX1_SSL  0x88
++#define hfc_AUX2_SSL  0x8C
++#define hfc_B1_RSL    0x90
++#define hfc_B2_RSL    0x94
++#define hfc_AUX1_RSL  0x98
++#define hfc_AUX2_RSL  0x9C
++
++/* GCI/IOM bus data registers */
++
++#define hfc_B1_D      0xA0
++#define hfc_B2_D      0xA4
++#define hfc_AUX1_D    0xA8
++#define hfc_AUX2_D    0xAC
++
++/* GCI/IOM bus configuration registers */
++
++#define hfc_MST_EMOD  0xB4
++#define hfc_MST_MODE	 0xB8
++#define hfc_CONNECT 	 0xBC
++
++
++/* Interrupt and status registers */
++
++#define hfc_FIFO_EN   0x44
++#define hfc_TRM       0x48
++#define hfc_B_MODE    0x4C
++#define hfc_CHIP_ID   0x58
++#define hfc_CIRM  	 0x60
++#define hfc_CTMT	 0x64
++#define hfc_INT_M1  	 0x68
++#define hfc_INT_M2  	 0x6C
++#define hfc_INT_S1  	 0x78
++#define hfc_INT_S2  	 0x7C
++#define hfc_STATUS  	 0x70
++
++/* S/T section registers */
++
++#define hfc_STATES  	 0xC0
++#define hfc_SCTRL  	 0xC4
++#define hfc_SCTRL_E   0xC8
++#define hfc_SCTRL_R   0xCC
++#define hfc_SQ  	 0xD0
++#define hfc_CLKDEL  	 0xDC
++#define hfc_B1_REC    0xF0
++#define hfc_B1_SEND   0xF0
++#define hfc_B2_REC    0xF4
++#define hfc_B2_SEND   0xF4
++#define hfc_D_REC     0xF8
++#define hfc_D_SEND    0xF8
++#define hfc_E_REC     0xFC
++
++/* Bits and values in various HFC PCI registers */
++
++/* bits in status register (READ) */
++#define hfc_STATUS_PCI_PROC   0x02
++#define hfc_STATUS_NBUSY	  0x04 
++#define hfc_STATUS_TIMER_ELAP 0x10
++#define hfc_STATUS_STATINT	  0x20
++#define hfc_STATUS_FRAMEINT	  0x40
++#define hfc_STATUS_ANYINT	  0x80
++
++/* bits in CTMT (Write) */
++#define hfc_CTMT_CLTIMER    0x80
++#define hfc_CTMT_TIM3_125   0x04
++#define hfc_CTMT_TIM25      0x10
++#define hfc_CTMT_TIM50      0x14
++#define hfc_CTMT_TIM400     0x18
++#define hfc_CTMT_TIM800     0x1C
++#define hfc_CTMT_AUTO_TIMER 0x20
++#define hfc_CTMT_TRANSB2    0x02
++#define hfc_CTMT_TRANSB1    0x01
++
++/* bits in CIRM (Write) */
++#define hfc_CIRM_AUX_MSK    0x07
++#define hfc_CIRM_RESET  	  0x08
++#define hfc_CIRM_B1_REV     0x40
++#define hfc_CIRM_B2_REV     0x80
++
++/* bits in INT_M1 and INT_S1 */
++#define hfc_INTS_B1TRANS  0x01
++#define hfc_INTS_B2TRANS  0x02
++#define hfc_INTS_DTRANS   0x04
++#define hfc_INTS_B1REC    0x08
++#define hfc_INTS_B2REC    0x10
++#define hfc_INTS_DREC     0x20
++#define hfc_INTS_L1STATE  0x40
++#define hfc_INTS_TIMER    0x80
++
++/* bits in INT_M2 */
++#define hfc_M2_PROC_TRANS    0x01
++#define hfc_M2_GCI_I_CHG     0x02
++#define hfc_M2_GCI_MON_REC   0x04
++#define hfc_M2_IRQ_ENABLE    0x08
++#define hfc_M2_PMESEL        0x80
++
++/* bits in STATES */
++#define hfc_STATES_STATE_MASK     0x0F
++#define hfc_STATES_LOAD_STATE    0x10
++#define hfc_STATES_ACTIVATE	     0x20
++#define hfc_STATES_DO_ACTION     0x40
++#define hfc_STATES_NT_G2_G3      0x80
++
++/* bits in HFCD_MST_MODE */
++#define hfc_MST_MODE_MASTER	     0x01
++#define hfc_MST_MODE_SLAVE         0x00
++/* remaining bits are for codecs control */
++
++/* bits in HFCD_SCTRL */
++#define hfc_SCTRL_B1_ENA	     0x01
++#define hfc_SCTRL_B2_ENA	     0x02
++#define hfc_SCTRL_MODE_TE        0x00
++#define hfc_SCTRL_MODE_NT        0x04
++#define hfc_SCTRL_LOW_PRIO	     0x08
++#define hfc_SCTRL_SQ_ENA	     0x10
++#define hfc_SCTRL_TEST	     0x20
++#define hfc_SCTRL_NONE_CAP	     0x40
++#define hfc_SCTRL_PWR_DOWN	     0x80
++
++/* bits in SCTRL_E  */
++#define hfc_SCTRL_E_AUTO_AWAKE    0x01
++#define hfc_SCTRL_E_DBIT_1        0x04
++#define hfc_SCTRL_E_IGNORE_COL    0x08
++#define hfc_SCTRL_E_CHG_B1_B2     0x80
++
++/* bits in FIFO_EN register */
++#define hfc_FIFOEN_B1TX   0x01
++#define hfc_FIFOEN_B1RX   0x02
++#define hfc_FIFOEN_B2TX   0x04
++#define hfc_FIFOEN_B2RX   0x08
++#define hfc_FIFOEN_DTX    0x10
++#define hfc_FIFOEN_DRX    0x20
++
++#define hfc_FIFOEN_B1     (hfc_FIFOEN_B1TX|hfc_FIFOEN_B1RX)
++#define hfc_FIFOEN_B2     (hfc_FIFOEN_B2TX|hfc_FIFOEN_B2RX)
++#define hfc_FIFOEN_D      (hfc_FIFOEN_DTX|hfc_FIFOEN_DRX)
++
++/* bits in the CONNECT register */
++#define hfc_CONNECT_B1_shift	0
++#define hfc_CONNECT_B2_shift	3
++
++#define	hfc_CONNECT_HFC_from_ST		0x0
++#define hfc_CONNECT_HFC_from_GCI	0x1
++#define hfc_CONNECT_ST_from_HFC		0x0
++#define hfc_CONNECT_ST_from_GCI		0x2
++#define hfc_CONNECT_GCI_from_HFC	0x0
++#define	hfc_CONNECT_GCI_from_ST		0x4
++
++/* bits in the __SSL and __RSL registers */
++#define	hfc_SRSL_STIO	0x40
++#define hfc_SRSL_ENABLE	0x80
++#define hfc_SRCL_SLOT_MASK	0x1f
++
++/* FIFO memory definitions */
++
++#define hfc_FMASK	0x000f
++#define hfc_ZMASK	0x01ff
++#define hfc_ZMASKB	0x1fff
++
++#define hfc_D_FIFO_SIZE	0x0200
++#define hfc_B_SUB_VAL	0x0200
++#define hfc_B_FIFO_SIZE	0x1E00
++#define hfc_MAX_DFRAMES	0x000f
++
++#define hfc_FIFO_DTX_Z1	0x2080
++#define hfc_FIFO_DTX_Z2 0x2082
++#define hfc_FIFO_DTX_F1	0x20a0
++#define hfc_FIFO_DTX_F2	0x20a1
++#define hfc_FIFO_DTX	0x0000
++#define hfc_FIFO_DTX_ZOFF	0x000
++
++#define hfc_FIFO_DRX_Z1	0x6080
++#define hfc_FIFO_DRX_Z2 0x6082
++#define hfc_FIFO_DRX_F1	0x60a0
++#define hfc_FIFO_DRX_F2	0x60a1
++#define hfc_FIFO_DRX	0x4000
++#define hfc_FIFO_DRX_ZOFF	0x4000
++
++#define hfc_FIFO_B1TX_Z1	0x2000
++#define hfc_FIFO_B1TX_Z2 	0x2002
++#define hfc_FIFO_B1RX_Z1	0x6000
++#define hfc_FIFO_B1RX_Z2 	0x6002
++
++#define hfc_FIFO_B1TX_F1	0x2080
++#define hfc_FIFO_B1TX_F2	0x2081
++#define hfc_FIFO_B1RX_F1	0x6080
++#define hfc_FIFO_B1RX_F2	0x6081
++
++#define hfc_FIFO_B1RX_ZOFF	0x4000
++#define hfc_FIFO_B1TX_ZOFF	0x0000
++
++#define hfc_FIFO_B2TX_Z1	0x2100
++#define hfc_FIFO_B2TX_Z2 	0x2102
++#define hfc_FIFO_B2RX_Z1	0x6100
++#define hfc_FIFO_B2RX_Z2 	0x6102
++
++#define hfc_FIFO_B2TX_F1	0x2180
++#define hfc_FIFO_B2TX_F2	0x2181
++#define hfc_FIFO_B2RX_F1	0x6180
++#define hfc_FIFO_B2RX_F2	0x6181
++
++#define hfc_FIFO_B2RX_ZOFF	0x6000
++#define hfc_FIFO_B2TX_ZOFF	0x2000
++
++#define hfc_BTRANS_THRESHOLD 128
++#define hfc_BTRANS_THRESMASK 0x00
++
++/* Structures */
++
++typedef struct hfc_regs {
++    unsigned char fifo_en;
++    unsigned char ctmt;
++    unsigned char int_m1;
++    unsigned char int_m2;
++    unsigned char sctrl;
++    unsigned char sctrl_e;
++    unsigned char sctrl_r;
++    unsigned char connect;
++    unsigned char trm;
++    unsigned char mst_mode;
++    unsigned char bswapped;
++    unsigned char nt_mode;
++    unsigned char int_drec;
++} hfc_regs;
++
++typedef struct hfc_card {
++    spinlock_t lock;
++    unsigned int irq;
++    unsigned int iomem;
++    int ticks;		
++    int clicks;		
++    unsigned char *pci_io;
++    void *fifomem;		// start of the shared mem
++    volatile void *fifos;	// 32k aligned mem for the fifos
++    struct hfc_regs regs;
++    unsigned int pcibus;
++    unsigned int pcidevfn;
++    struct pci_dev *pcidev;
++    struct zt_hfc *ztdev;
++    int	drecinframe;
++    unsigned char drecbuf[hfc_D_FIFO_SIZE];
++    unsigned char dtransbuf[hfc_D_FIFO_SIZE];
++    unsigned char brecbuf[2][ZT_CHUNKSIZE];
++    unsigned char btransbuf[2][ZT_CHUNKSIZE];
++    unsigned char cardno;
++    struct hfc_card *next;
++} hfc_card;
++
++typedef struct zt_hfc {
++    unsigned int usecount;
++    struct zt_span span;
++    struct zt_chan chans[3];
++    struct hfc_card *card;
++} zt_hfc;
++
++/* tune this */
++#define hfc_BCHAN_BUFFER	8
++#define hfc_MAX_CARDS		8
+diff -urNad zaptel-1.2.3/zaphfc/zaptel.conf /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/zaptel.conf
+--- zaptel-1.2.3/zaphfc/zaptel.conf	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaphfc/zaptel.conf	2004-03-24 16:35:12.000000000 +0200
+@@ -0,0 +1,8 @@
++# hfc-s pci a span definition
++# most of the values should be bogus because we are not really zaptel
++loadzone=nl
++defaultzone=nl
++
++span=1,1,3,ccs,ami
++bchan=1-2
++dchan=3
+diff -urNad zaptel-1.2.3/zaptel.c /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaptel.c
+--- zaptel-1.2.3/zaptel.c	2005-12-17 04:04:05.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaptel.c	2006-02-06 13:54:07.000000000 +0200
+@@ -4913,11 +4913,40 @@
+ 					*(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc);
+ 				}
+ 				bytes -= left;
++#ifdef CONFIG_ZAPATA_BRI_DCHANS
++			} else if (ms->flags & ZT_FLAG_BRIDCHAN) {
++			    /*
++			     * Let's get this right, we want to transmit complete frames only.
++			     * The card driver will do the dirty HDLC work for us.
++			     * txb (transmit buffer) is supposed to be big enough to store one frame
++			     * we will make this as big as the D fifo (1KB or 2KB)
++			     */
++
++			    /* there are 'left' bytes in the user buffer left to transmit */
++			    left = ms->writen[ms->outwritebuf] - ms->writeidx[ms->outwritebuf] - 2;
++			    if (left > ms->maxbytes2transmit) {
++				memcpy(txb, buf + ms->writeidx[ms->outwritebuf], ms->maxbytes2transmit);
++				ms->writeidx[ms->outwritebuf] += ms->maxbytes2transmit;
++				txb += ms->maxbytes2transmit;
++				ms->bytes2transmit = ms->maxbytes2transmit;
++				ms->eoftx = 0;
++			    } else {
++				memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left);
++				ms->writeidx[ms->outwritebuf] += left + 2;
++				txb += left;
++				ms->bytes2transmit = left;
++				ms->eoftx = 1;
++			    }
++			    bytes = 0;
++#endif
+ 			} else {
+ 				memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left);
+ 				ms->writeidx[ms->outwritebuf]+=left;
+ 				txb += left;
+ 				bytes -= left;
++#if defined(CONFIG_ZAPATA_BRI_DCHANS)	
++				ms->bytes2transmit=ZT_CHUNKSIZE;
++#endif
+ 			}
+ 			/* Check buffer status */
+ 			if (ms->writeidx[ms->outwritebuf] >= ms->writen[ms->outwritebuf]) {
+@@ -4962,6 +4991,17 @@
+ 				/* Transmit a flag if this is an HDLC channel */
+ 				if (ms->flags & ZT_FLAG_HDLC)
+ 					fasthdlc_tx_frame_nocheck(&ms->txhdlc);
++#if defined(CONFIG_ZAPATA_BRI_DCHANS)	
++				if(ms->flags & ZT_FLAG_BRIDCHAN) { 
++			//	    if (ms->bytes2transmit > 0) {
++					// txb += 2;
++					// ms->bytes2transmit -= 2;
++					bytes=0;
++					ms->eoftx = 1;
++//					printk(KERN_CRIT "zaptel EOF(%d) bytes2transmit %d\n",ms->eoftx,ms->bytes2transmit);
++			//	    }
++				}
++#endif
+ #ifdef CONFIG_ZAPATA_NET
+ 				if (ms->flags & ZT_FLAG_NETDEV)
+ 					netif_wake_queue(ztchan_to_dev(ms));
+@@ -5018,6 +5058,10 @@
+ 				memset(txb, 0xFF, bytes);
+ 			}
+ 			bytes = 0;
++#if defined(CONFIG_ZAPATA_BRI_DCHANS)	
++		} else if(ms->flags & ZT_FLAG_BRIDCHAN) { 
++		    bytes = 0;
++#endif
+ 		} else {
+ 			memset(txb, ZT_LIN2X(0, ms), bytes);	/* Lastly we use silence on telephony channels */
+ 			bytes = 0;
+@@ -5743,6 +5787,13 @@
+ 	int left, x;
+ 
+ 	int bytes = ZT_CHUNKSIZE;
++#if defined(CONFIG_ZAPATA_BRI_DCHANS)	
++	if (ms->flags & ZT_FLAG_BRIDCHAN) {
++	    bytes = ms->bytes2receive;
++	    if (bytes < 1) return;
++//	    printk(KERN_CRIT "bytes2receive %d\n",ms->bytes2receive);
++	}
++#endif
+ 
+ 	while(bytes) {
+ #if defined(CONFIG_ZAPATA_NET)  || defined(CONFIG_ZAPATA_PPP)
+@@ -5801,6 +5852,19 @@
+ 						}
+ 					}
+ 				}
++#ifdef CONFIG_ZAPATA_BRI_DCHANS
++			} else if (ms->flags & ZT_FLAG_BRIDCHAN) {
++			    memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left);
++			    rxb += left;
++			    ms->readidx[ms->inreadbuf] += left;
++			    bytes -= left;
++			    if (ms->eofrx == 1) {
++				eof=1;
++			    }
++//			    printk(KERN_CRIT "receiving %d bytes\n",ms->bytes2receive);
++			    ms->bytes2receive = 0;
++			    ms->eofrx = 0;
++#endif
+ 			} else {
+ 				/* Not HDLC */
+ 				memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left);
+diff -urNad zaptel-1.2.3/zaptel.h /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaptel.h
+--- zaptel-1.2.3/zaptel.h	2005-12-17 04:04:05.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zaptel.h	2006-02-06 13:54:07.000000000 +0200
+@@ -994,6 +994,13 @@
+ 	int do_ppp_error;
+ 	struct sk_buff_head ppp_rq;
+ #endif
++#ifdef CONFIG_ZAPATA_BRI_DCHANS
++	int bytes2receive;
++	int maxbytes2transmit; /* size of the tx buffer in the card driver */
++	int bytes2transmit;
++	int eofrx;
++	int eoftx;
++#endif
+ 	spinlock_t lock;
+ 	char name[40];		/* Name */
+ 	/* Specified by zaptel */
+@@ -1231,6 +1238,10 @@
+ #define ZT_FLAG_T1PPP			(1 << 15)
+ #define ZT_FLAG_SIGFREEZE		(1 << 16)	/* Freeze signalling */
+ 
++#if defined(CONFIG_ZAPATA_BRI_DCHANS)	
++#define ZT_FLAG_BRIDCHAN		(1 << 17)
++#endif
++
+ struct zt_span {
+ 	spinlock_t lock;
+ 	void *pvt;			/* Private stuff */
+diff -urNad zaptel-1.2.3/zconfig.h /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zconfig.h
+--- zaptel-1.2.3/zconfig.h	2005-11-29 20:42:08.000000000 +0200
++++ /tmp/dpep.Uu0Ujg/zaptel-1.2.3/zconfig.h	2006-02-06 13:54:07.000000000 +0200
+@@ -152,4 +152,10 @@
+  */
+ /* #define FXSFLASH */
+ 
++/*
++ * Uncomment the following for BRI D channels
++ *
++ */
++#define CONFIG_ZAPATA_BRI_DCHANS
++
+ #endif


Property changes on: zaptel/trunk/debian/patches/bristuff.dpatch
___________________________________________________________________
Name: svn:executable
   + *




More information about the Pkg-voip-commits mailing list