--- zaptel-1.2.11.dfsg.orig/cwain/cwain.c +++ zaptel-1.2.11.dfsg/cwain/cwain.c @@ -0,0 +1,1629 @@ +/* + * 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 + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + * + */ +#include +#include +#include +#include +#include +#include +#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;ispans;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;ispans;i++) { + cwain_shutdown_span(cwaintmp->span[i]); + } + spin_unlock_irqrestore(&cwaintmp->lock,flags); + + for (i=0;ispans;i++) { + release_region(cwaintmp->span[i]->ioport, 8); + cwaintmp->span[i]->ioport = 0; + iounmap((void *) cwaintmp->span[i]->pci_io); + cwaintmp->span[i]->pci_io = NULL; + release_mem_region((unsigned long)cwaintmp->span[i]->pci_io_phys, 256); + } + + if (cwaintmp->spans == 2) { + free_irq(cwaintmp->span[1]->irq,cwaintmp); + } + 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 | PCI_COMMAND_IO); // 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_IRQMSK_MISC,0x0); + 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 %lx IRQ %d HZ %d CardID %d\n", + (unsigned long) 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 (%lx / %lx) IRQ %d HZ %d CardID (%d / %d) bus %#x\n", + (unsigned long) cwaintmp->span[0]->pci_io, (unsigned long) 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;xchans[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,f; + if (fifo >= 15) { + chan = fifo; + } else { + chan = fifo; + } + /* select fifo */ + cwain_outb(cwaintmp,cwain_R_FIFO,0x80 | (fifo << 1)); + cwain_waitbusy(cwaintmp); + + for (f=0; f < (cwain_FRAME_SIZE/4); f++) { + cwain_outdw(cwaintmp,cwain_A_FIFO_DATA0,*((unsigned int *) &cwaintmp->ftxbuf[chan][f * 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; idrxbuf[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 int data; + int len,i,f,flen = 0; + unsigned short z1=1,z2=1; + unsigned short oz1=0,oz2=0; + int mumbojumbo=0; + int x = 1000; + + 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))) { + len = z1 - z2; + if (len < 0) { + len += cwain_FIFO_SIZE; + } + flen = len; + if (len > cwain_FIFO_HW) { + mumbojumbo = len - (cwain_FIFO_HW - cwain_FRAME_SIZE); + len = cwain_FRAME_SIZE; + } + oz1 = z1; + oz2 = z2; + z1 = cwain_inw(cwaintmp,cwain_A_Z1) & 0x7f; + z2 = cwain_inw(cwaintmp,cwain_A_Z2) & 0x7f; + } + if (x < 500) { + printk(KERN_CRIT "cwain: prevented endless loop\n"); + } + + if (mumbojumbo > 0) { + for (i=0;i<(mumbojumbo/4);i++) { + data = cwain_indw(cwaintmp,cwain_A_FIFO_DATA0); + } + cwaintmp->clicks++; + } + if (len < cwain_FRAME_SIZE) { + /* dont get nervous here */ + if ((cwaintmp->clicks > 600) && (cwaintmp->span.alarms == ZT_ALARM_NONE)) { + printk(KERN_INFO "cwain: not enough to receive (%d bytes)\n",len); + } + return 0; + } else { + for (f=0;f<(cwain_FRAME_SIZE / 4);f++) { + *((unsigned int *) &cwaintmp->frxbuf[chan][f*4]) = cwain_indw(cwaintmp,cwain_A_FIFO_DATA0); + } + } + + + /* dont get nervous here */ + if ((cwaintmp->clicks > 500) && (cwaintmp->span.alarms == ZT_ALARM_NONE)) { + printk(KERN_INFO "cwain: span %d dropped audio fifo %d mj %d flen %d z1 %d z2 %d\n", cwaintmp->cardID, fifo, mumbojumbo, flen, z1, z2); + 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; + int sync_ok = 0; + + for (i=0; i < cwaintmp->spans; i++) { + if (cwaintmp->span[i]->span.lineconfig & ZT_CONFIG_CRC4) { + /* CRC4 requested */ + sync_ok = 0x27; + } else { + /* doubleframing requested */ + sync_ok = 0x07; + } + if ((cwaintmp->syncs[i] > 0) && ((cwaintmp->span[i]->sync_sta & sync_ok) == sync_ok)) { + 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 ticks) { + 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++) { + /* copy to fbuffer */ + if ((ticks < 1) || (ticks > 8)) { + printk(KERN_INFO "cwain: whicked ticks make whicked tricks (%d)\n",cwaintmp->ticks); + } else { + memcpy(&cwaintmp->ftxbuf[fifo][(ticks-1)*8], cwaintmp->txbuf[fifo], ZT_CHUNKSIZE); + } + + } + 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++) { + /* copy from fbuffer */ + memcpy(cwaintmp->rxbuf[fifo], &cwaintmp->frxbuf[fifo][(ticks-1)*8], ZT_CHUNKSIZE); + zt_ec_chunk(&cwaintmp->span.chans[fifo], cwaintmp->span.chans[fifo].readchunk, cwaintmp->span.chans[fifo].writechunk); + } + + /* 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)); + } +} + +static inline void cwain_isr_err(struct zt_cwain *cwaintmp) { + unsigned short crc, vio, ebit, fas; + + crc = (cwain_inb(cwaintmp, cwain_R_CRC_ECH) << 8) | cwain_inb(cwaintmp, cwain_R_CRC_ECL); + vio = (cwain_inb(cwaintmp, cwain_R_VIO_ECH) << 8) | cwain_inb(cwaintmp, cwain_R_VIO_ECL); + ebit = (cwain_inb(cwaintmp, cwain_R_E_ECH) << 8) | cwain_inb(cwaintmp, cwain_R_E_ECL); + fas = (cwain_inb(cwaintmp, cwain_R_FAS_ECH) << 8) | cwain_inb(cwaintmp, cwain_R_FAS_ECL); + + cwaintmp->span.crc4count += crc; + cwaintmp->span.bpvcount += vio; + cwaintmp->span.ebitcount += ebit; + cwaintmp->span.fascount += fas; + + if (debug > 2) + printk("cwain: CRC4 %d BPVIOL %d EBIT %d FAS %d\n", crc, vio, ebit, fas); +} + + +static inline void cwain_audio_run(struct zt_cwain *cwaintmp) { + int fifo=0; + for (fifo=0; fifo < 30; fifo++) { + /* B xmit */ + cwain_fifo_tx(cwaintmp, fifo); + } + + for (fifo=0; fifo < 30; fifo++) { + /* B rx */ + cwain_fifo_rx(cwaintmp, fifo); + } +} + +int cwain_isr_sync(struct zt_cwain *cwainspan) { + unsigned char sync_sta; + unsigned char sync_ok = 0; + unsigned char jatt_sta = 0; + int res = 0; /* assume no l1event */ + + if (!cwainspan->span.flags & ZT_FLAG_RUNNING) { + return res; + } + + 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.crc4count = 0; + cwainspan->span.bpvcount = 0; + cwainspan->span.ebitcount = 0; + cwainspan->span.fascount = 0; + cwainspan->span.alarms = ZT_ALARM_NONE; + zt_alarm_notify(&cwainspan->span); + res = 1; + } + 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); + res = 1; + } + + 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); + } + return res; +} + +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 cardID %d\n", cwainspan->cardID); + cwainspan->drx += 1; + } + } + return 1; + } + return 0; +} + +#ifdef LINUX26 +static irqreturn_t cwain_dummy_interrupt(int irq, void *dev_id, struct pt_regs *regs) { +#else +static void cwain_dummy_interrupt(int irq, void *dev_id, struct pt_regs *regs) { +#endif + struct zt_cwain_card *cwaintmp = dev_id; + if (!cwaintmp) { +#ifdef LINUX26 + return IRQ_NONE; +#else + return; +#endif + } + if (debug > 3) + printk(KERN_INFO "cwain: dummy irq\n"); +#ifdef LINUX26 + return IRQ_RETVAL(1); +#endif +} + + +#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 = 0; +#ifndef RELAXED_LOCKING + unsigned long flags; +#endif + int i = 0; + int l1event = 0; + + if (!cwaintmp || cwaintmp->dead) { +#ifdef LINUX26 + return IRQ_NONE; +#else + return; +#endif + } + +#ifdef RELAXED_LOCKING + spin_lock(&(cwaintmp->lock)); +#else + spin_lock_irqsave(&(cwaintmp->lock),flags); +#endif + status = cwain_inb(cwaintmp->span[0],cwain_R_STATUS); + + status2 = 0; + + for (i=0;ispans;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! +#ifdef RELAXED_LOCKING + spin_unlock(&(cwaintmp->lock)); +#else + spin_unlock_irqrestore(&(cwaintmp->lock),flags); +#endif +#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++; + if (cwaintmp->ticks == 1) { + for (i=0;ispans;i++) { + cwain_audio_run(cwaintmp->span[i]); + } + } + for (i=0;ispans;i++) { + cwain_isr_run(cwaintmp->span[i], cwaintmp->ticks); + } + if (cwaintmp->ticks == (cwain_FRAME_SIZE / 8)) { + 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) { + if (l1event == 0) { + /* just in case we missed it */ + for (i=0;ispans;i++) { + l1event += 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); + for (i=0;ispans;i++) { + cwain_isr_sync(cwaintmp->span[i]); + } + if (cwaintmp->spans == 2) { + cwain_check_timing(cwaintmp); + } + } + +#ifdef RELAXED_LOCKING + spin_unlock(&(cwaintmp->lock)); +#else + spin_unlock_irqrestore(&(cwaintmp->lock),flags); +#endif +#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,0xe0); + /* 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_OUT,0xe0); + /* layer 1, up! */ + cwain_outb(cwaintmp,cwain_R_E1_WR_STA,0x11); + } + + cwaintmp->sync = 0; + cwaintmp->sync_sta = 0; + + /* enable irqs */ + if (!span->offset) { + cwain_outb(cwaintmp,cwain_R_IRQ_CTRL, 8 | 1); + } else { + cwain_outb(cwaintmp,cwain_R_IRQ_CTRL, 0x1); + } + 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; + } + if (request_irq(cwaintmp->span[1]->irq, cwain_dummy_interrupt, SA_INTERRUPT | SA_SHIRQ, "cwaindummy", 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;ispans;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); + cwain_outb(cwaintmp->span[1],cwain_R_IRQMSK_MISC, 0x0); + } + /* 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_phys = (char *) tmp->resource[1].start; + if (!cwaintmp->pci_io_phys) { + 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->ioport = tmp->resource[0].start; + if (!cwaintmp->ioport) { + printk(KERN_WARNING "cwain: no ioport!\n"); + pci_disable_device(tmp); + multi_cwain = NULL; + return -EIO; + } + if (!request_region(cwaintmp->ioport, 8, "cwain")) { + printk(KERN_WARNING "cwain: couldnt request io range!\n"); + pci_disable_device(tmp); + multi_cwain = NULL; + return -EIO; + } + + if (!request_mem_region((unsigned long) cwaintmp->pci_io_phys, 256, "cwain")) { + printk(KERN_WARNING "cwain: couldnt request io mem range!\n"); + release_region(cwaintmp->ioport, 8); + pci_disable_device(tmp); + multi_cwain = NULL; + return -EIO; + } + + cwaintmp->irq = tmp->irq; + + cwaintmp->pci_io = ioremap((ulong) cwaintmp->pci_io_phys, 256); + + /* enable memio */ + pci_write_config_word(cwaintmp->pcidev, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_IO); + + /* 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; ispans; 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 + +#ifdef LINUX26 +module_param(ports, int, 0600); +module_param(debug, int, 0600); +#else +MODULE_PARM(ports,"i"); +MODULE_PARM(debug,"i"); +#endif + +MODULE_DESCRIPTION("cwain zaptel driver"); +MODULE_AUTHOR("Klaus-Peter Junghanns "); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif --- zaptel-1.2.11.dfsg.orig/cwain/zaptel.conf.doubleE1 +++ zaptel-1.2.11.dfsg/cwain/zaptel.conf.doubleE1 @@ -0,0 +1,14 @@ +loadzone=nl +defaultzone=nl +span=1,1,3,ccs,hdb3,crc4 +span=2,2,3,ccs,hdb3,crc4 + +alaw=1-62 + +bchan=1-15 +dchan=16 +bchan=17-31 + +bchan=32-46 +dchan=47 +bchan=48-62 --- zaptel-1.2.11.dfsg.orig/cwain/zapata.conf.doubleE1 +++ zaptel-1.2.11.dfsg/cwain/zapata.conf.doubleE1 @@ -0,0 +1,35 @@ +; +; Zapata telephony interface +; +; Configuration file + +[channels] +; +; Default language +; +;language=en +; +; Default context +; +; +switchtype = euroisdn + +signalling = pri_cpe + +pridialplan = local +prilocaldialplan = dynamic +nationalprefix = 0 +internationalprefix = 00 + +priindication = passthrough + +echocancel = yes + +context=demo + +group = 1 +channel => 1-15,17-31 + +group = 2 +channel => 32-46,48-62 + --- zaptel-1.2.11.dfsg.orig/cwain/zaptel.conf +++ zaptel-1.2.11.dfsg/cwain/zaptel.conf @@ -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 + + --- zaptel-1.2.11.dfsg.orig/cwain/zapata.conf +++ zaptel-1.2.11.dfsg/cwain/zapata.conf @@ -0,0 +1,32 @@ +; +; Zapata telephony interface +; +; Configuration file + +[channels] +; +; Default language +; +;language=en +; +; Default context +; +; +switchtype = euroisdn + +signalling = pri_cpe + +pridialplan = local +prilocaldialplan = dynamic +nationalprefix = 0 +internationalprefix = 00 + +priindication = passthrough + +echocancel = yes + +context=demo + +group = 1 +channel => 1-15,17-31 + --- zaptel-1.2.11.dfsg.orig/cwain/TODO +++ zaptel-1.2.11.dfsg/cwain/TODO @@ -0,0 +1 @@ + --- zaptel-1.2.11.dfsg.orig/cwain/cwain.h +++ zaptel-1.2.11.dfsg/cwain/cwain.h @@ -0,0 +1,245 @@ +#define cwain_FIFO_SIZE 128 +#define cwain_DFIFO_SIZE 4096 +#define cwain_FRAME_SIZE 16 /* has to be %4==0 */ +#define cwain_FIFO_HW cwain_FRAME_SIZE * 2 + ZT_CHUNKSIZE + +typedef struct zt_cwain { + /* pci resources */ + unsigned int irq; + unsigned int iomem; + unsigned long ioport; + unsigned char *pci_io; + void *pci_io_phys; + 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]; + + /* buffers */ + unsigned char frxbuf[30][cwain_FRAME_SIZE]; + unsigned char ftxbuf[30][cwain_FRAME_SIZE]; + + /* 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 */ + --- zaptel-1.2.11.dfsg.orig/cwain/Makefile +++ zaptel-1.2.11.dfsg/cwain/Makefile @@ -0,0 +1,90 @@ +KINCLUDES = /usr/src/linux/include +BRISTUFFBASE = $(shell dirname `pwd`) + +ZAP = $(shell [ -f $(BRISTUFFBASE)/zaptel/zaptel.h ] && echo "-I$(BRISTUFFBASE)/zaptel") + +HOSTCC=gcc + +CFLAGS+=-I. $(ZAP) -DRELAXED_LOCKING -O4 -g -Wall #-DBLINKYBLINK +CFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi) + +KFLAGS=-D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -DRELAXED_LOCKING -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 --- zaptel-1.2.11.dfsg.orig/vzaphfc/lapd.c +++ zaptel-1.2.11.dfsg/vzaphfc/lapd.c @@ -0,0 +1,45 @@ +/* + * lapd.c + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + * + */ + +#include +#include + +#include "lapd.h" + +static int lapd_change_mtu(struct net_device *dev, int mtu) +{ + return -EINVAL; +} + +static int lapd_mac_addr(struct net_device *dev, void *addr) +{ + return -EINVAL; +} + +void setup_lapd(struct net_device *netdev) +{ + + netdev->change_mtu = lapd_change_mtu; + netdev->hard_header = NULL; + netdev->rebuild_header = NULL; + netdev->set_mac_address = lapd_mac_addr; + netdev->hard_header_cache = NULL; + netdev->header_cache_update= NULL; + + netdev->type = ARPHRD_LAPD; + netdev->hard_header_len = 0; + netdev->mtu = 512; + netdev->addr_len = 0; + netdev->tx_queue_len = 10; + + memset(netdev->broadcast, 0x00, sizeof(netdev->broadcast)); + + netdev->flags = IFF_NOARP; +} + + --- zaptel-1.2.11.dfsg.orig/vzaphfc/fifo.c +++ zaptel-1.2.11.dfsg/vzaphfc/fifo.c @@ -0,0 +1,366 @@ +/* + * fifo.c - HFC FIFO management routines + * + * Copyright (C) 2006 headissue GmbH; Jens Wilke + * Copyright (C) 2004 Daniele Orlandi + * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH + * + * Original author of this code is + * Daniele "Vihai" Orlandi + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + * + */ + +#include + +#include "../zaptel.h" + +#include "fifo.h" + +static void hfc_fifo_mem_read(struct hfc_chan_simplex *chan, + int z_start, + void *data, int size) +{ + int bytes_to_boundary = chan->z_max - z_start + 1; + if (bytes_to_boundary >= size) { + memcpy(data, + chan->z_base + z_start, + size); + } else { + // Buffer wrap + memcpy(data, + chan->z_base + z_start, + bytes_to_boundary); + + memcpy(data + bytes_to_boundary, + chan->fifo_base, + size - bytes_to_boundary); + } +} + +static void hfc_fifo_mem_write(struct hfc_chan_simplex *chan, + void *data, int size) +{ + int bytes_to_boundary = chan->z_max - *Z1_F1(chan) + 1; + if (bytes_to_boundary >= size) { + memcpy(chan->z_base + *Z1_F1(chan), + data, + size); + } else { + // FIFO wrap + + memcpy(chan->z_base + *Z1_F1(chan), + data, + bytes_to_boundary); + + memcpy(chan->fifo_base, + data + bytes_to_boundary, + size - bytes_to_boundary); + } +} + +int hfc_fifo_get(struct hfc_chan_simplex *chan, + void *data, int size) +{ + int available_bytes; + + // Some useless statistic + chan->bytes += size; + + available_bytes = hfc_fifo_used_rx(chan); + + if (available_bytes < size && !chan->fifo_underrun++) { + // print the warning only once + printk(KERN_WARNING hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "RX FIFO not enough (%d) bytes to receive!\n", + chan->chan->card->cardnum, + chan->chan->name, + available_bytes); + return -1; + } + + hfc_fifo_mem_read(chan, *Z2_F2(chan), data, size); + *Z2_F2(chan) = Z_inc(chan, *Z2_F2(chan), size); + return available_bytes - size; +} + +/* +static void hfc_fifo_drop(struct hfc_chan_simplex *chan, int size) +{ + int available_bytes = hfc_fifo_used_rx(chan); + if (available_bytes + 1 < size) { + printk(KERN_WARNING hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "RX FIFO not enough (%d) bytes to drop!\n", + chan->chan->card->cardnum, + chan->chan->name, + available_bytes); + + return; + } + + *Z2_F2(chan) = Z_inc(chan, *Z2_F2(chan), size); +} +*/ + +void hfc_fifo_put(struct hfc_chan_simplex *chan, + void *data, int size) +{ + struct hfc_card *card = chan->chan->card; + int used_bytes = hfc_fifo_used_tx(chan); + int free_bytes = hfc_fifo_free_tx(chan); + + if (!used_bytes && !chan->fifo_underrun++) { + // print warning only once, to make timing not worse + printk(KERN_WARNING hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "TX FIFO has become empty\n", + card->cardnum, + chan->chan->name); + } + if (free_bytes < size) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "TX FIFO full!\n", + chan->chan->card->cardnum, + chan->chan->name); + chan->fifo_full++; + hfc_clear_fifo_tx(chan); + } + + hfc_fifo_mem_write(chan, data, size); + chan->bytes += size; + *Z1_F1(chan) = Z_inc(chan, *Z1_F1(chan), size); +} + +int hfc_fifo_get_frame(struct hfc_chan_simplex *chan, void *data, int max_size) +{ + int frame_size; + u16 newz2 ; + + if (*chan->f1 == *chan->f2) { + // nothing received, strange uh? + printk(KERN_WARNING hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "get_frame called with no frame in FIFO.\n", + chan->chan->card->cardnum, + chan->chan->name); + + return -1; + } + + // frame_size includes CRC+CRC+STAT + frame_size = hfc_fifo_get_frame_size(chan); + +#ifdef DEBUG + if(debug_level == 3) { + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "RX len %2d: ", + chan->chan->card->cardnum, + chan->chan->name, + frame_size); + } else if(debug_level >= 4) { + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "RX (f1=%02x, f2=%02x, z1=%04x, z2=%04x) len %2d: ", + chan->chan->card->cardnum, + chan->chan->name, + *chan->f1, *chan->f2, *Z1_F2(chan), *Z2_F2(chan), + frame_size); + } + + if(debug_level >= 3) { + int i; + for (i=0; i < frame_size; i++) { + printk("%02x", hfc_fifo_u8(chan, + Z_inc(chan, *Z2_F2(chan), i))); + } + + printk("\n"); + } +#endif + + if (frame_size <= 0) { +#ifdef DEBUG + if (debug_level >= 2) { + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "invalid (empty) frame received.\n", + chan->chan->card->cardnum, + chan->chan->name); + } +#endif + + hfc_fifo_drop_frame(chan); + return -1; + } + + // STAT is not really received + chan->bytes += frame_size - 1; + + // Calculate beginning of the next frame + newz2 = Z_inc(chan, *Z2_F2(chan), frame_size); + + // We cannot use hfc_fifo_get because of different semantic of + // "available bytes" and to avoid useless increment of Z2 + hfc_fifo_mem_read(chan, *Z2_F2(chan), data, + frame_size < max_size ? frame_size : max_size); + + if (hfc_fifo_u8(chan, Z_inc(chan, *Z2_F2(chan), + frame_size - 1)) != 0x00) { + // CRC not ok, frame broken, skipping +#ifdef DEBUG + if(debug_level >= 2) { + printk(KERN_WARNING hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "Received frame with wrong CRC\n", + chan->chan->card->cardnum, + chan->chan->name); + } +#endif + + chan->crc++; + chan->chan->net_device_stats.rx_errors++; + + hfc_fifo_drop_frame(chan); + return -1; + } + + chan->frames++; + + *chan->f2 = F_inc(chan, *chan->f2, 1); + + // Set Z2 for the next frame we're going to receive + *Z2_F2(chan) = newz2; + + return frame_size; +} + +void hfc_fifo_drop_frame(struct hfc_chan_simplex *chan) +{ + int available_bytes; + u16 newz2; + + if (*chan->f1 == *chan->f2) { + // nothing received, strange eh? + printk(KERN_WARNING hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "skip_frame called with no frame in FIFO.\n", + chan->chan->card->cardnum, + chan->chan->name); + + return; + } + +// chan->drops++; + + available_bytes = hfc_fifo_used_rx(chan) + 1; + + // Calculate beginning of the next frame + newz2 = Z_inc(chan, *Z2_F2(chan), available_bytes); + + *chan->f2 = F_inc(chan, *chan->f2, 1); + + // Set Z2 for the next frame we're going to receive + *Z2_F2(chan) = newz2; +} + +void hfc_fifo_put_frame(struct hfc_chan_simplex *chan, + void *data, int size) +{ + u16 newz1; + int available_frames; + +#ifdef DEBUG + if (debug_level == 3) { + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "TX len %2d: ", + chan->chan->card->cardnum, + chan->chan->name, + size); + } else if (debug_level >= 4) { + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "TX (f1=%02x, f2=%02x, z1=%04x, z2=%04x) len %2d: ", + chan->chan->card->cardnum, + chan->chan->name, + *chan->f1, *chan->f2, *Z1_F1(chan), *Z2_F1(chan), + size); + } + + if (debug_level >= 3) { + int i; + for (i=0; i= chan->f_num) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "TX FIFO total number of frames exceeded!\n", + chan->chan->card->cardnum, + chan->chan->name); + + chan->fifo_full++; + + return; + } + + hfc_fifo_put(chan, data, size); + + newz1 = *Z1_F1(chan); + + *chan->f1 = F_inc(chan, *chan->f1, 1); + + *Z1_F1(chan) = newz1; + + chan->frames++; +} + +void hfc_clear_fifo_rx(struct hfc_chan_simplex *chan) +{ + *chan->f2 = *chan->f1; + *Z2_F2(chan) = *Z1_F2(chan); +} + +void hfc_clear_fifo_tx(struct hfc_chan_simplex *chan) +{ + *chan->f1 = *chan->f2; + *Z1_F1(chan) = *Z2_F1(chan); + + if (chan->chan->status == open_voice) { + // Make sure that at least hfc_TX_FIFO_PRELOAD bytes are + // present in the TX FIFOs + + // Create hfc_TX_FIFO_PRELOAD bytes of empty data + // (0x7f is mute audio) + u8 empty_fifo[hfc_TX_FIFO_PRELOAD + ZT_CHUNKSIZE + hfc_RX_FIFO_PRELOAD]; + memset(empty_fifo, 0x7f, sizeof(empty_fifo)); + + hfc_fifo_put(chan, empty_fifo, sizeof(empty_fifo)); + } +} + --- zaptel-1.2.11.dfsg.orig/vzaphfc/lapd.h +++ zaptel-1.2.11.dfsg/vzaphfc/lapd.h @@ -0,0 +1,26 @@ +/* + * lapd.c - net_device LAPD link layer support functionss + * + * Copyright (C) 2004 Daniele Orlandi + * + * Daniele "Vihai" Orlandi + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + * + */ + +#ifndef _HFC_LAPD_H +#define _HFC_LAPD_H + +#ifndef ARPHRD_LAPD +#define ARPHRD_LAPD 1000 /* LAPD pseudo type */ +#endif + +#ifndef ETH_P_LAPD +#define ETH_P_LAPD 0x0030 /* LAPD pseudo type */ +#endif + +void setup_lapd(struct net_device *netdev); + +#endif --- zaptel-1.2.11.dfsg.orig/vzaphfc/vzaphfc_main.c +++ zaptel-1.2.11.dfsg/vzaphfc/vzaphfc_main.c @@ -0,0 +1,2033 @@ +/* + * zaphfc.c - Zaptel driver for HFC-S PCI A based ISDN BRI cards + * + * Copyright (C) 2006, headiisue GmbH; Jens Wilke + * Copyright (C) 2004 Daniele Orlandi + * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH + * + * Jens Wilke + * + * Original author of this code is + * Daniele "Vihai" Orlandi + * + * Major rewrite of the driver made by + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + * + * Please read the README file for important infos. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../zaptel.h" + +#include "vzaphfc.h" +#include "fifo.h" +#include "lapd.h" + +#if CONFIG_PCI + +#define ZT_B1 0 +#define ZT_B2 1 +#define ZT_D 2 + +#define D 0 +#define B1 1 +#define B2 2 + +static int modes = 0; // all TE +static int nt_modes[hfc_MAX_BOARDS]; +static int nt_modes_count; +static int force_l1_up = 0; +static int sniff_zaptel_d_channel = 0; +static struct proc_dir_entry *hfc_proc_zaphfc_dir; + +#ifdef DEBUG +int debug_level = 0; +#endif + +static struct pci_device_id hfc_pci_ids[] = { + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_3069, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, hfc_pci_ids); + +static int __devinit hfc_probe(struct pci_dev *dev + , const struct pci_device_id *ent); +static void __devexit hfc_remove(struct pci_dev *dev); + +struct pci_driver hfc_driver = { + .name = hfc_DRIVER_NAME, + .id_table = hfc_pci_ids, + .probe = hfc_probe, + .remove = hfc_remove, +}; + +/****************************************** + * HW routines + ******************************************/ + +static void hfc_softreset(struct hfc_card *card) +{ + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "resetting\n", + card->cardnum); + + hfc_outb(card, hfc_CIRM, hfc_CIRM_RESET); // softreset on + udelay(6); // wait at least 5.21us + hfc_outb(card, hfc_CIRM, 0); // softreset off + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((hfc_RESET_DELAY * HZ) / 1000); // wait 20 ms +} + +void hfc_resetCard(struct hfc_card *card) +{ + card->regs.m1 = 0; + hfc_outb(card, hfc_INT_M1, card->regs.m1); // no ints + + card->regs.m2 = 0; + hfc_outb(card, hfc_INT_M2, card->regs.m2); // not at all + + hfc_softreset(card); + + card->regs.trm = 0; + hfc_outb(card, hfc_TRM, card->regs.trm); + + // Select the non-capacitive line mode for the S/T interface */ + card->regs.sctrl = hfc_SCTRL_NONE_CAP; + + if (card->nt_mode) { + // ST-Bit delay for NT-Mode + hfc_outb(card, hfc_CLKDEL, hfc_CLKDEL_NT); + + card->regs.sctrl |= hfc_SCTRL_MODE_NT; + } else { + // ST-Bit delay for TE-Mode + hfc_outb(card, hfc_CLKDEL, hfc_CLKDEL_TE); + + card->regs.sctrl |= hfc_SCTRL_MODE_TE; + } + + hfc_outb(card, hfc_SCTRL, card->regs.sctrl); + + // S/T Auto awake + card->regs.sctrl_e = hfc_SCTRL_E_AUTO_AWAKE; + hfc_outb(card, hfc_SCTRL_E, card->regs.sctrl_e); + + // No B-channel enabled at startup + card->regs.sctrl_r = 0; + hfc_outb(card, hfc_SCTRL_R, card->regs.sctrl_r); + + // HFC Master Mode + hfc_outb(card, hfc_MST_MODE, hfc_MST_MODE_MASTER); + + // Connect internal blocks + card->regs.connect = + hfc_CONNECT_B1_HFC_from_ST | + hfc_CONNECT_B1_ST_from_HFC | + hfc_CONNECT_B1_GCI_from_HFC | + hfc_CONNECT_B2_HFC_from_ST | + hfc_CONNECT_B2_ST_from_HFC | + hfc_CONNECT_B2_GCI_from_HFC; + hfc_outb(card, hfc_CONNECT, card->regs.connect); + + // All bchans are HDLC by default, not useful, actually + // since mode is set during open() + hfc_outb(card, hfc_CTMT, 0); + + // bit order + hfc_outb(card, hfc_CIRM, 0); + + // Enable D-rx FIFO. At least one FIFO must be enabled (by specs) + card->regs.fifo_en = hfc_FIFOEN_DRX; + hfc_outb(card, hfc_FIFO_EN, card->regs.fifo_en); + + card->late_irqs=0; + + // Clear already pending ints + hfc_inb(card, hfc_INT_S1); + hfc_inb(card, hfc_INT_S2); + + // Enable IRQ output + card->regs.m1 = hfc_INTS_DREC | hfc_INTS_L1STATE | hfc_INTS_TIMER; + hfc_outb(card, hfc_INT_M1, card->regs.m1); + + card->regs.m2 = hfc_M2_IRQ_ENABLE; + hfc_outb(card, hfc_INT_M2, card->regs.m2); + + // Unlocks the states machine + hfc_outb(card, hfc_STATES, 0); + + // There's no need to explicitly activate L1 now. + // Activation is managed inside the interrupt routine. +} + +static void hfc_update_fifo_state(struct hfc_card *card) +{ + // I'm not sure if irqsave is needed but there could be a race + // condition since hfc_update_fifo_state could be called from + // both the IRQ handler and the *_(open|close) functions + + unsigned long flags; + spin_lock_irqsave(&card->chans[B1].lock, flags); + if (!card->fifo_suspended && + (card->chans[B1].status == open_framed || + card->chans[B1].status == open_voice)) { + + if(!(card->regs.fifo_en & hfc_FIFOEN_B1RX)) { + card->regs.fifo_en |= hfc_FIFOEN_B1RX; + hfc_clear_fifo_rx(&card->chans[B1].rx); + } + + if(!(card->regs.fifo_en & hfc_FIFOEN_B1TX)) { + card->regs.fifo_en |= hfc_FIFOEN_B1TX; + hfc_clear_fifo_tx(&card->chans[B1].tx); + } + } else { + if(card->regs.fifo_en & hfc_FIFOEN_B1RX) + card->regs.fifo_en &= ~hfc_FIFOEN_B1RX; + if(card->regs.fifo_en & hfc_FIFOEN_B1TX) + card->regs.fifo_en &= ~hfc_FIFOEN_B1TX; + } + spin_unlock_irqrestore(&card->chans[B1].lock, flags); + + spin_lock_irqsave(&card->chans[B2].lock, flags); + if (!card->fifo_suspended && + (card->chans[B2].status == open_framed || + card->chans[B2].status == open_voice || + card->chans[B2].status == sniff_aux)) { + + if(!(card->regs.fifo_en & hfc_FIFOEN_B2RX)) { + card->regs.fifo_en |= hfc_FIFOEN_B2RX; + hfc_clear_fifo_rx(&card->chans[B2].rx); + } + + if(!(card->regs.fifo_en & hfc_FIFOEN_B2TX)) { + card->regs.fifo_en |= hfc_FIFOEN_B2TX; + hfc_clear_fifo_tx(&card->chans[B2].tx); + } + } else { + if(card->regs.fifo_en & hfc_FIFOEN_B2RX) + card->regs.fifo_en &= ~hfc_FIFOEN_B2RX; + if(card->regs.fifo_en & hfc_FIFOEN_B2TX) + card->regs.fifo_en &= ~hfc_FIFOEN_B2TX; + } + spin_unlock_irqrestore(&card->chans[B2].lock, flags); + + spin_lock_irqsave(&card->chans[D].lock, flags); + if (!card->fifo_suspended && + card->chans[D].status == open_framed) { + +// if(!(card->regs.fifo_en & hfc_FIFOEN_DRX)) { +// hfc_clear_fifo_rx(&card->chans[B2].rx); +// +// card->chans[B2].rx.ugly_framebuf_size = 0; +// card->chans[B2].rx.ugly_framebuf_off = 0; +// } +// + if(!(card->regs.fifo_en & hfc_FIFOEN_DTX)) { + card->regs.fifo_en |= hfc_FIFOEN_DTX; + + card->chans[D].tx.ugly_framebuf_size = 0; + card->chans[D].tx.ugly_framebuf_off = 0; + } + } else { +// if(card->regs.fifo_en & hfc_FIFOEN_DRX) +// card->regs.fifo_en &= ~hfc_FIFOEN_DRX; + if(card->regs.fifo_en & hfc_FIFOEN_DTX) + card->regs.fifo_en &= ~hfc_FIFOEN_DTX; + } + spin_unlock_irqrestore(&card->chans[D].lock, flags); + + hfc_outb(card, hfc_FIFO_EN, card->regs.fifo_en); +} + +static inline void hfc_suspend_fifo(struct hfc_card *card) +{ + card->fifo_suspended = TRUE; + + hfc_update_fifo_state(card); + + // When L1 goes down D rx receives garbage; it is nice to + // clear it to avoid a CRC error on reactivation + // udelay is needed because the FIFO deactivation happens + // in 250us + udelay(250); + hfc_clear_fifo_rx(&card->chans[D].rx); + +#ifdef DEBUG + if (debug_level >= 3) { + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "FIFOs suspended\n", + card->cardnum); + } +#endif +} + +static inline void hfc_resume_fifo(struct hfc_card *card) +{ + card->fifo_suspended = FALSE; + + hfc_update_fifo_state(card); + +#ifdef DEBUG + if (debug_level >= 3) { + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "FIFOs resumed\n", + card->cardnum); + } +#endif +} + +static void hfc_check_l1_up(struct hfc_card *card) +{ + if ((!card->nt_mode && card->l1_state != 7) || + (card->nt_mode && card->l1_state != 3)) { +// 0 because this is quite verbose when an inferface is unconnected, jaw +#if 0 + if(debug_level >= 1) { + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "L1 is down, bringing up L1.\n", + card->cardnum); + } +#endif + + hfc_outb(card, hfc_STATES, hfc_STATES_DO_ACTION | + hfc_STATES_ACTIVATE| + hfc_STATES_NT_G2_G3); + } +} + +/****************************************** + * /proc interface functions + ******************************************/ + +struct hfc_status_to_name_names { + enum hfc_chan_status status; + char *name; +}; + +static char *hfc_status_to_name(int status) +{ + struct hfc_status_to_name_names names[] = { + { free, "free" }, + { open_framed, "framed" }, + { open_voice, "voice" }, + { sniff_aux, "sniff aux" }, + { loopback, "loopback" }, + }; + + int i; + + for (i=0; i> 4]; + dst[i*2+1]= hexchars[src[i] & 0xf]; + } + + dst[size*2]='\0'; +} + +static int hfc_proc_read_info(char *page, char **start, + off_t off, int count, + int *eof, void *data) +{ + struct hfc_card *card = data; + int len; + + u8 chip_id; + chip_id = hfc_inb(card, hfc_CHIP_ID); + + len = snprintf(page, PAGE_SIZE, + "Driver : %s\n" + "Cardnum : %d\n" + "IRQ : %d\n" + "PCI Mem : %#08lx (0x%p)\n" + "FIFO Mem : %#08lx (0x%p)\n" + "Mode : %s\n" + "CHIP_ID : %#02x\n" + "L1 State : %c%d\n" + "Sync Lost : %s\n" + "Late IRQs : %d\n" + "FIFO susp : %s\n" + "\nChannel %12s %12s %12s %12s %4s %4s %4s %4s %4s\n" + "D : %12llu %12llu %12llu %12llu %4llu %4llu %4llu %4llu %4llu %c%c %s\n" + "B1 : %12llu %12llu %12llu %12llu %4llu %4llu %4llu %4llu %4llu %c%c %s\n" + "B2 : %12llu %12llu %12llu %12llu %4llu %4llu %4llu %4llu %4llu %c%c %s\n" + ,hfc_DRIVER_STRING + ,card->cardnum + ,card->pcidev->irq + ,card->io_bus_mem, card->io_mem + ,(ulong)card->fifo_bus_mem, card->fifo_mem + ,card->nt_mode?"NT":"TE" + ,chip_id + ,card->nt_mode?'G':'F' + ,card->l1_state + ,card->sync_loss_reported?"YES":"NO" + ,card->late_irqs + ,card->fifo_suspended?"YES":"NO" + + ,"RX Frames","TX Frames","RX Bytes","TX Bytes","RXFF","TXFF","RXU","TXU","CRC" + ,card->chans[D].rx.frames + ,card->chans[D].tx.frames + ,card->chans[D].rx.bytes + ,card->chans[D].tx.bytes + ,card->chans[D].rx.fifo_full + ,card->chans[D].tx.fifo_full + ,card->chans[D].rx.fifo_underrun + ,card->chans[D].tx.fifo_underrun + ,card->chans[D].rx.crc + ,card->chans[D].open_by_netdev ? 'N' : ' ' + ,card->chans[D].open_by_zaptel ? 'Z' : ' ' + ,hfc_status_to_name(card->chans[D].status) + + ,card->chans[B1].rx.frames + ,card->chans[B1].tx.frames + ,card->chans[B1].rx.bytes + ,card->chans[B1].tx.bytes + ,card->chans[B1].rx.fifo_full + ,card->chans[B1].tx.fifo_full + ,card->chans[B1].rx.fifo_underrun + ,card->chans[B1].tx.fifo_underrun + ,card->chans[B1].rx.crc + ,card->chans[B1].open_by_netdev ? 'N' : ' ' + ,card->chans[B1].open_by_zaptel ? 'Z' : ' ' + ,hfc_status_to_name(card->chans[B1].status) + + ,card->chans[B2].rx.frames + ,card->chans[B2].tx.frames + ,card->chans[B2].rx.bytes + ,card->chans[B2].tx.bytes + ,card->chans[B2].rx.fifo_full + ,card->chans[B2].tx.fifo_full + ,card->chans[B2].rx.fifo_underrun + ,card->chans[B2].tx.fifo_underrun + ,card->chans[B2].rx.crc + ,card->chans[B2].open_by_netdev ? 'N' : ' ' + ,card->chans[B2].open_by_zaptel ? 'Z' : ' ' + ,hfc_status_to_name(card->chans[B2].status) + ); + + return len; +} + +static int hfc_proc_read_fifos(char *page, char **start, + off_t off, int count, + int *eof, void *data) +{ + struct hfc_card *card = data; + + int len; + len = snprintf(page, PAGE_SIZE, + " Receive Transmit\n" + "Channel F1 F2 Z1 Z2 Used F1 F2 Z1 Z2 Used\n" + "D : %02x %02x %04x %04x %4d %02x %02x %04x %04x %4d\n" + "B1 : %02x %02x %04x %04x %4d %02x %02x %04x %04x %4d\n" + "B2 : %02x %02x %04x %04x %4d %02x %02x %04x %04x %4d\n" + ,*card->chans[D].rx.f1 + ,*card->chans[D].rx.f2 + ,*Z1_F2(&card->chans[D].rx) + ,*Z2_F2(&card->chans[D].rx) + ,hfc_fifo_used_rx(&card->chans[D].rx) + ,*card->chans[D].tx.f1 + ,*card->chans[D].tx.f2 + ,*Z1_F1(&card->chans[D].tx) + ,*Z2_F1(&card->chans[D].tx) + ,hfc_fifo_used_tx(&card->chans[D].tx) + + ,*card->chans[B1].rx.f1 + ,*card->chans[B1].rx.f2 + ,*Z1_F2(&card->chans[B1].rx) + ,*Z2_F2(&card->chans[B1].rx) + ,hfc_fifo_used_rx(&card->chans[B1].rx) + ,*card->chans[B1].tx.f1 + ,*card->chans[B1].tx.f2 + ,*Z1_F1(&card->chans[B1].tx) + ,*Z2_F1(&card->chans[B1].tx) + ,hfc_fifo_used_tx(&card->chans[B1].tx) + + ,*card->chans[B2].rx.f1 + ,*card->chans[B2].rx.f2 + ,*Z1_F2(&card->chans[B2].rx) + ,*Z2_F2(&card->chans[B2].rx) + ,hfc_fifo_used_rx(&card->chans[B2].rx) + ,*card->chans[B2].tx.f1 + ,*card->chans[B2].tx.f2 + ,*Z1_F1(&card->chans[B2].tx) + ,*Z2_F1(&card->chans[B2].tx) + ,hfc_fifo_used_tx(&card->chans[B2].tx) + ); + + return len; +} + +static int hfc_proc_read_bufs(char *page, char **start, + off_t off, int count, + int *eof, void *data) +{ + struct hfc_card *card = data; + int len; + + char hex_rchunk[3][ZT_CHUNKSIZE * 2 + 1]; + char hex_wchunk[3][ZT_CHUNKSIZE * 2 + 1]; + + hfc_hexdump(card->chans[D].rx.zaptel_buffer, hex_rchunk[0], ZT_CHUNKSIZE); + hfc_hexdump(card->chans[D].tx.zaptel_buffer, hex_wchunk[0], ZT_CHUNKSIZE); + hfc_hexdump(card->chans[B1].rx.zaptel_buffer, hex_rchunk[1], ZT_CHUNKSIZE); + hfc_hexdump(card->chans[B1].tx.zaptel_buffer, hex_wchunk[1], ZT_CHUNKSIZE); + hfc_hexdump(card->chans[B2].rx.zaptel_buffer, hex_rchunk[2], ZT_CHUNKSIZE); + hfc_hexdump(card->chans[B2].tx.zaptel_buffer, hex_wchunk[2], ZT_CHUNKSIZE); + + len = snprintf(page, PAGE_SIZE, + "Channel Read Chunk Write Chunk\n" + "D : %16s %16s\n" + "B1 : %16s %16s\n" + "B2 : %16s %16s\n" + ,hex_rchunk[0],hex_wchunk[0] + ,hex_rchunk[1],hex_wchunk[1] + ,hex_rchunk[2],hex_wchunk[2] + ); + + return len; +} + +/****************************************** + * net_device interface functions + ******************************************/ + +static int hfc_open(struct net_device *netdev) +{ + struct hfc_chan_duplex *chan = netdev->priv; + struct hfc_card *card = chan->card; + + spin_lock(&chan->lock); + + if (chan->status != free && + (chan->number != D || chan->status != open_framed)) { + spin_unlock(&chan->lock); + return -EBUSY; + } + + chan->status = open_framed; + chan->open_by_netdev = TRUE; + + spin_unlock(&chan->lock); + + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "chan %s opened.\n", + card->cardnum, + chan->name); + + return 0; +} + +static int hfc_close(struct net_device *netdev) +{ + struct hfc_chan_duplex *chan = netdev->priv; + struct hfc_card *card = chan->card; + + spin_lock(&chan->lock); + + if (chan->status != open_framed) { + spin_unlock(&chan->lock); + return -EINVAL; + } + + chan->status = free; + chan->open_by_netdev = FALSE; + + spin_unlock(&chan->lock); + + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "chan %s closed.\n", + card->cardnum, + chan->name); + + return 0; +} + +static int hfc_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct hfc_chan_duplex *chan = netdev->priv; + struct hfc_card *card = chan->card; + + netdev->trans_start = jiffies; + + hfc_check_l1_up(card); + + hfc_fifo_put_frame(&chan->tx, skb->data, skb->len); + + // We're not called from IRQ handler, otherwise we'd need + // dev_kfree_skb + dev_kfree_skb(skb); + + return 0; +} + +static struct net_device_stats *hfc_get_stats(struct net_device *netdev) +{ + struct hfc_chan_duplex *chan = netdev->priv; +// struct hfc_card *card = chan->card; + + return &chan->net_device_stats; +} + +static void hfc_set_multicast_list(struct net_device *netdev) +{ + struct hfc_chan_duplex *chan = netdev->priv; + struct hfc_card *card = chan->card; + + spin_lock(&card->lock); + + if(netdev->flags & IFF_PROMISC && !card->echo_enabled) { + if (card->nt_mode) { + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d " + "is in NT mode, not going promiscuous\n", + card->cardnum); + + spin_unlock(&card->lock); + return; + } + + if (card->chans[B2].status != free) { + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "chan %s: is busy, not going promiscuous\n", + card->cardnum, + card->chans[B2].name); + + spin_unlock(&card->lock); + return; + } + + card->regs.trm |= hfc_TRM_ECHO; + card->regs.m1 |= hfc_INTS_B2REC; + card->regs.cirm &= ~hfc_CIRM_B2_REV; + card->regs.sctrl &= ~hfc_SCTRL_B2_ENA; + card->regs.sctrl_r &= ~hfc_SCTRL_R_B2_ENA; + card->regs.connect |= hfc_CONNECT_B2_ST_from_GCI; + card->regs.ctmt &= ~hfc_CTMT_TRANSB2; + + card->chans[B2].status = sniff_aux; + + card->echo_enabled = TRUE; + + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "chan %s entered echo mode on channel %s\n", + card->cardnum, + chan->name, + card->chans[B2].name); + + } else if(!(netdev->flags & IFF_PROMISC) && card->echo_enabled) { + if (!card->echo_enabled) { + spin_unlock(&card->lock); + return; + } + + card->regs.trm &= ~hfc_TRM_ECHO; + card->regs.m1 &= ~hfc_INTS_B2REC; + card->regs.cirm |= hfc_CIRM_B2_REV; + card->regs.sctrl &= ~hfc_SCTRL_B2_ENA; + card->regs.sctrl_r &= ~hfc_SCTRL_R_B2_ENA; + card->regs.connect = + hfc_CONNECT_B1_HFC_from_ST | + hfc_CONNECT_B1_ST_from_HFC | + hfc_CONNECT_B1_GCI_from_HFC | + hfc_CONNECT_B2_HFC_from_ST | + hfc_CONNECT_B2_ST_from_HFC | + hfc_CONNECT_B2_GCI_from_HFC; + + card->chans[B2].status = free; + + card->echo_enabled = FALSE; + + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "chan %s left promiscuous mode.\n", + card->cardnum, + chan->name); + } + + spin_unlock(&card->lock); + + hfc_outb(card, hfc_TRM, card->regs.trm); + hfc_outb(card, hfc_CIRM, card->regs.cirm); + hfc_outb(card, hfc_SCTRL, card->regs.sctrl); + hfc_outb(card, hfc_SCTRL_R, card->regs.sctrl_r); + hfc_outb(card, hfc_CONNECT, card->regs.connect); + hfc_outb(card, hfc_CTMT, card->regs.ctmt); + + // Enable appropriate B receive interrupt + hfc_outb(card, hfc_INT_M1, card->regs.m1); + + hfc_update_fifo_state(card); +} + +/****************************************** + * Zaptel interface (zaptel sucks) + ******************************************/ + +static int hfc_zap_open(struct zt_chan *zaptel_chan) +{ + struct hfc_chan_duplex *chan = zaptel_chan->pvt; + struct hfc_card *card = chan->card; + + spin_lock(&chan->lock); + + switch (chan->number) { + case D: + if (chan->status != free && + chan->status != open_framed) { + spin_unlock(&chan->lock); + return -EBUSY; + } + + chan->status = open_framed; + break; + + case B1: + case B2: + if (chan->status != free) { + spin_unlock(&chan->lock); + return -EBUSY; + } + + chan->status = open_voice; + break; + } + + chan->open_by_zaptel = TRUE; + +#ifndef LINUX26 + MOD_INC_USE_COUNT; +#else + // Zaptel is buggy + try_module_get(THIS_MODULE); +#endif + + spin_unlock(&chan->lock); + + switch (chan->number) { + case D: + break; + + case B1: + // B1 + card->regs.m2 |= hfc_M2_PROC_TRANS; + card->regs.ctmt |= hfc_CTMT_TRANSB1; // Enable transparent mode + card->regs.cirm |= hfc_CIRM_B1_REV; // Reversed bit order + card->regs.sctrl |= hfc_SCTRL_B1_ENA; // Enable transmission + card->regs.sctrl_r |= hfc_SCTRL_R_B1_ENA; // Enable reception + break; + + case B2: + // B2 + card->regs.m2 |= hfc_M2_PROC_TRANS; + card->regs.ctmt |= hfc_CTMT_TRANSB2; // Enable transparent mode + card->regs.cirm |= hfc_CIRM_B2_REV; // Reversed bit order + card->regs.sctrl |= hfc_SCTRL_B2_ENA; // Enable transmission + card->regs.sctrl_r |= hfc_SCTRL_R_B2_ENA; // Enable reception + break; + + } + + // If not already enabled, enable processing transition (8KHz) + // interrupt + hfc_outb(card, hfc_INT_M2, card->regs.m2); + hfc_outb(card, hfc_CTMT, card->regs.ctmt); + hfc_outb(card, hfc_CIRM, card->regs.cirm); + hfc_outb(card, hfc_SCTRL, card->regs.sctrl); + hfc_outb(card, hfc_SCTRL_R, card->regs.sctrl_r); + + hfc_update_fifo_state(card); + + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "chan %s opened as %s.\n", + card->cardnum, + chan->name, + zaptel_chan->name); + + return 0; +} + +static int hfc_zap_close(struct zt_chan *zaptel_chan) +{ + struct hfc_chan_duplex *chan = zaptel_chan->pvt; + struct hfc_card *card = chan->card; + + if (!card) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "hfc_zap_close called with NULL card\n"); + return -1; + } + + spin_lock(&chan->lock); + + if (chan->status == free) { + spin_unlock(&chan->lock); + return -EINVAL; + } + + chan->status = free; + chan->open_by_zaptel = FALSE; + + spin_unlock(&chan->lock); + + switch (chan->number) { + case D: + break; + + case B1: + // B1 + card->regs.ctmt &= ~hfc_CTMT_TRANSB1; + card->regs.cirm &= ~hfc_CIRM_B1_REV; + card->regs.sctrl &= ~hfc_SCTRL_B1_ENA; + card->regs.sctrl_r &= ~hfc_SCTRL_R_B1_ENA; + break; + + case B2: + // B2 + card->regs.ctmt &= ~hfc_CTMT_TRANSB2; + card->regs.cirm &= ~hfc_CIRM_B2_REV; + card->regs.sctrl &= ~hfc_SCTRL_B2_ENA; + card->regs.sctrl_r &= ~hfc_SCTRL_R_B2_ENA; + break; + } + + if (card->chans[B1].status == free && + card->chans[B2].status == free) + card->regs.m2 &= ~hfc_M2_PROC_TRANS; + + hfc_outb(card, hfc_INT_M2, card->regs.m2); + hfc_outb(card, hfc_CTMT, card->regs.ctmt); + hfc_outb(card, hfc_CIRM, card->regs.cirm); + hfc_outb(card, hfc_SCTRL, card->regs.sctrl); + hfc_outb(card, hfc_SCTRL_R, card->regs.sctrl_r); + + hfc_update_fifo_state(card); + +#ifndef LINUX26 + MOD_DEC_USE_COUNT; +#else + // Zaptel is buggy + module_put(THIS_MODULE); +#endif + + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "chan %s closed as %s.\n", + card->cardnum, + chan->name, + zaptel_chan->name); + + return 0; +} + +static int hfc_zap_rbsbits(struct zt_chan *chan, int bits) +{ + return 0; +} + +static int hfc_zap_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) +{ + switch(cmd) { + default: + return -ENOTTY; + } + + return 0; +} + +static int hfc_zap_startup(struct zt_span *span) +{ + struct hfc_card *card = span->pvt; + int alreadyrunning; + + if (!card) { + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "no card for span at startup!\n", + card->cardnum); + } + + alreadyrunning = span->flags & ZT_FLAG_RUNNING; + + if (!alreadyrunning) { + span->chans[ZT_D].flags &= ~ZT_FLAG_HDLC; + span->chans[ZT_D].flags |= ZT_FLAG_BRIDCHAN; + span->flags |= ZT_FLAG_RUNNING; + } + + return 0; +} + +static int hfc_zap_shutdown(struct zt_span *span) +{ + return 0; +} + +static int hfc_zap_maint(struct zt_span *span, int cmd) +{ + return 0; +} + +static int hfc_zap_chanconfig(struct zt_chan *chan, int sigtype) +{ + return 0; +} + +static int hfc_zap_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) +{ + span->lineconfig = lc->lineconfig; + + return 0; +} + +static int hfc_zap_initialize(struct hfc_card *card) +{ + int i; + memset(&card->zt_span, 0x0, sizeof(struct zt_span)); + + snprintf(card->zt_span.name, sizeof(card->zt_span.name), + "ZTHFC%d", card->cardnum + 1); + + snprintf(card->zt_span.desc, sizeof(card->zt_span.desc), + hfc_DRIVER_DESCR " card %d [%s]", + card->cardnum, + card->nt_mode?"NT":"TE"); + + card->zt_span.spanconfig = hfc_zap_spanconfig; + card->zt_span.chanconfig = hfc_zap_chanconfig; + card->zt_span.startup = hfc_zap_startup; + card->zt_span.shutdown = hfc_zap_shutdown; + card->zt_span.maint = hfc_zap_maint; + card->zt_span.rbsbits = hfc_zap_rbsbits; + card->zt_span.open = hfc_zap_open; + card->zt_span.close = hfc_zap_close; + card->zt_span.ioctl = hfc_zap_ioctl; + + card->zt_span.chans = card->zt_chans; + card->zt_span.channels = 3; + card->zt_span.deflaw = ZT_LAW_ALAW; + card->zt_span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_CCS; // <--- this is really BS + card->zt_span.offset = 0; + init_waitqueue_head(&card->zt_span.maintq); + card->zt_span.pvt = card; + + for (i = 0; i < card->zt_span.channels; i++) { + memset(&card->zt_chans[i], 0x0, sizeof(struct zt_chan)); + + snprintf(card->zt_chans[i].name, sizeof(card->zt_chans[i].name), + "ZTHFC%d/%d/%d", + card->cardnum + 1, 0, i + 1); + + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "registered %s\n", + card->cardnum, + card->zt_chans[i].name); + + card->zt_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; + + card->zt_chans[i].chanpos = i + 1; + } + + card->zt_chans[ZT_D].readchunk = card->chans[D].rx.zaptel_buffer; + card->zt_chans[ZT_D].writechunk = card->chans[D].tx.zaptel_buffer; + card->zt_chans[ZT_D].pvt = &card->chans[D]; + + card->zt_chans[ZT_B1].readchunk = card->chans[B1].rx.zaptel_buffer; + card->zt_chans[ZT_B1].writechunk = card->chans[B1].tx.zaptel_buffer; + card->zt_chans[ZT_B1].pvt = &card->chans[B1]; + + card->zt_chans[ZT_B2].readchunk = card->chans[B2].rx.zaptel_buffer; + card->zt_chans[ZT_B2].writechunk = card->chans[B2].tx.zaptel_buffer; + card->zt_chans[ZT_B2].pvt = &card->chans[B2]; + + if (zt_register(&card->zt_span,0)) { + printk(KERN_CRIT "unable to register zaptel device!\n"); + return -1; + } + + return 0; +} + +static void hfc_zap_transmit(struct hfc_chan_simplex *chan) +{ + hfc_fifo_put(chan, chan->zaptel_buffer, ZT_CHUNKSIZE); +} + +static void hfc_zap_receive(struct hfc_chan_simplex *chan) +{ + hfc_fifo_get(chan, chan->zaptel_buffer, ZT_CHUNKSIZE); +} + +/****************************************** + * Interrupt Handler + ******************************************/ + +static void hfc_handle_timer_interrupt(struct hfc_card *card); +static void hfc_handle_state_interrupt(struct hfc_card *card); +static void hfc_handle_processing_interrupt(struct hfc_card *card); +static void hfc_frame_arrived(struct hfc_chan_duplex *chan); +static void hfc_handle_voice(struct hfc_card *card); + +static irqreturn_t hfc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct hfc_card *card = dev_id; + unsigned long flags; + u8 status,s1,s2; + + if (!card) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "spurious interrupt (IRQ %d)\n", + irq); + return IRQ_NONE; + } + + spin_lock_irqsave(&card->lock, flags); + status = hfc_inb(card, hfc_STATUS); + if (!(status & hfc_STATUS_ANYINT)) { + // maybe we are sharing the irq + spin_unlock_irqrestore(&card->lock,flags); + return IRQ_NONE; + } + + /* We used to ingore the IRQ when the card was in processing + * state but apparently there is no restriction to access the + * card in such state: + * + * Joerg Ciesielski wrote: + * > There is no restriction for the IRQ handler to access + * > HFC-S PCI during processing phase. A IRQ latency of 375 us + * > is also no problem since there are no interrupt sources in + * > HFC-S PCI which must be handled very fast. + * > Due to its deep fifos the IRQ latency can be several ms with + * > out the risk of loosing data. Even the S/T state interrupts + * > must not be handled with a latency less than <5ms. + * > + * > The processing phase only indicates that HFC-S PCI is + * > processing the Fifos as PCI master so that data is read and + * > written in the 32k memory window. But there is no restriction + * > to access data in the memory window during this time. + * + * // if (status & hfc_STATUS_PCI_PROC) { + * // return IRQ_HANDLED; + * // } + */ + + s1 = hfc_inb(card, hfc_INT_S1); + s2 = hfc_inb(card, hfc_INT_S2); + + if (s1 != 0) { + if (s1 & hfc_INTS_TIMER) { + // timer (bit 7) + hfc_handle_timer_interrupt(card); + } + + if (s1 & hfc_INTS_L1STATE) { + // state machine (bit 6) + hfc_handle_state_interrupt(card); + } + + if (s1 & hfc_INTS_DREC) { + // D chan RX (bit 5) + hfc_frame_arrived(&card->chans[D]); + } + + if (s1 & hfc_INTS_B1REC) { + // B1 chan RX (bit 3) + hfc_frame_arrived(&card->chans[B1]); + } + + if (s1 & hfc_INTS_B2REC) { + // B2 chan RX (bit 4) + hfc_frame_arrived(&card->chans[B2]); + } + + if (s1 & hfc_INTS_DTRANS) { + // D chan TX (bit 2) + } + + if (s1 & hfc_INTS_B1TRANS) { + // B1 chan TX (bit 0) + } + + if (s1 & hfc_INTS_B2TRANS) { + // B2 chan TX (bit 1) + } + + } + + if (s2 != 0) { + if (s2 & hfc_M2_PMESEL) { + // kaboom irq (bit 7) + + /* CologneChip says: + * + * the meaning of this fatal error bit is that HFC-S PCI as PCI + * master could not access the PCI bus within 125us to finish its + * data processing. If this happens only very seldom it does not + * cause big problems but of course some B-channel or D-channel + * data will be corrupted due to this event. + * + * Unfortunately this bit is only set once after the problem occurs + * and can only be reseted by a software reset. That means it is not + * easily possible to check how often this fatal error happens. + */ + + if(!card->sync_loss_reported) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "card %d: " + "sync lost, pci performance too low!\n", + card->cardnum); + + card->sync_loss_reported = TRUE; + } + } + + 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) + hfc_handle_processing_interrupt(card); + } + + } + + spin_unlock_irqrestore(&card->lock,flags); + + return IRQ_HANDLED; +} + +static void hfc_handle_timer_interrupt(struct hfc_card *card) +{ + if(card->ignore_first_timer_interrupt) { + card->ignore_first_timer_interrupt = FALSE; + return; + } + + if ((card->nt_mode && card->l1_state == 3) || + (!card->nt_mode && card->l1_state == 7)) { + + card->regs.ctmt &= ~hfc_CTMT_TIMER_MASK; + hfc_outb(card, hfc_CTMT, card->regs.ctmt); + + hfc_resume_fifo(card); + } +} + +static void hfc_handle_state_interrupt(struct hfc_card *card) +{ + u8 new_state = hfc_inb(card,hfc_STATES) & hfc_STATES_STATE_MASK; + +#ifdef DEBUG + if (debug_level >= 1) { + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "layer 1 state = %c%d\n", + card->cardnum, + card->nt_mode?'G':'F', + new_state); + } +#endif + + if (card->nt_mode) { + // NT mode + + if (new_state == 3) { + // fix to G3 state (see specs) + hfc_outb(card, hfc_STATES, hfc_STATES_LOAD_STATE | 3); + } + + if (new_state == 3 && card->l1_state != 3) { + hfc_resume_fifo(card); + } + + if (new_state != 3 && card->l1_state == 3) { + hfc_suspend_fifo(card); + } + } else { + if (new_state == 3) { + // Keep L1 up... zaptel & libpri expects a always up L1... + // Enable only when using an unpatched libpri + + if (force_l1_up) { + hfc_outb(card, hfc_STATES, + hfc_STATES_DO_ACTION | + hfc_STATES_ACTIVATE| + hfc_STATES_NT_G2_G3); + } + } + + if (new_state == 7 && card->l1_state != 7) { + // TE is now active, schedule FIFO activation after + // some time, otherwise the first frames are lost + + card->regs.ctmt |= hfc_CTMT_TIMER_50 | hfc_CTMT_TIMER_CLEAR; + hfc_outb(card, hfc_CTMT, card->regs.ctmt); + + // Activating the timer firest an interrupt immediately, we + // obviously need to ignore it + card->ignore_first_timer_interrupt = TRUE; + } + + if (new_state != 7 && card->l1_state == 7) { + // TE has become inactive, disable FIFO + hfc_suspend_fifo(card); + } + } + + card->l1_state = new_state; +} + +static void hfc_handle_processing_interrupt(struct hfc_card *card) +{ + int available_bytes=0; + + // Synchronize with the first enabled channel + if(card->regs.fifo_en & hfc_FIFOEN_B1RX) + available_bytes = hfc_fifo_used_rx(&card->chans[B1].rx); + if(card->regs.fifo_en & hfc_FIFOEN_B2RX) + available_bytes = hfc_fifo_used_rx(&card->chans[B2].rx); + else + available_bytes = -1; + + if ((available_bytes == -1 && card->ticks == 8) || + available_bytes >= ZT_CHUNKSIZE + hfc_RX_FIFO_PRELOAD) { + card->ticks = 0; + + if (available_bytes > ZT_CHUNKSIZE*2 + hfc_RX_FIFO_PRELOAD) { + card->late_irqs++; + // we are out of sync, clear fifos, jaw + hfc_clear_fifo_rx(&card->chans[B1].rx); + hfc_clear_fifo_tx(&card->chans[B1].tx); + hfc_clear_fifo_rx(&card->chans[B2].rx); + hfc_clear_fifo_tx(&card->chans[B2].tx); + +#ifdef DEBUG + if (debug_level >= 4) { + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "late IRQ, %d bytes late\n", + card->cardnum, + available_bytes - + (ZT_CHUNKSIZE + + hfc_RX_FIFO_PRELOAD)); + } +#endif + } else { + hfc_handle_voice(card); + } + } + + card->ticks++; +} + +static void hfc_sniff_zaptel_d_channel(struct hfc_card *card) +{ + struct sk_buff *skb = + dev_alloc_skb(card->chans[D].tx.ugly_framebuf_size); + + if (!skb) { + printk(KERN_ERR hfc_DRIVER_PREFIX + "card %d: " + "cannot allocate skb: sniffed frame dropped\n", + card->cardnum); + return; + } + + skb->dev = card->chans[D].netdev; + skb->protocol = htons(card->chans[D].protocol); +#ifndef CHECKSUM_HW + skb->ip_summed = CHECKSUM_COMPLETE; +#else + skb->ip_summed = CHECKSUM_HW; +#endif + skb->pkt_type = PACKET_OUTGOING; + + memcpy(skb_put(skb, card->chans[D].tx.ugly_framebuf_size), + card->chans[D].tx.ugly_framebuf, + card->chans[D].tx.ugly_framebuf_size); + + netif_rx(skb); +} + +static void hfc_handle_voice(struct hfc_card *card) +{ + if (card->chans[B1].status != open_voice && + card->chans[B2].status != open_voice) + return; + + card->zt_chans[ZT_D].bytes2transmit = 0; + card->zt_chans[ZT_D].maxbytes2transmit = ZT_CHUNKSIZE; + + zt_transmit(&card->zt_span); + + if (card->regs.fifo_en & hfc_FIFOEN_B1TX) + hfc_zap_transmit(&card->chans[B1].tx); + if (card->regs.fifo_en & hfc_FIFOEN_B2TX) + hfc_zap_transmit(&card->chans[B2].tx); + + if (card->zt_chans[ZT_D].bytes2transmit) { + hfc_check_l1_up(card); + + memcpy(card->chans[D].tx.ugly_framebuf + + card->chans[D].tx.ugly_framebuf_size, + card->chans[D].tx.zaptel_buffer, + card->zt_chans[ZT_D].bytes2transmit); + + card->chans[D].tx.ugly_framebuf_size += + card->zt_chans[ZT_D].bytes2transmit; + + if (card->zt_chans[ZT_D].eoftx) { + hfc_fifo_put_frame(&card->chans[D].tx, + card->chans[D].tx.ugly_framebuf, + card->chans[D].tx.ugly_framebuf_size); + + if (sniff_zaptel_d_channel) + hfc_sniff_zaptel_d_channel(card); + + card->chans[D].tx.ugly_framebuf_size = 0; + card->zt_chans[ZT_D].eoftx = FALSE; + } + } + + if (card->regs.fifo_en & hfc_FIFOEN_B1RX) + hfc_zap_receive(&card->chans[B1].rx); + else + memset(&card->chans[B1].rx.zaptel_buffer, 0x7f, + sizeof(card->chans[B1].rx.zaptel_buffer)); + + if (card->regs.fifo_en & hfc_FIFOEN_B2RX) + hfc_zap_receive(&card->chans[B2].rx); + else + memset(&card->chans[B2].rx.zaptel_buffer, 0x7f, + sizeof(card->chans[B1].rx.zaptel_buffer)); + + // Echo cancellation + zt_ec_chunk(&card->zt_chans[ZT_B1], + card->chans[B1].rx.zaptel_buffer, + card->chans[B1].tx.zaptel_buffer); + zt_ec_chunk(&card->zt_chans[ZT_B2], + card->chans[B2].rx.zaptel_buffer, + card->chans[B2].tx.zaptel_buffer); + + // If there's a frame in the FIFO, read it all and make it + // available to zaptel + if (hfc_fifo_has_frames(&card->chans[D].rx)) { + hfc_frame_arrived(&card->chans[D]); + } + + // Stupid zaptel frame handling + if (!card->chans[D].rx.ugly_framebuf_size) { + // hmm....ok, let zaptel receive nothing + card->zt_chans[ZT_D].bytes2receive = 0; + card->zt_chans[ZT_D].eofrx = FALSE; + } + else if (card->chans[D].rx.ugly_framebuf_size - + card->chans[D].rx.ugly_framebuf_off > ZT_CHUNKSIZE) { + + // the frame is longer than ZT_CHUNKSIZE + memcpy(card->chans[D].rx.zaptel_buffer, + card->chans[D].rx.ugly_framebuf+ + card->chans[D].rx.ugly_framebuf_off, + ZT_CHUNKSIZE); + + card->zt_chans[ZT_D].bytes2receive = ZT_CHUNKSIZE; + card->zt_chans[ZT_D].eofrx = FALSE; + + card->chans[D].rx.ugly_framebuf_off += ZT_CHUNKSIZE; + } else { + // we can read it all + memcpy(card->chans[D].rx.zaptel_buffer, + card->chans[D].rx.ugly_framebuf+ + card->chans[D].rx.ugly_framebuf_off, + card->chans[D].rx.ugly_framebuf_size); + + card->zt_chans[ZT_D].bytes2receive = card->chans[D].rx.ugly_framebuf_size- + card->chans[D].rx.ugly_framebuf_off; + card->zt_chans[ZT_D].eofrx = TRUE; + + card->chans[D].rx.ugly_framebuf_size = 0; + card->chans[D].rx.ugly_framebuf_off = 0; + } + + if (card->zt_span.flags & ZT_FLAG_RUNNING) { + zt_receive(&card->zt_span); + } + +} + +static void hfc_frame_arrived(struct hfc_chan_duplex *chan) +{ + struct hfc_card *card = chan->card; + int antiloop = 16; + struct sk_buff *skb; + + while(hfc_fifo_has_frames(&chan->rx) && --antiloop) { + int frame_size = hfc_fifo_get_frame_size(&chan->rx); + + if (frame_size < 3) { +#ifdef DEBUG + if (debug_level>=2) + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "invalid frame received, just %d bytes\n", + card->cardnum, + chan->name, + frame_size); +#endif + + hfc_fifo_drop_frame(&chan->rx); + + chan->net_device_stats.rx_dropped++; + + continue; + } else if(frame_size == 3) { +#ifdef DEBUG + if (debug_level>=2) + printk(KERN_DEBUG hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "empty frame received\n", + card->cardnum, + chan->name); +#endif + + hfc_fifo_drop_frame(&chan->rx); + + chan->net_device_stats.rx_dropped++; + + continue; + } + + if (chan->open_by_zaptel && + card->chans[D].rx.ugly_framebuf_size) { + // We have to wait for zaptel to transmit the + // frame... wait for next time + + break; + } + + skb = dev_alloc_skb(frame_size - 3); + + if (!skb) { + printk(KERN_ERR hfc_DRIVER_PREFIX + "card %d: " + "chan %s: " + "cannot allocate skb: frame dropped\n", + card->cardnum, + chan->name); + + hfc_fifo_drop_frame(&chan->rx); + + chan->net_device_stats.rx_dropped++; + + continue; + } + + // Oh... this is the echo channel... redirect to D + // channel's netdev + if (card->echo_enabled && chan->number == B2) { + skb->protocol = htons(card->chans[D].protocol); + skb->dev = card->chans[D].netdev; + skb->pkt_type = PACKET_OTHERHOST; + } else { + skb->protocol = htons(chan->protocol); + skb->dev = chan->netdev; + skb->pkt_type = PACKET_HOST; + } + + // HFC does the checksum +#ifndef CHECKSUM_HW + skb->ip_summed = CHECKSUM_COMPLETE; +#else + skb->ip_summed = CHECKSUM_HW; +#endif + + if (chan->open_by_zaptel) { + card->chans[D].rx.ugly_framebuf_size = frame_size - 1; + + if (hfc_fifo_get_frame(&card->chans[D].rx, + card->chans[D].rx.ugly_framebuf, + frame_size - 1) == -1) { + dev_kfree_skb(skb); + continue; + } + + memcpy(skb_put(skb, frame_size - 3), + card->chans[D].rx.ugly_framebuf, + frame_size - 3); + } else { + if (hfc_fifo_get_frame(&chan->rx, + skb_put(skb, frame_size - 3), + frame_size - 3) == -1) { + dev_kfree_skb(skb); + continue; + } + } + + chan->net_device_stats.rx_packets++; + chan->net_device_stats.rx_bytes += frame_size - 1; + + netif_rx(skb); + } + + if (!antiloop) + printk(KERN_CRIT hfc_DRIVER_PREFIX + "card %d: " + "Infinite loop detected\n", + card->cardnum); +} + +/****************************************** + * Module initialization and cleanup + ******************************************/ + +static void hfc_setup_lapd(struct hfc_chan_duplex *chan) +{ + chan->netdev->priv = chan; + chan->netdev->open = hfc_open; + chan->netdev->stop = hfc_close; + chan->netdev->hard_start_xmit = hfc_xmit_frame; + chan->netdev->get_stats = hfc_get_stats; + chan->netdev->set_multicast_list = hfc_set_multicast_list; + + memset(chan->netdev->dev_addr, 0x00, sizeof(chan->netdev->dev_addr)); + + SET_MODULE_OWNER(chan->netdev); +} + +static int __devinit hfc_probe(struct pci_dev *pci_dev, + const struct pci_device_id *ent) +{ + static int cardnum=0; + int err; + int i; + + struct hfc_card *card = NULL; + card = kmalloc(sizeof(struct hfc_card), GFP_KERNEL); + if (!card) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "unable to kmalloc!\n"); + err = -ENOMEM; + goto err_alloc_hfccard; + } + + memset(card, 0x00, sizeof(struct hfc_card)); + card->cardnum = cardnum; + card->pcidev = pci_dev; + spin_lock_init(&card->lock); + + pci_set_drvdata(pci_dev, card); + + if ((err = pci_enable_device(pci_dev))) { + goto err_pci_enable_device; + } + + if ((err = pci_set_dma_mask(pci_dev, PCI_DMA_32BIT))) { + printk(KERN_ERR hfc_DRIVER_PREFIX + "card %d: " + "No suitable DMA configuration available.\n", + card->cardnum); + goto err_pci_set_dma_mask; + } + + pci_write_config_word(pci_dev, PCI_COMMAND, PCI_COMMAND_MEMORY); + + if((err = pci_request_regions(pci_dev, hfc_DRIVER_NAME))) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "card %d: " + "cannot request I/O memory region\n", + card->cardnum); + goto err_pci_request_regions; + } + + pci_set_master(pci_dev); + + if (!pci_dev->irq) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "card %d: " + "no irq!\n", + card->cardnum); + err = -ENODEV; + goto err_noirq; + } + + card->io_bus_mem = pci_resource_start(pci_dev,1); + if (!card->io_bus_mem) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "card %d: " + "no iomem!\n", + card->cardnum); + err = -ENODEV; + goto err_noiobase; + } + + if(!(card->io_mem = ioremap(card->io_bus_mem, hfc_PCI_MEM_SIZE))) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "card %d: " + "cannot ioremap I/O memory\n", + card->cardnum); + err = -ENODEV; + goto err_ioremap; + } + + // pci_alloc_consistent guarantees alignment (Documentation/DMA-mapping.txt) + card->fifo_mem = pci_alloc_consistent(pci_dev, hfc_FIFO_SIZE, &card->fifo_bus_mem); + if (!card->fifo_mem) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "card %d: " + "unable to allocate FIFO DMA memory!\n", + card->cardnum); + err = -ENOMEM; + goto err_alloc_fifo; + } + + memset(card->fifo_mem, 0x00, hfc_FIFO_SIZE); + + card->fifos = card->fifo_mem; + + pci_write_config_dword(card->pcidev, hfc_PCI_MWBA, card->fifo_bus_mem); + + if ((err = request_irq(card->pcidev->irq, &hfc_interrupt, + SA_SHIRQ, hfc_DRIVER_NAME, card))) { + printk(KERN_CRIT hfc_DRIVER_PREFIX + "card %d: " + "unable to register irq\n", + card->cardnum); + goto err_request_irq; + } + + card->nt_mode = FALSE; + + if (modes & (1 << card->cardnum)) + card->nt_mode = TRUE; + + for (i=0; icardnum) + card->nt_mode=TRUE; + } + +//---------------------------------- D + card->chans[D].card = card; + card->chans[D].name = "D"; + card->chans[D].status = free; + card->chans[D].number = D; + card->chans[D].protocol = ETH_P_LAPD; + spin_lock_init(&card->chans[D].lock); + + card->chans[D].rx.chan = &card->chans[D]; + card->chans[D].rx.fifo_base = card->fifos + 0x4000; + card->chans[D].rx.z_base = card->fifos + 0x4000; + card->chans[D].rx.z1_base = card->fifos + 0x6080; + card->chans[D].rx.z2_base = card->fifos + 0x6082; + card->chans[D].rx.z_min = 0x0000; + card->chans[D].rx.z_max = 0x01FF; + card->chans[D].rx.f_min = 0x10; + card->chans[D].rx.f_max = 0x1F; + card->chans[D].rx.f1 = card->fifos + 0x60a0; + card->chans[D].rx.f2 = card->fifos + 0x60a1; + card->chans[D].rx.fifo_size = card->chans[D].rx.z_max - card->chans[D].rx.z_min + 1; + card->chans[D].rx.f_num = card->chans[D].rx.f_max - card->chans[D].rx.f_min + 1; + + card->chans[D].tx.chan = &card->chans[D]; + card->chans[D].tx.fifo_base = card->fifos + 0x0000; + card->chans[D].tx.z_base = card->fifos + 0x0000; + card->chans[D].tx.z1_base = card->fifos + 0x2080; + card->chans[D].tx.z2_base = card->fifos + 0x2082; + card->chans[D].tx.z_min = 0x0000; + card->chans[D].tx.z_max = 0x01FF; + card->chans[D].tx.f_min = 0x10; + card->chans[D].tx.f_max = 0x1F; + card->chans[D].tx.f1 = card->fifos + 0x20a0; + card->chans[D].tx.f2 = card->fifos + 0x20a1; + card->chans[D].tx.fifo_size = card->chans[D].tx.z_max - card->chans[D].tx.z_min + 1; + card->chans[D].tx.f_num = card->chans[D].tx.f_max - card->chans[D].tx.f_min + 1; + + if(!(card->chans[D].netdev = alloc_netdev(0, "isdn%dd", setup_lapd))) { + printk(KERN_ERR hfc_DRIVER_PREFIX + "net_device alloc failed, abort.\n"); + err = -ENOMEM; + goto err_alloc_netdev_d; + } + + hfc_setup_lapd(&card->chans[D]); + + card->chans[D].netdev->irq = card->pcidev->irq; + card->chans[D].netdev->base_addr = card->io_bus_mem; +/* card->chans[D].netdev->rmem_start = card->fifo_bus_mem + 0x4000; + card->chans[D].netdev->rmem_end = card->fifo_bus_mem + 0x4000 + + card->chans[D].rx.fifo_size - 1;*/ + card->chans[D].netdev->mem_start = card->fifo_bus_mem + 0x0000; + card->chans[D].netdev->mem_end = card->fifo_bus_mem + 0x0000 + + card->chans[D].tx.fifo_size - 1; + + if((err = register_netdev(card->chans[D].netdev))) { + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "Cannot register net device, aborting.\n", + card->cardnum); + goto err_register_netdev_d; + } + +//---------------------------------- B1 + card->chans[B1].card = card; + card->chans[B1].name = "B1"; + card->chans[B1].status = free; + card->chans[B1].number = B1; + card->chans[B1].protocol = 0; + spin_lock_init(&card->chans[B1].lock); + + card->chans[B1].rx.chan = &card->chans[B1]; + card->chans[B1].rx.fifo_base = card->fifos + 0x4200; + card->chans[B1].rx.z_base = card->fifos + 0x4000; + card->chans[B1].rx.z1_base = card->fifos + 0x6000; + card->chans[B1].rx.z2_base = card->fifos + 0x6002; + card->chans[B1].rx.z_min = 0x0200; + card->chans[B1].rx.z_max = 0x1FFF; + card->chans[B1].rx.f_min = 0x00; + card->chans[B1].rx.f_max = 0x1F; + card->chans[B1].rx.f1 = card->fifos + 0x6080; + card->chans[B1].rx.f2 = card->fifos + 0x6081; + card->chans[B1].rx.fifo_size = card->chans[B1].rx.z_max - card->chans[B1].rx.z_min + 1; + card->chans[B1].rx.f_num = card->chans[B1].rx.f_max - card->chans[B1].rx.f_min + 1; + + card->chans[B1].tx.chan = &card->chans[B1]; + card->chans[B1].tx.fifo_base = card->fifos + 0x0200; + card->chans[B1].tx.z_base = card->fifos + 0x0000; + card->chans[B1].tx.z1_base = card->fifos + 0x2000; + card->chans[B1].tx.z2_base = card->fifos + 0x2002; + card->chans[B1].tx.z_min = 0x0200; + card->chans[B1].tx.z_max = 0x1FFF; + card->chans[B1].tx.f_min = 0x00; + card->chans[B1].tx.f_max = 0x1F; + card->chans[B1].tx.f1 = card->fifos + 0x2080; + card->chans[B1].tx.f2 = card->fifos + 0x2081; + card->chans[B1].tx.fifo_size = card->chans[B1].tx.z_max - card->chans[B1].tx.z_min + 1; + card->chans[B1].tx.f_num = card->chans[B1].tx.f_max - card->chans[B1].tx.f_min + 1; + +// card->chans[B1].netdev->irq = card->pcidev->irq; +// card->chans[B1].netdev->base_addr = card->io_bus_mem; +/* card->chans[B1].netdev->rmem_start = card->fifo_bus_mem + 0x4200; + card->chans[B1].netdev->rmem_end = card->fifo_bus_mem + 0x4200 + + card->chans[B1].rx.fifo_size - 1;*/ +// card->chans[B1].netdev->mem_start = card->fifo_bus_mem + 0x0200; +// card->chans[B1].netdev->mem_end = card->fifo_bus_mem + 0x0200 + +// card->chans[B1].tx.fifo_size - 1; + +//---------------------------------- B2 + card->chans[B2].card = card; + card->chans[B2].name = "B2"; + card->chans[B2].status = free; + card->chans[B2].number = B2; + card->chans[B2].protocol = 0; + spin_lock_init(&card->chans[B2].lock); + + card->chans[B2].rx.chan = &card->chans[B2]; + card->chans[B2].rx.fifo_base = card->fifos + 0x6200, + card->chans[B2].rx.z_base = card->fifos + 0x6000; + card->chans[B2].rx.z1_base = card->fifos + 0x6100; + card->chans[B2].rx.z2_base = card->fifos + 0x6102; + card->chans[B2].rx.z_min = 0x0200; + card->chans[B2].rx.z_max = 0x1FFF; + card->chans[B2].rx.f_min = 0x00; + card->chans[B2].rx.f_max = 0x1F; + card->chans[B2].rx.f1 = card->fifos + 0x6180; + card->chans[B2].rx.f2 = card->fifos + 0x6181; + card->chans[B2].rx.fifo_size = card->chans[B2].rx.z_max - card->chans[B2].rx.z_min + 1; + card->chans[B2].rx.f_num = card->chans[B2].rx.f_max - card->chans[B2].rx.f_min + 1; + + card->chans[B2].tx.chan = &card->chans[B2]; + card->chans[B2].tx.fifo_base = card->fifos + 0x2200; + card->chans[B2].tx.z_base = card->fifos + 0x2000; + card->chans[B2].tx.z1_base = card->fifos + 0x2100; + card->chans[B2].tx.z2_base = card->fifos + 0x2102; + card->chans[B2].tx.z_min = 0x0200; + card->chans[B2].tx.z_max = 0x1FFF; + card->chans[B2].tx.f_min = 0x00; + card->chans[B2].tx.f_max = 0x1F; + card->chans[B2].tx.f1 = card->fifos + 0x2180; + card->chans[B2].tx.f2 = card->fifos + 0x2181; + card->chans[B2].tx.fifo_size = card->chans[B2].tx.z_max - card->chans[B2].tx.z_min + 1; + card->chans[B2].tx.f_num = card->chans[B2].tx.f_max - card->chans[B2].tx.f_min + 1; + +// card->chans[B2].netdev->irq = card->pcidev->irq; +// card->chans[B2].netdev->base_addr = card->io_bus_mem; +/* card->chans[B2].netdev->rmem_start = card->fifo_bus_mem + 0x6200; + card->chans[B2].netdev->rmem_end = card->fifo_bus_mem + 0x6200 + + card->chans[B2].rx.fifo_size - 1;*/ +// card->chans[B2].netdev->mem_start = card->fifo_bus_mem + 0x2200; +// card->chans[B2].netdev->mem_end = card->fifo_bus_mem + 0x2200 + +// card->chans[B2].tx.fifo_size - 1; + +// ------------------------------------------------------- + + hfc_zap_initialize(card); + + snprintf(card->proc_dir_name, + sizeof(card->proc_dir_name), + "%d", card->cardnum); + card->proc_dir = proc_mkdir(card->proc_dir_name, hfc_proc_zaphfc_dir); + card->proc_dir->owner = THIS_MODULE; + + card->proc_info = create_proc_read_entry( + "info", 0444, card->proc_dir, + hfc_proc_read_info, card); + card->proc_info->owner = THIS_MODULE; + + card->proc_fifos = create_proc_read_entry( + "fifos", 0400, card->proc_dir, + hfc_proc_read_fifos, card); + card->proc_fifos->owner = THIS_MODULE; + + card->proc_bufs = create_proc_read_entry( + "bufs", 0400, card->proc_dir, + hfc_proc_read_bufs, card); + card->proc_bufs->owner = THIS_MODULE; + + hfc_resetCard(card); + + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d configured for %s mode at mem %#lx (0x%p) IRQ %u\n", + card->cardnum, + card->nt_mode?"NT":"TE", + card->io_bus_mem, + card->io_mem, + card->pcidev->irq); + + cardnum++; + + return 0; + +// unregister_netdev(card->chans[D].netdev); +err_register_netdev_d: + free_netdev(card->chans[D].netdev); +err_alloc_netdev_d: + free_irq(pci_dev->irq, card); +err_request_irq: + pci_free_consistent(pci_dev, hfc_FIFO_SIZE, + card->fifo_mem, card->fifo_bus_mem); +err_alloc_fifo: + iounmap(card->io_mem); +err_ioremap: +err_noiobase: +err_noirq: + pci_release_regions(pci_dev); +err_pci_request_regions: +err_pci_set_dma_mask: +err_pci_enable_device: + kfree(card); +err_alloc_hfccard: + return err; +} + +static void __devexit hfc_remove(struct pci_dev *pci_dev) +{ + struct hfc_card *card = pci_get_drvdata(pci_dev); + + unregister_netdev(card->chans[D].netdev); + +// unsigned long flags; +// spin_lock_irqsave(&card->lock,flags); + + printk(KERN_INFO hfc_DRIVER_PREFIX + "card %d: " + "shutting down card at %p.\n", + card->cardnum, + card->io_mem); + + hfc_softreset(card); + + zt_unregister(&card->zt_span); + + + // disable memio and bustmaster + pci_write_config_word(pci_dev, PCI_COMMAND, 0); + +// spin_unlock_irqrestore(&card->lock,flags); + + remove_proc_entry("bufs", card->proc_dir); + remove_proc_entry("fifos", card->proc_dir); + remove_proc_entry("info", card->proc_dir); + remove_proc_entry(card->proc_dir_name, hfc_proc_zaphfc_dir); + + free_irq(pci_dev->irq, card); + + pci_free_consistent(pci_dev, hfc_FIFO_SIZE, + card->fifo_mem, card->fifo_bus_mem); + + iounmap(card->io_mem); + + pci_release_regions(pci_dev); + + pci_disable_device(pci_dev); + + free_netdev(card->chans[D].netdev); + kfree(card); +} + +/****************************************** + * Module stuff + ******************************************/ + +static int __init hfc_init_module(void) +{ + int ret; + + printk(KERN_INFO hfc_DRIVER_PREFIX + hfc_DRIVER_STRING " loading\n"); + + hfc_proc_zaphfc_dir = proc_mkdir(hfc_DRIVER_NAME, proc_root_driver); + + ret = pci_module_init(&hfc_driver); + return ret; +} + +module_init(hfc_init_module); + +static void __exit hfc_module_exit(void) +{ + pci_unregister_driver(&hfc_driver); + + remove_proc_entry(hfc_DRIVER_NAME, proc_root_driver); + + printk(KERN_INFO hfc_DRIVER_PREFIX + hfc_DRIVER_STRING " unloaded\n"); +} + +module_exit(hfc_module_exit); + +#endif + +MODULE_DESCRIPTION(hfc_DRIVER_DESCR); +MODULE_AUTHOR("Jens Wilke , Daniele (Vihai) Orlandi "); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +#ifdef LINUX26 + +module_param(modes, int, 0444); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) +module_param_array(nt_modes, int, &nt_modes_count, 0444); +#else +module_param_array(nt_modes, int, nt_modes_count, 0444); +#endif + +module_param(force_l1_up, int, 0444); +module_param(sniff_zaptel_d_channel, int, 0444); +#ifdef DEBUG +module_param(debug_level, int, 0444); +#endif + +#else + +MODULE_PARM(modes,"i"); +MODULE_PARM(force_l1_up,"i"); +MODULE_PARM(sniff_zaptel_d_channel,"i"); +#ifdef DEBUG +MODULE_PARM(debug_level,"i"); +#endif + +#endif // LINUX26 + +MODULE_PARM_DESC(modes, "[Deprecated] bit-mask to configure NT mode"); +MODULE_PARM_DESC(nt_modes, "Comma-separated list of card IDs to configure in NT mode"); +MODULE_PARM_DESC(force_l1_up, "Don't allow L1 to go down"); +MODULE_PARM_DESC(sniff_zaptel_d_channel, "Make frames transmitted from zaptel" + " appear as received by the board"); +#ifdef DEBUG +MODULE_PARM_DESC(debug_level, "Debug verbosity level"); +#endif --- zaptel-1.2.11.dfsg.orig/vzaphfc/ChangeLog +++ zaptel-1.2.11.dfsg/vzaphfc/ChangeLog @@ -0,0 +1,4 @@ +1.42 - 2006jun06 - Jens Wilke +- fixed fifo timing issue +- added statistics for fifo underruns (RXU&TXU) +- maintanance now done by jw --- zaptel-1.2.11.dfsg.orig/vzaphfc/vzaphfc.h +++ zaptel-1.2.11.dfsg/vzaphfc/vzaphfc.h @@ -0,0 +1,387 @@ +/* + * zaphfc.c - Zaptel driver for HFC-S PCI A based ISDN BRI cards + * + * Copyright (C) 2006 headissue GmbH; Jens Wilke + * Copyright (C) 2004 Daniele Orlandi + * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH + * + * Jens Wilke + * + * Orginal author of this code is + * Daniele "Vihai" Orlandi + * + * Major rewrite of the driver made by + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + * + */ + +#ifndef _HFC_ZAPHFC_H +#define _HFC_ZAPHFC_H + +#include +#include + +#include "../zaptel.h" + +#define hfc_DRIVER_NAME "vzaphfc" +#define hfc_DRIVER_PREFIX hfc_DRIVER_NAME ": " +#define hfc_DRIVER_DESCR "HFC-S PCI A Zaptel Driver" +#define hfc_DRIVER_VERSION "1.42" +#define hfc_DRIVER_STRING hfc_DRIVER_DESCR " (V" hfc_DRIVER_VERSION ")" + +#define hfc_MAX_BOARDS 32 + +#ifndef LINUX26 +#define IRQ_NONE +#define IRQ_HANDLED +#define irqreturn_t void +#endif + +#ifndef PCI_DMA_32BIT +#define PCI_DMA_32BIT 0x00000000ffffffffULL +#endif + +#ifndef PCI_VENDOR_ID_SITECOM +#define PCI_VENDOR_ID_SITECOM 0x182D +#endif + +#ifndef PCI_DEVICE_ID_SITECOM_3069 +#define PCI_DEVICE_ID_SITECOM_3069 0x3069 +#endif + +#define hfc_RESET_DELAY 20 + +#define hfc_CLKDEL_TE 0x0f /* CLKDEL in TE mode */ +#define hfc_CLKDEL_NT 0x6c /* CLKDEL in NT mode */ + +/* PCI memory mapped I/O */ + +#define hfc_PCI_MEM_SIZE 0x0100 +#define hfc_PCI_MWBA 0x80 + +/* 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_TRANSB1 0x01 +#define hfc_CTMT_TRANSB2 0x02 +#define hfc_CTMT_TIMER_CLEAR 0x80 +#define hfc_CTMT_TIMER_MASK 0x1C +#define hfc_CTMT_TIMER_3_125 (0x01 << 2) +#define hfc_CTMT_TIMER_6_25 (0x02 << 2) +#define hfc_CTMT_TIMER_12_5 (0x03 << 2) +#define hfc_CTMT_TIMER_25 (0x04 << 2) +#define hfc_CTMT_TIMER_50 (0x05 << 2) +#define hfc_CTMT_TIMER_400 (0x06 << 2) +#define hfc_CTMT_TIMER_800 (0x07 << 2) +#define hfc_CTMT_AUTO_TIMER 0x20 + +/* 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 SCTRL_R */ +#define hfc_SCTRL_R_B1_ENA 0x01 +#define hfc_SCTRL_R_B2_ENA 0x02 + +/* 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_HFC_from_ST 0x00 +#define hfc_CONNECT_B1_HFC_from_GCI 0x01 +#define hfc_CONNECT_B1_ST_from_HFC 0x00 +#define hfc_CONNECT_B1_ST_from_GCI 0x02 +#define hfc_CONNECT_B1_GCI_from_HFC 0x00 +#define hfc_CONNECT_B1_GCI_from_ST 0x04 + +#define hfc_CONNECT_B2_HFC_from_ST 0x00 +#define hfc_CONNECT_B2_HFC_from_GCI 0x08 +#define hfc_CONNECT_B2_ST_from_HFC 0x00 +#define hfc_CONNECT_B2_ST_from_GCI 0x10 +#define hfc_CONNECT_B2_GCI_from_HFC 0x00 +#define hfc_CONNECT_B2_GCI_from_ST 0x20 + +/* bits in the TRM register */ +#define hfc_TRM_TRANS_INT_00 0x00 +#define hfc_TRM_TRANS_INT_01 0x01 +#define hfc_TRM_TRANS_INT_10 0x02 +#define hfc_TRM_TRANS_INT_11 0x04 +#define hfc_TRM_ECHO 0x20 +#define hfc_TRM_B1_PLUS_B2 0x40 +#define hfc_TRM_IOM_TEST_LOOP 0x80 + +/* 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_FIFO_SIZE 0x8000 + +#define hfc_UGLY_FRAMEBUF 0x2000 + +#define hfc_TX_FIFO_PRELOAD ZT_CHUNKSIZE + 2 +#define hfc_RX_FIFO_PRELOAD 4 + +/* NOTE: FIFO pointers are not declared volatile because accesses to the + * FIFOs are inherently safe. + */ + +#ifdef DEBUG +extern int debug_level; +#endif + +struct hfc_chan; + +struct hfc_chan_simplex { + struct hfc_chan_duplex *chan; + + u8 zaptel_buffer[ZT_CHUNKSIZE]; + + u8 ugly_framebuf[hfc_UGLY_FRAMEBUF]; + int ugly_framebuf_size; + u16 ugly_framebuf_off; + + void *z1_base,*z2_base; + void *fifo_base; + void *z_base; + u16 z_min; + u16 z_max; + u16 fifo_size; + + u8 *f1,*f2; + u8 f_min; + u8 f_max; + u8 f_num; + + unsigned long long frames; + unsigned long long bytes; + unsigned long long fifo_full; + unsigned long long crc; + unsigned long long fifo_underrun; +}; + +enum hfc_chan_status { + free, + open_framed, + open_voice, + sniff_aux, + loopback, +}; + +struct hfc_chan_duplex { + struct hfc_card *card; + + char *name; + int number; + + enum hfc_chan_status status; + int open_by_netdev; + int open_by_zaptel; + + unsigned short protocol; + + spinlock_t lock; + + struct hfc_chan_simplex rx; + struct hfc_chan_simplex tx; + + struct net_device *netdev; + struct net_device_stats net_device_stats; +}; + +typedef struct hfc_card { + int cardnum; + spinlock_t lock; + + int ticks; + + struct pci_dev *pcidev; + + struct proc_dir_entry *proc_dir; + char proc_dir_name[32]; + + struct proc_dir_entry *proc_info; + struct proc_dir_entry *proc_fifos; + struct proc_dir_entry *proc_bufs; + + unsigned long io_bus_mem; + void *io_mem; + + dma_addr_t fifo_bus_mem; + void *fifo_mem; + void *fifos; + + int nt_mode; + int sync_loss_reported; + int late_irqs; + + u8 l1_state; + int fifo_suspended; + int ignore_first_timer_interrupt; + + struct { + u8 m1; + u8 m2; + u8 fifo_en; + u8 trm; + u8 connect; + u8 sctrl; + u8 sctrl_r; + u8 sctrl_e; + u8 ctmt; + u8 cirm; + } regs; + + struct hfc_chan_duplex chans[3]; + int echo_enabled; + + struct zt_span zt_span; + struct zt_chan zt_chans[3]; + + int debug_event; +} hfc_card; + +static inline u8 hfc_inb(struct hfc_card *card, int offset) +{ + return readb(card->io_mem + offset); +} + +static inline void hfc_outb(struct hfc_card *card, int offset, u8 value) +{ + writeb(value, card->io_mem + offset); +} + +#endif --- zaptel-1.2.11.dfsg.orig/vzaphfc/fifo.h +++ zaptel-1.2.11.dfsg/vzaphfc/fifo.h @@ -0,0 +1,131 @@ +/* + * zaphfc.c - Zaptel driver for HFC-S PCI A based ISDN BRI cards + * + * Copyright (C) 2004 Daniele Orlandi + * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH + * + * Daniele "Vihai" Orlandi + * + * Major rewrite of the driver made by + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + * + */ + +#ifndef _HFC_FIFO_H +#define _HFC_FIFO_H + +#include "vzaphfc.h" + +static inline u16 *Z1_F1(struct hfc_chan_simplex *chan) +{ + return chan->z1_base + (*chan->f1 * 4); +} + +static inline u16 *Z2_F1(struct hfc_chan_simplex *chan) +{ + return chan->z2_base + (*chan->f1 * 4); +} + +static inline u16 *Z1_F2(struct hfc_chan_simplex *chan) +{ + return chan->z1_base + (*chan->f2 * 4); +} + +static inline u16 *Z2_F2(struct hfc_chan_simplex *chan) +{ + return chan->z2_base + (*chan->f2 * 4); +} + +static inline u16 Z_inc(struct hfc_chan_simplex *chan, u16 z, u16 inc) +{ + // declared as u32 in order to manage overflows + u32 newz = z + inc; + if (newz > chan->z_max) + newz -= chan->fifo_size; + + return newz; +} + +static inline u8 F_inc(struct hfc_chan_simplex *chan, u8 f, u8 inc) +{ + // declared as u16 in order to manage overflows + u16 newf = f + inc; + if (newf > chan->f_max) + newf -= chan->f_num; + + return newf; +} + +static inline u16 hfc_fifo_used_rx(struct hfc_chan_simplex *chan) +{ + return (*Z1_F2(chan) - *Z2_F2(chan) + chan->fifo_size) % chan->fifo_size; +} + +static inline u16 hfc_fifo_get_frame_size(struct hfc_chan_simplex *chan) +{ + // This +1 is needed because in frame mode the available bytes are Z2-Z1+1 + // while in transparent mode I wouldn't consider the byte pointed by Z2 to + // be available, otherwise, the FIFO would always contain one byte, even + // when Z1==Z2 + + return hfc_fifo_used_rx(chan) + 1; +} + +static inline u8 hfc_fifo_u8(struct hfc_chan_simplex *chan, u16 z) +{ + return *((u8 *)(chan->z_base + z)); +} + +static inline u16 hfc_fifo_used_tx(struct hfc_chan_simplex *chan) +{ + return (*Z1_F1(chan) - *Z2_F1(chan) + chan->fifo_size) % chan->fifo_size; +} + +static inline u16 hfc_fifo_free_rx(struct hfc_chan_simplex *chan) +{ + u16 free_bytes=*Z2_F1(chan) - *Z1_F1(chan); + + if (free_bytes > 0) + return free_bytes; + else + return free_bytes + chan->fifo_size; +} + +static inline u16 hfc_fifo_free_tx(struct hfc_chan_simplex *chan) +{ + u16 free_bytes=*Z2_F1(chan) - *Z1_F1(chan); + + if (free_bytes > 0) + return free_bytes; + else + return free_bytes + chan->fifo_size; +} + +static inline int hfc_fifo_has_frames(struct hfc_chan_simplex *chan) +{ + return *chan->f1 != *chan->f2; +} + +static inline u8 hfc_fifo_used_frames(struct hfc_chan_simplex *chan) +{ + return (*chan->f1 - *chan->f2 + chan->f_num) % chan->f_num; +} + +static inline u8 hfc_fifo_free_frames(struct hfc_chan_simplex *chan) +{ + return (*chan->f2 - *chan->f1 + chan->f_num) % chan->f_num; +} + +int hfc_fifo_get(struct hfc_chan_simplex *chan, void *data, int size); +void hfc_fifo_put(struct hfc_chan_simplex *chan, void *data, int size); +void hfc_fifo_drop(struct hfc_chan_simplex *chan, int size); +int hfc_fifo_get_frame(struct hfc_chan_simplex *chan, void *data, int max_size); +void hfc_fifo_drop_frame(struct hfc_chan_simplex *chan); +void hfc_fifo_put_frame(struct hfc_chan_simplex *chan, void *data, int size); +void hfc_clear_fifo_rx(struct hfc_chan_simplex *chan); +void hfc_clear_fifo_tx(struct hfc_chan_simplex *chan); + +#endif --- zaptel-1.2.11.dfsg.orig/vzaphfc/Makefile +++ zaptel-1.2.11.dfsg/vzaphfc/Makefile @@ -0,0 +1,38 @@ +# +# Copyright (C) 2006 headissue GmbH; Jens Wilke +# +# This program is free software and may be modified and +# distributed under the terms of the GNU Public License. +# + +KSOURCE ?= /lib/modules/`uname -r`/build + +ifndef src + src=$(shell pwd) +endif + +ZAPTEL_SOURCE = $(src)/../../bristuff12/zaptel/ + +EXTRA_CFLAGS += -I $(ZAPTEL_SOURCE) + +obj-m := vzaphfc.o +vzaphfc-objs := vzaphfc_main.o fifo.o lapd.o + +all: + $(MAKE) -C $(KSOURCE) SUBDIRS=`pwd` modules + +clean: + $(MAKE) -C $(KSOURCE) SUBDIRS=`pwd` clean + +debug: + $(MAKE) -C $(KSOURCE) modules SUBDIRS=`pwd` EXTRA_CFLAGS="$(EXTRA_CFLAGS) -DDEBUG" CONFIG_DEBUG_INFO=1 + +# 2.4 stuff #### +modules: $(obj-m) + sync + +vzaphfc.o: vzaphfc_main.c fifo.c vzaphfc.h fifo.h lapd.h + $(CC) -c vzaphfc_main.c fifo.c $(CFLAGS) $(EXTRA_CFLAGS) + +install: + install -D -m 644 vzaphfc.ko $(INSTALL_PREFIX)/lib/modules/`uname -r`/misc/vzaphfc.ko --- zaptel-1.2.11.dfsg.orig/vzaphfc/README +++ zaptel-1.2.11.dfsg/vzaphfc/README @@ -0,0 +1,45 @@ +== General Info == + +This is a Zaptel driver for HFC-S PCI A based ISDN BRI cards (Cologne +Chipdesign). + +== Driver Build == + +You need the kernel source (2.6) and the Zaptel driver sources +to build the module. + +== Module Parameters == + + nt_modes: + comma seperated list + + sniff_zaptel_d_channel: + Make frames transmitted from Zaptel appear as received by the board + Set this to 1 if you want to debug D channel signaling with Etherreal + + force_l1_up: + Keep ISDN bus activated. Usually set by PtP TE interfaces. + + nt_modes: + Comma-separated list of card IDs to configure in NT mode (array of int) + +== Information in the proc file system == + + You will find valuable data about the current state of your ISDN + interface in /proc/drivers/vzaphfc/. The following files + are present for each card: + + info: + Information about the bus activation, transmit errors (CRC), and + overall transfer statistics + + bufs: + Except from the data that is currently transmitted + + fifo: + sizes and counter values from the FIFOs, mainly for debugging + purposes + + +Latest Change: 6 Jun 2006 Jens Wilke + --- zaptel-1.2.11.dfsg.orig/debian/patches/Makefile_vzaphfc.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/Makefile_vzaphfc.dpatch @@ -0,0 +1,18 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## Makefile_vzaphfc.dpatch by Kilian Krause +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Add vzaphfc to linux-2.6 modules + +@DPATCH@ +diff -urNad zaptel-1.2.9.1.dfsg~/Makefile zaptel-1.2.9.1.dfsg/Makefile +--- zaptel-1.2.9.1.dfsg~/Makefile 2006-10-09 10:31:49.000000000 +1000 ++++ zaptel-1.2.9.1.dfsg/Makefile 2006-10-09 10:32:29.000000000 +1000 +@@ -151,6 +151,7 @@ + + obj-m:=$(MODULESO) + obj-m+=wct4xxp/ ++obj-m += vzaphfc/ + + # Also build xpp in the subdirectory xpp/ . But only for >=2.6.10 and only + # for i386. On other archs the module will probably build but panic. --- zaptel-1.2.11.dfsg.orig/debian/patches/ukcid.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/ukcid.dpatch @@ -0,0 +1,139 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## ukcid.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: UK Caller-ID patch from http://www.lusyn.com/asterisk/patches.html , +## DP: zaptel part + +@DPATCH@ +diff -urNad zaptel-1.1.9.0beta2/zaptel.c /tmp/dpep.qnDT2q/zaptel-1.1.9.0beta2/zaptel.c +--- zaptel-1.1.9.0beta2/zaptel.c 2005-10-04 23:34:36.000000000 +0300 ++++ /tmp/dpep.qnDT2q/zaptel-1.1.9.0beta2/zaptel.c 2005-11-01 23:37:26.435046197 +0200 +@@ -734,6 +734,20 @@ + unsigned char *newbuf, *oldbuf; + unsigned long flags; + int x; ++ ++ /* Allocate history buffer, or not. This probably shouldn't ++ * be here, but it's convenient */ ++ if(!j) ++ { ++ if(ss->history) kfree(ss->history); ++ ss->history = NULL; ++ } ++ else ++ { ++ if(!ss->history) ss->history=kmalloc(ZT_HISTORY_BUF_LEN, GFP_KERNEL); ++ } ++ ss->historypos=0; ++ + /* Check numbufs */ + if (numbufs < 2) + numbufs = 2; +@@ -3955,11 +3969,12 @@ + { + struct zt_chan *chan = chans[unit]; + unsigned long flags; +- int j, rv; ++ int j, k1, k2, rv; + int ret; + int oldconf; + void *rxgain=NULL; + echo_can_state_t *ec, *tec; ++ struct zt_history hist; + + if (!chan) + return -ENOSYS; +@@ -4311,6 +4326,29 @@ + return -EINVAL; + break; + #endif ++ case ZT_GET_HISTORY: ++ if (copy_from_user(&hist,(struct zt_history *) data,sizeof(hist))) ++ return -EIO; ++ ++ if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL); ++ if (!chan->history) return -EINVAL; ++ j=hist.len; ++ k1=ZT_HISTORY_BUF_LEN-chan->historypos; ++ k2=chan->historypos; ++ if(j>0 && k1>0) ++ { ++ if (copy_to_user(hist.buf,chan->history+chan->historypos,min(j,k1))) ++ return -EIO; ++ j-=min(j,k1); ++ } ++ if(j>0 && k2>0) ++ { ++ if (copy_to_user(hist.buf+k1,chan->history,min(j,k2))) ++ return -EIO; ++ j-=min(j,k2); ++ } ++ /* Probably should assert j==0 here */ ++ break; + default: + return zt_chanandpseudo_ioctl(inode, file, cmd, data, unit); + } +@@ -5575,6 +5613,15 @@ + memcpy(ms->putlin, putlin, ZT_CHUNKSIZE * sizeof(short)); + memcpy(ms->putraw, rxb, ZT_CHUNKSIZE); + } ++ ++ /* Store in the history buffer */ ++ if(ms->history) ++ { ++ memcpy(ms->history+ms->historypos,rxb,ZT_CHUNKSIZE); ++ ms->historypos+=ZT_CHUNKSIZE; ++ if(ms->historypos >= ZT_HISTORY_BUF_LEN) ++ ms->historypos=0; ++ } + + /* Take the rxc, twiddle it for conferencing if appropriate and put it + back */ +diff -urNad zaptel-1.1.9.0beta2/zaptel.h /tmp/dpep.qnDT2q/zaptel-1.1.9.0beta2/zaptel.h +--- zaptel-1.1.9.0beta2/zaptel.h 2005-10-27 18:05:07.000000000 +0200 ++++ /tmp/dpep.qnDT2q/zaptel-1.1.9.0beta2/zaptel.h 2005-11-01 23:37:26.446044778 +0200 +@@ -143,6 +143,8 @@ + #define ZT_MAX_NUM_BUFS 32 + #define ZT_MAX_BUF_SPACE 32768 + ++#define ZT_HISTORY_BUF_LEN 16384 /* Count of ulaw samples */ ++ + #define ZT_DEFAULT_BLOCKSIZE 1024 + #define ZT_DEFAULT_MTR_MRU 2048 + +@@ -289,6 +291,11 @@ + int reserved[4]; /* Reserved for future expansion -- always set to 0 */ + } ZT_DIAL_PARAMS; + ++typedef struct zt_history ++{ ++ unsigned char *buf; /* Sample buffer */ ++ int len; /* Length of buffer, in bytes */ ++} ZT_HISTORY; + + typedef struct zt_dynamic_span { + char driver[20]; /* Which low-level driver to use */ +@@ -604,6 +611,11 @@ + #define ZT_TIMERPONG _IOW (ZT_CODE, 53, int) + + /* ++ * Return history buffer ++ */ ++#define ZT_GET_HISTORY _IOR(ZT_CODE, 54, struct zt_history) ++ ++/* + * Set/get signalling freeze + */ + #define ZT_SIGFREEZE _IOW (ZT_CODE, 54, int) +@@ -1039,6 +1051,10 @@ + + int blocksize; /* Block size */ + ++ ++ u_char *history; /* History buffer, for pre-ring caller ID (ZT_HISTORY_BUF_LEN) */ ++ u_short historypos; /* Current position within buffer */ ++ + int eventinidx; /* out index in event buf (circular) */ + int eventoutidx; /* in index in event buf (circular) */ + unsigned int eventbuf[ZT_MAX_EVENTSIZE]; /* event circ. buffer */ --- zaptel-1.2.11.dfsg.orig/debian/patches/Makefile_bristuff.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/Makefile_bristuff.dpatch @@ -0,0 +1,61 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## Makefile_bristuff.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: A bit of extra Makefile changes to build bristuff +## DP: Also adds two unrelated modules: opvxa1200 + +@DPATCH@ +diff -urNad zaptel-1.2.9.1.dfsg~/Makefile zaptel-1.2.9.1.dfsg/Makefile +--- zaptel-1.2.9.1.dfsg~/Makefile 2006-09-23 13:48:37.000000000 +0100 ++++ zaptel-1.2.9.1.dfsg/Makefile 2006-09-23 13:48:37.000000000 +0100 +@@ -129,6 +129,11 @@ + MODULES+=ztdummy + endif + ++BRIMODS=cwain qozap zaphfc ztgsm ++MODULES+=$(BRIMODS) ++MODULES+=opvxa1200 ++BINS+=ztpty ++ + MODULESO:=$(MODULES:%=%.o) + MODULESKO:=$(MODULES:%=%.ko) + ifeq ($(BUILDVER),linux26) +@@ -164,6 +169,8 @@ + usbfxstest fxstest fxotune fxsdump ztdiag + UTILSO:=$(UTILS:%=%.o) + ++BINS+=ztpty ++ + all: modules $(LIBTONEZONE_SO) + + programs: $(BINS) $(LIBTONEZONE_SO) +@@ -209,6 +216,28 @@ + + ztdummy.o: ztdummy.h + ++$(BRIMODS:%=%.o): %.o: %.h ++ifneq (,$(wildcard /usr/src/modules/rtai/base/include/rtai.h)) ++zaphfc.o: KFLAGS+=-DRTAITIMING \ ++ -I/usr/src/modules/rtai/base/include -I/usr/src/modules/rtai ++endif ++# copy the zaptel modules to current directory before building modules: ++prereq: $(BRIMODS:%=%.c) $(BRIMODS:%=%.h) ++ ++# copy bristuff files from subdirectories ++# provide zaphfc.[ch] from zaphfc/zaphfc.[ch] etc. Any better way? ++ztgsm.%: ztgsm/ztgsm.% ++ cp $^ $@ ++ ++zaphfc.%: zaphfc/zaphfc.% ++ cp $^ $@ ++ ++qozap.%: qozap/qozap.% ++ cp $^ $@ ++ ++cwain.%: cwain/cwain.% ++ cp $^ $@ ++ + $(MODULESO): %.o: %.c zaptel.h + $(CC) $(KFLAGS) -o $@ -c $< + --- zaptel-1.2.11.dfsg.orig/debian/patches/wct4xxp-dfsg.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/wct4xxp-dfsg.dpatch @@ -0,0 +1,22 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## wct4xxp-dfsg.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: This patch builds the wct4xxp module without firmware support +## DP: The module is completely usable without the firmware, as long +## DP: as the user does not have the optional Octasic module on their +## DP: TE4XXP card (and most users do not have those modules). + +@DPATCH@ +diff -urNad zaptel-1.2.11.dfsg~/wct4xxp/Kbuild zaptel-1.2.11.dfsg/wct4xxp/Kbuild +--- zaptel-1.2.11.dfsg~/wct4xxp/Kbuild 2006-11-05 06:44:13.000000000 +0000 ++++ zaptel-1.2.11.dfsg/wct4xxp/Kbuild 2006-12-02 13:25:37.000000000 +0000 +@@ -12,7 +12,7 @@ + $(obj)/base.o: $(src)/vpm450m.h $(src)/wct4xxp.h + $(obj)/base.o: $(src)/../zaptel.h + +-$(obj)/vpm450m.o: $(obj)/vpmoct128_fw.h $(obj)/vpmoct064_fw.h $(src)/vpm450m.h ++$(obj)/vpm450m.o: $(src)/vpm450m.h + $(obj)/vpm450m.o: $(src)/../oct612x/include/oct6100api/oct6100_api.h + + $(obj)/vpmoct128_fw.h: $(src)/OCT6114-128D.ima $(obj)/fw2h --- zaptel-1.2.11.dfsg.orig/debian/patches/Makefile_uname.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/Makefile_uname.dpatch @@ -0,0 +1,77 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## Makefile_unamem.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Removes unnecessary calls to uname -r and uname -m . Use UNAME_M +## DP: and KVERS/KVERS_MAJ instead. +## DP: Impact: Minimal: fixes a possible incorrect behaviour (try version +## DP: no. 2.6.2-4) and will also consider 2.5 as linux26 BUILDVER . + +@DPATCH@ +diff -urNad zaptel-1.2.11.dfsg~/Makefile zaptel-1.2.11.dfsg/Makefile +--- zaptel-1.2.11.dfsg~/Makefile 2006-12-02 14:12:47.000000000 +0000 ++++ zaptel-1.2.11.dfsg/Makefile 2006-12-02 14:12:54.000000000 +0000 +@@ -11,6 +11,11 @@ + + INSTALL_PREFIX:=$(DESTDIR) + ++ifeq ($(DEB_HOST_GNU_TYPE),) ++UNAME_M:=$(shell uname -m) ++else ++UNAME_M:=$(DEB_HOST_GNU_TYPE) ++endif + # If you want to build for a kernel other than the current kernel, set KVERS + ifndef KVERS + KVERS:=$(shell uname -r) +@@ -23,11 +28,16 @@ + KSRC:=$(shell for dir in $(KSRC_SEARCH_PATH); do if [ -d $$dir ]; then echo $$dir; break; fi; done) + endif + endif ++KVERS_MAJ:=$(shell echo $(KVERS) | cut -d. -f1-2) + KINCLUDES:=$(KSRC)/include + +-CFLAGS+=-I. -O4 -g -Wall -DBUILDING_TONEZONE #-DTONEZONE_DRIVER +-CFLAGS_PPC:=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi) +-CFLAGS_X86-64:=$(shell if uname -m | grep -q x86_64; then echo "-m64"; fi) ++CFLAGS+=-I. -O2 -g -Wall -DBUILDING_TONEZONE #-DTONEZONE_DRIVER ++ifneq (,$(findstring ppc,$(UNAME_M))) ++CFLAGS_PPC:=-fsigned-char ++endif ++ifneq (,$(findstring x86_64,$(UNAME_M))) ++CFLAGS_X86-64:=-m64 ++endif + CFLAGS+=$(CFLAGS_PPC) $(CFLAGS_X86-64) + LCFLAGS:=-fPIC $(CFLAGS) -DBUILDING_TONEZONE + KFLAGS:=-I$(KINCLUDES) -O6 +@@ -36,9 +46,15 @@ + ifneq (,$(wildcard $(KINCLUDES)/linux/modversions.h)) + KFLAGS+=-DMODVERSIONS -include $(KINCLUDES)/linux/modversions.h + endif +-KFLAGS_PPC:=$(shell if uname -m | grep -q ppc; then echo "-msoft-float -fsigned-char"; fi) ++ifneq (,$(findstring ppc,$(UNAME_M))) ++KFLAGS_PPC:=-msoft-float -fsigned-char ++endif + KFLAGS+=$(KFLAGS_PPC) +-KFLAGS+=$(shell if uname -r | grep -q 2.4; then if uname -m | grep -q x86_64; then echo "-mcmodel=kernel"; fi; fi) ++ifeq ($(KVERS_MAJ),2.4) ++ ifneq (,$(findstring x86_64,$(UNAME_M))) ++ KFLAGS+=-mcmodel=kernel ++ endif ++endif + + # + # Features are now configured in zconfig.h +@@ -52,10 +68,10 @@ + CONFIG_FILE:=$(INSTALL_PREFIX)/etc/zaptel.conf + CFLAGS+=-DZAPTEL_CONFIG=\"$(CONFIG_FILE)\" + +-ifeq (2.6,$(shell echo $(KVERS) | cut -d. -f1-2)) +- BUILDVER:=linux26 +-else ++ifeq ($(KVERS_MAJ),2.4) + BUILDVER:=linux24 ++else ++ BUILDVER:=linux26 + endif + + ifeq ($(BUILDVER),linux24) --- zaptel-1.2.11.dfsg.orig/debian/patches/bristuff.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/bristuff.dpatch @@ -0,0 +1,354 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## bristuff.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: This is the patch zaptel.patch from bristuff, with the Makefile +## DP: patch removed. Version: bristuff-0.3.0-PRE-1v + +@DPATCH@ +diff -urN zaptel-1.2.10.orig/zaptel.c zaptel-1.2.10/zaptel.c +--- zaptel-1.2.10.orig/zaptel.c 2006-09-16 09:45:04.000000000 +0200 ++++ zaptel-1.2.10/zaptel.c 2006-10-19 11:16:47.000000000 +0200 +@@ -139,6 +139,7 @@ + EXPORT_SYMBOL(zt_qevent_lock); + EXPORT_SYMBOL(zt_hooksig); + EXPORT_SYMBOL(zt_alarm_notify); ++EXPORT_SYMBOL(zt_alarm_notify_no_master_change); + EXPORT_SYMBOL(zt_set_dynamic_ioctl); + EXPORT_SYMBOL(zt_ec_chunk); + EXPORT_SYMBOL(zt_ec_span); +@@ -2700,6 +2701,30 @@ + } + } + ++void zt_alarm_notify_no_master_change(struct zt_span *span) ++{ ++ int j; ++ int x; ++ ++ span->alarms &= ~ZT_ALARM_LOOPBACK; ++ /* Determine maint status */ ++ if (span->maintstat || span->mainttimer) ++ span->alarms |= ZT_ALARM_LOOPBACK; ++ /* DON'T CHANGE THIS AGAIN. THIS WAS DONE FOR A REASON. ++ The expression (a != b) does *NOT* do the same thing ++ as ((!a) != (!b)) */ ++ /* if change in general state */ ++ if ((!span->alarms) != (!span->lastalarms)) { ++ if (span->alarms) ++ j = ZT_EVENT_ALARM; ++ else ++ j = ZT_EVENT_NOALARM; ++ span->lastalarms = span->alarms; ++ for (x=0;x < span->channels;x++) ++ zt_qevent_lock(&span->chans[x], j); ++ } ++} ++ + #define VALID_SPAN(j) do { \ + if ((j >= ZT_MAX_SPANS) || (j < 1)) \ + return -EINVAL; \ +@@ -4928,11 +4953,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]) { +@@ -4977,6 +5031,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)); +@@ -4987,7 +5052,7 @@ + tasklet_schedule(&ms->ppp_calls); + } + #endif +- } ++ } + } else if (ms->curtone && !(ms->flags & ZT_FLAG_PSEUDO)) { + left = ms->curtone->tonesamples - ms->tonep; + if (left > bytes) +@@ -5033,6 +5098,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; +@@ -5758,6 +5827,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) +@@ -5816,6 +5892,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 -urN zaptel-1.2.10.orig/zaptel.h zaptel-1.2.10/zaptel.h +--- zaptel-1.2.10.orig/zaptel.h 2005-12-17 03:04:05.000000000 +0100 ++++ zaptel-1.2.10/zaptel.h 2006-10-19 11:16:47.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 */ +@@ -1068,7 +1075,7 @@ + int txbufpolicy; /* Buffer policy */ + int rxbufpolicy; /* Buffer policy */ + int txdisable; /* Disable transmitter */ +- int rxdisable; /* Disable receiver */ ++ int rxdisable; /* Disable receiver */ + + + /* Tone zone stuff */ +@@ -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 */ +@@ -1404,6 +1415,9 @@ + /* Notify a change possible change in alarm status */ + extern void zt_alarm_notify(struct zt_span *span); + ++/* Notify a change possible change in alarm status, DONT change the zaptel master! */ ++extern void zt_alarm_notify_no_master_change(struct zt_span *span); ++ + /* Initialize a tone state */ + extern void zt_init_tone_state(struct zt_tone_state *ts, struct zt_tone *zt); + +diff -urN zaptel-1.2.10.orig/zconfig.h zaptel-1.2.10/zconfig.h +--- zaptel-1.2.10.orig/zconfig.h 2005-11-29 19:42:08.000000000 +0100 ++++ zaptel-1.2.10/zconfig.h 2006-10-19 11:16:47.000000000 +0200 +@@ -49,11 +49,11 @@ + /* #define ECHO_CAN_MARK */ + /* #define ECHO_CAN_MARK2 */ + /* #define ECHO_CAN_MARK3 */ +-#define ECHO_CAN_KB1 ++/* #define ECHO_CAN_KB1 */ + /* MG2 is a version of KB1 that has some changes to it that are + * supposed to improve how it performs. If you have echo problems, + * try it out! */ +-/* #define ECHO_CAN_MG2 */ ++#define ECHO_CAN_MG2 + + /* + * Uncomment for aggressive residual echo supression under +@@ -152,4 +152,10 @@ + */ + /* #define FXSFLASH */ + ++/* ++ * Uncomment the following for BRI D channels ++ * ++ */ ++#define CONFIG_ZAPATA_BRI_DCHANS ++ + #endif +diff -urN zaptel-1.2.10.orig/ztpty.c zaptel-1.2.10/ztpty.c +--- zaptel-1.2.10.orig/ztpty.c 1970-01-01 01:00:00.000000000 +0100 ++++ zaptel-1.2.10/ztpty.c 2006-10-19 11:16:47.000000000 +0200 +@@ -0,0 +1,112 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "zaptel.h" ++ ++#define SIZE 8000 ++ ++ ++ ++void doit(int fd, int stdinfd) { ++ fd_set fds; ++ char inbuffer[4096]; ++ char outbuffer[4096]; ++ int res = 0; ++ int i = 0; ++ ++// fprintf(stderr, "fd %d stdin fd %d\n", fd, stdinfd); ++ ++ for (;;) { ++ FD_ZERO(&fds); ++ FD_SET(fd, &fds); ++ FD_SET(stdinfd, &fds); ++ /* Wait for *some* sort of I/O */ ++ res = select(stdinfd + 1, &fds, NULL, NULL, NULL); ++ if (res < 0) { ++ fprintf(stderr, "Error in select: %s\n", strerror(errno)); ++ return; ++ } ++ if (FD_ISSET(stdinfd, &fds)) { ++ res = read(stdinfd, inbuffer, sizeof(inbuffer)); ++ if (res > 0) { ++// fprintf(stderr, "read %d bytes from stdin\n", res); ++ if (res > 0) { ++ for (i=0; i < res ; i++) { ++ if (inbuffer[i] == '\n') { ++ if ((i > 0) && (inbuffer[i-1] == ' ')) { ++ inbuffer[i-1] = 0x1a; ++ } ++ inbuffer[i] = 0xd; ++ } ++ } ++ res = write(fd, inbuffer, res+2); ++// res = write(STDOUT_FILENO, inbuffer, res); ++// fprintf(stderr, "wrote %d bytes to stdout\n", res); ++ } ++ } ++ } ++ if (FD_ISSET(fd, &fds)) { ++ res = read(fd, outbuffer, sizeof(outbuffer)); ++// fprintf(stderr, "read %d bytes from fd\n", res); ++ if (res > 0) { ++ res = write(STDOUT_FILENO, outbuffer, res); ++// fprintf(stderr, "wrote %d bytes to stdout\n", res); ++ } ++ } ++ } ++ ++ ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int fd; ++ int stdinfd; ++ struct zt_params p; ++ struct zt_bufferinfo bi; ++ int blocksize=0; ++ fd = open(argv[1], O_RDWR | O_NONBLOCK); ++ if (fd < 0) { ++ fprintf(stderr, "Unable to open zap interface: %s\n", strerror(errno)); ++ exit(1); ++ } ++ if (ioctl(fd, ZT_GET_PARAMS, &p)) { ++ fprintf(stderr, "Unable to get parameters on '%s': %s\n", argv[1], strerror(errno)); ++ exit(1); ++ } ++ if ((p.sigtype != ZT_SIG_HDLCRAW) && (p.sigtype != ZT_SIG_HDLCFCS)) { ++ fprintf(stderr, "%s is in %d signalling, not FCS HDLC or RAW HDLC mode\n", argv[1], p.sigtype); ++ exit(1); ++ } ++ ++ if (ioctl(fd, ZT_GET_BLOCKSIZE, &blocksize)) { ++ fprintf(stderr, "Unable to get blocksize on '%s': %s\n", argv[1], strerror(errno)); ++ exit(1); ++ } else { ++// fprintf(stderr, "blocksize %d\n", blocksize); ++ } ++ ++ bi.txbufpolicy = ZT_POLICY_IMMEDIATE; ++ bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; ++ bi.numbufs = 16; ++ bi.bufsize = 1024; ++ if (ioctl(fd, ZT_SET_BUFINFO, &bi)) { ++ fprintf(stderr, "Unable to set buffer info on '%s': %s\n", argv[1], strerror(errno)); ++ exit(1); ++ } ++ ++ stdinfd = open("/dev/stdin", O_RDONLY | O_NONBLOCK); ++ ++ ++ doit(fd, stdinfd); ++ close(stdinfd); ++ close(fd); ++ return 0; ++} --- zaptel-1.2.11.dfsg.orig/debian/patches/bristuff_local_zaptelh.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/bristuff_local_zaptelh.dpatch @@ -0,0 +1,72 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## bristuff_local_zaptelh.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Allow bristuff modules to be built in the same directory as +## DP: zaptel itself (when -DSTANDALONE_ZAPATA is used) + +@DPATCH@ +diff -urNad trunk/cwain/cwain.c /tmp/dpep.u4G4Tv/trunk/cwain/cwain.c +--- trunk/cwain/cwain.c 2006-04-25 22:15:34.000000000 +0300 ++++ /tmp/dpep.u4G4Tv/trunk/cwain/cwain.c 2006-06-27 18:23:08.474483444 +0300 +@@ -18,7 +18,11 @@ + #include + #include + #include +-#include ++#ifdef STANDALONE_ZAPATA ++#include "zaptel.h" ++#else ++#include ++#endif + #include "cwain.h" + + #if CONFIG_PCI +diff -urNad trunk/qozap/qozap.c /tmp/dpep.u4G4Tv/trunk/qozap/qozap.c +--- trunk/qozap/qozap.c 2006-04-25 16:37:39.000000000 +0300 ++++ /tmp/dpep.u4G4Tv/trunk/qozap/qozap.c 2006-06-27 18:24:14.512637006 +0300 +@@ -15,7 +15,11 @@ + #include + #include + #include +-#include ++#ifdef STANDALONE_ZAPATA ++#include "zaptel.h" ++#else ++#include ++#endif + #include "qozap.h" + + #if CONFIG_PCI +diff -urNad trunk/zaphfc/zaphfc.c /tmp/dpep.u4G4Tv/trunk/zaphfc/zaphfc.c +--- trunk/zaphfc/zaphfc.c 2006-04-25 16:38:47.000000000 +0300 ++++ /tmp/dpep.u4G4Tv/trunk/zaphfc/zaphfc.c 2006-06-27 18:25:06.105038433 +0300 +@@ -24,7 +24,11 @@ + #include + #include + #include +-#include ++#ifdef STANDALONE_ZAPATA ++#include "zaptel.h" ++#else ++#include ++#endif + #include "zaphfc.h" + + #if CONFIG_PCI +diff -urNad trunk/ztgsm/ztgsm.c /tmp/dpep.u4G4Tv/trunk/ztgsm/ztgsm.c +--- trunk/ztgsm/ztgsm.c 2006-04-25 16:48:02.000000000 +0300 ++++ /tmp/dpep.u4G4Tv/trunk/ztgsm/ztgsm.c 2006-06-27 18:25:19.518522688 +0300 +@@ -14,7 +14,11 @@ + #include + #include + #include +-#include ++#ifdef STANDALONE_ZAPATA ++#include "zaptel.h" ++#else ++#include ++#endif + #include "ztgsm.h" + + #if CONFIG_PCI --- zaptel-1.2.11.dfsg.orig/debian/patches/sangoma.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/sangoma.dpatch @@ -0,0 +1,38 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## sangoma.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: The patch zaptel.patch from the Sangoma wanpipe driver distribution. + +@DPATCH@ +diff -urNad zaptel-1.2.8.xpp.r2496/zaptel.c /tmp/dpep.3jOAuc/zaptel-1.2.8.xpp.r2496/zaptel.c +--- zaptel-1.2.8.xpp.r2496/zaptel.c 2006-08-24 12:08:11.000000000 +0300 ++++ /tmp/dpep.3jOAuc/zaptel-1.2.8.xpp.r2496/zaptel.c 2006-10-26 21:15:01.000000000 +0200 +@@ -1774,6 +1774,13 @@ + } else { + if (copy_from_user(chan->writebuf[chan->inwritebuf], usrbuf, amnt)) + return -EFAULT; ++ ++ if ((chan->flags & ZT_FLAG_HDLC) && chan->span->ioctl != NULL){ ++ if (chan->span->ioctl(chan, ZT_DCHAN_TX_V2, amnt)==0){ ++ return amnt; ++ } ++ } ++ + chan->writen[chan->inwritebuf] = amnt; + } + chan->writeidx[chan->inwritebuf] = 0; +diff -urNad zaptel-1.2.8.xpp.r2496/zaptel.h /tmp/dpep.3jOAuc/zaptel-1.2.8.xpp.r2496/zaptel.h +--- zaptel-1.2.8.xpp.r2496/zaptel.h 2006-08-24 12:08:11.000000000 +0300 ++++ /tmp/dpep.3jOAuc/zaptel-1.2.8.xpp.r2496/zaptel.h 2006-10-26 21:15:01.000000000 +0200 +@@ -632,6 +632,10 @@ + * 60-80 are reserved for private drivers + * 80-85 are reserved for dynamic span stuff + */ ++#define ZT_DCHAN_TX _IOR (ZT_CODE, 60, int) ++#define ZT_DCHAN_TX_V1 ZT_DCHAN_TX ++#define ZT_DCHAN_TX_V2 ZT_DCHAN_TX ++ + + /* + * Create a dynamic span --- zaptel-1.2.11.dfsg.orig/debian/patches/Makefile_targets.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/Makefile_targets.dpatch @@ -0,0 +1,64 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## Makefile_modules.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Adds targets modules, programs, install-modules and install-programs to +## DP: allow separate installation of the programs and the modules +## -- will be fixed later on.. still pending. + +@DPATCH@ +diff -urNad zaptel-1.2.1/Makefile /tmp/dpep.hnX6Yg/zaptel-1.2.1/Makefile +--- zaptel-1.2.1/Makefile 2005-12-22 00:01:06.000000000 +0200 ++++ /tmp/dpep.hnX6Yg/zaptel-1.2.1/Makefile 2005-12-22 00:09:25.000000000 +0200 +@@ -122,6 +122,16 @@ + endif + MODULESO:=$(MODULES:%=%.o) + MODULESKO:=$(MODULES:%=%.ko) ++ifeq ($(BUILDVER),linux26) ++MODULES_BUILD:=$(MODULESKO) ++else ++MODULES_BUILD:=$(MODULESO) ++endif ++ ++BIN_DIR:=$(INSTALL_PREFIX)/sbin ++LIB_DIR:=$(INSTALL_PREFIX)/usr/lib ++INC_DIR:=$(INSTALL_PREFIX)/usr/include ++MOD_DIR:=$(INSTALL_PREFIX)/lib/modules/$(KVERS)/misc + + ifneq (,$(wildcard /usr/include/newt.h)) + ZTTOOL:=zttool +@@ -136,7 +146,11 @@ + #PRIMARY=wcfxo + PWD:=$(shell pwd) + +-all: $(BUILDVER) $(LIBTONEZONE_SO) ++all: modules $(LIBTONEZONE_SO) ++ ++programs: $(BINS) $(LIBTONEZONE_SO) ++ ++modules: $(BUILDVER) + + linux24: $(MODULESO) $(BINS) + +@@ -387,6 +401,21 @@ + echo "Not under version control"; \ + fi + ++# make should *fail* and not silently succeed if a program did not build ++install-programs: $(BINS) $(LIBTONEZONE) libtonezone.a ++ install -d $(BIN_DIR) ++ install $(BINS) $(BIN_DIR) ++ install -d $(LIB_DIR) ++ install -m 755 $(LIBTONEZONE) libtonezone.a $(LIB_DIR) ++ install -D -m 755 $(LIBTONEZONE_SO) $(INSTALL_PREFIX)/usr/lib/$(LIBTONEZONE_SO).$(LIBTONEZONE_SO_MAJOR_VER).$(LIBTONEZONE_SO_MINOR_VER) ++ install -d $(INC_DIR)/linux ++ install -m 644 tonezone.h $(INC_DIR) ++ install -m 644 zaptel.h torisa.h $(INC_DIR)/linux ++ ++install-modules: $(MODULES_BUILD) ++ install -d $(MOD_DIR) ++ install -m 644 $(MODULES_BUILD) $(MOD_DIR) ++ + clean: + rm -f torisatool makefw tor2fw.h radfw.h + rm -f ${BINS} --- zaptel-1.2.11.dfsg.orig/debian/patches/Makefile_kbuild.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/Makefile_kbuild.dpatch @@ -0,0 +1,28 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## Makefile_kbuild.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: use kbuild (the kernel build system) more extensively. This will +## DP: be useful for recursive builds. +## -- applied upstream in 1.2 branch + +@DPATCH@ +diff -urNad zaptel-1.2.6/Makefile /tmp/dpep.x8Bqi9/zaptel-1.2.6/Makefile +--- zaptel-1.2.6/Makefile 2006-06-22 13:14:41.994504042 +0300 ++++ /tmp/dpep.x8Bqi9/zaptel-1.2.6/Makefile 2006-06-22 13:23:59.447070160 +0300 +@@ -408,10 +408,14 @@ + install -m 644 tonezone.h $(INC_DIR) + install -m 644 zaptel.h torisa.h $(INC_DIR)/linux + +-install-modules: $(MODULES_BUILD) ++install-modules: install-$(BUILDVER) ++install-linux24: $(MODULES_BUILD) + install -d $(MOD_DIR) + install -m 644 $(MODULES_BUILD) $(MOD_DIR) + ++install-linux26: $(MODULESKO) ++ $(KMAKE_INST) ++ + clean: + rm -f torisatool makefw tor2fw.h radfw.h + rm -f $(BINS) --- zaptel-1.2.11.dfsg.orig/debian/patches/Makefile_deps_utils.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/Makefile_deps_utils.dpatch @@ -0,0 +1,108 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## Makefile_progdeps.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Clean dependencies and build flags of misc. utils +## -- make specific, cannot be commited upstream. + +@DPATCH@ +diff -urNad zaptel-1.2.0-0beta1/Makefile /tmp/dpep.GxuAYU/zaptel-1.2.0-0beta1/Makefile +--- zaptel-1.2.0-0beta1/Makefile 2005-09-10 17:14:59.442470186 +0300 ++++ /tmp/dpep.GxuAYU/zaptel-1.2.0-0beta1/Makefile 2005-09-10 18:43:28.224686623 +0300 +@@ -109,7 +109,10 @@ + ifneq (,$(wildcard /usr/include/newt.h)) + ZTTOOL:=zttool + endif +-BINS=ztcfg torisatool makefw ztmonitor ztspeed $(ZTTOOL) zttest fxotune ++BINS:=ztcfg ztmonitor ztspeed $(ZTTOOL) zttest fxotune ++UTILS:=tor2ee ztspeed zttool ztmonitor sethdlc-new \ ++ usbfxstest fxstest fxotune fxsdump ztdiag ++UTILSO:=$(UTILS:%=%.o) + + #PRIMARY=wcfxsusb + PRIMARY=torisa +@@ -173,8 +176,7 @@ + + tor2ee.o: tor2-hw.h + +-tor2ee: tor2ee.o +- $(CC) $(CFLAGS) -o $@ $^ -lpci ++tor2ee: LDFLAGS+=-lpci + + zonedata.lo: zonedata.c + $(CC) -c $(LCFLAGS) -o $@ $^ +@@ -194,8 +196,7 @@ + radfw.h: makefw pciradio.rbt + ./makefw pciradio.rbt radfw > radfw.h + +-gendigits: gendigits.o +- $(CC) -o $@ $^ -lm ++gendigits: LDFLAGS+=-lm + + zaptel.c: tones.h + +@@ -207,23 +208,10 @@ + + ztmonitor.o: ztmonitor.c zaptel.h + +-ztspeed.o: ztspeed.c +- $(CC) -o $@ -c $^ +- +-zttool: zttool.o +- $(CC) -o $@ $^ -lnewt +- +-ztmonitor: ztmonitor.o +- $(CC) -o $@ $^ +- +-ztspeed: ztspeed.o +- $(CC) -o $@ $^ +- +-sethdlc-new: sethdlc-new.o +- $(CC) -o $@ $^ +- +-sethdlc-new.o: sethdlc-new.c +- $(CC) -o $@ -c $(CFLAGS) -I$(KINCLUDES) $^ ++ztspeed: CFLAGS= ++ztspeed.o: CFLAGS= ++zttool: LDFLAGS+=-lnewt ++sethdlc-new.o: CFLAGS+=-I$(KINCLUDES) + + libtonezone.a: $(TZOBJS) + ar rcs libtonezone.a $^ +@@ -248,26 +236,20 @@ + complex.o: complex.cc + $(CC) -o $@ -c $^ + +-usbfxstest.o: usbfxstest.c +- $(CC) -o $@ -g -c $^ +- +-usbfxstest: usbfxstest.o +- $(CC) -o $@ $^ -lzap +- +-fxstest: fxstest.o $(LIBTONEZONE_SO) +- $(CC) -o $@ $^ -lm +- +-fxotune: fxotune.o +- $(CC) -o $@ $^ -lm +- +-fxsdump: fxsdump.o +- $(CC) -o $@ $^ -lm ++usbfxstest: LDFLAGS+=-lzap ++fxstest: $(LIBTONEZONE_SO) ++fxstest: LDFLAGS+=-lm ++fxotune: LDFLAGS+=-lm ++fxsdump: LDFLAGS+=-lm + + stackcheck: checkstack $(BUILDVER) + ./checkstack *.o + +-ztdiag: ztdiag.o +- $(CC) -o $@ $^ ++$(UTILS): %: %.o ++ $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) ++ ++$(UTILSO): %.o: %.c ++ $(CC) $(CFLAGS) -o $@ -c $< + + devices: + ifndef DYNFS --- zaptel-1.2.11.dfsg.orig/debian/patches/echocan_env.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/echocan_env.dpatch @@ -0,0 +1,48 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## echhcan_env.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Allow setting the echo cancceler from the environment at (modules) +## DP: build time. + +@DPATCH@ +diff -urNad zaptel-1.1.9.0rc1/Makefile /tmp/dpep.m12xU5/zaptel-1.1.9.0rc1/Makefile +--- zaptel-1.1.9.0rc1/Makefile 2005-11-10 09:02:00.424207126 +0200 ++++ /tmp/dpep.m12xU5/zaptel-1.1.9.0rc1/Makefile 2005-11-10 09:04:15.366618603 +0200 +@@ -217,7 +217,12 @@ + + gendigits: LDFLAGS+=-lm + +-zaptel.c: tones.h ++ifndef EC_TYPE ++ EC_TYPE:=KB1 ++endif ++# only for for 2.6 kernel: ++EXTRA_CFLAGS+=-DECHO_CAN_SET -DECHO_CAN_$(EC_TYPE) ++zaptel.c: tones.h + + prereq: tones.h tor2fw.h radfw.h + +diff -urNad zaptel-1.1.9.0rc1/zconfig.h /tmp/dpep.m12xU5/zaptel-1.1.9.0rc1/zconfig.h +--- zaptel-1.1.9.0rc1/zconfig.h 2005-11-10 09:01:58.140487865 +0200 ++++ /tmp/dpep.m12xU5/zaptel-1.1.9.0rc1/zconfig.h 2005-11-10 09:02:01.534070690 +0200 +@@ -44,12 +44,18 @@ + * Pick your echo canceller: MARK2, MARK3, STEVE, or STEVE2 :) + * + */ ++ ++// you must define externally both ECHO_CAN_SET and ECHO_CAN_foo ++#ifndef ECHO_CAN_SET ++#define ECHO_CAN_SET ECHO_CAN_KB1 ++#define ECHO_CAN_KB1 ++#endif + /* #define ECHO_CAN_STEVE */ + /* #define ECHO_CAN_STEVE2 */ + /* #define ECHO_CAN_MARK */ + /* #define ECHO_CAN_MARK2 */ + /* #define ECHO_CAN_MARK3 */ +-#define ECHO_CAN_KB1 ++/*#define ECHO_CAN_KB1 */ + /* MG2 is a version of KB1 that has some changes to it that are + * supposed to improve how it performs. If you have echo problems, + * try it out! */ --- zaptel-1.2.11.dfsg.orig/debian/patches/00list +++ zaptel-1.2.11.dfsg/debian/patches/00list @@ -0,0 +1,14 @@ +Makefile_deps_utils +Makefile_uname +Makefile_targets +Makefile_kbuild +# probably depends on previus Makefile_* patches (specifically: Makefile_targets) +Makefile_bristuff +# touches the Makefile as well: +#echocan_env +ukcid +bristuff +bristuff_local_zaptelh +Makefile_vzaphfc.dpatch +wct4xxp-dfsg.dpatch +dbug391840.dpatch --- zaptel-1.2.11.dfsg.orig/debian/patches/dbug391840.dpatch +++ zaptel-1.2.11.dfsg/debian/patches/dbug391840.dpatch @@ -0,0 +1,32 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## dbug391840.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Fixes: Bug#391840: ztcfg segfaults because of -O4 +## DP: http://bugs.debian.org/391840 + +@DPATCH@ +diff -urNad zaptel-1.2.9.1.dfsg~/debian/rules zaptel-1.2.9.1.dfsg/debian/rules +--- zaptel-1.2.9.1.dfsg~/debian/rules 2006-10-09 12:52:10.000000000 +1000 ++++ zaptel-1.2.9.1.dfsg/debian/rules 2006-10-09 12:56:32.000000000 +1000 +@@ -12,6 +12,8 @@ + + -include /usr/share/dpatch/dpatch.make + ++export CFLAGS += -fno-inline-functions ++ + ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) + CFLAGS += -g + endif +diff -urNad zaptel-1.2.9.1.dfsg~/ztcfg.c zaptel-1.2.9.1.dfsg/ztcfg.c +--- zaptel-1.2.9.1.dfsg~/ztcfg.c 2006-02-01 13:33:54.000000000 +1100 ++++ zaptel-1.2.9.1.dfsg/ztcfg.c 2006-10-09 12:56:32.000000000 +1000 +@@ -929,6 +929,8 @@ + if (ind_ioctl(x,fd,ZT_RADIO_GETPARAM,&p) == -1) + error("Cannot get number of tones for channel %d\n",x); + n = p.data; ++ if (n > NUM_TONES) ++ error("Too many tones for channel %d: %d\n",x,n); + p.radpar = ZT_RADPAR_INITTONE; + if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1) + error("Cannot init tones for channel %d\n",x); --- zaptel-1.2.11.dfsg.orig/debian/backports/sarge +++ zaptel-1.2.11.dfsg/debian/backports/sarge @@ -0,0 +1,13 @@ +#!/bin/bash +# +# Hook for automatic backports at buildserver.net +# +# Target dist: Debian Sarge + +# Remove libnewt-dev +sed -i -e 's#^\(Build-Depends:.*\)libnewt-dev[^\ ]* \(.*\)$#\1\2#' debian/control + +# Downgrade debhelper to 4.0.4 compat level as in zaptel 1:1.0.7-5 (DH_COMPAT=4 is set in rules anyway?!) +sed -i -e 's#^\(Build-Depends:.*\)debhelper[^,$]*[\ ,$]\+\(.*\)$#\1debhelper (>= 4.0.4), \2#' debian/control + +exit 0 --- zaptel-1.2.11.dfsg.orig/debian/backports/dapper +++ zaptel-1.2.11.dfsg/debian/backports/dapper @@ -0,0 +1,10 @@ +#!/bin/bash +# +# Hook for automatic backports at buildserver.net +# +# Target dist: Ubuntu Dapper + +# Downgrade debhelper to 4.0.4 compat level as in zaptel 1:1.0.7-5 (DH_COMPAT=4 is set in rules anyway?!) +sed -i -e 's#^\(Build-Depends:.*\)debhelper[^,$]*[\ ,$]\+\(.*\)$#\1debhelper (>= 4.0.4), \2#' debian/control + +exit 0 --- zaptel-1.2.11.dfsg.orig/debian/control +++ zaptel-1.2.11.dfsg/debian/control @@ -0,0 +1,49 @@ +Source: zaptel +Section: comm +Priority: optional +Maintainer: Debian VoIP Team +Uploaders: Kilian Krause , Jose Carlos Garcia Sogo , Mark Purcell , Santiago Garcia Mantinan , Santiago Ruano Rincón , Tzafrir Cohen +Build-Depends: debhelper (>= 5.0.37), libnewt-dev, dpatch (>= 2.0.9), bzip2, libusb-dev +Standards-Version: 3.6.2 + +Package: zaptel +Section: comm +Architecture: any +# Xorcom packages depend on xpp-firmware. Debian zaptel will probably +# just recommend it. +Depends: ${shlibs:Depends}, procps, fxload +Description: zapata telephony utilities + Userspace utilities for configuring the Zapata telephony kernel driver, + which supports various telephony hardware, such as Wildcard series of + interface cards (X100P, T400P, E400P, S100P, S100U). + . + Includes ztcfg and zttool utils. + +Package: libtonezone1 +Section: libs +Architecture: any +Depends: ${shlibs:Depends} +Description: tonezone library (runtime) + A library for generating tones used for telephone signalling. + +Package: libtonezone-dev +Section: libdevel +Architecture: any +Depends: libtonezone1 (= ${Source-Version}) +Description: tonezone library (development) + A library for generating tones used for telephone signalling. + . + This package contains the development files. + +Package: zaptel-source +Section: devel +Architecture: all +Depends: debhelper (>> 4.0), module-assistant (>= 0.8.1), bzip2 +Recommends: zaptel +Suggests: rtai-source +Description: Zapata telephony interface (source code for kernel driver) + This package contains the source code for zaptel kernel module providing + device drivers for various telephony hardware, including the Wildcard + series of interface cards (X100P, T400P, E400P, S100P, S100U). + . + It is normally used to build kernel modules package: m-a a-i zaptel --- zaptel-1.2.11.dfsg.orig/debian/zaptel.postinst +++ zaptel-1.2.11.dfsg/debian/zaptel.postinst @@ -0,0 +1,67 @@ +#! /bin/sh + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-deconfigure' `in-favour' +# `removing' +# + +DYNFS=`ps ax | grep -v grep` + +case "$1" in + configure) + + #MAKEDEV zaptel + + if ! echo $DYNFS | grep -q devfsd || echo $DYNFS | grep -q udevd ; then + mkdir -p /dev/zap + rm -f /dev/zap/ctl + rm -f /dev/zap/channel + rm -f /dev/zap/pseudo + rm -f /dev/zap/timer + rm -f /dev/zap/253 + rm -f /dev/zap/252 + rm -f /dev/zap/251 + rm -f /dev/zap/250 + mknod /dev/zap/ctl c 196 0 + mknod /dev/zap/timer c 196 253 + mknod /dev/zap/channel c 196 254 + mknod /dev/zap/pseudo c 196 255 + N=1; + for N in `seq 250`; do + rm -f /dev/zap/$N; + mknod /dev/zap/$N c 196 $N; + N=`expr $N + 1` + done + chown 0:dialout /dev/zap/ -R + chmod 0660 /dev/zap/* + else + echo "**** Dynamic filesystem detected -- not creating device nodes" + echo "**** If you are running udev, read README.Debian" + fi + + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + --- zaptel-1.2.11.dfsg.orig/debian/libtonezone-dev.links +++ zaptel-1.2.11.dfsg/debian/libtonezone-dev.links @@ -0,0 +1,2 @@ +usr/lib/libtonezone.so.1.0 usr/lib/libtonezone.so + --- zaptel-1.2.11.dfsg.orig/debian/ztspeed.8 +++ zaptel-1.2.11.dfsg/debian/ztspeed.8 @@ -0,0 +1,26 @@ +.TH ztspeed 8 "2005-06-25" +.SH NAME +ztspeed \(em A generic speed test +.SH SYNOPSIS +.B ztspeed + +.SH DESCRIPTION +.B ztspeed +runs a simple 100% CPU loop for 5 seconds to see how many loops are +performed. Used to measure how much CPU zaptel \fBreally\fR is taking. + +.SH OPTIONS +None. Nothing else to see. + +.SH SEE ALSO +zttool(8), ztmonitor(8), zttest(8), ztcfg(8), asterisk(8). + +.SH AUTHOR + +This manual page was written by Tzafrir Cohen +Permission is granted to copy, distribute and/or modify this document under +the terms of the GNU General Public License, Version 2 any +later version published by the Free Software Foundation. + +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL. --- zaptel-1.2.11.dfsg.orig/debian/docs +++ zaptel-1.2.11.dfsg/debian/docs @@ -0,0 +1,5 @@ +README +README.fxotune +README.fxsusb +README.Linux26 +xpp/README.Astribank --- zaptel-1.2.11.dfsg.orig/debian/zaptel.lintian +++ zaptel-1.2.11.dfsg/debian/zaptel.lintian @@ -0,0 +1,5 @@ +zaptel: mknod-in-maintainer-script postinst:31 +zaptel: mknod-in-maintainer-script postinst:32 +zaptel: mknod-in-maintainer-script postinst:33 +zaptel: mknod-in-maintainer-script postinst:34 +zaptel: mknod-in-maintainer-script postinst:38 --- zaptel-1.2.11.dfsg.orig/debian/zaptel.dirs +++ zaptel-1.2.11.dfsg/debian/zaptel.dirs @@ -0,0 +1,3 @@ +etc/modprobe.d +etc/udev/rules.d +usr/share/lintian/overrides --- zaptel-1.2.11.dfsg.orig/debian/zaptel.init +++ zaptel-1.2.11.dfsg/debian/zaptel.init @@ -0,0 +1,163 @@ +#! /bin/sh +# +# skeleton example file to build /etc/init.d/ scripts. +# This file should be used to construct scripts for /etc/init.d. +# +# Written by Miquel van Smoorenburg . +# Modified for Debian +# by Ian Murdock . +# +# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl +# + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/sbin/ztcfg +ZAPCONF_FILE=/etc/zaptel.conf +NAME=zaptel +DESC="Zaptel telephony kernel driver" +FXOTUNE=/usr/sbin/fxotune + +# Include am defaults if available +if [ -f /etc/default/zaptel ] ; then + . /etc/default/zaptel +fi + +if [ ! -x $DAEMON ] ; then + echo >&2 $NAME ":" $DAEMON "fails test for exists and executable" ; + exit 0 +fi + +if [ ! -f $ZAPCONF_FILE ] ; then + echo >&2 $NAME ":" $ZAPCONF_FILE "fails test for exists and readable"; + exit 0 +fi + +# defined in /etc/default/zaptel +# ZAPTEL_MODS is a list of modules to be loaded at startup + +set -e + +zap_reg_xpp() { + if [ ! -d /proc/xpp ]; then return; fi + + # Get a list of connected Astribank devices, sorted by the name of + # the USB connector. That order is rather arbitrary, but will not + # change without changes to the cabling. + xbusses=`sort -k 2 /proc/xpp/xbuses | awk -F: '/STATUS=connected/ {print $1}'` + + # get a list of XPDs that were not yet registered as zaptel spans. + # this will be the case if you set the parameter zap_autoreg=0 to + # the module xpp + # Append /dev/null to provide a valid file name in case of an empty pattern. + xbusses_pattern=`echo $xbusses| sed -e 's|XBUS-[0-9]*|/proc/xpp/&/XPD-*/zt_registration|g'`' /dev/null' + xpds_to_register=`grep -l 0 $xbusses_pattern 2>/dev/null` || true + for file in $xpds_to_register; do + echo 1 >$file + done +} + +fix_asterisbank_sync() { + # do nothing if module not present + if [ ! -d /proc/xpp ]; then return; fi + + #if ! grep -q '^HOST' /proc/xpp/sync 2>/dev/null; then return; fi + + case "$XPP_SYNC" in + n*|N*) return;; + host|HOST) sync_value="HOST";; + [0-9]*)sync_value="$XPP_SYNC";; + *) + # find the number of the first bus, and sync from it: + fxo_pat=`awk -F: '/STATUS=connected/{print $1}' /proc/xpp/xbuses | sed -e 's|.*|/proc/xpp/&/*/fxo_info|'` + # find the first FXO unit, and set it as the sync master + bus=`ls -1 $fxo_pat 2> /dev/null | head -n1 | cut -d- -f2 | cut -d/ -f1` + + # do nothing if there is no bus: + case "$bus" in [0-9]*):;; *) return;; esac + sync_value="$bus 0" + ;; + esac + # the built-in echo of bash fails to print a proper error on failure + if ! /bin/echo "$sync_value" >/proc/xpp/sync + then + echo >&2 "Updating XPP sync source failed (used XPP_SYNC='$XPP_SYNC')" + fi +} + +# recursively unload a module and its dependencies, if possible. +# where's modprobe -r when you need it? +# inputs: module to unload. +unload_module() { + set +e + module="$1" + line=`lsmod 2>/dev/null | grep "^$module "` + if [ "$line" = '' ]; then return; fi # module was not loaded + + set -- $line + # $1: the original module, $2: size, $3: refcount, $4: deps list + mods=`echo $4 | tr , ' '` + # xpd_fxs actually sort of depends on xpp: + case "$module" in xpd_*) mods="xpp_usb $mods";; esac + for mod in $mods; do + # run in a subshell, so it won't step over our vars: + (unload_module $mod) + done + rmmod $module || true + set -e +} + +# sleep a while until the xpp modules fully register +wait_for_xpp() { + if [ -d /proc/xpp ] && \ + [ "`cat /sys/module/xpp/parameters/zap_autoreg`" = 'Y' ] + then + # wait for the XPDs to register: + # TODO: improve error reporting and produce a messagee here + cat /proc/xpp/XBUS-*/waitfor_xpds 2>/dev/null >/dev/null || true + fi +} + +case "$1" in + start|reload) + echo -n "$DESC: " + #for module in $ZAPTEL_MODS + #do + # modprobe $module + #done + wait_for_xpp + zap_reg_xpp + fix_asterisbank_sync + + # If there is no zaptel timing source, load + # ztdummy. Other modules should have been loaded by + # now. + if ! head -c 0 /dev/zap/pseudo 2>/dev/null + then modprobe ztdummy || true # will fail if there is no module package + fi + if [ -r /etc/fxotune.conf ] && [ -x $FXOTUNE ]; then + $FXOTUNE -s + fi + + # configure existing modules: + $DAEMON $DAEMON_OPTS || echo -n $DAEMON "failed. Check" $ZAPCONF_FILE + echo "$NAME." + ;; + stop) + : # do nothing + ;; + unload) + unload_module zaptel + ;; + force-reload|restart) + # there's no 'stop' + $0 start + ;; + *) + N=/etc/init.d/$NAME + # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 --- zaptel-1.2.11.dfsg.orig/debian/zaptel.install +++ zaptel-1.2.11.dfsg/debian/zaptel.install @@ -0,0 +1,6 @@ +etc/zaptel.conf +sbin/* +usr/sbin/* +usr/share/zaptel/* +usr/share/man/man8/* +etc/hotplug/usb/* --- zaptel-1.2.11.dfsg.orig/debian/watch +++ zaptel-1.2.11.dfsg/debian/watch @@ -0,0 +1,8 @@ +# format version number, currently 2; this line is compulsory! +version=3 + +# Full-site-with-pattern [Version [Action]] +#opts=pasv ftp://ftp.asterisk.org/pub/telephony/zaptel/ zaptel-(.*)\.tar\.gz \ +# debian svn-upgrade +opts=dversionmangle=s/\.dfsg// \ + http://ftp.digium.com/pub/zaptel/ zaptel-(1.2.*)\.tar\.gz debian svn-upgrade --- zaptel-1.2.11.dfsg.orig/debian/libtonezone-dev.install +++ zaptel-1.2.11.dfsg/debian/libtonezone-dev.install @@ -0,0 +1,3 @@ +usr/include/*.h +usr/lib/lib*.a +usr/lib/lib*.so --- zaptel-1.2.11.dfsg.orig/debian/zaptel-modules.modules +++ zaptel-1.2.11.dfsg/debian/zaptel-modules.modules @@ -0,0 +1,11 @@ +options torisa base=0xd0000 +alias char-major-196 torisa +post-install wcfxs /sbin/ztcfg +post-install wcfxsusb /sbin/ztcfg +post-install torisa /sbin/ztcfg +post-install tor2 /sbin/ztcfg +post-install wcfxo /sbin/ztcfg +post-install wct1xxp /sbin/ztcfg +post-install qozap /sbin/ztcfg +post-install zaphfc /sbin/ztcfg +post-install zaphfc-florz /sbin/ztcfg --- zaptel-1.2.11.dfsg.orig/debian/zaptel.postrm +++ zaptel-1.2.11.dfsg/debian/zaptel.postrm @@ -0,0 +1,42 @@ +#! /bin/sh +# postrm script for zaptel +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' overwrit>r> +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + +# if test -d /dev/zap/ ; then +# rm -rf /dev/zap +# fi + + + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 --- zaptel-1.2.11.dfsg.orig/debian/changelog +++ zaptel-1.2.11.dfsg/debian/changelog @@ -0,0 +1,686 @@ +zaptel (1:1.2.11.dfsg-1) unstable; urgency=low + + [ Tzafrir Cohen ] + * Reverting my changes from 1:1.2.9.1.dfsg-2. Moved to the experimental + branch. + + [ Kilian Krause ] + * Remove bogus zaptel-modules from being Recommends (Closes: #387961) + * Update vzaphfc as proposed by Jens Wilke + + [ Mark Purcell ] + * New Upstream Release + - Fixes: Fails to build with pristine upstream kernel, very recent version + (Closes: #400705) + - Fixes: Please package version 1.2.11 (Closes: #399634) + - Fixes: vzaphfc: error: 'CHECKSUM_HW' undeclared (Closes: #386498) + * Cleanup debian/patches/wct4xxp-dfsg.dpatch + * debian/rules call dh_installmodules from binary_modules: + - Fixes: I had to do depmod -a manually after doing m-a a-i zaptel (Closes: + #332787) + * Update debian/patches/Makefile_uname.dpatch to force -O2 + - Fixes: Cannot initiate a call to BRI (Closes: #386052) + * Remove Depends: zaptel from debian/control.modules.in + - please don't depend on zaptel (Closes: #391826) + + -- Mark Purcell Sat, 2 Dec 2006 14:33:30 +0000 + +zaptel (1:1.2.10.dfsg-2) unstable; urgency=low + + * bristuff-0.3.0-PRE-1v + * Remove redundant GPL LICENCE text + + -- Mark Purcell Tue, 24 Oct 2006 22:41:01 +0100 + +zaptel (1:1.2.10.dfsg-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Sun, 22 Oct 2006 20:27:19 +0100 + +zaptel (1:1.2.9.1.dfsg-2) unstable; urgency=low + + [ Tzafrir Cohen ] + * zaptel 1.4 compatibility changes: + - place zaptel.h and tonezone.h in /usr/include/zaptel (through symlinks) + - zaptelh_14.dpatch: declare some zaptel 1.4 interfaces (not implemented + anywhere, though). + + [ Mark Purcell ] + * debian/rules patch from Robert Millan + - the package doesn't compile (Closes: #390903) + * add debian/patches/dbug391840.dpatch + - ztcfg segfaults because of -O4 (Closes: #391840) + * add debian/patches/wct4xxp-dfsg.dpatch + - wct4xxp and other modules are not built anymore on zaptel- + 1.2.8.dfsg-1 (Closes: #388756) + + -- Mark Purcell Tue, 10 Oct 2006 09:36:58 +1000 + +zaptel (1:1.2.9.1.dfsg-1) unstable; urgency=low + + * New Upstream Release + * firmware removed from wct4xxp/OCT6114-128D.ima + * Lintian cleanup; spelling-error-in-copyright + + -- Mark Purcell Sat, 23 Sep 2006 13:58:15 +0100 + +zaptel (1:1.2.8.dfsg-1) unstable; urgency=low + + * New Upstream Release + + -- Mark Purcell Wed, 23 Aug 2006 07:30:22 +0100 + +zaptel (1:1.2.7.dfsg-4) unstable; urgency=low + + * Install zaptel.conf.sample as a confile under /etc + * Add Recommends: zaptel-modules + * Improve error handling and conf file checking in init.d. (Closes: + Bug#382604) + + -- Mark Purcell Thu, 17 Aug 2006 08:34:43 +0100 + +zaptel (1:1.2.7.dfsg-3) unstable; urgency=low + + [ Kilian Krause ] + * Simplified vzaphfc patch. + + [ Mark Purcell ] + * Build-Depends: debhelper (>= 5.0.37) and dh_installmodules makes + zaptel-source.postinst & zaptel-modules.post{inst,rm} obsolete + Fixes: postinst/postrm depmod -- update templates to use dh_installmodules + instead (Closes: #381754) + * postinst failure (Closes: #361312) + * zaptel-modules from testing don't compile on Sarge (Closes: #376719) + * pciradio.c:1810: error: syntax error before string constant (Closes: + #368145) + * Can't recompile zaptel modules on Sarge (Closes: #375581) + * zaptel-modules from testing don't compile on Sarge (Closes: #376719) + + -- Mark Purcell Thu, 10 Aug 2006 23:39:58 +0100 + +zaptel (1:1.2.7.dfsg-2) unstable; urgency=low + + * Fix get-orig-source target to make dfsg repacking work + * Fix zaptel-source to build without firmware again. Required dropping + wct4xxp module. Added vzaphfc to linux-2.6 modules. (Closes: #381123) + + -- Kilian Krause Thu, 3 Aug 2006 11:48:14 +0000 + +zaptel (1:1.2.7.dfsg-1) unstable; urgency=high + + * Urgency high as this is blocking a security fix for asterisk + * Remove non-modifiable firmware to make DFSG compliant. Does + anyone need this firmware? (Closes: #379458) + + -- Mark Purcell Tue, 1 Aug 2006 15:27:09 +0100 + +zaptel (1:1.2.7-2) unstable; urgency=low + + * Copying Makefile as before to the source package, + Copying some extra files now needed for building (Closes: #378864) + + -- Mark Purcell Tue, 1 Aug 2006 06:29:39 +0100 + +zaptel (1:1.2.7-1) unstable; urgency=low + + * New upstream release + + [ Kilian Krause ] + * Add vzaphfc driver (enhanced zaphfc) by Jens Wilke. + + [ Tzafrir Cohen ] + * Separating ZapBRI modules to directories, rather than patches + * Example configs moved from zaptel-source to zaptel + * Removing some unneeded dirs from zaptel-source + * debian/patches/Makefile_kbuild: a small part of the original one. + Fixes building on Sarge + * genzaptelconf is now in zaptel + * xpp/utils/Makefile has a decent install target + * debian/rules: Use CURDIR + * debian/modulestest: Building modules for -3 kernels + * fix x bit of files in /usr/share/zaptel + * removed genzaptelconf from debian/ + * Added support for the OpenVox A1200P card (http://www.openvox.com.cn/) + * debian/control: require libusb-dev for building xpp firmware loader. + * debian/control: Recommend package xpp-firmware (should be added to + non-free) + * bristuff_local_zaptelh.dpatch: Build bristuff modules with correct + zaptel.conf (in Sarge) + * Makefile_uname.dpatch: Updated. Note: watch for PWD issues. + * Makefile_bristuff.dpatch: updated to reflect Makefile change. + + -- Mark Purcell Mon, 17 Jul 2006 21:48:21 +0100 + +zaptel (1:1.2.6-2) unstable; urgency=high + + * Urgency high as this is blocking a security fix for asterisk [CVE-2006-2898] + + * Add debian/libtonezone-dev.links + - Realy fix: missing libtonezone.so.1 symlink (Closes: #372887) + + -- Mark Purcell Wed, 14 Jun 2006 13:40:31 +1000 + +zaptel (1:1.2.6-1) unstable; urgency=high + + [ Mark Purcell ] + * Urgency high as this is blocking a security fix for asterisk [CVE-2006-2898] + + * New upstream release. + - can't find zaptel.h during build (Closes: #330137) + - errors in fxotune.c (Closes: #370213) + - Cannot make zaptel-source: SUBDIR not found (Closes: #368561) + + [ Kilian Krause ] + * Weed out old unused patches. Add comments which patches have been included + upstream for next release. + + [ Lionel Elie Mamane ] + * Load ztdummy when needed, not when not needed. + + [ Tzafrir Cohen ] + * bristuff: 0.3.0-PRE1p + * We have another ZapBRI module: ztgsm + * Experimental support in genzaptelconf for ztgsm (from sample files) + * genzaptelconf: 0.5.1 (does not require restart of asterisk) + * zaptel.init: 'unload' operation. Better support for Astribank + * moduletest script fixes + * bristuff added ztpty + * genzaptelconf: wait for xpp (astribank) module to register after loadin it + * minor xpp driver fixes (already in 1.2 branch) + + [ Julien BLACHE ] + * debian/libtonezone1.links: + + Create the libtonezone.so.1 symlink (closes: #372887). + + -- Mark Purcell Wed, 14 Jun 2006 10:59:52 +1000 + +zaptel (1:1.2.5-1) unstable; urgency=low + + [ Tzafrir Cohen ] + * New upstream version + * Only build xpp for i386, as it currently crashes on other arches. + * Fix compilation of xpp for 2.6.14 + + [ Kilian Krause ] + * Fix gendigits to write to stdout. + + -- Kilian Krause Thu, 30 Mar 2006 23:52:38 +0300 + +zaptel (1:1.2.4-1) unstable; urgency=low + + * New upstrream release (Closes: #353094) + * removing xpp.dpatch: merged in upstream + * removing dot_version: bug fixed upstream + * Makefile_kbuild.dpatch: modified, as it was not properly merged in + upstream + * Makefile_bristuff.dpatch: really build zaptel modules again + * Makefile_xpp: fixed. + * debian/modulestest: a script for postbuild of zaptel modules from a svn + build + * zaptel-source: removing unnecessary dependency on dpatch + + -- Tzafrir Cohen Thu, 23 Feb 2006 09:40:47 +0200 + +zaptel (1:1.2.3-2) unstable; urgency=low + + * bristuff 0.3.0-PRE1k. Also, renamed the dpatch to simply "bristuff" + * updated version in dot_version.dpatch. + * Include build_tools and .version in copied files + * newer versions of genzaptelconf and xpp.dpatch + + -- Tzafrir Cohen Mon, 6 Feb 2006 15:30:06 +0200 + +zaptel (1:1.2.3-1) unstable; urgency=low + + * new upstrream release + * ukcid.dpatch: for UK Caller ID support (Zaptel part, closes: #302380) + * newer versions of genzaptelconf and xpp.dpatch + * Makefile_pscmd.dpatch disabled due to a small upstream change. Revive it? + * dot_version.dpatch: the tarball is missing the .version file. Remove + it when it provides one + + -- Tzafrir Cohen Mon, 6 Feb 2006 14:02:04 +0200 + +zaptel (1:1.2.1-3) unstable; urgency=low + + * Fix compilation with binary-only mode. + * bristuff 0.3.0-PRE-1f + * make lintian override apply + + -- Tzafrir Cohen Sat, 7 Jan 2006 20:39:33 +0200 + +zaptel (1:1.2.1-2) unstable; urgency=low + + * Added bristuff 0.3.0-PRE1d patch. bristuff re-enabled. + (Closes: #340627, #344432) + * Documentation fixes (Closes: #316801) + * Makefile_targets.dpatch is ba its small self + * readded bristuff examples. with cwain this time + * zaptel.init: a slightly different test for a zaptel timing source + * Depend on procps due to using ps in postinst (Closes: #342699) + + -- Tzafrir Cohen Fri, 30 Dec 2005 19:12:54 +0200 + +zaptel (1:1.2.1-1) unstable; urgency=low + + * New upstream release + * Disable bristuff for new upstream + + -- Mark Purcell Wed, 7 Dec 2005 21:28:23 +0000 + +zaptel (1:1.2.0-2) unstable; urgency=low + + [ Kilian Krause ] + * Added bristuff 0.3.0-PRE1 for Asterisk 1.2.0 support. + + [Tzafrir Cohen] + * fix Makefile_deps_kern.dpatch + * remove .rej from Makefile.uname.dpatch + * do install genzaptelconf man page + * update genzaptelconf and its man page + * echocan_env.dpatch: allow changing the echo canceller at zaptel-modules + build time + * Makefile_kbuild.dpatch: use kbuild for 2.6 modules build. used for: + * Makefile_xpp.dpatch: (not applied by default) + a small patch to enable the build of: + * xpp.dpatch: drivers for Xorcom Asteribank + + [ Mark Purcell ] + * Build and package libtonezone.so + + -- Mark Purcell Wed, 30 Nov 2005 16:28:51 +0000 + +zaptel (1:1.2.0-1) unstable; urgency=low + + * New upstream release + * Remove Makefile_deps_kern.dpatch as it doesnt apply upstream + + -- Mark Purcell Thu, 17 Nov 2005 17:50:00 +0000 + +zaptel (1:1.2.0-rc2-1) experimental; urgency=low + + * New upstream release + + -- Mark Purcell Sun, 13 Nov 2005 18:24:17 +0000 + +zaptel (1:1.2.0-rc1-1) experimental; urgency=low + + * New upstream release + * Update Makefile_uname.dpatch + * FTBFS: missing or incorrect directory modexamples/ (Closes: #329084) + * debian/rules export DH_COMPAT=4 + + -- Mark Purcell Wed, 9 Nov 2005 21:37:47 +0000 + +zaptel (1:1.2.0-beta2-3) experimental; urgency=low + + * Not Released Yet + * Copyright audit to debian/copyright + + -- Mark Purcell Mon, 7 Nov 2005 19:19:27 +0000 + +zaptel (1:1.0.9.2-1) unstable; urgency=low + + * New Upstream Release + + -- Mark Purcell Tue, 8 Nov 2005 20:47:48 +0000 + +zaptel (1:1.2.0-beta2-2) experimental; urgency=low + + * Suggestions from Tzafrir Cohen + - Makefile_man.dpatch can be removed: fixed by upstream + - fxotune.tmpfile.dpatch can be removed: fixed by upstream + - a small manual fix to Makefile_targets.dpatch: s/ manpages$// + - debian/rules: dh_installman: 's/debian/doc/' a number of times + (don't use doc/*.8 as there is no reason to install the pathetic + torisatool.8 man page) + + -- Mark Purcell Tue, 1 Nov 2005 21:26:36 +0000 + +zaptel (1:1.2.0-beta2-1) experimental; urgency=low + + * New upstream release + * Update Makefile_targets.dpatch + * Update Makefile_man + * Update fxotune_tmpfile.dpatch + + -- Mark Purcell Tue, 1 Nov 2005 20:51:02 +0000 + +zaptel (1:1.2.0-0beta1-1) experimental; urgency=low + + * New upstream release + * Disable bristuff for experimental upload + * Apply patch from Tzafrir Cohen for 1.2.0 build + + -- Mark Purcell Sun, 18 Sep 2005 12:48:59 +0100 + +zaptel (1:1.0.9.1-4) unstable; urgency=low + + (NOT YET RELEASED - needs still some tweaking with florz' patches) + * debian/patches/ztcfg_init.dpatch: Make ztcfg not kill the channels when + executed twice. + * debian/patches/zaphfc_0.2.0-RC8n_florz-8.dpatch: Add florz' improved + zaphfc implementation as zaphfc-florz. This should reduce system IO load + among other improvements. Taken from http://zaphfc.florz.dyndns.org/ + + -- Kilian Krause Sat, 27 Aug 2005 21:32:50 +0200 + +zaptel (1:1.0.9.1-3) unstable; urgency=low + + * debian/control: fixed overrides disparity with zaptel-source belonging to + devel rather than comm. + + -- Kilian Krause Sat, 27 Aug 2005 14:35:48 +0200 + +zaptel (1:1.0.9.1-2) unstable; urgency=low + + * Closes: #302836: zaptel-source: zaphfc module missing after + compiling modules. + * Closes: #323753: zaptel-source: cannot compile zaphfc in unstable + with gcc-4.0.1. + + -- Santiago Ruano Rincon Fri, 19 Aug 2005 00:40:56 -0500 + +zaptel (1:1.0.9.1-1) unstable; urgency=low + + * New upstream release + * Update debian/watch + * Please package version 1.0.9.1 (Closes: #320600) + * FXO hardware stops working after 25 days (Closes: #321239) + + -- Mark Purcell Mon, 8 Aug 2005 18:34:10 +0100 + +zaptel (1:1.0.9-5) unstable; urgency=low + + * Import bristuff-0.2.0-RC8l.dpatch + + -- Santiago Ruano Rincon Sat, 30 Jul 2005 11:26:42 -0500 + +zaptel (1:1.0.9-4) unstable; urgency=low + + Santiago Ruano Rincon: + * Man pages are builded from sgml's using docbook-utils + Deleted the *.8 files + * Closes: #317297: Applied a patch to improve the ztdummy + accuracy on kernel 2.6 + + Mark Purcell: + * Reinstate debian/zaptel.install + - Closes: #318575: this package does not install ztcfg, ztmonitor, + ztspeed, zttest, zttool. + + -- Mark Purcell Sun, 17 Jul 2005 07:11:27 +1000 + +zaptel (1:1.0.9-3) unstable; urgency=low + + * Import bristuff-0.2.0-RC8j.dpatch + * Closes: #315251: zaptel should be in group comm + * Note that the cloned report is still active against ftp.debian.org + * Closes: #316800: zaptel package 1.0.9 ships headers + + -- Mark Purcell Thu, 14 Jul 2005 12:19:10 +0100 + +zaptel (1:1.0.9-2) unstable; urgency=low + + * Import bristuff-0.2.0-RC8h.dpatch + * Enable rtia.dpatch + + -- Mark Purcell Mon, 4 Jul 2005 02:35:37 +0100 + +zaptel (1:1.0.9-1) unstable; urgency=low + + * New upstream release + * Disable bristuff to allow 1.0.9 upload + * Disable rtia to allow 1.0.9 upload + + -- Mark Purcell Sun, 3 Jul 2005 15:51:32 +0100 + +zaptel (1:1.0.7-5) unstable; urgency=low + + * ACK NMUs. Thanks for helping with this. (Closes: #305731, #310150) + * Actually doesn't fail if dpatch is not installed when building modules. + * zaptel-modules.postinst: New. Run depmod -a on modules install + * zaptel: should build-dep on debhelper (>= 4.0.4). (Closes: #310788) + * zaptel: should build-dep on dpatch >= 2.0.9 (Closes: #314549) + * zaptel: bashism in postinst (Closes: #314552) + * zaptel-source: compilation error in zaphfc.c (Closes: #305193) + * zaptel-source Build-Depends on dpatch, should Depend on + it though. (Closes: #309258) + * zaptel-source: Fails to enable RTAI support (Closes: #304648) + + -- Kilian Krause Sun, 19 Jun 2005 15:38:25 +0200 + +zaptel (1:1.0.7-4.1) unstable; urgency=high + + * Non-maintainer upload. + * High-urgency upload for sarge-targetted RC bugfix + * Make sure directories are created mode 755 instead of mode 644, as + this otherwise causes problems for building (apparently on xfs + filesystems). Closes: #310150. + * Tweak debian/patches/Makefile.dpatch fix from the previous NMU so + that it isn't unnecessarily fragile: -fsigned-char is *always* + either a no-op or required, so lose the architecture checking and + enable it unconditionally. Closes: #305731. + + -- Steve Langasek Sun, 22 May 2005 02:48:44 -0700 + +zaptel (1:1.0.7-4) unstable; urgency=high + + * NMU as VOIP team taking so long. Fix compiler flags so that ztcfg + works. (Closes: #305731) + + -- Matthew Grant Fri, 22 Apr 2005 07:35:28 +1200 + +zaptel (1:1.0.7-3) unstable; urgency=medium + + * Closes: #302903: libtonezone1 package is empty + * Closes: #302833: binary files missing, e.g. /sbin/ztcfg + * Move debian/*.files -> debian/*.install + * Closes: #302847: zaptel command ztcfg freezes on Debian PowerPC + causing boot failure. + + -- Mark Purcell Sun, 3 Apr 2005 19:44:25 +0100 + +zaptel (1:1.0.7-2) unstable; urgency=medium + + * Debian VoIP Team upload. + * Jose Carlos: + + Working support for module-assistant included in zaptel-source. + Thanks to Eduard Bloch for his help (Closes: #301665) + + debian/control.modules.in: + - make generated modules package depend on zaptel binary package. + - updated description to refer to module-assistant. + + debian/control: + - build-depend on bzip2. + - zaptel-source depends on module-assistant tool and bzip2. + - updated and improved descriptions. + + debian/rules: + - remaked with the new m-a stuff. + - don't need dpatch installed for building the modules (Closes: #301666) + + debian/postinst: doesn't output garbage (Closes: #296958) + + debian/postrm: don't remove creeated devices. Only box admin can do + that, per Policy 10.6 + + Removed zaphfc and qozap examples from zaptel-source. Only ship them + in zaptel binary package. + + README.Debian: file added. Talk about how compile modules and + use them with udev (Closes: #163857) + + Don't install zaptel.h file in zaptel-modules packages. (Closes: #297306) + + * Kilian Krause: + + Increased urgency for fixing RC-bug and this is the last deb to + allow the whole Debian VoIP suit proceed to testing. + + -- Jose Carlos Garcia Sogo Sat, 2 Apr 2005 01:14:23 +0200 + +zaptel (1:1.0.7-1) unstable; urgency=low + + * New upstream version. + + -- Kilian Krause Sat, 19 Mar 2005 23:28:07 +0100 + +zaptel (1:1.0.6-1) unstable; urgency=low + + * New upstream version. (zaptel 1.0.6, bristuff RC7k) + * added zaphfc and qozap modules. + + -- Kilian Krause Sat, 5 Mar 2005 20:05:35 +0100 + +zaptel (1:1.0.4-3) unstable; urgency=low + + * Debian VoIP team upload. + * debian/rules, debian/zaptel-source.files: fixed zaptel.h includes problem + * debian/patches/Makefile.dpatch: imported from old package (now dpatch + instead directly in the diff). Fixed building on hosts with differring + userland and kernel arch. Now also including symlink for SONAME. + * debian/patches/bristuff.dpatch: imported bristuff patch to include zaphfc. + (Closes: #294183) + * debian/zaptel.postinst: Fixed permissions issue problem. + * debian/zaptel.modprobe.d: Added zaphfc RC7f. + + -- Kilian Krause Thu, 24 Feb 2005 01:42:36 +0100 + +zaptel (1:1.0.4-2) experimental; urgency=low + + * Better "use" of uname -r in Makefile for zaptel-source + + -- Santiago Ruano Rincon Mon, 21 Feb 2005 00:27:14 -0500 + +zaptel (1:1.0.4-1) experimental; urgency=low + + * New upstream release (zaptel-1.0.4) + * Included zttest and ztspeed binaries + * Added Depends on debhelper and Recomends zaptel for zaptel-source + * Added /etc/modprobe.d/zaptel and corrected the path for the binaries, + /sbin instead of /usr/sbin + + -- Santiago Ruano Rincon Wed, 26 Jan 2005 23:05:20 -0500 + +zaptel (1:1.0.2-2) unstable; urgency=low + + * libtonezone out of zaptel-source + * /dev/zap/ are now created by zaptel.postinst and deleted by + zaptel.postrm. Now, the zap devices match with the upstream version + (Closes: #274384). + * Added lintian overrides for mknod-in-maintainer-script warnings + * docbook-to-man out of the Build-Depends + + -- Santiago Ruano Rincon Wed, 24 Nov 2004 22:05:52 -0500 + +zaptel (1:1.0.2-1) unstable; urgency=low + + * New upstream release (zaptel-1.0.2) + + -- Santiago Ruano Rincon Sat, 30 Oct 2004 00:51:54 -0500 + +zaptel (1:1.0.0-2) unstable; urgency=low + + * New maintainer (Closes: #251938). + * Man pages created for ztcfg, ztmonitor and zttool + (Closes: #274632, #274633, #274634). + * Mark Purcell made the package for version 1.0 + (Closes: #273255, #251929). + * zaptel-modules can be build from zaptel-source with + make-kpkg (Closes: #274085). + * Now it compiles for 2.6 Kernels (Closes: #251930). + + -- Santiago Ruano Rincon Sun, 26 Sep 2004 02:05:44 -0500 + +zaptel (1:1.0.0-1) unstable; urgency=low + + * NMU (See Bug#251938) + * New upstream release + + -- Mark Purcell Fri, 24 Sep 2004 22:46:55 +1000 + +zaptel (1:0.8.1+1.0-RC2-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Thu, 9 Sep 2004 19:17:28 +1000 + +zaptel (1:0.8.1+1.0-RC1-1) unstable; urgency=low + + * New upstream release + * Add a debian/watch file + + -- Mark Purcell Wed, 21 Jul 2004 17:51:22 +1000 + +zaptel (1:0.8.1-1) unstable; urgency=low + + * New upstream release + + -- Matt Zimmerman Wed, 11 Feb 2004 15:29:20 -0800 + +zaptel (1:0.8.0-2) unstable; urgency=low + + * Create usr/include ahead of time so that tonezone.h is installed + correctly (Closes: #227795) + + -- Matt Zimmerman Wed, 14 Jan 2004 17:24:26 -0800 + +zaptel (1:0.8.0-1) unstable; urgency=low + + * New upstream release + + -- Matt Zimmerman Tue, 13 Jan 2004 14:44:56 -0800 + +zaptel (1:0.6.0-2) unstable; urgency=low + + * Rebuild with new libnewt + + -- Matt Zimmerman Mon, 30 Jun 2003 22:51:18 -0400 + +zaptel (1:0.6.0-1) unstable; urgency=low + + * New upstream release, needed for new asterisk (Closes: #189661) + + -- Matt Zimmerman Sat, 19 Apr 2003 23:56:59 -0400 + +zaptel (1:0.4.0-2) unstable; urgency=low + + * Break out into {build,install,binary}-indep targets + (Closes: #184528) + * libtonezone-dev Section: libdevel + * Escape $ properly in instructions in postinst + + -- Matt Zimmerman Wed, 12 Mar 2003 19:16:10 -0500 + +zaptel (1:0.4.0-1) unstable; urgency=low + + * New upstream release + + -- Matt Zimmerman Sun, 16 Feb 2003 15:12:02 -0500 + +zaptel (0.cvs.20021029-1) unstable; urgency=low + + * New upstream CVS + * Use MARK2 echo canceller + + -- Matt Zimmerman Tue, 29 Oct 2002 10:37:53 -0500 + +zaptel (0.cvs.20020729-1) unstable; urgency=low + + * New upstream CVS + * Include ztmonitor binary + + -- Matt Zimmerman Mon, 29 Jul 2002 12:36:58 -0400 + +zaptel (0.cvs.20020708-1) unstable; urgency=low + + * New upstream CVS + + -- Matt Zimmerman Mon, 8 Jul 2002 15:32:20 -0400 + +zaptel (0.cvs.20020624-2) unstable; urgency=low + + * Include Makefile in the -source package (oops, Closes: #152014) + + -- Matt Zimmerman Fri, 5 Jul 2002 11:00:08 -0400 + +zaptel (0.cvs.20020624-1) unstable; urgency=low + + * Initial Release (Closes: #150874) + + -- Matt Zimmerman Mon, 17 Jun 2002 10:31:21 -0400 + --- zaptel-1.2.11.dfsg.orig/debian/zaptel.modprobe.d +++ zaptel-1.2.11.dfsg/debian/zaptel.modprobe.d @@ -0,0 +1,14 @@ +options torisa base=0xd0000 +alias char-major-196 torisa +install tor2 /sbin/modprobe --ignore-install tor2 && /sbin/ztcfg +install torisa /sbin/modprobe --ignore-install torisa && /sbin/ztcfg +install wcusb /sbin/modprobe --ignore-install wcusb && /sbin/ztcfg +install wcfxo /sbin/modprobe --ignore-install wcfxo && /sbin/ztcfg +install wcfxs /sbin/modprobe --ignore-install wcfxs && /sbin/ztcfg +install ztdynamic /sbin/modprobe --ignore-install ztdynamic && /sbin/ztcfg +install ztd-eth /sbin/modprobe --ignore-install ztd-eth && /sbin/ztcfg +install wct1xxp /sbin/modprobe --ignore-install wct1xxp && /sbin/ztcfg +install wct4xxp /sbin/modprobe --ignore-install wct4xxp && /sbin/ztcfg +install wcte11xp /sbin/modprobe --ignore-install wcte11xp && /sbin/ztcfg +install zaphfc /sbin/modprobe --ignore-install zaphfc && /sbin/ztcfg +install qozap /sbin/modprobe --ignore-install qozap && /sbin/ztcfg --- zaptel-1.2.11.dfsg.orig/debian/libtonezone1.links +++ zaptel-1.2.11.dfsg/debian/libtonezone1.links @@ -0,0 +1,2 @@ +usr/lib/libtonezone.so.1.0 usr/lib/libtonezone.so.1 + --- zaptel-1.2.11.dfsg.orig/debian/rules +++ zaptel-1.2.11.dfsg/debian/rules @@ -0,0 +1,221 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatibility version to use. +export DH_COMPAT=4 +USE_BRISTUFF=1 +export HOTPLUG_FIRMWARE=1 + +-include /usr/share/dpatch/dpatch.make + +ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) + CFLAGS += -g +endif + +## MODULE-ASSISTANT STUFF +# prefix of the target package name +PREFIX:=zaptel +SKPG:=$(PREFIX)-source +PACKAGE:=$(PREFIX)-modules +# modifieable for experiments or debugging m-a +MA_DIR ?= /usr/share/modass +# load generic variable handling +-include $(MA_DIR)/include/generic.make +# load default rules +-include $(MA_DIR)/include/common-rules.make + +DEBVERSION:=$(shell head -n 1 debian/changelog \ + | sed -e 's/^[^(]*(\([^)]*\)).*/\1/') +UPVERSION:=$(shell echo $(DEBVERSION) | sed -e 's/^.*://' -e 's/-[0-9.]*$$//' -e 's/.dfsg$$//') + +UPFILENAME := zaptel_$(UPVERSION).orig.tar.gz +FILENAME := zaptel_$(UPVERSION).dfsg.orig.tar.gz +URL := http://ftp2.digium.com/pub/zaptel/releases/zaptel-$(UPVERSION).tar.gz + +MOD_EXAMPLES_DIR:=modexamples +ifeq (1,$(USE_BRISTUFF)) + BRISTUFF_EXAMPLES:=$(MOD_EXAMPLES_DIR)/* +endif + +kdist_clean: clean-unpatched + +kdist_config: prep-deb-files + +binary-modules: prep-deb-files + dh_testdir + dh_testroot + dh_clean -k + make modules KERNEL_SOURCES=$(KSRC) MODVERSIONS=detect KERNEL=linux-$(KVERS) + make install-modules KERNELRELEASE=$(KVERS) INSTALL_PREFIX=$(CURDIR)/debian/$(PKGNAME) +ifeq (2.6,$(shell echo $(KVERS) | cut -d. -f1-2)) + # The 2.6 modules are way too big. This is only in kernel 2.6 + find debian/$(PKGNAME)/lib/modules -name '*.ko' |xargs strip -g +endif + dh_installmodules + dh_installdebconf + dh_installchangelogs + dh_compress + dh_fixperms + dh_installdeb + dh_gencontrol -- -v$(VERSION) + dh_md5sums + dh_builddeb --destdir=$(DEB_DESTDIR) + +## END OF M-A SECTION + +build: build-stamp +build-stamp: patch-stamp + dh_testdir + + $(MAKE) programs + $(MAKE) -C xpp/utils + touch $@ + +clean: clean-unpatched unpatch +clean-unpatched: + dh_testdir + dh_testroot + rm -f *-stamp + + # Add here commands to clean up after the build process. + rm -rf $(MOD_EXAMPLES_DIR) + -$(MAKE) clean + + #rm -f debian/manpage.links debian/manpage.refs debian/*.8 + + dh_clean + +install: install-arch install-indep + +install-arch: build-stamp + dh_testdir + dh_testroot + dh_clean -k -a + dh_installdirs -a + + # Add here commands to install the package into debian/tmp + + $(MAKE) install-programs INSTALL_PREFIX=$(CURDIR)/debian/tmp + $(MAKE) -C xpp/utils install DESTDIR=$(CURDIR)/debian/tmp + /sbin/ldconfig -n $(CURDIR)/debian/tmp/usr/lib + install -m 644 zaptel.conf.sample $(CURDIR)/debian/tmp/etc/zaptel.conf + + dh_install -a --sourcedir=$(CURDIR)/debian/tmp + + cp $(CURDIR)/debian/zaptel.permissions.rules \ + $(CURDIR)/debian/$(PREFIX)/etc/udev/rules.d/zaptel.perms + cp debian/$(PREFIX).lintian \ + $(CURDIR)/debian/$(PREFIX)/usr/share/lintian/overrides/$(PREFIX) + +TARPARDIR=$(CURDIR)/debian/tmp +TARDIR=$(TARPARDIR)/modules/$(PREFIX) +install-indep: build-stamp + dh_testdir + dh_testroot + dh_clean -k -i + dh_installdirs -i + + # driver source code + mkdir -p $(TARDIR)/debian + cp Makefile .version *.c *.h *.rbt $(TARDIR)/ + for dir in build_tools include cwain qozap vzaphfc oct612x wct4xxp xpp zaphfc ztgsm; do \ + if [ -d $$dir ]; then cp -r $$dir $(TARDIR); fi; \ + done + dh_install -i zaptel.h torisa.h usr/include/linux/ + + # Packaging infrastructure + cp -r debian/*-modules.* debian/rules debian/changelog debian/copyright\ + debian/control \ + debian/control.modules.in \ + $(TARDIR)/debian/ + + tar cjf debian/$(PREFIX)-source/usr/src/$(PREFIX).tar.bz2 \ + -C $(TARPARDIR) modules +ifeq (1,$(USE_BRISTUFF)) + set -e; for module in cwain qozap zaphfc ztgsm; do \ + mkdir -p $(MOD_EXAMPLES_DIR)/$$module; \ + cp -a $$module/*.conf* $(MOD_EXAMPLES_DIR)/$$module; \ + done +else + mkdir -p $(MOD_EXAMPLES_DIR)/bristuff_stub +endif + + #rm -rf modules + + # TODO: this rmdir should not be required! (Tzafrir) + #rmdir debian/zaptel-source/usr/share/modass/overrides/zaptel + #dh_install -i debian/$(PREFIX)-source.modass \ + # usr/share/modass/overrides/$(PREFIX) + +# Build architecture-independent files here. +binary-indep: build install-indep + dh_testdir + dh_testroot + + dh_installdocs -i + dh_installchangelogs -i ChangeLog + dh_installexamples -i $(BRISTUFF_EXAMPLES) + dh_link -i + dh_compress -i + dh_fixperms -i + dh_installdeb -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i + +# Build architecture-dependent files here. +binary-arch: build install-arch + dh_testdir + dh_testroot + + #install -m644 debian/$(PREFIX).modprobe.d debian/$(PREFIX)/etc/modprobe.d/$(PREFIX) + + dh_installdocs -a + # TODO: this installs a man page for torisatool, which we don't build + dh_installman -a doc/*.8 + + # should be removed, eventually. Still left for compatibility + dh_installinit --update-rcd-params="defaults 15 30" + dh_installexamples -a zaptel.conf.sample + + dh_installmodules -a + dh_installchangelogs -a ChangeLog + dh_link -a + dh_strip -a + dh_compress -a + dh_fixperms -a + dh_makeshlibs -a -V + dh_installdeb -a + dh_shlibdeps -a -ldebian/libtonezone1/usr/lib + dh_gencontrol -a + dh_md5sums -a + dh_builddeb -a + +print-version: + @@echo "Debian version: $(DEBVERSION)" + @@echo "Upstream version: $(UPVERSION)" + +get-orig-source: + @@dh_testdir + @@[ -d ../tarballs/. ]||mkdir -p ../tarballs + @@echo Downloading $(UPFILENAME) from $(URL) ... + @@wget -N -nv -T10 -t3 -O ../tarballs/$(UPFILENAME) $(URL) + @@echo Repacking as DFSG-free... + @@mkdir -p ../tarballs/zaptel-$(UPVERSION).tmp/ + @@cd ../tarballs/zaptel-$(UPVERSION).tmp ; \ + tar xfz ../$(UPFILENAME) + @@rm -rf ../tarballs/zaptel-$(UPVERSION).tmp/zaptel-$(UPVERSION)/OCT6114-128D.ima + @@rm -rf ../tarballs/zaptel-$(UPVERSION).tmp/zaptel-$(UPVERSION)/wct4xxp/OCT6114-128D.ima + @@rm -rf ../tarballs/zaptel-$(UPVERSION).tmp/zaptel-$(UPVERSION)/xpp/utils/*.hex + @@cd ../tarballs/zaptel-$(UPVERSION).tmp ; \ + tar cfz ../$(FILENAME) * + @@echo Cleaning up... + @@$(RM) -rf ../tarballs/zaptel-$(UPVERSION).tmp/ + @@$(RM) -f ../tarballs/$(UPFILENAME) + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure patch unpatch --- zaptel-1.2.11.dfsg.orig/debian/zttool.sgml +++ zaptel-1.2.11.dfsg/debian/zttool.sgml @@ -0,0 +1,104 @@ + + + + Santiago"> + Ruano Rincón"> + + July 14, 2005"> + + 8"> + santiago@unicauca.edu.co"> + + zttool"> + + + Debian"> + GNU"> + GPL"> +]> + + + +
+ &dhemail; +
+ + &dhfirstname; + &dhsurname; + + + 2005 + &dhusername; + + &dhdate; +
+ + &dhucpackage; + + &dhsection; + + + &dhpackage; + + Zaptel Tool shows status of Digium's interface cards. + + + + &dhpackage; + + + + DESCRIPTION + + zttool shows the current status the Digium Zaptel inteface + cards plugged to the computer. + + It displays values like Current Alarms, SyncSource, Tx/Rx + Levels for each Zaptel interface. + + + + + SEE ALSO + + ztmonitor(8), asterisk (8). + + + + AUTHOR + + This manual page was written by &dhusername; &dhemail; for + the &debian; system (but may be used by others). Permission is + granted to copy, distribute and/or modify this document under + the terms of the &gnu; General Public License, Version 2 any + later version published by the Free Software Foundation. + + + On Debian systems, the complete text of the GNU General Public + License can be found in /usr/share/common-licenses/GPL. + + + +
+ + + + --- zaptel-1.2.11.dfsg.orig/debian/control.modules.in +++ zaptel-1.2.11.dfsg/debian/control.modules.in @@ -0,0 +1,17 @@ +Source: zaptel +Section: comm +Priority: extra +Maintainer: Debian VoIP Team +Uploaders: Kilian Krause , Jose Carlos Garcia Sogo , Mark Purcell , Santiago Garcia Mantinan , Santiago Ruano Rincon +Build-Depends: debhelper (>> 3.0.0), bzip2 +Standards-Version: 3.6.1.1 + +Package: zaptel-modules-_KVERS_ +Architecture: any +Provides: zaptel-modules +Description: zaptel modules for Linux (kernel _KVERS_). + This package contains the set of loadable kernel modules for the + zapata telephony API. + This package contains the compiled kernel modules for _KVERS_ + . + In order to compile these modules use the module-assistant utility. --- zaptel-1.2.11.dfsg.orig/debian/zaptel-source.dirs +++ zaptel-1.2.11.dfsg/debian/zaptel-source.dirs @@ -0,0 +1,2 @@ +usr/src +usr/include/linux --- zaptel-1.2.11.dfsg.orig/debian/fxotune.8 +++ zaptel-1.2.11.dfsg/debian/fxotune.8 @@ -0,0 +1,66 @@ +.TH FXOTUNE 8 "September 10th, 2005" "Xorcom Rapid Asterisk" "Linux Programmer's Manual" +.SH NAME +.B fxotune +\(em automatically tune FXO channels on a Digium TDM400 card +.SH SYNOPSIS +.B fxotune -i +.I +\(em detect + +.B fxotune -s +\(em load settings + +.SH DESCRIPTION +.B fxotune +is a script that fine-tune parameters of the FXO modules of the TDM400 +card. Whene run in +.I detect +mode (-i) it detects and tunes all the FXO channels of such cards. It +needs a dial string after which the line(s) will give dial tone. + +It writes settings to a configuration file (/etc/fxotune.conf , name +is hardwired) from which it can be loaded (e.g: at startup) using -s . + + +.SH OPTIONS +.B -i +.RS +.I dialstr +Start detecting optimal settings. +.I dialstr +Is a number needed to dial to get a dial tone. +The test can take several minutes, and must be performed when Asterisk +is not running. + +For example: +.RS +fxotune -i 9 +.RE +if you need to dial 9 for an external line. If you always get a line, you +can simply use any digit. +.RE + +.B -s +.RS +Load settings from the last test. Used at startup. +.RE + +.SH FILES +.I /etc/fxotune.conf +.RS +The configuration file generated by fxotune in detect mode and from which +configuration is loaded when +.B -s +is used. + +.SH SEE ALSO +ztcfg(8), zttool(8), ztmonitor(8), asterisk(8). + +.SH AUTHOR +This manual page was written by Tzafrir Cohen +Permission is granted to copy, distribute and/or modify this document under +the terms of the GNU General Public License, Version 2 any +later version published by the Free Software Foundation. + +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL. --- zaptel-1.2.11.dfsg.orig/debian/zaptel.permissions.rules +++ zaptel-1.2.11.dfsg/debian/zaptel.permissions.rules @@ -0,0 +1,4 @@ +# Some extra udev rules that are missing fromt he current ones in Sarge. +# See http://bugs.debian.org/316801 +# Being added to our Sarge backport as it was only resolved in Etch +SUBSYSTEM=="zaptel", GROUP="dialout" --- zaptel-1.2.11.dfsg.orig/debian/zttest.8 +++ zaptel-1.2.11.dfsg/debian/zttest.8 @@ -0,0 +1,45 @@ +.TH zttest 8 "2005-06-25" +.SH "NAME" +zttest \(em Test if the zaptel timer provides timely response +.SH "SYNOPSIS" +.B zttest +.I [ -v ] + +.SH "DESCRIPTION" +.B zttest +zttest runs a timing test in a loop and prints the result of each loop. +The test is as follows: + +It reads 8192 bytes from the zaptel timer device (\fI/dev/zap/pseudo\fR). +This should take exactly 8000 ms . It uses calls to +.I gettimeofday(2) +before and after that read to check that indeed exactly 8000ms have passed. + +Values of 100% and 99.99% Are normally considered a definite +.I pass. +Values of 99.98% and 99.97% are probably OK as well. + +.SH OPTIONS +.B -v +.RS +Be more verbose: print one line per test. +.RE + +.SH FILES +.B /dev/zap/pseudo +.RS +.RE +The device file used to access the zaptel timer. + +.SH SEE ALSO +zttool(8), ztmonitor(8), ztspeed(8), ztcfg(8), asterisk(8). gettimeofday(2) + +.SH AUTHOR + +This manual page was written by Tzafrir Cohen +Permission is granted to copy, distribute and/or modify this document under +the terms of the GNU General Public License, Version 2 any +later version published by the Free Software Foundation. + +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL. --- zaptel-1.2.11.dfsg.orig/debian/ztmonitor.sgml +++ zaptel-1.2.11.dfsg/debian/ztmonitor.sgml @@ -0,0 +1,133 @@ + + + + Santiago"> + Ruano Rincón"> + + July 14, 2005"> + + 8"> + santiago@unicauca.edu.co"> + + ztmonitor"> + + + Debian"> + GNU"> + GPL"> +]> + + + +
+ &dhemail; +
+ + &dhfirstname; + &dhsurname; + + + 2005 + &dhusername; + + &dhdate; +
+ + &dhucpackage; + + &dhsection; + + + &dhpackage; + + checks the rx/tx levels of the zaptel + inteface cards. + + + + &dhpackage; + + + + + + + DESCRIPTION + + &dhpackage; monitors a zaptel channel. It gives you a visual + representation of the sound strengths and makes it easy to see if + the received or transmitted signals are too high or out of + balance + + + + + + OPTIONS + + The first (mandatory) parameter is the number of the channel + to monitor. + + + + + + + + Display visual audio levels. + + + + + + + + Write output to FILE + + + + + + SEE ALSO + + zttool(8), ztcfg(8), asterisk(8). + + + + AUTHOR + + This manual page was written by &dhusername; &dhemail; for + the &debian; system (but may be used by others). Permission is + granted to copy, distribute and/or modify this document under + the terms of the &gnu; General Public License, Version 2 any + later version published by the Free Software Foundation. + + + On Debian systems, the complete text of the GNU General Public + License can be found in /usr/share/common-licenses/GPL. + + + +
+ + + + --- zaptel-1.2.11.dfsg.orig/debian/zaptel.modules +++ zaptel-1.2.11.dfsg/debian/zaptel.modules @@ -0,0 +1,20 @@ +# Uncomment the appropriate alias line, and change 'torisa' to the +# driver for your card + +# DevFS +#alias /dev/zap torisa + +# Non-DevFS +#alias char-major-196 torisa + +options torisa base=0xd0000 + +post-install wcfxs ztcfg +post-install wcfxsusb ztcfg +post-install torisa ztcfg +post-install tor2 ztcfg +post-install wcfxo ztcfg +post-install wct1xxp ztcfg +post-install zaphfc ztcfg +post-install zaphfc-florz ztcfg +post-install qozap ztcfg --- zaptel-1.2.11.dfsg.orig/debian/modulestest +++ zaptel-1.2.11.dfsg/debian/modulestest @@ -0,0 +1,103 @@ +#!/bin/sh + +# debian/modulestest: a postbuild script to build zaptel modules +# example usage: +# +# svn-buildpackage -rfakeroot --svn-postbuild='debian/modulestest -a' --svn-ignore-new --svn-lintian -uc -us + +# At least one of the following two must be set to a sensible value: +# If both are empty, the script does nothing useful) +# +# kernel versions: Comma-separated. Use those if you have their +# kernel-headers/linux-headers packages installed +# + +# Full pathes to trees: +# Use this to provide a full path to a custom kernel tree: +#KERNEL_SOURCES=$HOME/Proj/Debs/Kernel/SwSusp/linux-2.6.15-rc5 +KERNEL_HEADERS= +KERNEL_SOURCES= +# run module-asustant with environment params that will generate +# .changes files even without signing +MODASS="env SIGNCHANGES=1 DEBSIGNCOMMAND=not_an_executable m-a" + +# workaround for silly bash parsing issue in our build scripts: +if [ "$#" -lt 1 ]; then + set -- $MODULESTEST_ARGS +fi + +while getopts ah:s:txX arg +do + case "$arg" in + a) # All of the kernel-headers packages installed: + KERNEL_HEADERS=`COLUMNS=160 dpkg -l 'kernel-headers-2.[46].*-*-*' | awk '/^.i/{print $2}' | sed -e 's/^kernel-headers-//'| xargs| tr ' ' ,` + ;; + h) KERNEL_HEADERS=$OPTARG;; + s) KERNEL_SOURCES=$OPTARG;; + t) # TODO: make this test per-distro or something + KERNEL_HEADERS=2.4.27-2-386,2.6.8-2-686-smp + ;; + x) + # used internally in xorcom. Don't like it: file a bug report to remove + # it (Tzafrir) + for conf in 386 686 686-smp k7 k7-smp + do + for ver in 2.4.27-2 2.4.27-3 2.6.8-2 2.6.8-3 + do + KERNEL_HEADERS=$KERNEL_HEADERS,$ver-$conf + done + done + for conf in 386 686 k7 rapidbox2 + do + for ver in 2.6.12-1 + do + KERNEL_HEADERS=$KERNEL_HEADERS,$ver-$conf + done + done + # remove the leading ',': + KERNEL_HEADERS=${KERNEL_HEADERS#,} + ;; + X) + for conf in 386 686 k7 rapidbox2 + do + for ver in 2.6.12-1 + do + KERNEL_HEADERS=$KERNEL_HEADERS,$ver-$conf + done + done + # remove the leading ',': + KERNEL_HEADERS=${KERNEL_HEADERS#,} + ;; + esac +done +shift $(( $OPTIND-1 )) + +echo "Building for: Headers: $KERNEL_HEADERS, Sources: $KERNEL_SOURCES" + +if [ "$KERNEL_HEADERS" != '' ]; then hdrs_sw="-l $KERNEL_HEADERS"; fi +if [ "$KERNEL_SOURCES" != '' ]; then srcs_sw="-k $KERNEL_SOURCES"; fi + +# must be absolute for m-a ta accept TARBALL: +# Also note that $PWD is ugly and is abot to be deleted. +if [ -x /usr/bin/realpath ] +then TOP_DIR=`realpath $PWD/../` +else TOP_DIR=$PWD/../ +fi +MODS_DIR=$TOP_DIR/modules +TAR_BALL=$MODS_DIR/usr/src/zaptel.tar.bz2 +DEB=$TOP_DIR/$PACKAGE-source_${TAG_VERSION}_all.deb +LOG_FILE=$TOP_DIR/$PACKAGE-modules-build-$TAG_VERSION.log + +rm -f $LOG_FILE +dpkg -x $DEB $MODS_DIR + +rm -f $TOP_DIR/ +if [ "$hdrs_sw" != '' ]; then + TARBALL=$TAR_BALL $MODASS -u $TOP_DIR -t -i -f $hdrs_sw build $PACKAGE >>$LOG_FILE +fi +if [ "$srcs_sw" != '' ]; then + TARBALL=$TAR_BALL $MODASS -u $TOP_DIR -t -i -f $srcs_sw build $PACKAGE >>$LOG_FILE +fi + +ls -l $TOP_DIR/$PACKAGE-modules-*_$TAG_VERSION+*.deb + --- zaptel-1.2.11.dfsg.orig/debian/copyright +++ zaptel-1.2.11.dfsg/debian/copyright @@ -0,0 +1,65 @@ +This package was debianized by Matt Zimmerman on +Mon, 17 Jun 2002 10:31:21 -0400. + +It was downloaded from http://www.asterisk.org/ + +Upstream source has been modified to comply with the Debian Free +Software Guildlines (DFSG), by the removal of the firmware files: + + wct4xxp/OCT6114-128D.ima + +xpp/LICENSE.firmware permits redistribution but does not mention +modification, which is a requirement of Debian Policy 2.1 ("Derived works"). + + +Upstream Authors: Jim Dixon / Zapate Telephony, Linux Support Services, Inc. + +Copyright (from zaptel.c): + + * Copyright (C) 2001 Jim Dixon / Zapata Telephony. + * Copyright (C) 2001 Linux Support Services, Inc. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + +On Debian systems, a copy of the GNU General Public License may be found in +/usr/share/common-licenses/GPL. + +Other Portions: + + * Copyright (C) 2001-2005, Digium, Inc. + * Copyright (C) 2002 Steve Underwood +sethdlc.c: * Copyright (C) 2000 Krzysztof Halasa +ztd-loc.c: * Copyright (C) 2004, Axialys Interactive +ztdummy.c: * Copyright (C) 2002, Hermes Softlab + +bristuff driver: + * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH + +vzaphfc is derived from bristuff and since enhanced by: + * Copyright (C) 2004-2006, Daniele "Vihai" Orlandi + * Copyright (C) 2006, headissue GmbH; Jens Wilke + +Files in the xpp/ subdirectory: + +* Written by Oron Peled +* Copyright (C) 2004-2006, Xorcom + +opvxa1200.c: +* OpenVox A1200P FXS/FXO Interface Driver for Zapata Telephony interface +* +* Modify from wctdm.c by MiaoLin + +opvxa1200.c is available for download from +http://www.openvox.com.cn/members_downloads.php +(requires no login. Does require javascript) + --- zaptel-1.2.11.dfsg.orig/debian/README.Debian +++ zaptel-1.2.11.dfsg/debian/README.Debian @@ -0,0 +1,54 @@ +Building kernel modules +----------------------- + +First, install zaptel-source package if you have not yet done so. + +You can build and install the modules package (as root) with the +following command: +# module-assistant a-i zaptel + +It may be handy (for e.g., testing purposes) to build the module packages +for all of the kernel-header packages installed on your system. Something +in the lines of: + + m-a -u . -t -i -f -k "`echo usr/src/kernel-headers-*`" build zaptel + +You can also use the environment variable TARBALL to build the modules +with a custom zaptel.tar.bz2 tarball with some local modifications. + +Using udev +---------- + +If you are using udev, zaptel devices will be created when kernel modules +are loaded by using modprobe, or devices are detected by hotplug at boot time. + +If you cannot access the zap/ctl device, check which user asterisk is +running as and add these permissions to your permissions file +(ie /etc/udev/permissions.d/50-udev.permissions): +# zaptel devices -- asterisk is expected to be part of 'dialout' group +zap/*:root:dialout:660 + +Note, however, that sarting from Sarge, the defualt udev settings should +include those lines. + + +Bristuff +-------- +This version has the bristuff (0.3.0-PRE1d) of the bristuff patch and +kernel modules. The bristuffed modules require a bristuffed Asterisk +to work. +(TODO: what about standard Digium cards? can they work with a non-bristuffed +chn_zap?) + +fxotune +------- +fxotune is a utulity provided by Digium for fine-tuning parameters of the +FXO modules of their TDM cards. + +This package includes the fxotune binary. It will also load configuration +from /etc/fxotune.conf if fxotune was used to tune the FXO modules. Note +that fxotune onlt works with the newer wctdm driver of zaptel 1.2 and will +not work ith X100P and clones. + +-- Debian VoIP Team +-- 30 December 2005 --- zaptel-1.2.11.dfsg.orig/debian/libtonezone1.install +++ zaptel-1.2.11.dfsg/debian/libtonezone1.install @@ -0,0 +1 @@ +usr/lib/lib*.so.* --- zaptel-1.2.11.dfsg.orig/debian/ztcfg.sgml +++ zaptel-1.2.11.dfsg/debian/ztcfg.sgml @@ -0,0 +1,167 @@ + + + Santiago"> + Ruano Rincón"> + + July 14, 2005"> + 8"> + santiago@unicauca.edu.co"> + + ztcfg"> + + + Debian"> + GNU"> + GPL"> +]> + + + +
+ &dhemail; +
+ + &dhfirstname; + &dhsurname; + + + 2005 + &dhusername; + + &dhdate; +
+ + &dhucpackage; + + &dhsection; + + + &dhpackage; + + reads and loads zaptel.conf + + + + + &dhpackage; + + + + + + + + + &dhpackage + + + + + + + DESCRIPTION + + ztcfg configures zaptel interface cards + from a config file. + + You generally need to run it with a valid configurations + in order for zaptel modules to work properly. + + + + + OPTIONS + + + + + CFG_FILEUse an alternative configuration file instead of + /etc/zaptel.conf + + + + + + + Only shutdown spans. + + + + + + + + Test mode. Don't do anything, just report what you + wanted to do. + + + + + + + Be more verbose. Add extra v-s for extra verbosity. + + + + + + + Display a brief help about the usage of &dhpackage + + + + + + + + + + FILES + + /etc/zaptel.conf The default location for the configuration file. + + + + + SEE ALSO + + zttool(8), ztmonitor(8), asterisk(8). + + + + AUTHOR + + This manual page was written by &dhusername; &dhemail; for + the &debian; system (but may be used by others). Permission is + granted to copy, distribute and/or modify this document under + the terms of the &gnu; General Public License, Version 2 any + later version published by the Free Software Foundation. + + + On Debian systems, the complete text of the GNU General Public + License can be found in /usr/share/common-licenses/GPL. + + + +
+ + + + --- zaptel-1.2.11.dfsg.orig/ztgsm/zaptel.conf.duoGSM +++ zaptel-1.2.11.dfsg/ztgsm/zaptel.conf.duoGSM @@ -0,0 +1,11 @@ +loadzone=nl +defaultzone=nl + +alaw=1,3 + +span=1,1,3,ccs,ami +span=2,2,3,ccs,ami + +bchan=1,3 +dchan=2,4 + --- zaptel-1.2.11.dfsg.orig/ztgsm/zapata.conf.duoGSM +++ zaptel-1.2.11.dfsg/ztgsm/zapata.conf.duoGSM @@ -0,0 +1,23 @@ +[channels] +txgain = -10.0 +rxgain = 0.0 + +signalling = gsm +context = from-gsm + +;group=1 + +; phone number for SIM card in slot A +;exten=016012345671 +; PIN for SIM card in slot A +;pin=1234 + +;channel => 1 + +; phone number for SIM card in slot B +;exten=016012345672 +; PIN for SIM card in slot B +;pin=1234 + +;channel => 3 + --- zaptel-1.2.11.dfsg.orig/ztgsm/zaptel.conf.quadGSM +++ zaptel-1.2.11.dfsg/ztgsm/zaptel.conf.quadGSM @@ -0,0 +1,13 @@ +loadzone=nl +defaultzone=nl + +alaw=1,3,5,7 + +span=1,1,3,ccs,ami +span=2,2,3,ccs,ami +span=3,3,3,ccs,ami +span=4,4,3,ccs,ami + +bchan=1,3,5,7 +dchan=2,4,6,8 + --- zaptel-1.2.11.dfsg.orig/ztgsm/zapata.conf.quadGSM +++ zaptel-1.2.11.dfsg/ztgsm/zapata.conf.quadGSM @@ -0,0 +1,36 @@ +[channels] +txgain = -10.0 +rxgain = 0.0 + +signalling = gsm +context = from-gsm + +;group=1 + +; phone number for SIM card in slot A +;exten=016012345671 +; PIN for SIM card in slot A +;pin=1234 + +;channel => 1 + +; phone number for SIM card in slot B +;exten=016012345672 +; PIN for SIM card in slot B +;pin=1234 + +;channel => 3 + +; phone number for SIM card in slot C +;exten=016012345673 +; PIN for SIM card in slot C +;pin=1234 + +;channel => 5 + +; phone number for SIM card in slot D +;exten=016012345674 +; PIN for SIM card in slot D +;pin=1234 + +;channel => 7 --- zaptel-1.2.11.dfsg.orig/ztgsm/ztgsm.c +++ zaptel-1.2.11.dfsg/ztgsm/ztgsm.c @@ -0,0 +1,1205 @@ +/* + * ztgsm.c - Zaptel driver for the uno/duo/quad GSM PCI cards + * + * Copyright (C) 2005, 2006 Junghanns.NET GmbH + * + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + * + */ +#include +#include +#include +#include +#include +#include +#include "ztgsm.h" + +#ifdef LINUX26 +#include +#endif + +#if CONFIG_PCI + +static int debug=0; +static int pcm_xbar=0; +static struct ztgsm_card *ztgsm_dev_list = NULL; +static int ztgsm_dev_count = 0; +static int ztgsm_spans = 0; +static struct pci_dev *multi_gsm = NULL; +static spinlock_t registerlock = SPIN_LOCK_UNLOCKED; + +void ztgsm_init_xbar(struct ztgsm_card *gsmtmp) { + int i = 0; + for (i=0; i <= 0x01FF; i++) { + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x00000182 | i); + } +} + +void ztgsm_switch_on(struct ztgsm_card *gsmtmp, int span) { + unsigned int dtr_on_off = 0; + unsigned int rts_o = 0; + unsigned long flags; + + printk(KERN_INFO "ztgsm: Powering up span %d ...", span); + spin_lock_irqsave(&(gsmtmp->lock),flags); + gsmtmp->gsmspan[span].led = 0xC1; + dtr_on_off = ztgsm_indw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF); + dtr_on_off |= (1 << span) | (1 << (span+4)); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, dtr_on_off); + + rts_o = ztgsm_indw_io(gsmtmp, ztgsm_SER_RTS_O); + rts_o |= (1 << span); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_RTS_O, rts_o); + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((1000 * HZ) / 1000); + + spin_lock_irqsave(&(gsmtmp->lock),flags); + dtr_on_off = ztgsm_indw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF); + dtr_on_off &= ~(1 << span); + dtr_on_off |= 1 << (span+4); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, dtr_on_off); + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((800 * HZ) / 1000); + + spin_lock_irqsave(&(gsmtmp->lock),flags); + dtr_on_off = ztgsm_indw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF); + dtr_on_off |= (1 << span) | (1 << (span+4)); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, dtr_on_off); + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((8000 * HZ) / 1000); + + spin_lock_irqsave(&(gsmtmp->lock),flags); + dtr_on_off = ztgsm_indw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF); + dtr_on_off &= ~(1 << (span+4)); + dtr_on_off |= (1 << span); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, dtr_on_off); + + rts_o = ztgsm_indw_io(gsmtmp, ztgsm_SER_RTS_O); + rts_o &= ~(1 << span); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_RTS_O, 0x0); + gsmtmp->power[span] = 1; + gsmtmp->gsmspan[span].led = 0x81; + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + + printk(" done.\n"); +} + +void ztgsm_switch_off(struct ztgsm_card *gsmtmp, int span) { + unsigned int dtr_on_off = 0; + unsigned long flags; + + spin_lock_irqsave(&(gsmtmp->lock),flags); + gsmtmp->gsmspan[span].led = 0xC0; + dtr_on_off = ztgsm_indw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF); + printk(KERN_INFO "ztgsm: Powering down span %d (SER_DTR_ON_OFF %x)...", span, dtr_on_off); + + dtr_on_off &= ~ (1 << span); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, dtr_on_off); + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((5000 * HZ) / 1000); + + spin_lock_irqsave(&(gsmtmp->lock),flags); + dtr_on_off = ztgsm_indw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF); + dtr_on_off |= (1 << span); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, dtr_on_off); + gsmtmp->power[span] = 0; + gsmtmp->gsmspan[span].led = 0x80; + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + printk(" done.\n"); +} + +void ztgsm_switch_on_all(struct ztgsm_card *gsmtmp) { + unsigned long flags; + printk(KERN_INFO "ztgsm: Powering up all spans..."); + spin_lock_irqsave(&(gsmtmp->lock),flags); + gsmtmp->gsmspan[0].led = 0xC1; + gsmtmp->gsmspan[1].led = 0xC1; + gsmtmp->gsmspan[2].led = 0xC1; + gsmtmp->gsmspan[3].led = 0xC1; + + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, 0xff); + + ztgsm_outdw_io(gsmtmp, ztgsm_SER_RTS_O, 0x0f); + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((1000 * HZ) / 1000); + + spin_lock_irqsave(&(gsmtmp->lock),flags); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, 0xf0); + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((800 * HZ) / 1000); + + spin_lock_irqsave(&(gsmtmp->lock),flags); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, 0xff); + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((8000 * HZ) / 1000); + + spin_lock_irqsave(&(gsmtmp->lock),flags); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, 0xff); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_RTS_O, 0x0); /* 1 == -12 v */ + +/* new + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, 0x00); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((1000 * HZ) / 1000); + + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, 0x0f); +*/ + + gsmtmp->power[0] = 1; + gsmtmp->power[1] = 1; + gsmtmp->power[2] = 1; + gsmtmp->power[3] = 1; + + gsmtmp->gsmspan[0].led = 0x81; + gsmtmp->gsmspan[1].led = 0x81; + gsmtmp->gsmspan[2].led = 0x81; + gsmtmp->gsmspan[3].led = 0x81; + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + + printk(" done.\n"); +} + +void ztgsm_switch_off_all(struct ztgsm_card *gsmtmp) { + unsigned long flags; + + if (gsmtmp->power[0] || gsmtmp->power[1] || gsmtmp->power[2] || gsmtmp->power[3]) { + spin_lock_irqsave(&(gsmtmp->lock),flags); + gsmtmp->gsmspan[0].led = 0xC0; + gsmtmp->gsmspan[1].led = 0xC0; + gsmtmp->gsmspan[2].led = 0xC0; + gsmtmp->gsmspan[3].led = 0xC0; + + printk(KERN_INFO "ztgsm: Powering down all spans..."); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, 0x0); + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((5000 * HZ) / 1000); + + spin_lock_irqsave(&(gsmtmp->lock),flags); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_DTR_ON_OFF, 0xf); + printk(" done.\n"); + + gsmtmp->power[0] = 0; + gsmtmp->power[1] = 0; + gsmtmp->power[2] = 0; + gsmtmp->power[3] = 0; + + gsmtmp->gsmspan[0].led = 0x80; + gsmtmp->gsmspan[1].led = 0x80; + gsmtmp->gsmspan[2].led = 0x80; + gsmtmp->gsmspan[3].led = 0x80; + spin_unlock_irqrestore(&(gsmtmp->lock),flags); + } +} + + +void ztgsm_shutdownCard(struct ztgsm_card *gsmtmp) { + unsigned long flags; + struct ztgsm_span *gsmspan = NULL; + int i = 0; + if (gsmtmp == NULL) { + printk(KERN_INFO "ztgsm: shutting down NULL card!\n"); + return; + } + + ztgsm_switch_off_all(gsmtmp); + + spin_lock_irqsave(&gsmtmp->lock,flags); + + gsmtmp->dead = 1; + + if ((!gsmtmp->pci_io) || (gsmtmp->ioport == 0)) { + return; + } + ztgsm_outdw_io(gsmtmp, ztgsm_SER_INT_MASK, 0x0); + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_FC_TOG_BIT, 0x0); + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_SAP_EN, 0x0); + + +/* for (i=0; i < gsmtmp->gsmspans; i++) { + ztgsm_switch_off(gsmtmp, i); + } */ + + + ztgsm_outdw_io(gsmtmp, ztgsm_LED_DUAL, 0xFF00); + + + // softreset + + release_region(gsmtmp->ioport, 0x100); + iounmap((void *) gsmtmp->pci_io); + release_mem_region(gsmtmp->pci_io_phys, gsmtmp->iomem_size); + + gsmtmp->pci_io = 0; + gsmtmp->ioport = 0; + + // turn off irqs + + free_irq(gsmtmp->irq,gsmtmp); + + pci_write_config_word(gsmtmp->pcidev, PCI_COMMAND, 0); + + if (gsmtmp->pcidev != NULL) { + pci_disable_device(gsmtmp->pcidev); + } + + spin_unlock_irqrestore(&gsmtmp->lock,flags); + + for (i=0; i < gsmtmp->gsmspans; i++) { + gsmspan = &gsmtmp->gsmspan[i]; + if(gsmspan->span.flags & ZT_FLAG_RUNNING) { +// ztgsm_shutdown(&gsmspan->span); + if (debug) + printk(KERN_INFO "ztgsm: shutdown card %d span %d.\n",gsmtmp->cardno,i); + } + if(gsmspan->span.flags & ZT_FLAG_REGISTERED) { + zt_unregister(&gsmspan->span); + if (debug) + printk(KERN_INFO "ztgsm: unregistered card %d span %d.\n",gsmtmp->cardno,i); + } + } + +} + +void ztgsm_register_card(struct ztgsm_card *gsmtmp) { + spin_lock(®isterlock); + if (gsmtmp != NULL) { + gsmtmp->prev = NULL; + gsmtmp->next = ztgsm_dev_list; + if (ztgsm_dev_list) { + ztgsm_dev_list->prev = gsmtmp; + } + ztgsm_dev_list = gsmtmp; + gsmtmp->cardno = ++ztgsm_dev_count; + } else { + printk(KERN_INFO "ztgsm: trying to register NULL card.\n"); + } + spin_unlock(®isterlock); +} + + +void ztgsm_resetCard(struct ztgsm_card *gsmtmp) { + unsigned long flags; + spin_lock_irqsave(&(gsmtmp->lock),flags); +// pci_write_config_word(gsmtmp->pcidev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + + ztgsm_outdw_io(gsmtmp, ztgsm_SER_CLK_DIV, 0x12); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_CLK_PRE_DIV, 0x06); +// ztgsm_outdw_io(gsmtmp, ztgsm_SER_CLK_PRE_DIV, 0x03); +// ztgsm_outdw_io(gsmtmp, ztgsm_PCM_CLK_PRE_DIV, 0x06); + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_CLK_PRE_DIV, 0x0C); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_INT_MASK, 0x0); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_IDLE_VAL, 0x01); + + ztgsm_outdw_io(gsmtmp, ztgsm_SER_TX_EN, 0x0); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_RX_EN, 0x0); + + + gsmtmp->ticks = 0; + gsmtmp->clicks = 0; + + spin_unlock_irqrestore(&(gsmtmp->lock),flags); +} + +void ztgsm_startCard(struct ztgsm_card *gsmtmp) { + unsigned long flags; + spin_lock_irqsave(&(gsmtmp->lock),flags); + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_FC_TOG_BIT, 0x03); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_INT_MASK, 0x1FFFF); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_RX_WATERMARK, 0x0A); + ztgsm_outdw_io(gsmtmp, ztgsm_SIM_SEL, 0x0); + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_SAP_EN, 0x0); + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_MASK_LAST, 0x001F0000 | 0x1F); /* PCM32 0x100 frames */ +// ztgsm_outdw_io(gsmtmp, ztgsm_PCM_MASK_LAST, (0x001FC000 | 0x1F)); /* PCM32 0x40 frames */ + + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_SAP_EN, 0x1F); + switch (gsmtmp->gsmspans) { + case 4: + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x01010186); /* GSM_A (alaw) -> pci slot 0x01 */ + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x01840101); /* pci slot 0x01 -> GSM_A */ + + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x0103018A); /* GSM_B (alaw) -> pci slot 0x03 */ + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x01880103); /* pci slot 0x03 -> GSM_B */ + + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x0105018E); /* GSM_C (alaw) -> pci slot 0x05 */ + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x018C0105); /* pci slot 0x05 -> GSM_C */ + + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x01070192); /* GSM_D (alaw) -> pci slot 0x07 */ + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x01900107); /* pci slot 0x07 -> GSM_D */ + break; + case 2: + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x01010186); /* GSM_A (alaw) -> pci slot 0x01 */ + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x01840101); /* pci slot 0x01 -> GSM_A */ + + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x0103018A); /* GSM_B (alaw) -> pci slot 0x03 */ + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x01880103); /* pci slot 0x03 -> GSM_B */ + break; + case 1: + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x01010186); /* GSM_A (alaw) -> pci slot 0x01 */ + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, 0x01840101); /* pci slot 0x01 -> GSM_A */ + break; + } + + ztgsm_outdw_io(gsmtmp, ztgsm_SER_RX_EN, 0x0F); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_TX_EN, 0x0F); + if (debug) + printk(KERN_INFO "ztgsm: SER_TX_EN %d SER_RX_EN %d \n", ztgsm_indw_io(gsmtmp, ztgsm_SER_TX_EN), ztgsm_indw_io(gsmtmp, ztgsm_SER_RX_EN)); + spin_unlock_irqrestore(&(gsmtmp->lock),flags); +} + +static void ztgsm_xbar(struct ztgsm_card *gsmtmp, int dst, int src, int slin) { + unsigned long flags; + int format = 0; + + if (!gsmtmp) return; + + if (slin) format = 0x2000; + spin_lock_irqsave(&(gsmtmp->lock), flags); + if (debug > 1) + printk(KERN_INFO "ztgsm: ztgsm_PCM_VECTOR_CFG %4x \n", (dst << 16) | src | format); + ztgsm_outdw_io(gsmtmp, ztgsm_PCM_VECTOR_CFG, (dst << 16) | src | format); + spin_unlock_irqrestore(&(gsmtmp->lock), flags); +} + +static int ztgsm_dacs(struct zt_chan *dst, struct zt_chan *src) { + struct ztgsm_span *src_span; + struct ztgsm_span *dst_span; + + dst_span = dst->pvt; + if (dst->chanpos == 2) return -1; + + if (src) { + if (src->chanpos == 2) return -1; + src_span = src->pvt; + if (debug > 1) + printk(KERN_INFO "linking channel %d span %d to channel %d span %d\n", src->chanpos, src_span->span.offset, dst->chanpos, dst_span->span.offset); + /* ALAW */ + ztgsm_xbar(dst->span->pvt, 0x184 + (4 * dst_span->span.offset), 0x186 + (4 * src_span->span.offset), 0); + + /* SLIN */ +/* ztgsm_xbar(dst->span->pvt, 0x184 + (4 * dst_span->span.offset), 0x184 + (4 * src_span->span.offset), 1); + ztgsm_xbar(dst->span->pvt, 0x185 + (4 * dst_span->span.offset), 0x185 + (4 * src_span->span.offset), 1); */ + + } else { + if (debug > 1) + printk(KERN_INFO "unlinking channel %d span %d\n", dst->chanpos, dst_span->span.offset); + /* reassign pci source */ + ztgsm_xbar(dst->span->pvt, 0x184 + (4 * dst_span->span.offset), 0x100 | ((dst_span->span.offset * 2)+1), 0); + /* reassign pci destination */ + ztgsm_xbar(dst->span->pvt, 0x100 | ((dst_span->span.offset * 2)+1), 0x186 + (4 * dst_span->span.offset), 0); + } + + return 0; +} + +static int ztgsm_ser_rx(struct ztgsm_card *gsmtmp, int span) { + unsigned int rxcreg = 0; + unsigned int rxdreg = 0; + int rx_count = 0; + int i = 0; + unsigned char data = 0; + unsigned int count_reg = 0; + int rd_ptr = 0; + int wr_ptr = 0; + switch (span) { + case 0: rxcreg = ztgsm_SER_RX_COUNT_A; + rxdreg = ztgsm_SER_RX_DATA_A; + break; + case 1: rxcreg = ztgsm_SER_RX_COUNT_B; + rxdreg = ztgsm_SER_RX_DATA_B; + break; + case 2: rxcreg = ztgsm_SER_RX_COUNT_C; + rxdreg = ztgsm_SER_RX_DATA_C; + break; + case 3: rxcreg = ztgsm_SER_RX_COUNT_D; + rxdreg = ztgsm_SER_RX_DATA_D; + break; + } + count_reg = ztgsm_indw_io(gsmtmp, rxcreg); + rx_count = count_reg & 0x1F; + if (rx_count) { + rd_ptr = (count_reg & 0x03E0) >> 5; + wr_ptr = (count_reg & 0x7C00) >> 10; +// if (debug) +// printk(KERN_CRIT "ztgsm: SER_RX_COUNT_%d [wr_ptr %d rd_ptr %d count %d]\n", span, wr_ptr, rd_ptr, rx_count); + if ((gsmtmp->ser_rx_idx[span] + rx_count) < ztgsm_SER_BUF_SIZE) { + if (debug) printk(KERN_CRIT "ztgsm: SER_RX span %d [", span); + for (i=0;igsmspan[span].span.flags & ZT_FLAG_RUNNING) + gsmtmp->ser_rx_buf[span][gsmtmp->ser_rx_idx[span]++] = data; + } + if (debug) printk("]\n"); + } else { + printk(KERN_INFO "ztgsm: RX buffer overflow on span %d\n", span); + } + } + return rx_count; +} + +static int ztgsm_zap_rx(struct ztgsm_card *gsmtmp, int span) { + int i = 0; + + if (gsmtmp->ser_rx_idx[span]) { + memcpy(gsmtmp->drxbuf[span], &gsmtmp->ser_rx_buf[span], gsmtmp->ser_rx_idx[span]); + if (debug) { + printk(KERN_INFO "ztgsm: span %d RX [ \n", span); + for (i=0;iser_rx_idx[span]; i++) { + if (gsmtmp->ser_rx_buf[span][i] != 0x0d) + printk("%c", gsmtmp->ser_rx_buf[span][i]); + } + printk("]\n"); + } + gsmtmp->gsmspan[span].chans[1].eofrx = 1; + gsmtmp->gsmspan[span].chans[1].bytes2receive = gsmtmp->ser_rx_idx[span]; + gsmtmp->ser_rx_idx[span] = 0; + } + return 0; +} + +static int ztgsm_ser_tx(struct ztgsm_card *gsmtmp, int span) { + unsigned int txcreg = 0; + unsigned int txdreg = 0; + unsigned int tx_wm_sen = 0; + int left = 0; + int i = 0; + int count = 0; + unsigned int count_reg = 0; + int rd_ptr = 0; + int wr_ptr = 0; + struct ztgsm_span *gsmspan = NULL; + + switch (span) { + case 0: txcreg = ztgsm_SER_TX_COUNT_A; + txdreg = ztgsm_SER_TX_DATA_A; + break; + case 1: txcreg = ztgsm_SER_TX_COUNT_B; + txdreg = ztgsm_SER_TX_DATA_B; + break; + case 2: txcreg = ztgsm_SER_TX_COUNT_C; + txdreg = ztgsm_SER_TX_DATA_C; + break; + case 3: txcreg = ztgsm_SER_TX_COUNT_D; + txdreg = ztgsm_SER_TX_DATA_D; + break; + } + gsmspan = &gsmtmp->gsmspan[span]; + if (gsmspan) { + count_reg = ztgsm_indw_io(gsmtmp, txcreg); + left = ztgsm_FIFO_SIZE - (count_reg & 0x1F); + if (left >= 1 ) { + rd_ptr = (count_reg & 0x03E0) >> 5; + wr_ptr = (count_reg & 0x7C00) >> 10; + if (debug) + printk(KERN_CRIT "ztgsm: SER_TX_COUNT_%d [wr_ptr %d rd_ptr %d free %d]\n", span, wr_ptr, rd_ptr, left); + if (gsmtmp->ser_tx_idx[span] < left) { + count = gsmtmp->ser_tx_idx[span]; + } else { + count = left; + } + if (debug) + printk(KERN_INFO "ztgsm: span %d SER_TX [ ", span); + for (i=0;iser_tx_buf[span][i]); + ztgsm_outdw_io(gsmtmp, txdreg, gsmtmp->ser_tx_buf[span][i]); + } + if (debug) + printk("]\n"); + gsmtmp->ser_tx_idx[span] -= count; + if (gsmtmp->ser_tx_idx[span] > 0) { + memmove(&gsmtmp->ser_tx_buf[span][0], &gsmtmp->ser_tx_buf[span][i], gsmtmp->ser_tx_idx[span]); + } + tx_wm_sen = (ztgsm_indw_io(gsmtmp, ztgsm_SER_TX_WM_SEN) & 0xF) | (1 << span); + ztgsm_outdw_io(gsmtmp, ztgsm_SER_TX_WM_SEN, tx_wm_sen); +// printk(KERN_INFO "ztgsm: span %d TX_IDX %d count %d tx_wm_send %d\n", span, gsmtmp->ser_tx_idx[span], count, tx_wm_sen); + } + } + return i; +} + +static int ztgsm_zap_tx(struct ztgsm_card *gsmtmp, int span) { + struct ztgsm_span *gsmspan = NULL; + int i = 0; + + gsmspan = &gsmtmp->gsmspan[span]; + if (!gsmspan) + return -1; + if (gsmspan->chans[1].bytes2transmit) { + if (debug) { + printk(KERN_INFO "ztgsm: span %d TX [ ", span); + for (i=0;ichans[1].bytes2transmit; i++) { + printk("%c ", gsmtmp->dtxbuf[span][i]); + } + printk("]\n"); + } + if (gsmtmp->ser_tx_idx[span] + gsmspan->chans[1].bytes2transmit < ztgsm_SER_BUF_SIZE) { + memcpy(&gsmtmp->ser_tx_buf[span][gsmtmp->ser_tx_idx[span]], gsmtmp->dtxbuf[span], gsmspan->chans[1].bytes2transmit); + gsmtmp->ser_tx_idx[span] += gsmspan->chans[1].bytes2transmit; + ztgsm_ser_tx(gsmtmp, span); + } else { + printk(KERN_INFO "ztgsm: TX buffer overflow on span %d (TX_IDX %d BTT %d)\n", span, gsmtmp->ser_tx_idx[span] , gsmspan->chans[1].bytes2transmit); + } + } + + gsmspan->chans[1].bytes2receive = 0; + gsmspan->chans[1].bytes2transmit = 0; + gsmspan->chans[1].eofrx = 0; + gsmspan->chans[1].eoftx = 0; + return 0; +} + + +static int ztgsm_span_rx(struct ztgsm_card *gsmtmp, int span) { + struct ztgsm_span *gsmspan = NULL; + unsigned int addr = 0; + unsigned int framecnt = 0; + unsigned int pcmframecnt = 0; + unsigned int fraddr = 0; + unsigned int data = 0; + int start = 0; + int len = 0; + int i = 0; + unsigned int slot = 0; + + switch(span) { + case 0: + slot = 1; + break; + case 1: + slot = 3; + break; + case 2: + slot = 5; + break; + case 3: + slot = 7; + break; + } +// slot = span; + gsmspan = &gsmtmp->gsmspan[span]; + if (gsmspan) { + framecnt = gsmtmp->framecnt; + pcmframecnt = framecnt; + framecnt &= ztgsm_FRAMES - 1; + start = framecnt - 16; + if (start < 0) { + len = -start; + if (len > ZT_CHUNKSIZE) len = ZT_CHUNKSIZE; + fraddr = ztgsm_FRAMES + start; + } else { + len = ZT_CHUNKSIZE; + fraddr = start; + } + + if (fraddr & 3) { + if (debug > 0) + printk(KERN_INFO "ztgsm: RX span %d unaligned word address %#x (fraddr & 3 = %d)\n", span, fraddr, (fraddr & 3)); + fraddr -= fraddr & 3; /* align */ + } + if (len == ZT_CHUNKSIZE) { + addr = (slot << 8) | fraddr; +// addr = ((span+1) << 8) | fraddr; +// ztgsm_outdw_io(gsmtmp, ztgsm_LED_DUAL, addr & 0x4); + data = ztgsm_indw(gsmtmp, addr); + *((unsigned int *)&gsmtmp->rxbuf[span][0]) = data; + + +// ztgsm_outdw_io(gsmtmp, ztgsm_LED_DUAL, addr & 0x4); + addr = (slot << 8) | (fraddr + 4); +// addr = ((span+1) << 8) | (fraddr + 4); + data = ztgsm_indw(gsmtmp, addr); + *((unsigned int *)&gsmtmp->rxbuf[span][4]) = data; +// ztgsm_outdw_io(gsmtmp, ztgsm_LED_DUAL, 0xf); + } else { + printk(KERN_INFO "ztgsm: dropped audio span %d fraddr %d addr %d\n", span, fraddr, addr); + } +if (!(gsmtmp->ticks % 1000) && (debug > 4)) { + printk(KERN_INFO "ztgsm: RX DATA:"); + for (i=0; i < ZT_CHUNKSIZE; i++) { + printk("%x", gsmtmp->rxbuf[span][i]); + } + printk("\n"); +} + + } + return 0; +} + +static int ztgsm_span_tx(struct ztgsm_card *gsmtmp, int span) { + struct ztgsm_span *gsmspan = NULL; + unsigned int addr = 0; + unsigned int framecnt = 0; + unsigned int fraddr = 0; + int start = 0; + int len = 0; + unsigned int slot = 0; + + switch(span) { + case 0: + slot = 1; + break; + case 1: + slot = 3; + break; + case 2: + slot = 5; + break; + case 3: + slot = 7; + break; + } +// slot = span; + + gsmspan = &gsmtmp->gsmspan[span]; + if (gsmspan) { + framecnt = gsmtmp->framecnt; + framecnt &= ztgsm_FRAMES - 1; + start = framecnt + 16; + + if (start < 0x0) { + len = -start; + if (len > ZT_CHUNKSIZE) len = ZT_CHUNKSIZE; + fraddr = ztgsm_FRAMES + start; + } else { + len = ZT_CHUNKSIZE; + fraddr = start; + } + fraddr -= fraddr & 3; /* align */ + + if (fraddr & 3) { +// printk(KERN_EMERG "ztgsm: unaligned word address %#x\n", addr); + } else if (len == ZT_CHUNKSIZE) { + addr =(slot << 8 ) | fraddr; +// addr =( (span+1) << 8 ) | fraddr; + ztgsm_outdw(gsmtmp, addr, *((unsigned int*)&(gsmtmp->txbuf[span][0]))); +// addr =( (span+1) << 8 ) | (fraddr + 4); + addr =(slot << 8 ) | (fraddr + 4); + ztgsm_outdw(gsmtmp, addr, *((unsigned int*)&(gsmtmp->txbuf[span][4]))); + } + + } + return 0; +} + +static void ztgsm_leds(struct ztgsm_card *gsmtmp, int tick) { + int i = 0; + unsigned int leds = 0; + unsigned int color = 0; + for (i=0; igsmspans; i++) { +// printk(KERN_INFO "ztgsm: led = %x\n",gsmtmp->gsmspan[i].led); + color = gsmtmp->gsmspan[i].led & 0x1; + leds |= (color << i); + if (!(gsmtmp->gsmspan[i].led & 0x80)) { + leds |= (1 << (i+8)); + } + if ((gsmtmp->gsmspan[i].led & 0x40)) { + if (tick == 300) + leds |= (1 << (i+8)); + } + + } +// printk(KERN_INFO "ztgsm: leds = %d\n",leds); + ztgsm_outdw_io(gsmtmp, ztgsm_LED_DUAL, leds); +} + +static inline void ztgsm_run(struct ztgsm_card *gsmtmp) { + int s=0; + struct ztgsm_span *gsmspan = NULL; + for (s=0;sgsmspans;s++) { + gsmspan = &gsmtmp->gsmspan[s]; + if (gsmspan) { + if (!(gsmtmp->ticks % 1000)) { + gsmtmp->ticks = 0; + } + if (gsmtmp->ticks % 300 == 0) + ztgsm_leds(gsmtmp, gsmtmp->ticks); + if (gsmspan->span.flags & ZT_FLAG_RUNNING) { + /* oh zaptel! tell us what to transmit... */ + zt_transmit(&gsmspan->span); + if (debug && (gsmspan->chans[1].bytes2transmit > 0)) + printk(KERN_CRIT "ztgsm: span %d bytes2transmit = %d\n", s, gsmspan->chans[1].bytes2transmit); + ztgsm_span_tx(gsmtmp, s); + ztgsm_zap_tx(gsmtmp, s); + } + + if (gsmspan->span.flags & ZT_FLAG_RUNNING) { + ztgsm_zap_rx(gsmtmp, s); + ztgsm_span_rx(gsmtmp, s); + /* oh zaptel! thou shall receive! */ + zt_receive(&gsmspan->span); + } + } + } +} + + + +#ifdef LINUX26 +static irqreturn_t ztgsm_interrupt(int irq, void *dev_id, struct pt_regs *regs) { +#else +static void ztgsm_interrupt(int irq, void *dev_id, struct pt_regs *regs) { +#endif + struct ztgsm_card *gsmtmp = dev_id; + unsigned int ser_status = 0; + unsigned char mods = 0; + int s = 0; + int rx_count = 0; + unsigned long flags; + + if (!gsmtmp || gsmtmp->dead) { +#ifdef LINUX26 + return IRQ_NONE; +#else + return; +#endif + } + + if ((!gsmtmp->pci_io) || (!gsmtmp->ioport)) { + printk(KERN_CRIT "ztgsm: no pci mem/io\n"); +#ifdef LINUX26 + return IRQ_NONE; +#else + return; +#endif + } + + spin_lock_irqsave(&(gsmtmp->lock),flags); +// printk(KERN_INFO "gsm: irq\n"); + gsmtmp->last_framecnt = gsmtmp->framecnt; + gsmtmp->framecnt = ztgsm_indw_io(gsmtmp, ztgsm_PCM_FRAME_CNT); + ser_status = ztgsm_indw_io(gsmtmp, ztgsm_SER_STATUS); + if (ser_status) { + if (ser_status & 0x10000) { + if (gsmtmp->framecnt - gsmtmp->last_framecnt != 8) { +// printk(KERN_INFO "ztgsm: missed IRQ, framecnt %d last_framecnt %d (diff %d)\n", gsmtmp->framecnt, gsmtmp->last_framecnt, (gsmtmp->framecnt - gsmtmp->last_framecnt)); + } + gsmtmp->ticks++; + if (!(gsmtmp->ticks % 1000)) { +// printk(KERN_INFO "ztgsm: pcm framce counter %d\n", ztgsm_indw_io(gsmtmp, ztgsm_PCM_FRAME_CNT) & 0x1f); + } + if (!(gsmtmp->ticks % 300)) { + for (s=0; sgsmspans; s++) { + rx_count = ztgsm_ser_rx(gsmtmp, s); + if (debug && rx_count) + printk(KERN_INFO "ztgsm: RX %d bytes on span %d\n", rx_count, s); + } + } + ztgsm_run(gsmtmp); + } else if (ser_status & 0x0F) { + mods = (ser_status & 0x0F); + for (s=0; sgsmspans; s++) { + if (mods & (1 << s)) { + rx_count = ztgsm_ser_rx(gsmtmp, s); + if (debug) + printk(KERN_INFO "ztgsm: TX fifo overrun on span %d\n", s); + } + } + } else if (ser_status & 0xF0) { + mods = (ser_status & 0xF0) >> 4; + if (debug) + printk(KERN_INFO "ztgsm: RX mods %d\n", mods); + for (s=0; sgsmspans; s++) { + if (mods & (1 << s)) { + rx_count = ztgsm_ser_rx(gsmtmp, s); + if (debug) + printk(KERN_INFO "ztgsm: RX %d bytes on span %d\n", rx_count, s); + } + } + } else if (ser_status & 0xF00) { + mods = (ser_status & 0xF00) >> 8; + for (s=0; sgsmspans; s++) { + if (mods & (1 << s)) { + rx_count = ztgsm_ser_rx(gsmtmp, s); + if (debug) + printk(KERN_INFO "ztgsm: RX fifo overrun on span %d\n", s); + } + } + } else if (ser_status & 0xF000) { + mods = (ser_status & 0xF000) >> 12; + for (s=0; sgsmspans; s++) { + if (mods & (1 << s)) { + if (gsmtmp->ser_tx_idx[s]) { + /* sumfin left to transmit */ + ztgsm_ser_tx(gsmtmp, s); + } + if (debug) + printk(KERN_INFO "ztgsm: TX low water status %#x\n", ser_status); + } + } + } else { + if (debug) { + printk(KERN_INFO "ztgsm: SER_STATUS = %#x\n", ser_status); + } + } + } + spin_unlock_irqrestore(&(gsmtmp->lock),flags); +#ifdef LINUX26 + return IRQ_RETVAL(1); +#endif +} + + +static int ztgsm_open(struct zt_chan *chan) { +// printk(KERN_INFO "ztgsm: channel %d opened.\n",chan->channo); +#ifndef LINUX26 + MOD_INC_USE_COUNT; +#else + try_module_get(THIS_MODULE); +#endif + return 0; +} + +static int ztgsm_close(struct zt_chan *chan) { +// printk(KERN_INFO "ztgsm: channel %d closed.\n",chan->channo); +#ifndef LINUX26 + MOD_DEC_USE_COUNT; +#else + module_put(THIS_MODULE); +#endif + return 0; +} + +static int ztgsm_chanconfig(struct zt_chan *chan,int sigtype) { +// printk(KERN_INFO "chan_config sigtype=%d\n",sigtype); + return 0; +} + +static int ztgsm_spanconfig(struct zt_span *span,struct zt_lineconfig *lc) { +// span->lineconfig = lc->lineconfig; + return 0; +} + + +static int ztgsm_startup(struct zt_span *span) { + struct ztgsm_card *gsmtmp = span->pvt; + int running; + + if (gsmtmp == NULL) { + printk(KERN_INFO "ztgsm: no card for span at startup!\n"); + } + + running = span->flags & ZT_FLAG_RUNNING; + span->chans[1].flags &= ~ZT_FLAG_HDLC; + span->chans[1].flags |= ZT_FLAG_BRIDCHAN; + + if (!running) { + if (!gsmtmp->power[span->offset]) + ztgsm_switch_on(gsmtmp, span->offset); + span->flags |= ZT_FLAG_RUNNING; + + } else { + printk(KERN_CRIT "already running\n"); + return 0; + } + return 0; +} + +static int ztgsm_shutdown(struct zt_span *span) { + int running; + struct ztgsm_card *gsmtmp = span->pvt; + + if (gsmtmp == NULL) { + printk(KERN_INFO "ztgsm: no card for span at shutdown!\n"); + } + + running = span->flags & ZT_FLAG_RUNNING; + + if (running) { + span->flags |= ZT_FLAG_RUNNING; + if (gsmtmp->power[span->offset]) + ztgsm_switch_off(gsmtmp, span->offset); + } + return 0; +} + +static int ztgsm_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) { + switch(cmd) { + default: + return -ENOTTY; + } + return 0; +} + + +static int ztgsm_init(struct ztgsm_span *gsmspan, struct ztgsm_card *gsmtmp, int offset) { + memset(&gsmspan->span,0,sizeof(struct zt_span)); // you never can tell... + sprintf(gsmspan->span.name,"ztgsm/%d",gsmtmp->cardno); + switch (gsmtmp->type) { + case 0xb55d: + sprintf(gsmspan->span.desc,"Junghanns.NET unoGSM PCI Card %d",gsmtmp->cardno); + break; + case 0xb55e: + sprintf(gsmspan->span.desc,"Junghanns.NET duoGSM PCI Card %d",gsmtmp->cardno); + break; + case 0xb55f: + sprintf(gsmspan->span.desc,"Junghanns.NET quadGSM PCI Card %d",gsmtmp->cardno); + break; + } + + gsmspan->span.spanconfig = ztgsm_spanconfig; + gsmspan->span.chanconfig = ztgsm_chanconfig; + gsmspan->span.startup = ztgsm_startup; + gsmspan->span.shutdown = ztgsm_shutdown; + gsmspan->span.maint = NULL; + gsmspan->span.rbsbits = NULL; + gsmspan->span.open = ztgsm_open; + gsmspan->span.close = ztgsm_close; + gsmspan->span.ioctl = ztgsm_ioctl; + + if (pcm_xbar == 1) + gsmspan->span.dacs = ztgsm_dacs; + + gsmspan->span.chans = gsmspan->chans; + gsmspan->span.channels = 2; + gsmspan->span.deflaw = ZT_LAW_ALAW; + gsmspan->span.linecompat = ZT_CONFIG_CCS | ZT_CONFIG_AMI; + init_waitqueue_head(&gsmspan->span.maintq); + gsmspan->span.pvt = gsmtmp; + gsmspan->span.offset = offset; + + memset(&(gsmspan->chans[0]),0x0,sizeof(struct zt_chan)); + sprintf(gsmspan->chans[0].name,"ztgsm/%d", 0); + gsmspan->chans[0].pvt = gsmspan; + gsmspan->chans[0].sigcap = ZT_SIG_CLEAR; + gsmspan->chans[0].chanpos = 1; + + memset(&(gsmspan->chans[1]),0x0,sizeof(struct zt_chan)); + sprintf(gsmspan->chans[1].name,"ztgsm/%d", 1); + gsmspan->chans[1].pvt = gsmspan; + gsmspan->chans[1].sigcap = ZT_SIG_CLEAR; + gsmspan->chans[1].chanpos = 2; + + + if (zt_register(&gsmspan->span,0)) { + printk(KERN_INFO "ztgm: unable to register zaptel span!\n"); + return -1; + } + + /* setup B channel buffers (8 bytes each) */ + memset(gsmtmp->rxbuf[offset],0x0,sizeof(gsmtmp->rxbuf[offset])); + gsmspan->span.chans[0].readchunk = gsmtmp->rxbuf[offset]; + memset(gsmtmp->txbuf[offset],0x0,sizeof(gsmtmp->txbuf[offset])); + gsmspan->span.chans[0].writechunk = gsmtmp->txbuf[offset]; + + /* setup D channel buffer */ + memset(gsmtmp->dtxbuf[offset],0x0,sizeof(gsmtmp->dtxbuf[offset])); + gsmspan->span.chans[1].writechunk = gsmtmp->dtxbuf[offset]; + gsmspan->span.chans[1].maxbytes2transmit = sizeof(gsmtmp->dtxbuf[offset]); + + memset(gsmtmp->drxbuf[offset],0x0,sizeof(gsmtmp->drxbuf[offset])); + gsmspan->span.chans[1].readchunk = gsmtmp->drxbuf[offset]; + + return 0; +} + + +int ztgsm_findCards(unsigned int pcidid) { + struct pci_dev *tmp; + struct ztgsm_card *gsmtmp = NULL; + struct ztgsm_span *gsmspan = NULL; + unsigned int ioport_size = 0; + int i=0; + int cid=0; + tmp = pci_find_device(PCI_VENDOR_ID_CCD,pcidid,NULL); + while (tmp != NULL) { + multi_gsm = tmp; + + if (pci_enable_device(tmp)) { + return -1; + } + + gsmtmp = kmalloc(sizeof(struct ztgsm_card),GFP_KERNEL); + if (!gsmtmp) { + printk(KERN_WARNING "ztgsm: unable to kmalloc!\n"); + pci_disable_device(tmp); + return -ENOMEM; + } + memset(gsmtmp, 0x0, sizeof(struct ztgsm_card)); + + spin_lock_init(&gsmtmp->lock); + gsmtmp->pcidev = tmp; + gsmtmp->pcibus = tmp->bus->number; + gsmtmp->pcidevfn = tmp->devfn; + + if (!tmp->irq) { + printk(KERN_WARNING "ztgsm: no irq!\n"); + } else { + gsmtmp->irq = tmp->irq; + } + + gsmtmp->pci_io_phys = tmp->resource[1].start; + if (!gsmtmp->pci_io_phys) { + printk(KERN_WARNING "ztgsm: no iomem!\n"); + pci_disable_device(tmp); + return -EIO; + } + gsmtmp->iomem_size = (tmp->resource[1].end - tmp->resource[1].start + 1); + printk(KERN_INFO "ztgsm: iomem at %lx size %ld\n", gsmtmp->pci_io_phys, gsmtmp->iomem_size); + + if (check_mem_region(gsmtmp->pci_io_phys, gsmtmp->iomem_size)) { + printk(KERN_INFO "ztgsm: iomem already in use!\n");; + pci_disable_device(tmp); + return -EBUSY; + } + + request_mem_region(gsmtmp->pci_io_phys, gsmtmp->iomem_size, "ztgsm"); + + gsmtmp->pci_io = ioremap(gsmtmp->pci_io_phys, gsmtmp->iomem_size); /* 8kb */ + + gsmtmp->ioport = tmp->resource[0].start; + if (!gsmtmp->ioport) { + printk(KERN_WARNING "ztgsm: no ioport!\n"); + pci_disable_device(tmp); + return -EIO; + } + ioport_size = (tmp->resource[0].end - tmp->resource[0].start + 1); + printk(KERN_INFO "ztgsm: ioport size %d\n", ioport_size); + + if (!request_region(gsmtmp->ioport, 0x100, "ztgsm")) { + printk(KERN_WARNING "ztgsm: couldnt request io range!\n"); + release_mem_region(gsmtmp->pci_io_phys, gsmtmp->iomem_size); + pci_disable_device(tmp); + return -EIO; + } + + if (request_irq(gsmtmp->irq, ztgsm_interrupt, SA_INTERRUPT | SA_SHIRQ, "ztgsm", gsmtmp)) { + printk(KERN_WARNING "ztgsm: unable to register irq\n"); + release_region(gsmtmp->ioport, 0x100); + release_mem_region(gsmtmp->pci_io_phys, gsmtmp->iomem_size); + kfree(gsmtmp); + pci_disable_device(tmp); + return -EIO; + } + + pci_write_config_word(gsmtmp->pcidev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + + // disable ints + + gsmtmp->type = tmp->subsystem_device; + + switch (gsmtmp->type) { + case 0xb55d: + printk(KERN_INFO + "ztgsm: Junghanns.NET unoGSM card configured at io port %x IRQ %d io mem %lx HZ %d CardID %d\n", + (u_int) gsmtmp->ioport, gsmtmp->irq, (u_long) gsmtmp->pci_io, HZ, cid); + break; + case 0xb55e: + printk(KERN_INFO + "ztgsm: Junghanns.NET duoGSM card configured at io port %x IRQ %d io mem %lx HZ %d CardID %d\n", + (u_int) gsmtmp->ioport, gsmtmp->irq, (u_long) gsmtmp->pci_io, HZ, cid); + break; + case 0xb55f: + printk(KERN_INFO + "ztgsm: Junghanns.NET quadGSM card configured at io port %x IRQ %d io mem %lx HZ %d CardID %d\n", + (u_int) gsmtmp->ioport, gsmtmp->irq, (u_long) gsmtmp->pci_io, HZ, cid); + break; + } + + ztgsm_resetCard(gsmtmp); + ztgsm_init_xbar(gsmtmp); + + switch (ztgsm_indw_io(gsmtmp, ztgsm_SER_G20_ACTIVATED)) { + case 0xf: + gsmtmp->gsmspans = 4; + break; + case 0x3: + gsmtmp->gsmspans = 2; + break; + case 0x1: + gsmtmp->gsmspans = 1; + break; + } + ztgsm_spans += gsmtmp->gsmspans; + + for (i=0; i < gsmtmp->gsmspans; i++) { + gsmspan = &gsmtmp->gsmspan[i]; + ztgsm_init(gsmspan, gsmtmp, i); + gsmspan->led = 0x80; + } + ztgsm_leds(gsmtmp, 0); + + + gsmtmp->version = ztgsm_indw_io(gsmtmp, ztgsm_VERS_A); + printk(KERN_INFO "ztgsm: VERSION %x\n", gsmtmp->version); + if (debug) { + printk(KERN_INFO "ztgsm: G20_ACTIVATED %d\n", ztgsm_indw_io(gsmtmp, ztgsm_SER_G20_ACTIVATED)); + printk(KERN_INFO "ztgsm: DIPS %#x\n", ztgsm_indw_io(gsmtmp, ztgsm_DIP_SWITCH)); + printk(KERN_INFO "ztgsm: tx_wm_sen %d\n", ztgsm_indw_io(gsmtmp, ztgsm_SER_TX_WM_SEN)); + } + + ztgsm_register_card(gsmtmp); + + ztgsm_startCard(gsmtmp); + ztgsm_switch_on_all(gsmtmp); + + tmp = pci_find_device(PCI_VENDOR_ID_CCD,pcidid,multi_gsm); + } + return 0; +} + + +int init_module(void) { + ztgsm_findCards(0xf001); + if (ztgsm_dev_count == 0) { + printk(KERN_INFO "ztgsm: no multiGSM cards found.\n"); + } else { + printk(KERN_INFO "ztgsm: %d multiGSM card(s) in this box, %d GSM spans total.\n",ztgsm_dev_count, ztgsm_spans); + } + return 0; +} + +void cleanup_module(void) { + struct ztgsm_card *tmpcard,*tmplist; + int i=0; + tmplist = ztgsm_dev_list; + while (tmplist != NULL) { + ztgsm_shutdownCard(tmplist); + tmplist = tmplist->next; + } + tmplist = ztgsm_dev_list; + spin_lock(®isterlock); + while (tmplist != NULL) { + tmpcard = tmplist->next; + kfree(tmplist); + i++; + tmplist = tmpcard; + } + spin_unlock(®isterlock); + printk(KERN_INFO "ztgsm: shutdown %d multiGSM cards.\n", i); +} +#endif + +#ifdef LINUX26 +module_param(debug, int, 0600); +module_param(pcm_xbar, int, 0600); +#else +MODULE_PARM(debug,"i"); +MODULE_PARM(pcm_xbar,"i"); +#endif + +MODULE_DESCRIPTION("uno/duao/quad GSM zaptel driver"); +MODULE_AUTHOR("Klaus-Peter Junghanns "); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif --- zaptel-1.2.11.dfsg.orig/ztgsm/zaptel.conf.unoGSM +++ zaptel-1.2.11.dfsg/ztgsm/zaptel.conf.unoGSM @@ -0,0 +1,10 @@ +loadzone=nl +defaultzone=nl + +alaw=1 + +span=1,1,3,ccs,ami + +bchan=1 +dchan=2 + --- zaptel-1.2.11.dfsg.orig/ztgsm/ztgsm.h +++ zaptel-1.2.11.dfsg/ztgsm/ztgsm.h @@ -0,0 +1,135 @@ +#define ztgsm_RX_MAX 1000 +#define ztgsm_FIFO_SIZE 16 +#define ztgsm_SPANS 4 +#define ztgsm_SER_BUF_SIZE 1000 +#define ztgsm_FRAMES 0x100 + +typedef struct ztgsm_span { + int led; /* 0 == RED 1 == GREEN 0x80 == on 0x40 == blink */ + int sim_led; + /* zaptel resources */ + struct zt_span span; + struct zt_chan chans[2]; + + /* more zaptel stuff */ + unsigned int usecount; + int spantype; + int spanflags; +} ztgsm_span; + +typedef struct ztgsm_card { + spinlock_t lock; + unsigned char power[ztgsm_SPANS]; + int cardID; + int dead; + unsigned char cardno; + unsigned int irq; + unsigned int iomem; + void *pci_io; + unsigned int framecnt; + unsigned int last_framecnt; + unsigned long pci_io_phys; + unsigned int version; +// unsigned char *pci_io; +// unsigned char *pci_io_phys; + unsigned long iomem_size; + unsigned long ioport; + struct ztgsm_span gsmspan[ztgsm_SPANS]; + unsigned int gsmspans; + unsigned int pcibus; + unsigned int pcidevfn; + struct pci_dev *pcidev; + unsigned char gsms; + unsigned int ticks; + unsigned int clicks; + unsigned int type; + unsigned char rxbuf[ztgsm_SPANS][ZT_CHUNKSIZE]; + unsigned char txbuf[ztgsm_SPANS][ZT_CHUNKSIZE]; + unsigned char drxbuf[ztgsm_SPANS][ztgsm_SER_BUF_SIZE]; + unsigned char dtxbuf[ztgsm_SPANS][ztgsm_FIFO_SIZE]; + unsigned short rxbufi[ztgsm_SPANS]; + + unsigned char ser_rx_buf[ztgsm_SPANS][ztgsm_SER_BUF_SIZE]; + unsigned char ser_tx_buf[ztgsm_SPANS][ztgsm_SER_BUF_SIZE]; + unsigned short ser_rx_idx[ztgsm_SPANS]; + unsigned short ser_tx_idx[ztgsm_SPANS]; + unsigned char tx_wm_sen; + struct ztgsm_card *next; + struct ztgsm_card *prev; +} ztgsm_card; + +#define ztgsm_outb_io(a,b,c) \ + outw((b), ((a)->ioport+4)); \ + outb((c), ((a)->ioport)); + +#define ztgsm_inb_io(a,b) ({ outw((b), (a)->ioport+4); inb((a)->ioport); }) + +#define ztgsm_outw_io(a,b,c) \ + outw((b), ((a)->ioport+4)); \ + outw((c), ((a)->ioport)); + +#define ztgsm_inw_io(a,b) ({ outw((b), (a)->ioport+4); inw((a)->ioport); }) + +#define _ztgsm_outdw_io(a,b,c) \ + outw((b), ((a)->ioport+4)); \ + outl((c), ((a)->ioport)); + +#define ztgsm_outdw_io(a,b,c) (outl((c), ((a)->ioport+b))) + +#define ztgsm_indw_io(a,b) (inl((a)->ioport+b)) + +#define ztgsm_outb(a,b,c) (writeb((c),(a)->pci_io+(b))) +#define ztgsm_inb(a,b) (readb((a)->pci_io+(b))) + +#define ztgsm_outw(a,b,c) (writew((c),(a)->pci_io+(b))) +#define ztgsm_inw(a,b) (readw((a)->pci_io+(b))) + +#define ztgsm_outdw(a,b,c) (writel((c),(a)->pci_io+(b))) +#define ztgsm_indw(a,b) (readl((a)->pci_io+(b))) + +#define ztgsm_IO_BASE 0x0 +#define ztgsm_VERS_A ztgsm_IO_BASE +#define ztgsm_SER_CLK_DIV ztgsm_IO_BASE + 4 +#define ztgsm_SER_CLK_PRE_DIV ztgsm_IO_BASE + (4 * 0x02) +#define ztgsm_PCM_CLK_PRE_DIV ztgsm_IO_BASE + (4 * 0x03) +#define ztgsm_SER_IDLE_VAL ztgsm_IO_BASE + (4 * 0x04) +#define ztgsm_SER_RTS_O ztgsm_IO_BASE + (4 * 0x05) +#define ztgsm_SER_TX_EN ztgsm_IO_BASE + (4 * 0x06) +#define ztgsm_SER_RX_EN ztgsm_IO_BASE + (4 * 0x07) +#define ztgsm_SER_DTR_ON_OFF ztgsm_IO_BASE + (4 * 0x08) +#define ztgsm_DIP_SWITCH ztgsm_IO_BASE + (4 * 0x09) +#define ztgsm_LED_DUAL ztgsm_IO_BASE + (4 * 0x0A) +#define ztgsm_SER_G20_ACTIVATED ztgsm_IO_BASE + (4 * 0x0B) +#define ztgsm_SIM_SEL ztgsm_IO_BASE + (4 * 0x0C) +#define ztgsm_PCM_DIR ztgsm_IO_BASE + (4 * 0x0D) + +#define ztgsm_SER_TX_DATA_A ztgsm_IO_BASE + (4 * 0x10) +#define ztgsm_SER_TX_COUNT_A ztgsm_IO_BASE + (4 * 0x11) +#define ztgsm_SER_TX_DATA_B ztgsm_IO_BASE + (4 * 0x12) +#define ztgsm_SER_TX_COUNT_B ztgsm_IO_BASE + (4 * 0x13) +#define ztgsm_SER_TX_DATA_C ztgsm_IO_BASE + (4 * 0x14) +#define ztgsm_SER_TX_COUNT_C ztgsm_IO_BASE + (4 * 0x15) +#define ztgsm_SER_TX_DATA_D ztgsm_IO_BASE + (4 * 0x16) +#define ztgsm_SER_TX_COUNT_D ztgsm_IO_BASE + (4 * 0x17) +#define ztgsm_SER_RX_DATA_A ztgsm_IO_BASE + (4 * 0x18) +#define ztgsm_SER_RX_COUNT_A ztgsm_IO_BASE + (4 * 0x19) +#define ztgsm_SER_RX_DATA_B ztgsm_IO_BASE + (4 * 0x1a) +#define ztgsm_SER_RX_COUNT_B ztgsm_IO_BASE + (4 * 0x1b) +#define ztgsm_SER_RX_DATA_C ztgsm_IO_BASE + (4 * 0x1c) +#define ztgsm_SER_RX_COUNT_C ztgsm_IO_BASE + (4 * 0x1d) +#define ztgsm_SER_RX_DATA_D ztgsm_IO_BASE + (4 * 0x1e) +#define ztgsm_SER_RX_COUNT_D ztgsm_IO_BASE + (4 * 0x1f) +#define ztgsm_SER_STATUS ztgsm_IO_BASE + (4 * 0x20) +#define ztgsm_SER_INT_MASK ztgsm_IO_BASE + (4 * 0x21) +#define ztgsm_SER_RX_WATERMARK ztgsm_IO_BASE + (4 * 0x22) +#define ztgsm_SER_TX_WATERMARK ztgsm_IO_BASE + (4 * 0x23) +#define ztgsm_SER_TX_WM_SEN ztgsm_IO_BASE + (4 * 0x24) + +#define ztgsm_PCM_SAP_EN ztgsm_IO_BASE + (4 * 0x30) +#define ztgsm_PCM_MASK_LAST ztgsm_IO_BASE + (4 * 0x31) +#define ztgsm_PCM_FRAME_CNT ztgsm_IO_BASE + (4 * 0x32) +#define ztgsm_PCM_FC_TOG_BIT ztgsm_IO_BASE + (4 * 0x33) +#define ztgsm_PCM_SIGNAL_CFG ztgsm_IO_BASE + (4 * 0x34) +#define ztgsm_PCM_VECTOR_CFG ztgsm_IO_BASE + (4 * 0x35) + + --- zaptel-1.2.11.dfsg.orig/ztgsm/zapata.conf.unoGSM +++ zaptel-1.2.11.dfsg/ztgsm/zapata.conf.unoGSM @@ -0,0 +1,15 @@ +[channels] +txgain = -10.0 +rxgain = 0.0 + +signalling = gsm +context = from-gsm + +;group=1 + +; phone number for SIM card in slot A +;exten=016012345671 +; PIN for SIM card in slot A +;pin=1234 + +;channel => 1 --- zaptel-1.2.11.dfsg.orig/ztgsm/Makefile +++ zaptel-1.2.11.dfsg/ztgsm/Makefile @@ -0,0 +1,53 @@ +KINCLUDES = /usr/src/linux/include +BRISTUFFBASE = $(shell dirname `pwd`) + +ZAP = $(shell [ -f $(BRISTUFFBASE)/zaptel/zaptel.h ] && echo "-I$(BRISTUFFBASE)/zaptel") + +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=ztgsm.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=ztgsm + +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) + +ztgsm.o: ztgsm.c ztgsm.h + $(CC) -c ztgsm.c $(KFLAGS) + +clean: + rm -f $(OBJS) *.ko *.mod.c *.mod.o .*o.cmd *~ + rm -rf .tmp_versions + +install: install$(BUILDVER) + +installlinux26: all + install -D -m 644 ztgsm.ko $(INSTALL_PREFIX)/lib/modules/`uname -r`/misc/ztgsm.ko + +installlinux24: all + install -D -m 644 ztgsm.o $(INSTALL_PREFIX)/lib/modules/`uname -r`/misc/ztgsm.o --- zaptel-1.2.11.dfsg.orig/qozap/qozap.h +++ zaptel-1.2.11.dfsg/qozap/qozap.h @@ -0,0 +1,239 @@ +#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 dead; + unsigned char leds[8]; + unsigned char cardno; + unsigned int irq; + unsigned int iomem; + unsigned char *pci_io; + void *pci_io_phys; + 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 + + --- zaptel-1.2.11.dfsg.orig/qozap/zaptel.conf +++ zaptel-1.2.11.dfsg/qozap/zaptel.conf @@ -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 + --- zaptel-1.2.11.dfsg.orig/qozap/zaptel.conf.octoBRI +++ zaptel-1.2.11.dfsg/qozap/zaptel.conf.octoBRI @@ -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 + --- zaptel-1.2.11.dfsg.orig/qozap/zapata.conf +++ zaptel-1.2.11.dfsg/qozap/zapata.conf @@ -0,0 +1,51 @@ +; +; 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 = dynamic +nationalprefix = 0 +internationalprefix = 00 + +priindication = passthrough + +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 + --- zaptel-1.2.11.dfsg.orig/qozap/zapata.conf.octoBRI +++ zaptel-1.2.11.dfsg/qozap/zapata.conf.octoBRI @@ -0,0 +1,67 @@ +; +; 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 = dynamic +nationalprefix = 0 +internationalprefix = 00 + +priindication = passthrough + +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 + --- zaptel-1.2.11.dfsg.orig/qozap/TODO +++ zaptel-1.2.11.dfsg/qozap/TODO @@ -0,0 +1,9 @@ +- native-native bridging +- onchip dtmf +- E channel support for full debug + + +t3 (5ms max) + +t4 (500ms) layer 1 down/up + --- zaptel-1.2.11.dfsg.orig/qozap/qozap.c +++ zaptel-1.2.11.dfsg/qozap/qozap.c @@ -0,0 +1,1669 @@ +/* + * 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 + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + * + */ +#include +#include +#include +#include +#include +#include +#include "qozap.h" + +#ifdef LINUX26 +#include +#endif + +#if CONFIG_PCI + +static int doubleclock=0; +static int ports=-1; /* autodetect */ +static int pcmslave=0; +static int bloop=0; +static int debug=0; +static 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); + + + // 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, 8); + iounmap((void *) qoztmp->pci_io); + release_mem_region((unsigned long) qoztmp->pci_io_phys, 256); + + qoztmp->pci_io = NULL; + qoztmp->ioport = 0; + + if (qoztmp->pcidev != NULL) { + pci_disable_device(qoztmp->pcidev); + } + pci_write_config_word(qoztmp->pcidev, PCI_COMMAND, 0); + + free_irq(qoztmp->irq,qoztmp); + spin_unlock_irqrestore(&qoztmp->lock,flags); + + 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 int 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); + + if (pcmslave) { + qoz_outb(qoztmp,qoz_R_PCM_MD0, 0x0); + } else { + qoz_outb(qoztmp,qoz_R_PCM_MD0, 0x1); + } + + for (i=0; i<256; i++) { + qoz_outb(qoztmp,qoz_R_SLOT, i); + qoz_outb(qoztmp,qoz_A_SL_CFG, 0x0); + } + + /* 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;istports;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(®isterlock); + 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(®isterlock); +} + +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;xztdev->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; idrxbuf[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;iclicks++; + if ((qoztmp->clicks > 10) && (debug > 0)) { + 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 void qoz_assign(struct qoz_card *qoztmp, int src_span, int src_chan, int dst_span, int dst_chan) { + int timeslot = src_span * 2 + (src_chan - 1); + int dst_fifo = dst_span * 2 + (dst_chan - 1); + int src_fifo = src_span * 2 + (src_chan - 1); + int src_hfc_chan = src_span * 4 + (src_chan - 1); + int dst_hfc_chan = dst_span * 4 + (dst_chan - 1); + + qoz_outb(qoztmp,qoz_R_FIFO,(src_fifo << 1) | 1); + qoz_waitbusy(qoztmp); + qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2); + qoz_waitbusy(qoztmp); + qoz_outb(qoztmp,qoz_A_CHANNEL,(src_hfc_chan << 1) | 1); + qoz_outb(qoztmp,qoz_A_CON_HDLC,0xDE); // was c2 + + qoz_outb(qoztmp,qoz_R_SLOT,timeslot << 1); + qoz_outb(qoztmp,qoz_A_SL_CFG, (src_hfc_chan << 1) | 0 | 0x40); + + qoz_outb(qoztmp,qoz_R_FIFO, dst_fifo << 1); + qoz_waitbusy(qoztmp); + qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2); + qoz_waitbusy(qoztmp); + qoz_outb(qoztmp,qoz_A_CHANNEL,dst_hfc_chan << 1); + qoz_outb(qoztmp,qoz_A_CON_HDLC,0xDE); // was c2 + + qoz_outb(qoztmp,qoz_R_SLOT,(timeslot << 1) | 1); + qoz_outb(qoztmp,qoz_A_SL_CFG, (dst_hfc_chan << 1) | 1 | 0x40); + +} + +static void qoz_unassign(struct qoz_card *qoztmp, int span, int chan) { + int timeslot = span * 2 + (chan - 1); + int fifo = span * 2 + (chan - 1); + int hfc_chan = span * 4 + (chan - 1); + + qoz_outb(qoztmp,qoz_R_FIFO,(fifo << 1)); + qoz_waitbusy(qoztmp); + qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2); + qoz_waitbusy(qoztmp); + qoz_outb(qoztmp,qoz_A_CON_HDLC,0x02); + qoz_outb(qoztmp,qoz_A_CHANNEL,(hfc_chan << 1)); + qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x1); + + qoz_outb(qoztmp,qoz_R_FIFO,(fifo << 1) | 1); + qoz_waitbusy(qoztmp); + qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2); + qoz_waitbusy(qoztmp); + qoz_outb(qoztmp,qoz_A_CON_HDLC,0x02); + qoz_outb(qoztmp,qoz_A_CHANNEL,(hfc_chan << 1) | 1); + qoz_outb(qoztmp,qoz_A_IRQ_MSK,0x1); + + qoz_outb(qoztmp,qoz_R_SLOT,(timeslot << 1) | 1); + qoz_outb(qoztmp,qoz_A_SL_CFG, 0x0); + + qoz_outb(qoztmp,qoz_R_SLOT,timeslot << 1); + qoz_outb(qoztmp,qoz_A_SL_CFG, 0x0); +} + + +static int ztqoz_dacs(struct zt_chan *dst, struct zt_chan *src) +{ + struct zt_qoz *ztqoz = NULL; + struct qoz_card *qoztmp = NULL; + if (src) { + ztqoz = src->pvt; + qoztmp = ztqoz->card; + } + if (src && (src->pvt != dst->pvt)) { + /* cross card bridging */ + if (debug) + printk("Not Assigning %d/%d -> %d/%d, different cards!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos); + return -1; + } + + if (src) { + if ((src->chanpos == 3) || (dst->chanpos == 3)) { + if (debug) + printk("Not Assigning D-channel %d/%d -> %d/%d!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos); + } else { + if (debug) + printk("Assigning channel %d/%d -> %d/%d!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos); + qoz_assign(qoztmp, src->span->offset, src->chanpos, dst->span->offset, dst->chanpos); + } + } else { + ztqoz = dst->pvt; + qoztmp = ztqoz->card; + if (dst->chanpos == 3) { + if (debug) + printk("Not Unassigning D-channel %d/%d!\n", dst->span->offset, dst->chanpos); + } else { + qoz_unassign(qoztmp, dst->span->offset, dst->chanpos); + if (debug) + printk("Unassigning channel %d/%d!\n", dst->span->offset, dst->chanpos); + } + } + return 0; +} + + +static inline void qoz_run(struct qoz_card *qoztmp) { + int s=0; + if (qoztmp->ztdev != NULL) { + for (s=0;sstports;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) { + if (debug > 2) + 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 */ + if (debug > 2) + printk(KERN_INFO "qozap: clearing alarms on span %d\n",s); + qoztmp->ztdev->spans[s].alarms = ZT_ALARM_NONE; + zt_alarm_notify_no_master_change(&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; +#ifndef RELAXED_LOCKING + unsigned long flags; +#endif + unsigned char irq_misc,irq_sci,status,l1state,irq_foview,fi; + int st=0,i=0,offset=0; + int j=0; + + if (!qoztmp) { +#ifdef LINUX26 + return IRQ_NONE; +#else + return; +#endif + } + + if ((!qoztmp->pci_io) || (!qoztmp->ioport)) { + printk(KERN_CRIT "qozap: no pci mem/io\n"); +#ifdef LINUX26 + return IRQ_NONE; +#else + return; +#endif + } + if (qoztmp->dead) { +#ifdef LINUX26 + return IRQ_RETVAL(1); +#else + return; +#endif + } + + +#ifdef RELAXED_LOCKING + spin_lock(&(qoztmp->lock)); +#else + spin_lock_irqsave(&(qoztmp->lock), flags); +#endif + 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! +#ifdef RELAXED_LOCKING + spin_unlock(&(qoztmp->lock)); +#else + spin_unlock_irqrestore(&(qoztmp->lock), flags); +#endif +#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); + } + if (qoztmp->type == 0xb552) { + offset = 24; + } else { + offset = 28; + } + for (st=0;ststports;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) { + if (debug > 2) + printk("qozap: re-activating layer1 span %d\n", st); + qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x60); + } + } else { + if (debug > 2) + printk("qozap: not re-activating layer1 span %d\n", st); + qoz_outb(qoztmp,qoz_A_ST_WR_STA,0x40); + /* if we tried to activate layer 1 and it failed make this an alarm */ +// qoztmp->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) { + /* reset D RX fifo */ + qoz_outb(qoztmp,qoz_R_FIFO,((st + offset) << 1) | 1); + qoz_waitbusy(qoztmp); + qoz_outb(qoztmp,qoz_R_INC_RES_FIFO,0x2); + qoz_waitbusy(qoztmp); + /* activation complete, stop timer t3 */ + qoztmp->st[st].t3 = -1; + qoztmp->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 */ + if (debug > 2) + 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;jstports;j++) { + /* t3 */ + if (qoztmp->st[j].t3 >= 0) { + qoztmp->st[j].t3++; + } + if (qoztmp->st[j].nt_mode != 1) { + if ((qoztmp->st[j].t3 > qoz_T3) && (qoztmp->st[j].layer1state != 7)) { + /* deactivate layer 1 */ + if (debug > 2) + printk(KERN_INFO "qozap: t3 timer expired for span %d\n", j); + 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_no_master_change(&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 */ + if (debug > 2) + 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_no_master_change(&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); + } + } + } + } + } + } + +#ifdef RELAXED_LOCKING + spin_unlock(&(qoztmp->lock)); +#else + spin_unlock_irqrestore(&(qoztmp->lock), flags); +#endif +#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); + } + 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 + } + + /* enable irqs */ + qoz_outb(qoztmp,qoz_R_IRQ_CTRL, 8 | 1); + 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].dacs = ztqoz_dacs; + + 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_phys = (char *) tmp->resource[1].start; + if (!qoztmp->pci_io_phys) { + 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, 8, "qozap")) { + printk(KERN_WARNING "qozap: couldnt request io range!\n"); + pci_disable_device(tmp); + multi_qoz = NULL; + return -EIO; + } + if (!request_mem_region((unsigned long) qoztmp->pci_io_phys, 256, "qozap")) { + printk(KERN_WARNING "qozap: couldnt request io mem range!\n"); + release_region(qoztmp->ioport, 8); + 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_phys, 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: + printk(KERN_INFO + "qozap: wtf\n"); + 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;istports;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(®isterlock); + 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(®isterlock); + 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); + multi_qoz = NULL; + 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, pcmslave %d.\n",qoz_dev_count, totalBRIs, bloop, pcmslave); + } + return 0; +} + +void cleanup_module(void) { + struct qoz_card *tmpcard,*tmplist; + int i=0; + tmplist = qoz_dev_list; + while (tmplist != NULL) { + tmplist->dead = 1; + qoz_undoWD(tmplist); + qoz_shutdownCard(tmplist); + tmplist = tmplist->next; + } + tmplist = qoz_dev_list; + spin_lock(®isterlock); + while (tmplist != NULL) { + tmpcard = tmplist->next; + kfree(tmplist); + i++; + tmplist = tmpcard; + } + spin_unlock(®isterlock); + printk(KERN_INFO "qozap: shutdown %d multiBRI cards.\n", i); +} +#endif + +#ifdef LINUX26 +module_param(doubleclock, int, 0600); +module_param(ports, int, 0600); +module_param(pcmslave, int, 0600); +module_param(bloop, int, 0600); +module_param(debug, int, 0600); +#else +MODULE_PARM(doubleclock,"i"); +MODULE_PARM(ports,"i"); +MODULE_PARM(pcmslave,"i"); +MODULE_PARM(bloop,"i"); +MODULE_PARM(debug,"i"); +#endif + + +MODULE_DESCRIPTION("quad/octo BRI zaptel driver"); +MODULE_AUTHOR("Klaus-Peter Junghanns "); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif --- zaptel-1.2.11.dfsg.orig/qozap/Makefile +++ zaptel-1.2.11.dfsg/qozap/Makefile @@ -0,0 +1,91 @@ +KINCLUDES = /usr/src/linux/include +BRISTUFFBASE = $(shell dirname `pwd`) + +ZAP = $(shell [ -f $(BRISTUFFBASE)/zaptel/zaptel.h ] && echo "-I$(BRISTUFFBASE)/zaptel") + +HOSTCC=gcc + +CFLAGS+=-I. $(ZAP) -DRELAXED_LOCKING -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 -DRELAXED_LOCKING -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 --- zaptel-1.2.11.dfsg.orig/zaphfc/zaphfc.h +++ zaptel-1.2.11.dfsg/zaphfc/zaphfc.h @@ -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 + * + * 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 --- zaptel-1.2.11.dfsg.orig/zaphfc/zaptel.conf +++ zaptel-1.2.11.dfsg/zaphfc/zaptel.conf @@ -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 --- zaptel-1.2.11.dfsg.orig/zaphfc/zapata.conf +++ zaptel-1.2.11.dfsg/zaphfc/zapata.conf @@ -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 --- zaptel-1.2.11.dfsg.orig/zaphfc/zaphfc.c +++ zaptel-1.2.11.dfsg/zaphfc/zaphfc.c @@ -0,0 +1,1155 @@ +/* + * 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 + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + * + */ + +#include +#include +#ifdef RTAITIMING +#include +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#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(®isterlock); + if (hfccard != NULL) { + hfccard->cardno = hfc_dev_count++; + hfccard->next = hfc_dev_list; + hfc_dev_list = hfccard; + } + spin_unlock(®isterlock); +} + +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; xdtransbuf[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 = (void *)(((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 %lx fifo %lx(%#x) IRQ %d HZ %d\n", + vendor_name, card_name, + (unsigned long) hfctmp->pci_io, + (unsigned long) 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(®isterlock); + 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(®isterlock); +} +#endif + + +#ifdef LINUX26 +module_param(modes, int, 0600); +module_param(debug, int, 0600); +#else +MODULE_PARM(modes,"i"); +MODULE_PARM(debug,"i"); +#endif + +MODULE_DESCRIPTION("HFC-S PCI A Zaptel Driver"); +MODULE_AUTHOR("Klaus-Peter Junghanns "); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif --- zaptel-1.2.11.dfsg.orig/zaphfc/Makefile +++ zaptel-1.2.11.dfsg/zaphfc/Makefile @@ -0,0 +1,118 @@ +KINCLUDES = /usr/src/linux/include +BRISTUFFBASE = $(shell dirname `pwd`) + +ZAP = $(shell [ -f $(BRISTUFFBASE)/zaptel/zaptel.h ] && echo "-I$(BRISTUFFBASE)/zaptel") +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 + --- zaptel-1.2.11.dfsg.orig/opvxa1200.c +++ zaptel-1.2.11.dfsg/opvxa1200.c @@ -0,0 +1,2722 @@ +/* + * OpenVox A1200P FXS/FXO Interface Driver for Zapata Telephony interface + * + * Modify from wctdm.c by MiaoLin + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* Rev histroy + * + * Rev 0.10 initial version + * Rev 0.11 + * fixed the led light on/off bug. + * modify some wctdm print to opvxa1200 + * support firmware version 1.2, faster i/o operation, and better LED control. + * + * Rev 0.12 patched to support new pci id 0x8519 + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "proslic.h" +#include "wctdm.h" + +//miaolin +#include +#include // get_fs(), set_fs(), KERNEL_DS +#include // fput() +//miaolin + + +/* + * Define for audio vs. register based ring detection + * + */ +/* #define AUDIO_RINGCHECK */ + +/* + Experimental max loop current limit for the proslic + Loop current limit is from 20 mA to 41 mA in steps of 3 + (according to datasheet) + So set the value below to: + 0x00 : 20mA (default) + 0x01 : 23mA + 0x02 : 26mA + 0x03 : 29mA + 0x04 : 32mA + 0x05 : 35mA + 0x06 : 37mA + 0x07 : 41mA +*/ +static int loopcurrent = 20; + +static int reversepolarity = 0; + +static alpha indirect_regs[] = +{ +{0,255,"DTMF_ROW_0_PEAK",0x55C2}, +{1,255,"DTMF_ROW_1_PEAK",0x51E6}, +{2,255,"DTMF_ROW2_PEAK",0x4B85}, +{3,255,"DTMF_ROW3_PEAK",0x4937}, +{4,255,"DTMF_COL1_PEAK",0x3333}, +{5,255,"DTMF_FWD_TWIST",0x0202}, +{6,255,"DTMF_RVS_TWIST",0x0202}, +{7,255,"DTMF_ROW_RATIO_TRES",0x0198}, +{8,255,"DTMF_COL_RATIO_TRES",0x0198}, +{9,255,"DTMF_ROW_2ND_ARM",0x0611}, +{10,255,"DTMF_COL_2ND_ARM",0x0202}, +{11,255,"DTMF_PWR_MIN_TRES",0x00E5}, +{12,255,"DTMF_OT_LIM_TRES",0x0A1C}, +{13,0,"OSC1_COEF",0x7B30}, +{14,1,"OSC1X",0x0063}, +{15,2,"OSC1Y",0x0000}, +{16,3,"OSC2_COEF",0x7870}, +{17,4,"OSC2X",0x007D}, +{18,5,"OSC2Y",0x0000}, +{19,6,"RING_V_OFF",0x0000}, +{20,7,"RING_OSC",0x7EF0}, +{21,8,"RING_X",0x0160}, +{22,9,"RING_Y",0x0000}, +{23,255,"PULSE_ENVEL",0x2000}, +{24,255,"PULSE_X",0x2000}, +{25,255,"PULSE_Y",0x0000}, +//{26,13,"RECV_DIGITAL_GAIN",0x4000}, // playback volume set lower +{26,13,"RECV_DIGITAL_GAIN",0x2000}, // playback volume set lower +{27,14,"XMIT_DIGITAL_GAIN",0x4000}, +//{27,14,"XMIT_DIGITAL_GAIN",0x2000}, +{28,15,"LOOP_CLOSE_TRES",0x1000}, +{29,16,"RING_TRIP_TRES",0x3600}, +{30,17,"COMMON_MIN_TRES",0x1000}, +{31,18,"COMMON_MAX_TRES",0x0200}, +{32,19,"PWR_ALARM_Q1Q2",0x07C0}, +{33,20,"PWR_ALARM_Q3Q4",0x2600}, +{34,21,"PWR_ALARM_Q5Q6",0x1B80}, +{35,22,"LOOP_CLOSURE_FILTER",0x8000}, +{36,23,"RING_TRIP_FILTER",0x0320}, +{37,24,"TERM_LP_POLE_Q1Q2",0x008C}, +{38,25,"TERM_LP_POLE_Q3Q4",0x0100}, +{39,26,"TERM_LP_POLE_Q5Q6",0x0010}, +{40,27,"CM_BIAS_RINGING",0x0C00}, +{41,64,"DCDC_MIN_V",0x0C00}, +{42,255,"DCDC_XTRA",0x1000}, +{43,66,"LOOP_CLOSE_TRES_LOW",0x1000}, +}; + +static struct fxo_mode { + char *name; + /* FXO */ + int ohs; + int ohs2; + int rz; + int rt; + int ilim; + int dcv; + int mini; + int acim; + int ring_osc; + int ring_x; +} fxo_modes[] = +{ + { "FCC", 0, 0, 0, 1, 0, 0x3, 0, 0, }, /* US, Canada */ + { "TBR21", 0, 0, 0, 0, 1, 0x3, 0, 0x2, 0x7e6c, 0x023a, }, + /* Austria, Belgium, Denmark, Finland, France, Germany, + Greece, Iceland, Ireland, Italy, Luxembourg, Netherlands, + Norway, Portugal, Spain, Sweden, Switzerland, and UK */ + { "ARGENTINA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "AUSTRALIA", 1, 0, 0, 0, 0, 0, 0x3, 0x3, }, + { "AUSTRIA", 0, 1, 0, 0, 1, 0x3, 0, 0x3, }, + { "BAHRAIN", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "BELGIUM", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "BRAZIL", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "BULGARIA", 0, 0, 0, 0, 1, 0x3, 0x0, 0x3, }, + { "CANADA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "CHILE", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "CHINA", 0, 0, 0, 0, 0, 0, 0x3, 0xf, }, + { "COLUMBIA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "CROATIA", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "CYRPUS", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "CZECH", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "DENMARK", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "ECUADOR", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "EGYPT", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "ELSALVADOR", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "FINLAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "FRANCE", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "GERMANY", 0, 1, 0, 0, 1, 0x3, 0, 0x3, }, + { "GREECE", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "GUAM", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "HONGKONG", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "HUNGARY", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "ICELAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "INDIA", 0, 0, 0, 0, 0, 0x3, 0, 0x4, }, + { "INDONESIA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "IRELAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "ISRAEL", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "ITALY", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "JAPAN", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "JORDAN", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "KAZAKHSTAN", 0, 0, 0, 0, 0, 0x3, 0, }, + { "KUWAIT", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "LATVIA", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "LEBANON", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "LUXEMBOURG", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "MACAO", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "MALAYSIA", 0, 0, 0, 0, 0, 0, 0x3, 0, }, /* Current loop >= 20ma */ + { "MALTA", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "MEXICO", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "MOROCCO", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "NETHERLANDS", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "NEWZEALAND", 0, 0, 0, 0, 0, 0x3, 0, 0x4, }, + { "NIGERIA", 0, 0, 0, 0, 0x1, 0x3, 0, 0x2, }, + { "NORWAY", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "OMAN", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "PAKISTAN", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "PERU", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "PHILIPPINES", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "POLAND", 0, 0, 1, 1, 0, 0x3, 0, 0, }, + { "PORTUGAL", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "ROMANIA", 0, 0, 0, 0, 0, 3, 0, 0, }, + { "RUSSIA", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "SAUDIARABIA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "SINGAPORE", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "SLOVAKIA", 0, 0, 0, 0, 0, 0x3, 0, 0x3, }, + { "SLOVENIA", 0, 0, 0, 0, 0, 0x3, 0, 0x2, }, + { "SOUTHAFRICA", 1, 0, 1, 0, 0, 0x3, 0, 0x3, }, + { "SOUTHKOREA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "SPAIN", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "SWEDEN", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "SWITZERLAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "SYRIA", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "TAIWAN", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "THAILAND", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "UAE", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "UK", 0, 1, 0, 0, 1, 0x3, 0, 0x5, }, + { "USA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "YEMEN", 0, 0, 0, 0, 0, 0x3, 0, 0, }, +}; + +#ifdef STANDALONE_ZAPATA +#include "zaptel.h" +#else +#include +#endif + +#ifdef LINUX26 +#include +#endif + +#define NUM_FXO_REGS 60 + +#define WC_MAX_IFACES 128 + +#define DELAY 0x0 /* 30 = 15 cycles, 10 = 8 cycles, 0 = 3 cycles */ +#define WC_OFFSET 4 /* Offset between transmit and receive, in bytes. */ +#define WC_SYNCFLAG 0xca1ef1ac + +#define WC_CNTL 0x00 +#define WC_OPER 0x01 +#define WC_AUXC 0x02 +#define WC_AUXD 0x03 +#define WC_MASK0 0x04 +#define WC_MASK1 0x05 +#define WC_INTSTAT 0x06 +#define WC_AUXR 0x07 + +#define WC_DMAWS 0x08 +#define WC_DMAWI 0x0c +#define WC_DMAWE 0x10 +#define WC_DMARS 0x18 +#define WC_DMARI 0x1c +#define WC_DMARE 0x20 + +#define WC_AUXFUNC 0x2b +#define WC_SERCTL 0x2d +#define WC_FSCDELAY 0x2f + +#define WC_REGBASE 0xc0 + +#define WC_VER 0x0 +#define WC_CS 0x1 +#define WC_SPICTRL 0x2 +#define WC_SPIDATA 0x3 + +#define BIT_SPI_BYHW (1 << 0) +#define BIT_SPI_BUSY (1 << 1) // 0=can read/write spi, 1=spi working. +#define BIT_SPI_START (1 << 2) + + +#define BIT_LED_CLK (1 << 0) // MiaoLin add to control the led. +#define BIT_LED_DATA (1 << 1) // MiaoLin add to control the led. + +#define BIT_CS (1 << 2) +#define BIT_SCLK (1 << 3) +#define BIT_SDI (1 << 4) +#define BIT_SDO (1 << 5) + +#define FLAG_EMPTY 0 +#define FLAG_WRITE 1 +#define FLAG_READ 2 + +/* the constants below control the 'debounce' periods enforced by the + check_hook routines; these routines are called once every 4 interrupts + (the interrupt cycles around the four modules), so the periods are + specified in _4 millisecond_ increments +*/ +#define RING_DEBOUNCE 4 /* Ringer Debounce (64 ms) */ +#define DEFAULT_BATT_DEBOUNCE 4 /* Battery debounce (64 ms) */ +#define POLARITY_DEBOUNCE 4 /* Polarity debounce (64 ms) */ +#define DEFAULT_BATT_THRESH 3 /* Anything under this is "no battery" */ + +#define OHT_TIMER 6000 /* How long after RING to retain OHT */ + +#define FLAG_3215 (1 << 0) + +//modify by MiaoLin from 4 to 12; +//#define NUM_CARDS 4 +#define NUM_CARDS 12 +#define NUM_FLAG 4 //number of flag channels. + +// if you want to record the last 8 sec voice before the driver unload, uncomment it and rebuild. +//#define TEST_LOG_INCOME_VOICE + +#define MAX_ALARMS 10 + +#define MOD_TYPE_FXS 0 +#define MOD_TYPE_FXO 1 + +#define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */ +#define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */ +#define PEGCOUNT 5 /* 5 cycles of pegging means RING */ + +#define NUM_CAL_REGS 12 + +struct calregs { + unsigned char vals[NUM_CAL_REGS]; +}; + +enum proslic_power_warn { + PROSLIC_POWER_UNKNOWN = 0, + PROSLIC_POWER_ON, + PROSLIC_POWER_WARNED, +}; + +#define voc_buffer_size (8000*8) + +struct wctdm { + struct pci_dev *dev; + char *variety; + struct zt_span span; + unsigned char ios; + int usecount; + unsigned int intcount; + int dead; + int pos; + int flags[NUM_CARDS]; + int freeregion; + int alt; + int curcard; + int cardflag; /* Bit-map of present cards */ + enum proslic_power_warn proslic_power; + spinlock_t lock; + + union { + struct { +#ifdef AUDIO_RINGCHECK + unsigned int pegtimer; + int pegcount; + int peg; + int ring; +#else + int wasringing; +#endif + int ringdebounce; + int offhook; + int battdebounce; + int nobatttimer; + int battery; + int lastpol; + int polarity; + int polaritydebounce; + } fxo; + struct { + int oldrxhook; + int debouncehook; + int lastrxhook; + int debounce; + int ohttimer; + int idletxhookstate; /* IDLE changing hook state */ + int lasttxhook; + int palarms; + struct calregs calregs; + } fxs; + } mod[NUM_CARDS]; + + /* Receive hook state and debouncing */ + int modtype[NUM_CARDS]; + unsigned char reg0shadow[NUM_CARDS]; + unsigned char reg1shadow[NUM_CARDS]; + + unsigned long ioaddr; + unsigned long mem_region; /* 32 bit Region allocated to tiger320 */ + unsigned long mem_len; /* Length of 32 bit region */ + volatile unsigned long mem32; /* Virtual representation of 32 bit memory area */ + + dma_addr_t readdma; + dma_addr_t writedma; + volatile unsigned char *writechunk; /* Double-word aligned write memory */ + volatile unsigned char *readchunk; /* Double-word aligned read memory */ + struct zt_chan chans[NUM_CARDS]; + +#ifdef TEST_LOG_INCOME_VOICE + //unsigned char tempo[NUM_CARDS + NUM_FLAG]; + char * voc_buf[NUM_CARDS + NUM_FLAG]; + int voc_ptr[NUM_CARDS + NUM_FLAG]; +#endif + //int offset; + int lastchan; + unsigned short ledstate; + unsigned char fwversion; +}; + + +struct wctdm_desc { + char *name; + int flags; +}; + +static struct wctdm_desc wctdme = { "OpenVox A1200P", 0 }; +static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 }; + +static struct wctdm *ifaces[WC_MAX_IFACES]; + +static void wctdm_release(struct wctdm *wc); + +static int battdebounce = DEFAULT_BATT_DEBOUNCE; +static int battthresh = DEFAULT_BATT_THRESH; +static int debug = 0; +//static int debug = 1; +static int robust = 0; +static int timingonly = 0; +static int lowpower = 0; +static int boostringer = 0; +static int _opermode = 0; +static char *opermode = "FCC"; +static int fxshonormode = 0; +static int alawoverride = 0; +static int spibyhw = 1; // MiaoLin add; +static int usememio = 1; + +static int wctdm_init_proslic(struct wctdm *wc, int card, int fast , int manual, int sane); + +static void wctdm_set_led(struct wctdm* wc, int card, int onoff) +{ + int i; + unsigned char c; + + wc->ledstate &= ~(0x01<ledstate |= (onoff<ioaddr + WC_AUXD)&~BIT_LED_CLK)|BIT_LED_DATA; + outb( c, wc->ioaddr + WC_AUXD); + for(i=NUM_CARDS-1; i>=0; i--) + { + if(wc->ledstate & (0x0001<fwversion == 0x11) + c &= ~BIT_LED_DATA; + else + c |= BIT_LED_DATA; + else + if(wc->fwversion == 0x11) + c |= BIT_LED_DATA; + else + c &= ~BIT_LED_DATA; + + outb( c, wc->ioaddr + WC_AUXD); + outb( c|BIT_LED_CLK, wc->ioaddr + WC_AUXD); + outb( (c&~BIT_LED_CLK)|BIT_LED_DATA, wc->ioaddr + WC_AUXD); + } +} + + +static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char ints) +{ + int x, y, chan_offset, pos; + volatile unsigned char *txbuf; + + if (ints & 0x04 /*0x01*/) + /* Write is at interrupt address. Start writing from normal offset */ + txbuf = wc->writechunk; + else + txbuf = wc->writechunk + ZT_CHUNKSIZE * (NUM_CARDS+NUM_FLAG); + + /* Calculate Transmission */ + zt_transmit(&wc->span); + + if(wc->lastchan == -1) // not in sync. + return; + + chan_offset = (wc->lastchan*4 + 4 ) % (NUM_CARDS+NUM_FLAG); + + //for (x=0;xoffset;x++) + // txbuf[x] = wc->tempo[x]; + for (y=0;yoffset; + // /* Put channel number as outgoing data */ + // if (pos < (NUM_CARDS+NUM_FLAG) * ZT_CHUNKSIZE) + // txbuf[pos] = wc->chans[x].writechunk[y]; + // else + // wc->tempo[pos - (NUM_CARDS+NUM_FLAG) * ZT_CHUNKSIZE] = wc->chans[x].writechunk[y]; + //} + //printk("\n"); + for (x=0;x<(NUM_CARDS+NUM_FLAG);x++) { + pos = y * (NUM_CARDS+NUM_FLAG) + ((x + chan_offset + NUM_CARDS+NUM_FLAG /*+ wc->offset*/ - WC_OFFSET)&0x0f); + if(xchans[x].writechunk[y]; + else + txbuf[pos] = 0; + //if(x==2) + // txbuf[pos] = 0x55;//trans_count; + //else + // txbuf[pos] = 0; + } + + /*for (x=0;x<(NUM_CARDS+NUM_FLAG);x++) { + pos = y * (NUM_CARDS+NUM_FLAG) + x + chan_offset + wc->offset - WC_OFFSET; + if ( pos<(NUM_CARDS+NUM_FLAG)*ZT_CHUNKSIZE ) + { + if(xchans[x].writechunk[y]; + else + txbuf[pos] = 0; + } + else + { + if(xtempo[pos - (NUM_CARDS+NUM_FLAG) * ZT_CHUNKSIZE] = wc->chans[x].writechunk[y]; + else + wc->tempo[pos - (NUM_CARDS+NUM_FLAG) * ZT_CHUNKSIZE] = 0; + } + }*/ +#endif + } + +} + +#ifdef AUDIO_RINGCHECK +static inline void ring_check(struct wctdm *wc, int card) +{ + int x; + short sample; + if (wc->modtype[card] != MOD_TYPE_FXO) + return; + wc->mod[card].fxo.pegtimer += ZT_CHUNKSIZE; + for (x=0;xchans[card].readchunk[x], (&(wc->chans[card]))); + if ((sample > 10000) && (wc->mod[card].fxo.peg != 1)) { + if (debug > 1) printk("High peg!\n"); + if ((wc->mod[card].fxo.pegtimer < PEGTIME) && (wc->mod[card].fxo.pegtimer > MINPEGTIME)) + wc->mod[card].fxo.pegcount++; + wc->mod[card].fxo.pegtimer = 0; + wc->mod[card].fxo.peg = 1; + } else if ((sample < -10000) && (wc->mod[card].fxo.peg != -1)) { + if (debug > 1) printk("Low peg!\n"); + if ((wc->mod[card].fxo.pegtimer < (PEGTIME >> 2)) && (wc->mod[card].fxo.pegtimer > (MINPEGTIME >> 2))) + wc->mod[card].fxo.pegcount++; + wc->mod[card].fxo.pegtimer = 0; + wc->mod[card].fxo.peg = -1; + } + } + if (wc->mod[card].fxo.pegtimer > PEGTIME) { + /* Reset pegcount if our timer expires */ + wc->mod[card].fxo.pegcount = 0; + } + /* Decrement debouncer if appropriate */ + if (wc->mod[card].fxo.ringdebounce) + wc->mod[card].fxo.ringdebounce--; + if (!wc->mod[card].fxo.offhook && !wc->mod[card].fxo.ringdebounce) { + if (!wc->mod[card].fxo.ring && (wc->mod[card].fxo.pegcount > PEGCOUNT)) { + /* It's ringing */ + if (debug) + printk("RING on %d/%d!\n", wc->span.spanno, card + 1); + if (!wc->mod[card].fxo.offhook) + zt_hooksig(&wc->chans[card], ZT_RXSIG_RING); + wc->mod[card].fxo.ring = 1; + } + if (wc->mod[card].fxo.ring && !wc->mod[card].fxo.pegcount) { + /* No more ring */ + if (debug) + printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1); + zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); + wc->mod[card].fxo.ring = 0; + } + } +} +#endif + + +static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char ints) +{ + volatile unsigned char *rxbuf; + int x, y, chan_offset; + + + if (ints & /*0x08*/0x04) + /* Read is at interrupt address. Valid data is available at normal offset */ + rxbuf = wc->readchunk; + else + rxbuf = wc->readchunk + ZT_CHUNKSIZE * (NUM_CARDS+NUM_FLAG); + + //search for the flag channel + for(x=0; x<4; x++) + { + //printk("0x%08x ", *(int*)(rxbuf+x*4)); + if( *(int*)(rxbuf+x*4) == WC_SYNCFLAG) + { + //printk(" found at %d ", x); + break; + } + } + + if(x==4) + { + printk("buffer sync misseed!\n"); + wc->lastchan = -1; + return; + } + else if(wc->lastchan != x) + { + + printk("buffer re-sync occur from %d to %d\n", wc->lastchan, x); + wc->lastchan = x; + } + chan_offset = (wc->lastchan*4 + 4 ) % (NUM_CARDS+NUM_FLAG); + + for (x=0;xcardflag & (1 << y)) + wc->chans[y].readchunk[x] = rxbuf[(NUM_CARDS+NUM_FLAG) * x + ((y + chan_offset ) & 0x0f)]; +#ifdef TEST_LOG_INCOME_VOICE + wc->voc_buf[y][wc->voc_ptr[y]] = rxbuf[(NUM_CARDS+NUM_FLAG) * x + ((y + chan_offset) & 0x0f)]; + wc->voc_ptr[y]++; + if(wc->voc_ptr[y] >= voc_buffer_size) + wc->voc_ptr[y] = 0; +#endif + } + +#endif + } +#ifdef AUDIO_RINGCHECK + for (x=0;xcards;x++) + ring_check(wc, x); +#endif + /* XXX We're wasting 8 taps. We should get closer :( */ + for (x = 0; x < NUM_CARDS; x++) { + if (wc->cardflag & (1 << x)) + zt_ec_chunk(&wc->chans[x], wc->chans[x].readchunk, wc->chans[x].writechunk); + } + zt_receive(&wc->span); +} + +static void wctdm_stop_dma(struct wctdm *wc); +static void wctdm_reset_tdm(struct wctdm *wc); +static void wctdm_restart_dma(struct wctdm *wc); + + +static unsigned char __wctdm_getcreg(struct wctdm *wc, unsigned char reg); +static void __wctdm_setcreg(struct wctdm *wc, unsigned char reg, unsigned char val); + + +static inline void __write_8bits(struct wctdm *wc, unsigned char bits) +{ + if(spibyhw == 0) + { + int x; + /* Drop chip select */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + wc->ios &= ~BIT_CS; + outb(wc->ios, wc->ioaddr + WC_AUXD); + for (x=0;x<8;x++) { + /* Send out each bit, MSB first, drop SCLK as we do so */ + if (bits & 0x80) + wc->ios |= BIT_SDI; + else + wc->ios &= ~BIT_SDI; + wc->ios &= ~BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Now raise SCLK high again and repeat */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + bits <<= 1; + } + /* Finally raise CS back high again */ + wc->ios |= BIT_CS; + outb(wc->ios, wc->ioaddr + WC_AUXD); + } + else + { + __wctdm_setcreg(wc, WC_SPIDATA, bits); + __wctdm_setcreg(wc, WC_SPICTRL, BIT_SPI_BYHW | BIT_SPI_START); + while ((__wctdm_getcreg(wc, WC_SPICTRL) & BIT_SPI_BUSY) != 0); + __wctdm_setcreg(wc, WC_SPICTRL, BIT_SPI_BYHW); + } +} + + +static inline void __reset_spi(struct wctdm *wc) +{ + __wctdm_setcreg(wc, WC_SPICTRL, 0); + + /* Drop chip select and clock once and raise and clock once */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + wc->ios &= ~BIT_CS; + outb(wc->ios, wc->ioaddr + WC_AUXD); + wc->ios |= BIT_SDI; + wc->ios &= ~BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Now raise SCLK high again and repeat */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Finally raise CS back high again */ + wc->ios |= BIT_CS; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Clock again */ + wc->ios &= ~BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Now raise SCLK high again and repeat */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + + __wctdm_setcreg(wc, WC_SPICTRL, spibyhw); + +} + +static inline unsigned char __read_8bits(struct wctdm *wc) +{ + unsigned char res=0, c; + int x; + if(spibyhw == 0) + { + wc->ios &= ~BIT_CS; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Drop chip select */ + wc->ios &= ~BIT_CS; + outb(wc->ios, wc->ioaddr + WC_AUXD); + for (x=0;x<8;x++) { + res <<= 1; + /* Get SCLK */ + wc->ios &= ~BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + /* Read back the value */ + c = inb(wc->ioaddr + WC_AUXR); + if (c & BIT_SDO) + res |= 1; + /* Now raise SCLK high again */ + wc->ios |= BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + } + /* Finally raise CS back high again */ + wc->ios |= BIT_CS; + outb(wc->ios, wc->ioaddr + WC_AUXD); + wc->ios &= ~BIT_SCLK; + outb(wc->ios, wc->ioaddr + WC_AUXD); + } + else + { + __wctdm_setcreg(wc, WC_SPICTRL, BIT_SPI_BYHW | BIT_SPI_START); + while ((__wctdm_getcreg(wc, WC_SPICTRL) & BIT_SPI_BUSY) != 0); + res = __wctdm_getcreg(wc, WC_SPIDATA); + __wctdm_setcreg(wc, WC_SPICTRL, BIT_SPI_BYHW); + } + + /* And return our result */ + return res; +} + +static void __wctdm_setcreg_mem(struct wctdm *wc, unsigned char reg, unsigned char val) +{ + unsigned int *p = (unsigned int*)(wc->mem32 + WC_REGBASE + ((reg & 0xf) << 2)); + *p = val; +} + +static unsigned char __wctdm_getcreg_mem(struct wctdm *wc, unsigned char reg) +{ + unsigned int *p = (unsigned int*)(wc->mem32 + WC_REGBASE + ((reg & 0xf) << 2)); + return (*p)&0x00ff; +} + + +static void __wctdm_setcreg(struct wctdm *wc, unsigned char reg, unsigned char val) +{ + if(usememio) + __wctdm_setcreg_mem(wc, reg, val); + else + outb(val, wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2)); +} + +static unsigned char __wctdm_getcreg(struct wctdm *wc, unsigned char reg) +{ + if(usememio) + return __wctdm_getcreg_mem(wc, reg); + else + return inb(wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2)); +} + +static inline void __wctdm_setcard(struct wctdm *wc, int card) +{ + if (wc->curcard != card) { + __wctdm_setcreg(wc, WC_CS, card); + wc->curcard = card; + //printk("Select card %d\n", card); + } +} + +static void __wctdm_setreg(struct wctdm *wc, int card, unsigned char reg, unsigned char value) +{ + __wctdm_setcard(wc, card); + if (wc->modtype[card] == MOD_TYPE_FXO) { + __write_8bits(wc, 0x20); + __write_8bits(wc, reg & 0x7f); + } else { + __write_8bits(wc, reg & 0x7f); + } + __write_8bits(wc, value); +} + +static void wctdm_setreg(struct wctdm *wc, int card, unsigned char reg, unsigned char value) +{ + unsigned long flags; + spin_lock_irqsave(&wc->lock, flags); + __wctdm_setreg(wc, card, reg, value); + spin_unlock_irqrestore(&wc->lock, flags); +} + +static unsigned char __wctdm_getreg(struct wctdm *wc, int card, unsigned char reg) +{ + __wctdm_setcard(wc, card); + if (wc->modtype[card] == MOD_TYPE_FXO) { + __write_8bits(wc, 0x60); + __write_8bits(wc, reg & 0x7f); + } else { + __write_8bits(wc, reg | 0x80); + } + return __read_8bits(wc); +} + +static inline void reset_spi(struct wctdm *wc, int card) +{ + unsigned long flags; + spin_lock_irqsave(&wc->lock, flags); + __wctdm_setcard(wc, card); + __reset_spi(wc); + __reset_spi(wc); + spin_unlock_irqrestore(&wc->lock, flags); +} + +static unsigned char wctdm_getreg(struct wctdm *wc, int card, unsigned char reg) +{ + unsigned long flags; + unsigned char res; + spin_lock_irqsave(&wc->lock, flags); + res = __wctdm_getreg(wc, card, reg); + spin_unlock_irqrestore(&wc->lock, flags); + return res; +} + +static int __wait_access(struct wctdm *wc, int card) +{ + unsigned char data = 0; + long origjiffies; + int count = 0; + + #define MAX 6000 /* attempts */ + + + origjiffies = jiffies; + /* Wait for indirect access */ + while (count++ < MAX) + { + data = __wctdm_getreg(wc, card, I_STATUS); + + if (!data) + return 0; + + } + + if(count > (MAX-1)) printk(" ##### Loop error (%02x) #####\n", data); + + return 0; +} + +static unsigned char translate_3215(unsigned char address) +{ + int x; + for (x=0;xflags[card] & FLAG_3215) { + address = translate_3215(address); + if (address == 255) + return 0; + } + spin_lock_irqsave(&wc->lock, flags); + if(!__wait_access(wc, card)) { + __wctdm_setreg(wc, card, IDA_LO,(unsigned char)(data & 0xFF)); + __wctdm_setreg(wc, card, IDA_HI,(unsigned char)((data & 0xFF00)>>8)); + __wctdm_setreg(wc, card, IAA,address); + res = 0; + }; + spin_unlock_irqrestore(&wc->lock, flags); + return res; +} + +static int wctdm_proslic_getreg_indirect(struct wctdm *wc, int card, unsigned char address) +{ + unsigned long flags; + int res = -1; + char *p=NULL; + /* Translate 3215 addresses */ + if (wc->flags[card] & FLAG_3215) { + address = translate_3215(address); + if (address == 255) + return 0; + } + spin_lock_irqsave(&wc->lock, flags); + if (!__wait_access(wc, card)) { + __wctdm_setreg(wc, card, IAA, address); + if (!__wait_access(wc, card)) { + unsigned char data1, data2; + data1 = __wctdm_getreg(wc, card, IDA_LO); + data2 = __wctdm_getreg(wc, card, IDA_HI); + res = data1 | (data2 << 8); + } else + p = "Failed to wait inside\n"; + } else + p = "failed to wait\n"; + spin_unlock_irqrestore(&wc->lock, flags); + if (p) + printk(p); + return res; +} + +static int wctdm_proslic_init_indirect_regs(struct wctdm *wc, int card) +{ + unsigned char i; + + for (i=0; iflags[card] & FLAG_3215) || (indirect_regs[i].altaddr != 255))) + { + printk("!!!!!!! %s iREG %X = %X should be %X\n", + indirect_regs[i].name,indirect_regs[i].address,j,initial ); + passed = 0; + } + } + + if (passed) { + if (debug) + printk("Init Indirect Registers completed successfully.\n"); + } else { + printk(" !!!!! Init Indirect Registers UNSUCCESSFULLY.\n"); + return -1; + } + return 0; +} + +static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card) +{ + int res; + /* Check loopback */ + res = wc->reg1shadow[card]; + if (!res && (res != wc->mod[card].fxs.lasttxhook)) { + res = wctdm_getreg(wc, card, 8); + if (res) { + printk("Ouch, part reset, quickly restoring reality (%d)\n", card); + wctdm_init_proslic(wc, card, 1, 0, 1); + } else { + if (wc->mod[card].fxs.palarms++ < MAX_ALARMS) { + printk("Power alarm on module %d, resetting!\n", card + 1); + if (wc->mod[card].fxs.lasttxhook == 4) + wc->mod[card].fxs.lasttxhook = 1; + wctdm_setreg(wc, card, 64, wc->mod[card].fxs.lasttxhook); + } else { + if (wc->mod[card].fxs.palarms == MAX_ALARMS) + printk("Too many power alarms on card %d, NOT resetting!\n", card + 1); + } + } + } +} + +static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) +{ +#ifndef AUDIO_RINGCHECK + unsigned char res; +#endif + signed char b; + int poopy = 0; + /* Try to track issues that plague slot one FXO's */ + b = wc->reg0shadow[card]; + if ((b & 0x2) || !(b & 0x8)) { + /* Not good -- don't look at anything else */ + if (debug) + printk("Poopy (%02x) on card %d!\n", b, card + 1); + poopy++; + } + b &= 0x9b; + if (wc->mod[card].fxo.offhook) { + if (b != 0x9) + wctdm_setreg(wc, card, 5, 0x9); + } else { + if (b != 0x8) + wctdm_setreg(wc, card, 5, 0x8); + } + if (poopy) + return; +#ifndef AUDIO_RINGCHECK + if (!wc->mod[card].fxo.offhook) { + res = wc->reg0shadow[card]; + if ((res & 0x60) && wc->mod[card].fxo.battery) { + wc->mod[card].fxo.ringdebounce += (ZT_CHUNKSIZE * 16); + if (wc->mod[card].fxo.ringdebounce >= ZT_CHUNKSIZE * 64) { + if (!wc->mod[card].fxo.wasringing) { + wc->mod[card].fxo.wasringing = 1; + zt_hooksig(&wc->chans[card], ZT_RXSIG_RING); + if (debug) + printk("RING on %d/%d!\n", wc->span.spanno, card + 1); + } + wc->mod[card].fxo.ringdebounce = ZT_CHUNKSIZE * 64; + } + } else { + wc->mod[card].fxo.ringdebounce -= ZT_CHUNKSIZE * 4; + if (wc->mod[card].fxo.ringdebounce <= 0) { + if (wc->mod[card].fxo.wasringing) { + wc->mod[card].fxo.wasringing = 0; + zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); + if (debug) + printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1); + } + wc->mod[card].fxo.ringdebounce = 0; + } + + } + } +#endif + b = wc->reg1shadow[card]; +#if 0 + { + static int count = 0; + if (!(count++ % 100)) { + printk("Card %d: Voltage: %d Debounce %d\n", card + 1, + b, wc->mod[card].fxo.battdebounce); + } + } +#endif + if (abs(b) < battthresh) { + wc->mod[card].fxo.nobatttimer++; +#if 0 + if (wc->mod[card].fxo.battery) + printk("Battery loss: %d (%d debounce)\n", b, wc->mod[card].fxo.battdebounce); +#endif + if (wc->mod[card].fxo.battery && !wc->mod[card].fxo.battdebounce) { + if (debug) + printk("NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1); + wc->mod[card].fxo.battery = 0; +#ifdef JAPAN + if ((!wc->ohdebounce) && wc->offhook) { + zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK); + if (debug) + printk("Signalled On Hook\n"); +#ifdef ZERO_BATT_RING + wc->onhook++; +#endif + } +#else + zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK); +#endif + wc->mod[card].fxo.battdebounce = battdebounce; + } else if (!wc->mod[card].fxo.battery) + wc->mod[card].fxo.battdebounce = battdebounce; + } else if (abs(b) > battthresh) { + if (!wc->mod[card].fxo.battery && !wc->mod[card].fxo.battdebounce) { + if (debug) + printk("BATTERY on %d/%d (%s)!\n", wc->span.spanno, card + 1, + (b < 0) ? "-" : "+"); +#ifdef ZERO_BATT_RING + if (wc->onhook) { + wc->onhook = 0; + zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); + if (debug) + printk("Signalled Off Hook\n"); + } +#else + zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); +#endif + wc->mod[card].fxo.battery = 1; + wc->mod[card].fxo.nobatttimer = 0; + wc->mod[card].fxo.battdebounce = battdebounce; + } else if (wc->mod[card].fxo.battery) + wc->mod[card].fxo.battdebounce = battdebounce; + + if (wc->mod[card].fxo.lastpol >= 0) { + if (b < 0) { + wc->mod[card].fxo.lastpol = -1; + wc->mod[card].fxo.polaritydebounce = POLARITY_DEBOUNCE; + } + } + if (wc->mod[card].fxo.lastpol <= 0) { + if (b > 0) { + wc->mod[card].fxo.lastpol = 1; + wc->mod[card].fxo.polaritydebounce = POLARITY_DEBOUNCE; + } + } + } else { + /* It's something else... */ + wc->mod[card].fxo.battdebounce = battdebounce; + } + if (wc->mod[card].fxo.battdebounce) + wc->mod[card].fxo.battdebounce--; + if (wc->mod[card].fxo.polaritydebounce) { + wc->mod[card].fxo.polaritydebounce--; + if (wc->mod[card].fxo.polaritydebounce < 1) { + if (wc->mod[card].fxo.lastpol != wc->mod[card].fxo.polarity) { + if (debug) + printk("%lu Polarity reversed (%d -> %d)\n", jiffies, + wc->mod[card].fxo.polarity, + wc->mod[card].fxo.lastpol); + if (wc->mod[card].fxo.polarity) + zt_qevent_lock(&wc->chans[card], ZT_EVENT_POLARITY); + wc->mod[card].fxo.polarity = wc->mod[card].fxo.lastpol; + } + } + } +} + +static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card) +{ + char res; + int hook; + + /* For some reason we have to debounce the + hook detector. */ + + res = wc->reg0shadow[card]; + hook = (res & 1); + if (hook != wc->mod[card].fxs.lastrxhook) { + /* Reset the debounce (must be multiple of 4ms) */ + wc->mod[card].fxs.debounce = 8 * (4 * 8); +#if 0 + printk("Resetting debounce card %d hook %d, %d\n", card, hook, wc->mod[card].fxs.debounce); +#endif + } else { + if (wc->mod[card].fxs.debounce > 0) { + wc->mod[card].fxs.debounce-= 16 * ZT_CHUNKSIZE; +#if 0 + printk("Sustaining hook %d, %d\n", hook, wc->mod[card].fxs.debounce); +#endif + if (!wc->mod[card].fxs.debounce) { +#if 0 + printk("Counted down debounce, newhook: %d...\n", hook); +#endif + wc->mod[card].fxs.debouncehook = hook; + } + if (!wc->mod[card].fxs.oldrxhook && wc->mod[card].fxs.debouncehook) { + /* Off hook */ +#if 1 + if (debug) +#endif + printk("opvxa1200: Card %d Going off hook\n", card); + zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); + if (robust) + wctdm_init_proslic(wc, card, 1, 0, 1); + wc->mod[card].fxs.oldrxhook = 1; + + } else if (wc->mod[card].fxs.oldrxhook && !wc->mod[card].fxs.debouncehook) { + /* On hook */ +#if 1 + if (debug) +#endif + printk("opvxa1200: Card %d Going on hook\n", card); + zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK); + wc->mod[card].fxs.oldrxhook = 0; + } + } + } + wc->mod[card].fxs.lastrxhook = hook; +} + +#ifdef LINUX26 +static irqreturn_t wctdm_interrupt(int irq, void *dev_id, struct pt_regs *regs) +#else +static void wctdm_interrupt(int irq, void *dev_id, struct pt_regs *regs) +#endif +{ + struct wctdm *wc = dev_id; + unsigned char ints; + int x, y, z; + int mode; + + ints = inb(wc->ioaddr + WC_INTSTAT); + outb(ints, wc->ioaddr + WC_INTSTAT); + + if (!ints) +#ifdef LINUX26 + return IRQ_NONE; +#else + return; +#endif + + if (ints & 0x10) { + /* Stop DMA, wait for watchdog */ + printk("TDM PCI Master abort\n"); + wctdm_stop_dma(wc); +#ifdef LINUX26 + return IRQ_RETVAL(1); +#else + return; +#endif + } + + if (ints & 0x20) { + printk("PCI Target abort\n"); +#ifdef LINUX26 + return IRQ_RETVAL(1); +#else + return; +#endif + } + + for (x=0;x<4*3;x++) { + if (wc->cardflag & (1 << x) && + (wc->modtype[x] == MOD_TYPE_FXS)) { + if (wc->mod[x].fxs.lasttxhook == 0x4) { + /* RINGing, prepare for OHT */ + wc->mod[x].fxs.ohttimer = OHT_TIMER << 3; + if (reversepolarity) + wc->mod[x].fxs.idletxhookstate = 0x6; /* OHT mode when idle */ + else + wc->mod[x].fxs.idletxhookstate = 0x2; + } else { + if (wc->mod[x].fxs.ohttimer) { + wc->mod[x].fxs.ohttimer-= ZT_CHUNKSIZE; + if (!wc->mod[x].fxs.ohttimer) { + if (reversepolarity) + wc->mod[x].fxs.idletxhookstate = 0x5; /* Switch to active */ + else + wc->mod[x].fxs.idletxhookstate = 0x1; + if ((wc->mod[x].fxs.lasttxhook == 0x2) || (wc->mod[x].fxs.lasttxhook = 0x6)) { + /* Apply the change if appropriate */ + if (reversepolarity) + wc->mod[x].fxs.lasttxhook = 0x5; + else + wc->mod[x].fxs.lasttxhook = 0x1; + wctdm_setreg(wc, x, 64, wc->mod[x].fxs.lasttxhook); + } + } + } + } + } + } + + if (ints & 0x0f) { + wc->intcount++; + z = wc->intcount & 0x3; + mode = wc->intcount & 0xc; + for(y=0; y<3; y++) + { + x = z + y*4; + if (wc->cardflag & (1 << x ) ) + { + switch(mode) + { + case 0: + /* Rest */ + break; + case 4: + /* Read first shadow reg */ + if (wc->modtype[x] == MOD_TYPE_FXS) + wc->reg0shadow[x] = wctdm_getreg(wc, x, 68); + else if (wc->modtype[x] == MOD_TYPE_FXO) + wc->reg0shadow[x] = wctdm_getreg(wc, x, 5); + break; + case 8: + /* Read second shadow reg */ + if (wc->modtype[x] == MOD_TYPE_FXS) + wc->reg1shadow[x] = wctdm_getreg(wc, x, 64); + else if (wc->modtype[x] == MOD_TYPE_FXO) + wc->reg1shadow[x] = wctdm_getreg(wc, x, 29); + break; + case 12: + /* Perform processing */ + if (wc->modtype[x] == MOD_TYPE_FXS) { + wctdm_proslic_check_hook(wc, x); + if (!(wc->intcount & 0xf0)) + wctdm_proslic_recheck_sanity(wc, x); + } else if (wc->modtype[x] == MOD_TYPE_FXO) { + wctdm_voicedaa_check_hook(wc, x); + } + break; + } + } + } + if (!(wc->intcount % 10000)) { + /* Accept an alarm once per 10 seconds */ + for (x=0;x<4*3;x++) + if (wc->modtype[x] == MOD_TYPE_FXS) { + if (wc->mod[x].fxs.palarms) + wc->mod[x].fxs.palarms--; + } + } + wctdm_receiveprep(wc, ints); + wctdm_transmitprep(wc, ints); + } +#ifdef LINUX26 + return IRQ_RETVAL(1); +#endif + +} + +static int wctdm_voicedaa_insane(struct wctdm *wc, int card) +{ + int blah; + blah = wctdm_getreg(wc, card, 2); + if (blah != 0x3) + return -2; + blah = wctdm_getreg(wc, card, 11); + if (debug) + printk("VoiceDAA System: %02x\n", blah & 0xf); + return 0; +} + +static int wctdm_proslic_insane(struct wctdm *wc, int card) +{ + int blah,insane_report; + insane_report=0; + + blah = wctdm_getreg(wc, card, 0); + if (debug) + printk("ProSLIC on module %d, product %d, version %d\n", card, (blah & 0x30) >> 4, (blah & 0xf)); + +#if 0 + if ((blah & 0x30) >> 4) { + printk("ProSLIC on module %d is not a 3210.\n", card); + return -1; + } +#endif + if (((blah & 0xf) == 0) || ((blah & 0xf) == 0xf)) { + /* SLIC not loaded */ + return -1; + } + if ((blah & 0xf) < 2) { + printk("ProSLIC 3210 version %d is too old\n", blah & 0xf); + return -1; + } + if ((blah & 0xf) == 2) { + /* ProSLIC 3215, not a 3210 */ + wc->flags[card] |= FLAG_3215; + } + blah = wctdm_getreg(wc, card, 8); + if (blah != 0x2) { + printk("ProSLIC on module %d insane (1) %d should be 2\n", card, blah); + return -1; + } else if ( insane_report) + printk("ProSLIC on module %d Reg 8 Reads %d Expected is 0x2\n",card,blah); + + blah = wctdm_getreg(wc, card, 64); + if (blah != 0x0) { + printk("ProSLIC on module %d insane (2)\n", card); + return -1; + } else if ( insane_report) + printk("ProSLIC on module %d Reg 64 Reads %d Expected is 0x0\n",card,blah); + + blah = wctdm_getreg(wc, card, 11); + if (blah != 0x33) { + printk("ProSLIC on module %d insane (3)\n", card); + return -1; + } else if ( insane_report) + printk("ProSLIC on module %d Reg 11 Reads %d Expected is 0x33\n",card,blah); + + /* Just be sure it's setup right. */ + wctdm_setreg(wc, card, 30, 0); + + if (debug) + printk("ProSLIC on module %d seems sane.\n", card); + return 0; +} + +static int wctdm_proslic_powerleak_test(struct wctdm *wc, int card) +{ + unsigned long origjiffies; + unsigned char vbat; + + /* Turn off linefeed */ + wctdm_setreg(wc, card, 64, 0); + + /* Power down */ + wctdm_setreg(wc, card, 14, 0x10); + + /* Wait for one second */ + origjiffies = jiffies; + + while((vbat = wctdm_getreg(wc, card, 82)) > 0x6) { + if ((jiffies - origjiffies) >= (HZ/2)) + break;; + } + + if (vbat < 0x06) { + printk("Excessive leakage detected on module %d: %d volts (%02x) after %d ms\n", card, + 376 * vbat / 1000, vbat, (int)((jiffies - origjiffies) * 1000 / HZ)); + return -1; + } else if (debug) { + printk("Post-leakage voltage: %d volts\n", 376 * vbat / 1000); + } + return 0; +} + +static int wctdm_powerup_proslic(struct wctdm *wc, int card, int fast) +{ + unsigned char vbat; + unsigned long origjiffies; + int lim; + + /* Set period of DC-DC converter to 1/64 khz */ + wctdm_setreg(wc, card, 92, 0xff /* was 0xff */); + + /* Wait for VBat to powerup */ + origjiffies = jiffies; + + /* Disable powerdown */ + wctdm_setreg(wc, card, 14, 0); + + /* If fast, don't bother checking anymore */ + if (fast) + return 0; + + while((vbat = wctdm_getreg(wc, card, 82)) < 0xc0) { + /* Wait no more than 500ms */ + if ((jiffies - origjiffies) > HZ/2) { + break; + } + } + + if (vbat < 0xc0) { + if (wc->proslic_power == PROSLIC_POWER_UNKNOWN) + printk("ProSLIC on module %d failed to powerup within %d ms (%d mV only)\n\n -- DID YOU REMEMBER TO PLUG IN THE HD POWER CABLE TO THE A1200P??\n", + card, (int)(((jiffies - origjiffies) * 1000 / HZ)), + vbat * 375); + wc->proslic_power = PROSLIC_POWER_WARNED; + return -1; + } else if (debug) { + printk("ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n", + card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ))); + } + wc->proslic_power = PROSLIC_POWER_ON; + + /* Proslic max allowed loop current, reg 71 LOOP_I_LIMIT */ + /* If out of range, just set it to the default value */ + lim = (loopcurrent - 20) / 3; + if ( loopcurrent > 41 ) { + lim = 0; + if (debug) + printk("Loop current out of range! Setting to default 20mA!\n"); + } + else if (debug) + printk("Loop current set to %dmA!\n",(lim*3)+20); + wctdm_setreg(wc,card,LOOP_I_LIMIT,lim); + + /* Engage DC-DC converter */ + wctdm_setreg(wc, card, 93, 0x19 /* was 0x19 */); +#if 0 + origjiffies = jiffies; + while(0x80 & wctdm_getreg(wc, card, 93)) { + if ((jiffies - origjiffies) > 2 * HZ) { + printk("Timeout waiting for DC-DC calibration on module %d\n", card); + return -1; + } + } + +#if 0 + /* Wait a full two seconds */ + while((jiffies - origjiffies) < 2 * HZ); + + /* Just check to be sure */ + vbat = wctdm_getreg(wc, card, 82); + printk("ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n", + card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ))); +#endif +#endif + return 0; + +} + +static int wctdm_proslic_manual_calibrate(struct wctdm *wc, int card){ + unsigned long origjiffies; + unsigned char i; + + wctdm_setreg(wc, card, 21, 0);//(0) Disable all interupts in DR21 + wctdm_setreg(wc, card, 22, 0);//(0)Disable all interupts in DR21 + wctdm_setreg(wc, card, 23, 0);//(0)Disable all interupts in DR21 + wctdm_setreg(wc, card, 64, 0);//(0) + + wctdm_setreg(wc, card, 97, 0x18); //(0x18)Calibrations without the ADC and DAC offset and without common mode calibration. + wctdm_setreg(wc, card, 96, 0x47); //(0x47) Calibrate common mode and differential DAC mode DAC + ILIM + + origjiffies=jiffies; + while( wctdm_getreg(wc,card,96)!=0 ){ + if((jiffies-origjiffies)>80) + return -1; + } +//Initialized DR 98 and 99 to get consistant results. +// 98 and 99 are the results registers and the search should have same intial conditions. + +/*******************************The following is the manual gain mismatch calibration****************************/ +/*******************************This is also available as a function *******************************************/ + // Delay 10ms + origjiffies=jiffies; + while((jiffies-origjiffies)<1); + wctdm_proslic_setreg_indirect(wc, card, 88,0); + wctdm_proslic_setreg_indirect(wc,card,89,0); + wctdm_proslic_setreg_indirect(wc,card,90,0); + wctdm_proslic_setreg_indirect(wc,card,91,0); + wctdm_proslic_setreg_indirect(wc,card,92,0); + wctdm_proslic_setreg_indirect(wc,card,93,0); + + wctdm_setreg(wc, card, 98,0x10); // This is necessary if the calibration occurs other than at reset time + wctdm_setreg(wc, card, 99,0x10); + + for ( i=0x1f; i>0; i--) + { + wctdm_setreg(wc, card, 98,i); + origjiffies=jiffies; + while((jiffies-origjiffies)<4); + if((wctdm_getreg(wc,card,88)) == 0) + break; + } // for + + for ( i=0x1f; i>0; i--) + { + wctdm_setreg(wc, card, 99,i); + origjiffies=jiffies; + while((jiffies-origjiffies)<4); + if((wctdm_getreg(wc,card,89)) == 0) + break; + }//for + +/*******************************The preceding is the manual gain mismatch calibration****************************/ +/**********************************The following is the longitudinal Balance Cal***********************************/ + wctdm_setreg(wc,card,64,1); + while((jiffies-origjiffies)<10); // Sleep 100? + + wctdm_setreg(wc, card, 64, 0); + wctdm_setreg(wc, card, 23, 0x4); // enable interrupt for the balance Cal + wctdm_setreg(wc, card, 97, 0x1); // this is a singular calibration bit for longitudinal calibration + wctdm_setreg(wc, card, 96,0x40); + + wctdm_getreg(wc,card,96); /* Read Reg 96 just cause */ + + wctdm_setreg(wc, card, 21, 0xFF); + wctdm_setreg(wc, card, 22, 0xFF); + wctdm_setreg(wc, card, 23, 0xFF); + + /**The preceding is the longitudinal Balance Cal***/ + return(0); + +} +#if 1 +static int wctdm_proslic_calibrate(struct wctdm *wc, int card) +{ + unsigned long origjiffies; + int x; + /* Perform all calibrations */ + wctdm_setreg(wc, card, 97, 0x1f); + + /* Begin, no speedup */ + wctdm_setreg(wc, card, 96, 0x5f); + + /* Wait for it to finish */ + origjiffies = jiffies; + while(wctdm_getreg(wc, card, 96)) { + if ((jiffies - origjiffies) > 2 * HZ) { + printk("Timeout waiting for calibration of module %d\n", card); + return -1; + } + } + + if (debug) { + /* Print calibration parameters */ + printk("Calibration Vector Regs 98 - 107: \n"); + for (x=98;x<108;x++) { + printk("%d: %02x\n", x, wctdm_getreg(wc, card, x)); + } + } + return 0; +} +#endif + +static void wait_just_a_bit(int foo) +{ + long newjiffies; + newjiffies = jiffies + foo; + while(jiffies < newjiffies); +} + +static int wctdm_init_voicedaa(struct wctdm *wc, int card, int fast, int manual, int sane) +{ + unsigned char reg16=0, reg26=0, reg30=0, reg31=0; + long newjiffies; + wc->modtype[card] = MOD_TYPE_FXO; + + /* Sanity check the ProSLIC */ + reset_spi(wc, card); + if (!sane && wctdm_voicedaa_insane(wc, card)) + return -2; + + /* Software reset */ + wctdm_setreg(wc, card, 1, 0x80); + + /* Wait just a bit */ + wait_just_a_bit(HZ/10); + + /* Enable PCM, ulaw */ + if (alawoverride) + wctdm_setreg(wc, card, 33, 0x20); + else + wctdm_setreg(wc, card, 33, 0x28); + + /* Set On-hook speed, Ringer impedence, and ringer threshold */ + reg16 |= (fxo_modes[_opermode].ohs << 6); + reg16 |= (fxo_modes[_opermode].rz << 1); + reg16 |= (fxo_modes[_opermode].rt); + wctdm_setreg(wc, card, 16, reg16); + + /* Set DC Termination: + Tip/Ring voltage adjust, minimum operational current, current limitation */ + reg26 |= (fxo_modes[_opermode].dcv << 6); + reg26 |= (fxo_modes[_opermode].mini << 4); + reg26 |= (fxo_modes[_opermode].ilim << 1); + wctdm_setreg(wc, card, 26, reg26); + + /* Set AC Impedence */ + reg30 = (fxo_modes[_opermode].acim); + wctdm_setreg(wc, card, 30, reg30); + + /* Misc. DAA parameters */ + reg31 = 0xa3; + reg31 |= (fxo_modes[_opermode].ohs2 << 3); + wctdm_setreg(wc, card, 31, reg31); + + /* Set Transmit/Receive timeslot */ + //printk("set card %d to %d\n", card, (3-(card%4)) * 8 + (card/4) * 64); + wctdm_setreg(wc, card, 34, (3-(card%4)) * 8 + (card/4) * 64); + wctdm_setreg(wc, card, 35, 0x00); + wctdm_setreg(wc, card, 36, (3-(card%4)) * 8 + (card/4) * 64); + wctdm_setreg(wc, card, 37, 0x00); + + /* Enable ISO-Cap */ + wctdm_setreg(wc, card, 6, 0x00); + + /* Wait 1000ms for ISO-cap to come up */ + newjiffies = jiffies; + newjiffies += 2 * HZ; + while((jiffies < newjiffies) && !(wctdm_getreg(wc, card, 11) & 0xf0)) + wait_just_a_bit(HZ/10); + + if (!(wctdm_getreg(wc, card, 11) & 0xf0)) { + printk("VoiceDAA did not bring up ISO link properly!\n"); + return -1; + } + if (debug) + printk("ISO-Cap is now up, line side: %02x rev %02x\n", + wctdm_getreg(wc, card, 11) >> 4, + (wctdm_getreg(wc, card, 13) >> 2) & 0xf); + /* Enable on-hook line monitor */ + wctdm_setreg(wc, card, 5, 0x08); + + /* NZ -- crank the tx gain up by 7 dB */ + if (!strcmp(fxo_modes[_opermode].name, "NEWZEALAND")) { + printk("Adjusting gain\n"); + wctdm_setreg(wc, card, 38, 0x7); + } + + return 0; + +} + +static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual, int sane) +{ + + unsigned short tmp[5]; + unsigned char r19; + int x; + int fxsmode=0; + + + /* By default, don't send on hook */ + if (reversepolarity) + wc->mod[card].fxs.idletxhookstate = 5; + else + wc->mod[card].fxs.idletxhookstate = 1; + + /* Sanity check the ProSLIC */ + if (!sane && wctdm_proslic_insane(wc, card)) + return -2; + + if (sane) { + /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */ + wctdm_setreg(wc, card, 14, 0x10); + } + + if (wctdm_proslic_init_indirect_regs(wc, card)) { + printk(KERN_INFO "Indirect Registers failed to initialize on module %d.\n", card); + return -1; + } + + /* Clear scratch pad area */ + wctdm_proslic_setreg_indirect(wc, card, 97,0); + + /* Clear digital loopback */ + wctdm_setreg(wc, card, 8, 0); + + /* Revision C optimization */ + wctdm_setreg(wc, card, 108, 0xeb); + + /* Disable automatic VBat switching for safety to prevent + Q7 from accidently turning on and burning out. */ + wctdm_setreg(wc, card, 67, 0x17); + + /* Turn off Q7 */ + wctdm_setreg(wc, card, 66, 1); + + /* Flush ProSLIC digital filters by setting to clear, while + saving old values */ + for (x=0;x<5;x++) { + tmp[x] = wctdm_proslic_getreg_indirect(wc, card, x + 35); + wctdm_proslic_setreg_indirect(wc, card, x + 35, 0x8000); + } + + /* Power up the DC-DC converter */ + if (wctdm_powerup_proslic(wc, card, fast)) { + printk("Unable to do INITIAL ProSLIC powerup on module %d\n", card); + return -1; + } + + if (!fast) { + + /* Check for power leaks */ + if (wctdm_proslic_powerleak_test(wc, card)) { + printk("ProSLIC module %d failed leakage test. Check for short circuit\n", card); + } + /* Power up again */ + if (wctdm_powerup_proslic(wc, card, fast)) { + printk("Unable to do FINAL ProSLIC powerup on module %d\n", card); + return -1; + } +#ifndef NO_CALIBRATION + /* Perform calibration */ + if(manual) { + if (wctdm_proslic_manual_calibrate(wc, card)) { + //printk("Proslic failed on Manual Calibration\n"); + if (wctdm_proslic_manual_calibrate(wc, card)) { + printk("Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n"); + return -1; + } + printk("Proslic Passed Manual Calibration on Second Attempt\n"); + } + } + else { + if(wctdm_proslic_calibrate(wc, card)) { + //printk("ProSlic died on Auto Calibration.\n"); + if (wctdm_proslic_calibrate(wc, card)) { + printk("Proslic Failed on Second Attempt to Auto Calibrate\n"); + return -1; + } + printk("Proslic Passed Auto Calibration on Second Attempt\n"); + } + } + /* Perform DC-DC calibration */ + wctdm_setreg(wc, card, 93, 0x99); + r19 = wctdm_getreg(wc, card, 107); + if ((r19 < 0x2) || (r19 > 0xd)) { + printk("DC-DC cal has a surprising direct 107 of 0x%02x!\n", r19); + wctdm_setreg(wc, card, 107, 0x8); + } + + /* Save calibration vectors */ + for (x=0;xmod[card].fxs.calregs.vals[x] = wctdm_getreg(wc, card, 96 + x); +#endif + + } else { + /* Restore calibration registers */ + for (x=0;xmod[card].fxs.calregs.vals[x]); + } + /* Calibration complete, restore original values */ + for (x=0;x<5;x++) { + wctdm_proslic_setreg_indirect(wc, card, x + 35, tmp[x]); + } + + if (wctdm_proslic_verify_indirect_regs(wc, card)) { + printk(KERN_INFO "Indirect Registers failed verification.\n"); + return -1; + } + + +#if 0 + /* Disable Auto Power Alarm Detect and other "features" */ + wctdm_setreg(wc, card, 67, 0x0e); + blah = wctdm_getreg(wc, card, 67); +#endif + +#if 0 + if (wctdm_proslic_setreg_indirect(wc, card, 97, 0x0)) { // Stanley: for the bad recording fix + printk(KERN_INFO "ProSlic IndirectReg Died.\n"); + return -1; + } +#endif + + if (alawoverride) + wctdm_setreg(wc, card, 1, 0x20); + else + wctdm_setreg(wc, card, 1, 0x28); + // U-Law 8-bit interface + + //printk("set card %d to %d\n", card, (3-(card%4)) * 8 + (card/4) * 64); + wctdm_setreg(wc, card, 2, (3-(card%4)) * 8 + (card/4) * 64); // Tx Start count low byte 0 + wctdm_setreg(wc, card, 3, 0); // Tx Start count high byte 0 + wctdm_setreg(wc, card, 4, (3-(card%4)) * 8 + (card/4) * 64); // Rx Start count low byte 0 + wctdm_setreg(wc, card, 5, 0); // Rx Start count high byte 0 + wctdm_setreg(wc, card, 18, 0xff); // clear all interrupt + wctdm_setreg(wc, card, 19, 0xff); + wctdm_setreg(wc, card, 20, 0xff); + wctdm_setreg(wc, card, 73, 0x04); + if (fxshonormode) { + fxsmode = acim2tiss[fxo_modes[_opermode].acim]; + wctdm_setreg(wc, card, 10, 0x08 | fxsmode); + if (fxo_modes[_opermode].ring_osc) + wctdm_proslic_setreg_indirect(wc, card, 20, fxo_modes[_opermode].ring_osc); + if (fxo_modes[_opermode].ring_x) + wctdm_proslic_setreg_indirect(wc, card, 21, fxo_modes[_opermode].ring_x); + } + if (lowpower) + wctdm_setreg(wc, card, 72, 0x10); + +#if 0 + wctdm_setreg(wc, card, 21, 0x00); // enable interrupt + wctdm_setreg(wc, card, 22, 0x02); // Loop detection interrupt + wctdm_setreg(wc, card, 23, 0x01); // DTMF detection interrupt +#endif + +#if 0 + /* Enable loopback */ + wctdm_setreg(wc, card, 8, 0x2); + wctdm_setreg(wc, card, 14, 0x0); + wctdm_setreg(wc, card, 64, 0x0); + wctdm_setreg(wc, card, 1, 0x08); +#endif + + /* Beef up Ringing voltage to 89V */ + if (boostringer) { + if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x1d1)) + return -1; + printk("Boosting ringinger on slot %d (89V peak)\n", card + 1); + } else if (lowpower) { + if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x108)) + return -1; + printk("Reducing ring power on slot %d (50V peak)\n", card + 1); + } + wctdm_setreg(wc, card, 64, 0x01); + return 0; +} + + +static int wctdm_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) +{ + struct wctdm_stats stats; + struct wctdm_regs regs; + struct wctdm_regop regop; + struct wctdm_echo_coefs echoregs; + struct wctdm *wc = chan->pvt; + int x; + switch (cmd) { + case ZT_ONHOOKTRANSFER: + if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) + return -EINVAL; + if (get_user(x, (int *)data)) + return -EFAULT; + wc->mod[chan->chanpos - 1].fxs.ohttimer = x << 3; + if (reversepolarity) + wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 0x6; /* OHT mode when idle */ + else + wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 0x2; + if (wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x1) { + /* Apply the change if appropriate */ + if (reversepolarity) + wc->mod[chan->chanpos - 1].fxs.lasttxhook = 0x6; + else + wc->mod[chan->chanpos - 1].fxs.lasttxhook = 0x2; + wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook); + } + break; + case ZT_SETPOLARITY: + if (get_user(x, (int *)data)) + return -EFAULT; + if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) + return -EINVAL; + /* Can't change polarity while ringing or when open */ + if ((wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x04) || + (wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x00)) + return -EINVAL; + + if ((x && !reversepolarity) || (!x && reversepolarity)) + wc->mod[chan->chanpos - 1].fxs.lasttxhook |= 0x04; + else + wc->mod[chan->chanpos - 1].fxs.lasttxhook &= ~0x04; + wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook); + break; + case WCTDM_GET_STATS: + if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { + stats.tipvolt = wctdm_getreg(wc, chan->chanpos - 1, 80) * -376; + stats.ringvolt = wctdm_getreg(wc, chan->chanpos - 1, 81) * -376; + stats.batvolt = wctdm_getreg(wc, chan->chanpos - 1, 82) * -376; + } else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { + stats.tipvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000; + stats.ringvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000; + stats.batvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000; + } else + return -EINVAL; + if (copy_to_user((struct wctdm_stats *)data, &stats, sizeof(stats))) + return -EFAULT; + break; + case WCTDM_GET_REGS: + if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { + for (x=0;xchanpos -1, x); + for (x=0;xchanpos - 1, x); + } else { + memset(®s, 0, sizeof(regs)); + for (x=0;xchanpos - 1, x); + } + if (copy_to_user((struct wctdm_regs *)data, ®s, sizeof(regs))) + return -EFAULT; + break; + case WCTDM_SET_REG: + if (copy_from_user(®op, (struct wctdm_regop *)data, sizeof(regop))) + return -EFAULT; + if (regop.indirect) { + if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) + return -EINVAL; + printk("Setting indirect %d to 0x%04x on %d\n", regop.reg, regop.val, chan->chanpos); + wctdm_proslic_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val); + } else { + regop.val &= 0xff; + printk("Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos); + wctdm_setreg(wc, chan->chanpos - 1, regop.reg, regop.val); + } + break; + case WCTDM_SET_ECHOTUNE: + printk("-- Setting echo registers: \n"); + if (copy_from_user(&echoregs, (struct wctdm_echo_coefs*)data, sizeof(echoregs))) + return -EFAULT; + + if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { + /* Set the ACIM register */ + wctdm_setreg(wc, chan->chanpos - 1, 30, echoregs.acim); + + /* Set the digital echo canceller registers */ + wctdm_setreg(wc, chan->chanpos - 1, 45, echoregs.coef1); + wctdm_setreg(wc, chan->chanpos - 1, 46, echoregs.coef2); + wctdm_setreg(wc, chan->chanpos - 1, 47, echoregs.coef3); + wctdm_setreg(wc, chan->chanpos - 1, 48, echoregs.coef4); + wctdm_setreg(wc, chan->chanpos - 1, 49, echoregs.coef5); + wctdm_setreg(wc, chan->chanpos - 1, 50, echoregs.coef6); + wctdm_setreg(wc, chan->chanpos - 1, 51, echoregs.coef7); + wctdm_setreg(wc, chan->chanpos - 1, 52, echoregs.coef8); + + printk("-- Set echo registers successfully\n"); + + break; + } else { + return -EINVAL; + + } + break; + default: + return -ENOTTY; + } + return 0; + +} + +static int wctdm_open(struct zt_chan *chan) +{ + struct wctdm *wc = chan->pvt; + if (!(wc->cardflag & (1 << (chan->chanpos - 1)))) + return -ENODEV; + if (wc->dead) + return -ENODEV; + wc->usecount++; +#ifndef LINUX26 + MOD_INC_USE_COUNT; +#else + try_module_get(THIS_MODULE); +#endif + return 0; +} + +static int wctdm_watchdog(struct zt_span *span, int event) +{ + printk("opvxa1200: Restarting DMA\n"); + wctdm_restart_dma(span->pvt); + return 0; +} + +static int wctdm_close(struct zt_chan *chan) +{ + struct wctdm *wc = chan->pvt; + wc->usecount--; +#ifndef LINUX26 + MOD_DEC_USE_COUNT; +#else + module_put(THIS_MODULE); +#endif + if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { + if (reversepolarity) + wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 5; + else + wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 1; + } + /* If we're dead, release us now */ + if (!wc->usecount && wc->dead) + wctdm_release(wc); + return 0; +} + +static int wctdm_hooksig(struct zt_chan *chan, zt_txsig_t txsig) +{ + struct wctdm *wc = chan->pvt; + int reg=0; + if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { + /* XXX Enable hooksig for FXO XXX */ + switch(txsig) { + case ZT_TXSIG_START: + case ZT_TXSIG_OFFHOOK: + wc->mod[chan->chanpos - 1].fxo.offhook = 1; + wctdm_setreg(wc, chan->chanpos - 1, 5, 0x9); + break; + case ZT_TXSIG_ONHOOK: + wc->mod[chan->chanpos - 1].fxo.offhook = 0; + wctdm_setreg(wc, chan->chanpos - 1, 5, 0x8); + break; + default: + printk("wcfxo: Can't set tx state to %d\n", txsig); + } + } else { + switch(txsig) { + case ZT_TXSIG_ONHOOK: + switch(chan->sig) { + case ZT_SIG_EM: + case ZT_SIG_FXOKS: + case ZT_SIG_FXOLS: + wc->mod[chan->chanpos-1].fxs.lasttxhook = wc->mod[chan->chanpos-1].fxs.idletxhookstate; + break; + case ZT_SIG_FXOGS: + wc->mod[chan->chanpos-1].fxs.lasttxhook = 3; + break; + } + break; + case ZT_TXSIG_OFFHOOK: + switch(chan->sig) { + case ZT_SIG_EM: + wc->mod[chan->chanpos-1].fxs.lasttxhook = 5; + break; + default: + wc->mod[chan->chanpos-1].fxs.lasttxhook = wc->mod[chan->chanpos-1].fxs.idletxhookstate; + break; + } + break; + case ZT_TXSIG_START: + wc->mod[chan->chanpos-1].fxs.lasttxhook = 4; + break; + case ZT_TXSIG_KEWL: + wc->mod[chan->chanpos-1].fxs.lasttxhook = 0; + break; + default: + printk("opvxa1200: Can't set tx state to %d\n", txsig); + } + if (debug) + printk("Setting FXS hook state to %d (%02x)\n", txsig, reg); + +#if 1 + wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos-1].fxs.lasttxhook); +#endif + } + return 0; +} + +static int wctdm_initialize(struct wctdm *wc) +{ + int x; + + /* Zapata stuff */ + sprintf(wc->span.name, "OPVXA1200/%d", wc->pos); + sprintf(wc->span.desc, "%s Board %d", wc->variety, wc->pos + 1); + if (alawoverride) { + printk("ALAW override parameter detected. Device will be operating in ALAW\n"); + wc->span.deflaw = ZT_LAW_ALAW; + } else + wc->span.deflaw = ZT_LAW_MULAW; + for (x = 0; x < NUM_CARDS; x++) { + sprintf(wc->chans[x].name, "OPVXA1200/%d/%d", wc->pos, x); + wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_SF | ZT_SIG_EM | ZT_SIG_CLEAR; + wc->chans[x].sigcap |= ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF | ZT_SIG_CLEAR; + wc->chans[x].chanpos = x+1; + wc->chans[x].pvt = wc; + } + wc->span.chans = wc->chans; + wc->span.channels = NUM_CARDS; + wc->span.hooksig = wctdm_hooksig; + wc->span.open = wctdm_open; + wc->span.close = wctdm_close; + wc->span.flags = ZT_FLAG_RBS; + wc->span.ioctl = wctdm_ioctl; + wc->span.watchdog = wctdm_watchdog; + init_waitqueue_head(&wc->span.maintq); + + wc->span.pvt = wc; + if (zt_register(&wc->span, 0)) { + printk("Unable to register span with zaptel\n"); + return -1; + } + return 0; +} + +static void wctdm_post_initialize(struct wctdm *wc) +{ + int x; + /* Finalize signalling */ + for (x = 0; x < NUM_CARDS; x++) { + if (wc->cardflag & (1 << x)) { + if (wc->modtype[x] == MOD_TYPE_FXO) + wc->chans[x].sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF | ZT_SIG_CLEAR; + else + wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_SF | ZT_SIG_EM | ZT_SIG_CLEAR; + } + } +} + +static int wctdm_hardware_init(struct wctdm *wc) +{ + /* Hardware stuff */ + unsigned char ver; + unsigned char x,y; + int failed; + //long origjiffies; //ml. + + /* Signal Reset */ + //printk("before raise reset\n"); + outb(0x01, wc->ioaddr + WC_CNTL); + + /* Wait for 2 second */ + /* + origjiffies = jiffies; + + while(1) + { + if ((jiffies - origjiffies) >= (HZ*5)) + break;; + } + + printk("after raise reset\n");*/ + + /* Check OpenVox chip */ + x=inb(wc->ioaddr + WC_CNTL); + ver = __wctdm_getcreg(wc, WC_VER); + wc->fwversion = ver; + printk("OpenVox A1200P version: %01x.%01x\n", ver>>4, ver&0x0f); + failed = 0; + if (ver != 0x00) { + for (x=0;x<16;x++) { + /* Test registers */ + __wctdm_setcreg(wc, WC_CS, x); + y = __wctdm_getcreg(wc, WC_CS) & 0x0f; + if (x != y) { + printk("%02x != %02x\n", x, y); + failed++; + } + } + + if (!failed) { + printk("OpenVox A1200P passed register test\n"); + } else { + printk("OpenVox A1200P failed register test\n"); + return -1; + } + } else { + printk("No OpenVox chip %02x\n", ver); + } + + if (spibyhw) + __wctdm_setcreg(wc, WC_SPICTRL, BIT_SPI_BYHW); // spi controled by hw MiaoLin; + else + __wctdm_setcreg(wc, WC_SPICTRL, 0); + + /* Reset PCI Interface chip and registers (and serial) */ + outb(0x06, wc->ioaddr + WC_CNTL); + /* Setup our proper outputs for when we switch for our "serial" port */ + wc->ios = BIT_CS | BIT_SCLK | BIT_SDI; + + outb(wc->ios, wc->ioaddr + WC_AUXD); + + /* Set all to outputs except AUX 5, which is an input */ + outb(0xdf, wc->ioaddr + WC_AUXC); + + /* Select alternate function for AUX0 *///MiaoLin modify it to normal io line. + //outb(0x4, wc->ioaddr + WC_AUXFUNC); + + /* Wait 1/4 of a sec */ + wait_just_a_bit(HZ/4); + + /* Back to normal, with automatic DMA wrap around */ + outb(0x30 | 0x01, wc->ioaddr + WC_CNTL); + wc->ledstate = 0; + wctdm_set_led(wc, 0, 0); + + /* Make sure serial port and DMA are out of reset */ + outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, WC_CNTL); + + /* Configure serial port for MSB->LSB operation */ + //outb(0xc1, wc->ioaddr + WC_SERCTL); + outb(0xc1, wc->ioaddr + WC_SERCTL); + + /* Delay FSC by 0 so it's properly aligned */ + //outb(0x0, wc->ioaddr + WC_FSCDELAY); + outb(0x01, wc->ioaddr + WC_FSCDELAY); + + /* Setup DMA Addresses */ + outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */ + outl(wc->writedma + ZT_CHUNKSIZE * 4 * 4 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */ + outl(wc->writedma + ZT_CHUNKSIZE * 8 * 4 - 4, wc->ioaddr + WC_DMAWE); /* End */ + + outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */ + outl(wc->readdma + ZT_CHUNKSIZE * 4 * 4 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */ + outl(wc->readdma + ZT_CHUNKSIZE * 8 * 4 - 4, wc->ioaddr + WC_DMARE); /* End */ + + /* Clear interrupts */ + outb(0xff, wc->ioaddr + WC_INTSTAT); + + /* Wait 1/4 of a second more */ + wait_just_a_bit(HZ/4); + + for (x = 0; x < NUM_CARDS; x++) { + int sane=0,ret=0,readi=0; +#if 1 + /* Init with Auto Calibration */ + if (!(ret=wctdm_init_proslic(wc, x, 0, 0, sane))) { + wc->cardflag |= (1 << x); + if (debug) { + readi = wctdm_getreg(wc,x,LOOP_I_LIMIT); + printk("Proslic module %d loop current is %dmA\n",x, + ((readi*3)+20)); + } + printk("Module %d: Installed -- AUTO FXS/DPO\n",x); + wctdm_set_led(wc, (unsigned int)x, 1); + } else { + if(ret!=-2) { + sane=1; + + printk("Init ProSlic with Manual Calibration \n"); + /* Init with Manual Calibration */ + if (!wctdm_init_proslic(wc, x, 0, 1, sane)) { + wc->cardflag |= (1 << x); + if (debug) { + readi = wctdm_getreg(wc,x,LOOP_I_LIMIT); + printk("Proslic module %d loop current is %dmA\n",x, + ((readi*3)+20)); + } + printk("Module %d: Installed -- MANUAL FXS\n",x); + } else { + printk("Module %d: FAILED FXS (%s)\n", x, fxshonormode ? fxo_modes[_opermode].name : "FCC"); + } + } else if (!(ret = wctdm_init_voicedaa(wc, x, 0, 0, sane))) { + wc->cardflag |= (1 << x); + printk("Module %d: Installed -- AUTO FXO (%s mode)\n",x, fxo_modes[_opermode].name); + wctdm_set_led(wc, (unsigned int)x, 1); + } else + printk("Module %d: Not installed\n", x); + } +#endif + } + + /* Return error if nothing initialized okay. */ + if (!wc->cardflag && !timingonly) + return -1; + //__wctdm_setcreg(wc, WC_SYNC, (wc->cardflag << 1) | 0x1); + return 0; +} + +static void wctdm_enable_interrupts(struct wctdm *wc) +{ + /* Clear interrupts */ + outb(0xff, wc->ioaddr + WC_INTSTAT); + + /* Enable interrupts (we care about all of them) */ + outb(0x3c /*0x3f*/, wc->ioaddr + WC_MASK0); + /* No external interrupts */ + outb(0x00, wc->ioaddr + WC_MASK1); +} + +static void wctdm_restart_dma(struct wctdm *wc) +{ + /* Reset Master and TDM */ + outb(0x01, wc->ioaddr + WC_CNTL); + outb(0x01, wc->ioaddr + WC_OPER); +} + +static void wctdm_start_dma(struct wctdm *wc) +{ + /* Reset Master and TDM */ + outb(0x0f, wc->ioaddr + WC_CNTL); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + outb(0x01, wc->ioaddr + WC_CNTL); + outb(0x01, wc->ioaddr + WC_OPER); +} + +static void wctdm_stop_dma(struct wctdm *wc) +{ + outb(0x00, wc->ioaddr + WC_OPER); +} + +static void wctdm_reset_tdm(struct wctdm *wc) +{ + /* Reset TDM */ + outb(0x0f, wc->ioaddr + WC_CNTL); +} + +static void wctdm_disable_interrupts(struct wctdm *wc) +{ + outb(0x00, wc->ioaddr + WC_MASK0); + outb(0x00, wc->ioaddr + WC_MASK1); +} + +static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int res; + struct wctdm *wc; + struct wctdm_desc *d = (struct wctdm_desc *)ent->driver_data; + int x; + int y; + + static int initd_ifaces=0; + + if(initd_ifaces){ + memset((void *)ifaces,0,(sizeof(struct wctdm *))*WC_MAX_IFACES); + initd_ifaces=1; + } + for (x=0;x= WC_MAX_IFACES) { + printk("Too many interfaces\n"); + return -EIO; + } + + if (pci_enable_device(pdev)) { + res = -EIO; + } else { + wc = kmalloc(sizeof(struct wctdm), GFP_KERNEL); + if (wc) { + int cardcount = 0; + + //wc->offset = 12; // miaolin add. + wc->lastchan = -1; // first channel offset = -1; + wc->ledstate = 0; + + ifaces[x] = wc; + memset(wc, 0, sizeof(struct wctdm)); + spin_lock_init(&wc->lock); + wc->curcard = -1; + wc->ioaddr = pci_resource_start(pdev, 0); + wc->mem_region = pci_resource_start(pdev, 1); + wc->mem_len = pci_resource_len(pdev, 1); + wc->mem32 = (unsigned long)ioremap(wc->mem_region, wc->mem_len); + wc->dev = pdev; + wc->pos = x; + wc->variety = d->name; + for (y=0;yflags[y] = d->flags; + /* Keep track of whether we need to free the region */ + if (request_region(wc->ioaddr, 0xff, "opvxa1200")) + wc->freeregion = 1; + else + wc->freeregion = 0; + + if (request_mem_region(wc->mem_region, wc->mem_len, "opvxa1200")) + wc->freeregion |= 0x02; + + /* Allocate enough memory for two zt chunks, receive and transmit. Each sample uses + 8 bits. */ + wc->writechunk = pci_alloc_consistent(pdev, ZT_MAX_CHUNKSIZE * (NUM_CARDS+NUM_FLAG) * 2 * 2, &wc->writedma); + if (!wc->writechunk) { + printk("opvxa1200: Unable to allocate DMA-able memory\n"); + if (wc->freeregion & 0x01) + release_region(wc->ioaddr, 0xff); + if (wc->freeregion & 0x02); + { + release_mem_region(wc->mem_region, wc->mem_len); + iounmap((void *)wc->mem32); + } + return -ENOMEM; + } + + wc->readchunk = wc->writechunk + ZT_MAX_CHUNKSIZE * (NUM_CARDS+NUM_FLAG) * 2; /* in bytes */ + wc->readdma = wc->writedma + ZT_MAX_CHUNKSIZE * (NUM_CARDS+NUM_FLAG) * 2; /* in bytes */ + + if (wctdm_initialize(wc)) { + printk("opvxa1200: Unable to intialize FXS\n"); + /* Set Reset Low */ + x=inb(wc->ioaddr + WC_CNTL); + outb((~0x1)&x, wc->ioaddr + WC_CNTL); + /* Free Resources */ + free_irq(pdev->irq, wc); + if (wc->freeregion & 0x01) + release_region(wc->ioaddr, 0xff); + if (wc->freeregion & 0x02); + { + release_mem_region(wc->mem_region, wc->mem_len); + iounmap((void *)wc->mem32); + } + pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * (NUM_CARDS+NUM_FLAG) * 2 * 2, (void *)wc->writechunk, wc->writedma); + kfree(wc); + return -EIO; + } + + /* Enable bus mastering */ + pci_set_master(pdev); + + /* Keep track of which device we are */ + pci_set_drvdata(pdev, wc); + + if (request_irq(pdev->irq, wctdm_interrupt, SA_SHIRQ, "opvxa1200", wc)) { + printk("opvxa1200: Unable to request IRQ %d\n", pdev->irq); + if (wc->freeregion & 0x01) + release_region(wc->ioaddr, 0xff); + if (wc->freeregion & 0x02); + { + release_mem_region(wc->mem_region, wc->mem_len); + iounmap((void *)wc->mem32); + } + pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * (NUM_CARDS+NUM_FLAG) * 2 * 2, (void *)wc->writechunk, wc->writedma); + pci_set_drvdata(pdev, NULL); + kfree(wc); + return -EIO; + } + + + if (wctdm_hardware_init(wc)) { + unsigned char x; + + /* Set Reset Low */ + x=inb(wc->ioaddr + WC_CNTL); + outb((~0x1)&x, wc->ioaddr + WC_CNTL); + /* Free Resources */ + free_irq(pdev->irq, wc); + if (wc->freeregion & 0x01) + release_region(wc->ioaddr, 0xff); + if (wc->freeregion & 0x02); + { + release_mem_region(wc->mem_region, wc->mem_len); + iounmap((void *)wc->mem32); + } + pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * (NUM_CARDS+NUM_FLAG) * 2 * 2, (void *)wc->writechunk, wc->writedma); + pci_set_drvdata(pdev, NULL); + zt_unregister(&wc->span); + kfree(wc); + return -EIO; + + } + +#ifdef TEST_LOG_INCOME_VOICE + for(i=0; ivoc_buf[i] = kmalloc(voc_buffer_size, GFP_KERNEL); + wc->voc_ptr[i] = 0; + } +#endif + + wctdm_post_initialize(wc); + + /* Enable interrupts */ + wctdm_enable_interrupts(wc); + /* Initialize Write/Buffers to all blank data */ + memset((void *)wc->writechunk,0, ZT_MAX_CHUNKSIZE * (NUM_CARDS+NUM_FLAG) * 2 * 2); + + /* Start DMA */ + wctdm_start_dma(wc); + + for (x = 0; x < NUM_CARDS; x++) { + if (wc->cardflag & (1 << x)) + cardcount++; + } + + printk("Found a OpenVox A1200P: Version %01x.%01x (%d modules)\n", wc->fwversion>>4, wc->fwversion&0x0f, cardcount); + + res = 0; + } else + res = -ENOMEM; + } + return res; +} + +static void wctdm_release(struct wctdm *wc) +{ +#ifdef TEST_LOG_INCOME_VOICE + struct file * f = NULL; + mm_segment_t orig_fs; + int i; + char fname[20]; +#endif + + zt_unregister(&wc->span); + if (wc->freeregion & 0x01) + release_region(wc->ioaddr, 0xff); + if (wc->freeregion & 0x02); + { + release_mem_region(wc->mem_region, wc->mem_len); + iounmap((void *)wc->mem32); + } + +#ifdef TEST_LOG_INCOME_VOICE + for(i=0; if_op || !f->f_op->read) + { + printk("WARNING: File (read) object is a null pointer!!!\n"); + continue; + } + + f->f_pos = 0; + + orig_fs = get_fs(); + set_fs(KERNEL_DS); + + if(wc->voc_buf[i]) + { + f->f_op->write(f, wc->voc_buf[i], voc_buffer_size, &f->f_pos); + kfree(wc->voc_buf[i]); + } + + set_fs(orig_fs); + fput(f); + } +#endif + + kfree(wc); + printk("Freed a OpenVox A1200 card\n"); +} + +static void __devexit wctdm_remove_one(struct pci_dev *pdev) +{ + struct wctdm *wc = pci_get_drvdata(pdev); + if (wc) { + + /* Stop any DMA */ + wctdm_stop_dma(wc); + wctdm_reset_tdm(wc); + + /* In case hardware is still there */ + wctdm_disable_interrupts(wc); + + /* Immediately free resources */ + pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * (NUM_CARDS+NUM_FLAG) * 2 * 2, (void *)wc->writechunk, wc->writedma); + free_irq(pdev->irq, wc); + + /* Reset PCI chip and registers */ + if(wc->fwversion > 0x11) + outb(0x0e, wc->ioaddr + WC_CNTL); + else + { + wc->ledstate = 0; + wctdm_set_led(wc,0,0); // power off all leds. + } + + /* Release span, possibly delayed */ + if (!wc->usecount) + wctdm_release(wc); + else + wc->dead = 1; + } +} + +static struct pci_device_id wctdm_pci_tbl[] = { + { 0xe159, 0x0001, 0x9100, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme }, + { 0xe159, 0x0001, 0x9519, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme }, + { 0xe159, 0x0001, 0x95D9, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme }, + { 0xe159, 0x0001, 0x8519, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, wctdm_pci_tbl); + +static struct pci_driver wctdm_driver = { + name: "opvxa1200", + probe: wctdm_init_one, +#ifdef LINUX26 + remove: __devexit_p(wctdm_remove_one), +#else + remove: wctdm_remove_one, +#endif + suspend: NULL, + resume: NULL, + id_table: wctdm_pci_tbl, +}; + +static int __init wctdm_init(void) +{ + int res; + int x; + for (x=0;x<(sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) { + if (!strcmp(fxo_modes[x].name, opermode)) + break; + } + if (x < sizeof(fxo_modes) / sizeof(fxo_modes[0])) { + _opermode = x; + } else { + printk("Invalid/unknown operating mode '%s' specified. Please choose one of:\n", opermode); + for (x=0;x"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +module_init(wctdm_init); +module_exit(wctdm_cleanup);