diff options
Diffstat (limited to 'main/dahdi-linux-hardened/dahdi-zaphfc.patch')
-rw-r--r-- | main/dahdi-linux-hardened/dahdi-zaphfc.patch | 1429 |
1 files changed, 1429 insertions, 0 deletions
diff --git a/main/dahdi-linux-hardened/dahdi-zaphfc.patch b/main/dahdi-linux-hardened/dahdi-zaphfc.patch new file mode 100644 index 0000000000..931c5b5cf6 --- /dev/null +++ b/main/dahdi-linux-hardened/dahdi-zaphfc.patch @@ -0,0 +1,1429 @@ +Index: dahdi-linux-2.1.0/drivers/dahdi/zaphfc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ dahdi-linux-2.1.0/drivers/dahdi/zaphfc.c 2008-12-10 12:46:14.000000000 +0200 +@@ -0,0 +1,1129 @@ ++/* ++ * zaphfc.c - Zaptel driver for HFC-S PCI A based ISDN BRI cards ++ * ++ * kernel module inspired by HFC PCI ISDN4Linux and Zaptel drivers ++ * ++ * Copyright (C) 2002, 2003, 2004, 2005 Junghanns.NET GmbH ++ * ++ * Klaus-Peter Junghanns <kpj@junghanns.net> ++ * ++ * This program is free software and may be modified and ++ * distributed under the terms of the GNU Public License. ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#ifdef RTAITIMING ++#include <asm/io.h> ++#include <rtai.h> ++#include <rtai_sched.h> ++#include <rtai_fifos.h> ++#endif ++#include <linux/pci.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++#include <dahdi/kernel.h> ++#include "zaphfc.h" ++ ++#include <linux/moduleparam.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 DEFINE_SPINLOCK(registerlock); ++ ++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) { ++ dahdi_unregister(&hfctmp->ztdev->span); ++ kfree(hfctmp->ztdev); ++ printk(KERN_INFO "unregistered from DAHDI.\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 = DAHDI_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 = DAHDI_CHUNKSIZE; ++ ++ if (bytes < DAHDI_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,DAHDI_CHUNKSIZE,bytes); ++#endif ++ return; ++ } ++ ++ /* allowing the buffering of hfc_BCHAN_BUFFER bytes of audio data works around irq jitter */ ++ if (bytes > hfc_BCHAN_BUFFER + DAHDI_CHUNKSIZE) { ++ /* if the system is too slow to handle it, we will have to drop it all (except 1 DAHDI chunk) */ ++ drop = bytes - DAHDI_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) { ++ dahdi_ec_chunk(&hfctmp->ztdev->chans[0], hfctmp->ztdev->chans[0].readchunk, hfctmp->ztdev->chans[0].writechunk); ++ } else { ++ dahdi_ec_chunk(&hfctmp->ztdev->chans[1], hfctmp->ztdev->chans[1].readchunk, hfctmp->ztdev->chans[1].writechunk); ++ } ++ return; ++} ++ ++ ++static void hfc_dtrans(struct hfc_card *hfctmp) { ++ // we are called with irqs disabled from the irq handler ++ int x; ++ int count, maxlen, total; ++ unsigned char *f1, *f2, newf1; ++ unsigned short *z1, *z2, newz1; ++ int frames, freebytes; ++ ++ if (hfctmp->ztdev->chans[2].bytes2transmit == 0) { ++ return; ++ } ++ ++ f1 = (char *)(hfctmp->fifos + hfc_FIFO_DTX_F1); ++ f2 = (char *)(hfctmp->fifos + hfc_FIFO_DTX_F2); ++ z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z1 + (*f1 * 4)); ++ z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z2 + (*f1 * 4)); ++ ++ frames = (*f1 - *f2) & hfc_FMASK; ++ if (frames < 0) { ++ frames += hfc_MAX_DFRAMES + 1; ++ } ++ ++ if (frames >= hfc_MAX_DFRAMES) { ++ printk(KERN_CRIT "zaphfc: dchan tx fifo total number of frames exceeded!\n"); ++ return; ++ } ++ ++ freebytes = *z2 - *z1; ++ if (freebytes <= 0) { ++ freebytes += hfc_D_FIFO_SIZE; ++ } ++ count = hfctmp->ztdev->chans[2].bytes2transmit; ++ ++ total = count; ++ if (freebytes < count) { ++ printk(KERN_CRIT "zaphfc: dchan tx fifo not enough free bytes! (z1=%d, z2=%d)\n",*z1,*z2); ++ return; ++ } ++ ++ newz1 = (*z1 + count) & hfc_ZMASK; ++ newf1 = ((*f1 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1); // next frame ++ ++ if (count > 0) { ++ if (debug) { ++ printk(KERN_CRIT "zaphfc: card %d TX [ ", hfctmp->cardno); ++ for (x=0; x<count; x++) { ++ printk("%#2x ",hfctmp->dtransbuf[x]); ++ } ++ if (hfctmp->ztdev->chans[2].eoftx == 1) { ++ printk("] %d bytes\n", count); ++ } else { ++ printk("..] %d bytes\n", count); ++ } ++ } ++ maxlen = hfc_D_FIFO_SIZE - *z1; ++ if (maxlen > count) { ++ maxlen = count; ++ } ++ memcpy((char *)(hfctmp->fifos + hfc_FIFO_DTX_ZOFF + *z1),hfctmp->ztdev->chans[2].writechunk, maxlen); ++ count -= maxlen; ++ if (count > 0) { ++ memcpy((char *)(hfctmp->fifos + hfc_FIFO_DTX_ZOFF),(char *)(hfctmp->ztdev->chans[2].writechunk + maxlen), count); ++ } ++ } ++ ++ *z1 = newz1; ++ ++ if (hfctmp->ztdev->chans[2].eoftx == 1) { ++ *f1 = newf1; ++ z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z1 + (*f1 * 4)); ++ *z1 = newz1; ++ hfctmp->ztdev->chans[2].eoftx = 0; ++ } ++// printk(KERN_CRIT "zaphfc: dchan tx fifo (f1=%d, f2=%d, z1=%d, z2=%d)\n",(*f1) & hfc_FMASK,(*f2) & hfc_FMASK, *z1, *z2); ++ return; ++} ++ ++/* receive a complete hdlc frame, skip broken or short frames */ ++static void hfc_drec(struct hfc_card *hfctmp) { ++ int count=0, maxlen=0, framelen=0; ++ unsigned char *f1, *f2, *crcstat; ++ unsigned short *z1, *z2, oldz2, newz2; ++ ++ hfctmp->ztdev->chans[2].bytes2receive=0; ++ hfctmp->ztdev->chans[2].eofrx = 0; ++ ++ /* put the received data into the DAHDI buffer ++ we'll call dahdi_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 ++DAHDI_IRQ_HANDLER(hfc_interrupt) { ++ struct hfc_card *hfctmp = dev_id; ++ unsigned long flags = 0; ++ unsigned char stat; ++#else ++static void hfc_service(struct hfc_card *hfctmp) { ++#endif ++ struct dahdi_hfc *zthfc; ++ unsigned char s1, s2, l1state; ++ int x; ++ ++ if (!hfctmp) { ++#ifndef RTAITIMING ++ return IRQ_NONE; ++#else ++ /* rtai */ ++ return; ++#endif ++ } ++ ++ if (!hfctmp->pci_io) { ++ printk(KERN_WARNING "%s: IO-mem disabled, cannot handle interrupt\n", ++ __FUNCTION__); ++#ifndef RTAITIMING ++ return IRQ_NONE; ++#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); ++ return IRQ_NONE; ++ } ++#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 DAHDI timing :) ++#endif ++ hfctmp->ticks = 0; ++ ++ if (hfctmp->ztdev->span.flags & DAHDI_FLAG_RUNNING) { ++ // clear dchan buffer ++ hfctmp->ztdev->chans[2].bytes2transmit = 0; ++ hfctmp->ztdev->chans[2].maxbytes2transmit = hfc_D_FIFO_SIZE; ++ ++ dahdi_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 DAHDI receive nothing ++ hfctmp->ztdev->chans[2].bytes2receive = 0; ++ } ++ if (hfctmp->ztdev->span.flags & DAHDI_FLAG_RUNNING) { ++ dahdi_receive(&(hfctmp->ztdev->span)); ++ } ++ ++#ifndef RTAITIMING ++ } ++#endif ++ } ++ ++ } ++#ifndef RTAITIMING ++ spin_unlock_irqrestore(&hfctmp->lock,flags); ++ return IRQ_RETVAL(1); ++#endif ++} ++ ++ ++static int zthfc_open(struct dahdi_chan *chan) { ++ struct dahdi_hfc *zthfc = chan->pvt; ++ struct hfc_card *hfctmp = zthfc->card; ++ ++ if (!hfctmp) { ++ return 0; ++ } ++ try_module_get(THIS_MODULE); ++ return 0; ++} ++ ++static int zthfc_close(struct dahdi_chan *chan) { ++ struct dahdi_hfc *zthfc = chan->pvt; ++ struct hfc_card *hfctmp = zthfc->card; ++ ++ if (!hfctmp) { ++ return 0; ++ } ++ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static int zthfc_rbsbits(struct dahdi_chan *chan, int bits) { ++ return 0; ++} ++ ++static int zthfc_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) { ++ switch(cmd) { ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int zthfc_startup(struct dahdi_span *span) { ++ struct dahdi_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 & DAHDI_FLAG_RUNNING; ++ ++ if (!alreadyrunning) { ++ span->chans[2]->flags &= ~DAHDI_FLAG_HDLC; ++ span->chans[2]->flags |= DAHDI_FLAG_BRIDCHAN; ++ ++ span->flags |= DAHDI_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 dahdi_span *span) { ++ return 0; ++} ++ ++static int zthfc_maint(struct dahdi_span *span, int cmd) { ++ return 0; ++} ++ ++static int zthfc_chanconfig(struct dahdi_chan *chan, int sigtype) { ++// printk(KERN_CRIT "chan_config sigtype=%d\n", sigtype); ++ return 0; ++} ++ ++static int zthfc_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc) { ++ span->lineconfig = lc->lineconfig; ++ return 0; ++} ++ ++static int zthfc_initialize(struct dahdi_hfc *zthfc) { ++ struct hfc_card *hfctmp = zthfc->card; ++ int i; ++ ++ memset(&zthfc->span, 0x0, sizeof(struct dahdi_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.channels = 3; ++ zthfc->span.chans = zthfc->_chans; ++ for (i = 0; i < zthfc->span.channels; i++) ++ zthfc->_chans[i] = &zthfc->chans[i]; ++ ++ zthfc->span.deflaw = DAHDI_LAW_ALAW; ++ zthfc->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_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 dahdi_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 = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_SF; ++ zthfc->chans[i].chanpos = i + 1; ++ } ++ ++ if (dahdi_register(&zthfc->span,0)) { ++ printk(KERN_CRIT "unable to register DAHDI device!\n"); ++ return -1; ++ } ++// printk(KERN_CRIT "zaphfc: registered DAHDI 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 dahdi_hfc *zthfc = NULL; ++ ++ tmp = pci_get_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, IRQF_SHARED, "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 dahdi_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 dahdi_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_get_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 ++ ++ ++module_param(modes, int, 0600); ++module_param(debug, int, 0600); ++ ++MODULE_DESCRIPTION("HFC-S PCI A Zaptel Driver"); ++MODULE_AUTHOR("Klaus-Peter Junghanns <kpj@junghanns.net>"); ++#ifdef MODULE_LICENSE ++MODULE_LICENSE("GPL"); ++#endif +Index: dahdi-linux-2.1.0/drivers/dahdi/zaphfc.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ dahdi-linux-2.1.0/drivers/dahdi/zaphfc.h 2008-12-10 12:46:14.000000000 +0200 +@@ -0,0 +1,290 @@ ++/* ++ * zaphfc.h - Zaptel driver for HFC-S PCI A based ISDN BRI cards ++ * ++ * kernel module based on HFC PCI ISDN4Linux and Zaptel drivers ++ * ++ * Copyright (C) 2002, 2003, 2004, 2005 Junghanns.NET GmbH ++ * ++ * Klaus-Peter Junghanns <kpj@junghanns.net> ++ * ++ * This program is free software and may be modified and ++ * distributed under the terms of the GNU Public License. ++ * ++ */ ++ ++/* HFC register addresses - accessed using memory mapped I/O */ ++/* For a list, see datasheet section 3.2.1 at page 21 */ ++ ++#define hfc_outb(a,b,c) (writeb((c),(a)->pci_io+(b))) ++#define hfc_inb(a,b) (readb((a)->pci_io+(b))) ++ ++/* GCI/IOM bus monitor registers */ ++ ++#define hfc_C_I 0x08 ++#define hfc_TRxR 0x0C ++#define hfc_MON1_D 0x28 ++#define hfc_MON2_D 0x2C ++ ++ ++/* GCI/IOM bus timeslot registers */ ++ ++#define hfc_B1_SSL 0x80 ++#define hfc_B2_SSL 0x84 ++#define hfc_AUX1_SSL 0x88 ++#define hfc_AUX2_SSL 0x8C ++#define hfc_B1_RSL 0x90 ++#define hfc_B2_RSL 0x94 ++#define hfc_AUX1_RSL 0x98 ++#define hfc_AUX2_RSL 0x9C ++ ++/* GCI/IOM bus data registers */ ++ ++#define hfc_B1_D 0xA0 ++#define hfc_B2_D 0xA4 ++#define hfc_AUX1_D 0xA8 ++#define hfc_AUX2_D 0xAC ++ ++/* GCI/IOM bus configuration registers */ ++ ++#define hfc_MST_EMOD 0xB4 ++#define hfc_MST_MODE 0xB8 ++#define hfc_CONNECT 0xBC ++ ++ ++/* Interrupt and status registers */ ++ ++#define hfc_FIFO_EN 0x44 ++#define hfc_TRM 0x48 ++#define hfc_B_MODE 0x4C ++#define hfc_CHIP_ID 0x58 ++#define hfc_CIRM 0x60 ++#define hfc_CTMT 0x64 ++#define hfc_INT_M1 0x68 ++#define hfc_INT_M2 0x6C ++#define hfc_INT_S1 0x78 ++#define hfc_INT_S2 0x7C ++#define hfc_STATUS 0x70 ++ ++/* S/T section registers */ ++ ++#define hfc_STATES 0xC0 ++#define hfc_SCTRL 0xC4 ++#define hfc_SCTRL_E 0xC8 ++#define hfc_SCTRL_R 0xCC ++#define hfc_SQ 0xD0 ++#define hfc_CLKDEL 0xDC ++#define hfc_B1_REC 0xF0 ++#define hfc_B1_SEND 0xF0 ++#define hfc_B2_REC 0xF4 ++#define hfc_B2_SEND 0xF4 ++#define hfc_D_REC 0xF8 ++#define hfc_D_SEND 0xF8 ++#define hfc_E_REC 0xFC ++ ++/* Bits and values in various HFC PCI registers */ ++ ++/* bits in status register (READ) */ ++#define hfc_STATUS_PCI_PROC 0x02 ++#define hfc_STATUS_NBUSY 0x04 ++#define hfc_STATUS_TIMER_ELAP 0x10 ++#define hfc_STATUS_STATINT 0x20 ++#define hfc_STATUS_FRAMEINT 0x40 ++#define hfc_STATUS_ANYINT 0x80 ++ ++/* bits in CTMT (Write) */ ++#define hfc_CTMT_CLTIMER 0x80 ++#define hfc_CTMT_TIM3_125 0x04 ++#define hfc_CTMT_TIM25 0x10 ++#define hfc_CTMT_TIM50 0x14 ++#define hfc_CTMT_TIM400 0x18 ++#define hfc_CTMT_TIM800 0x1C ++#define hfc_CTMT_AUTO_TIMER 0x20 ++#define hfc_CTMT_TRANSB2 0x02 ++#define hfc_CTMT_TRANSB1 0x01 ++ ++/* bits in CIRM (Write) */ ++#define hfc_CIRM_AUX_MSK 0x07 ++#define hfc_CIRM_RESET 0x08 ++#define hfc_CIRM_B1_REV 0x40 ++#define hfc_CIRM_B2_REV 0x80 ++ ++/* bits in INT_M1 and INT_S1 */ ++#define hfc_INTS_B1TRANS 0x01 ++#define hfc_INTS_B2TRANS 0x02 ++#define hfc_INTS_DTRANS 0x04 ++#define hfc_INTS_B1REC 0x08 ++#define hfc_INTS_B2REC 0x10 ++#define hfc_INTS_DREC 0x20 ++#define hfc_INTS_L1STATE 0x40 ++#define hfc_INTS_TIMER 0x80 ++ ++/* bits in INT_M2 */ ++#define hfc_M2_PROC_TRANS 0x01 ++#define hfc_M2_GCI_I_CHG 0x02 ++#define hfc_M2_GCI_MON_REC 0x04 ++#define hfc_M2_IRQ_ENABLE 0x08 ++#define hfc_M2_PMESEL 0x80 ++ ++/* bits in STATES */ ++#define hfc_STATES_STATE_MASK 0x0F ++#define hfc_STATES_LOAD_STATE 0x10 ++#define hfc_STATES_ACTIVATE 0x20 ++#define hfc_STATES_DO_ACTION 0x40 ++#define hfc_STATES_NT_G2_G3 0x80 ++ ++/* bits in HFCD_MST_MODE */ ++#define hfc_MST_MODE_MASTER 0x01 ++#define hfc_MST_MODE_SLAVE 0x00 ++/* remaining bits are for codecs control */ ++ ++/* bits in HFCD_SCTRL */ ++#define hfc_SCTRL_B1_ENA 0x01 ++#define hfc_SCTRL_B2_ENA 0x02 ++#define hfc_SCTRL_MODE_TE 0x00 ++#define hfc_SCTRL_MODE_NT 0x04 ++#define hfc_SCTRL_LOW_PRIO 0x08 ++#define hfc_SCTRL_SQ_ENA 0x10 ++#define hfc_SCTRL_TEST 0x20 ++#define hfc_SCTRL_NONE_CAP 0x40 ++#define hfc_SCTRL_PWR_DOWN 0x80 ++ ++/* bits in SCTRL_E */ ++#define hfc_SCTRL_E_AUTO_AWAKE 0x01 ++#define hfc_SCTRL_E_DBIT_1 0x04 ++#define hfc_SCTRL_E_IGNORE_COL 0x08 ++#define hfc_SCTRL_E_CHG_B1_B2 0x80 ++ ++/* bits in FIFO_EN register */ ++#define hfc_FIFOEN_B1TX 0x01 ++#define hfc_FIFOEN_B1RX 0x02 ++#define hfc_FIFOEN_B2TX 0x04 ++#define hfc_FIFOEN_B2RX 0x08 ++#define hfc_FIFOEN_DTX 0x10 ++#define hfc_FIFOEN_DRX 0x20 ++ ++#define hfc_FIFOEN_B1 (hfc_FIFOEN_B1TX|hfc_FIFOEN_B1RX) ++#define hfc_FIFOEN_B2 (hfc_FIFOEN_B2TX|hfc_FIFOEN_B2RX) ++#define hfc_FIFOEN_D (hfc_FIFOEN_DTX|hfc_FIFOEN_DRX) ++ ++/* bits in the CONNECT register */ ++#define hfc_CONNECT_B1_shift 0 ++#define hfc_CONNECT_B2_shift 3 ++ ++#define hfc_CONNECT_HFC_from_ST 0x0 ++#define hfc_CONNECT_HFC_from_GCI 0x1 ++#define hfc_CONNECT_ST_from_HFC 0x0 ++#define hfc_CONNECT_ST_from_GCI 0x2 ++#define hfc_CONNECT_GCI_from_HFC 0x0 ++#define hfc_CONNECT_GCI_from_ST 0x4 ++ ++/* bits in the __SSL and __RSL registers */ ++#define hfc_SRSL_STIO 0x40 ++#define hfc_SRSL_ENABLE 0x80 ++#define hfc_SRCL_SLOT_MASK 0x1f ++ ++/* FIFO memory definitions */ ++ ++#define hfc_FMASK 0x000f ++#define hfc_ZMASK 0x01ff ++#define hfc_ZMASKB 0x1fff ++ ++#define hfc_D_FIFO_SIZE 0x0200 ++#define hfc_B_SUB_VAL 0x0200 ++#define hfc_B_FIFO_SIZE 0x1E00 ++#define hfc_MAX_DFRAMES 0x000f ++ ++#define hfc_FIFO_DTX_Z1 0x2080 ++#define hfc_FIFO_DTX_Z2 0x2082 ++#define hfc_FIFO_DTX_F1 0x20a0 ++#define hfc_FIFO_DTX_F2 0x20a1 ++#define hfc_FIFO_DTX 0x0000 ++#define hfc_FIFO_DTX_ZOFF 0x000 ++ ++#define hfc_FIFO_DRX_Z1 0x6080 ++#define hfc_FIFO_DRX_Z2 0x6082 ++#define hfc_FIFO_DRX_F1 0x60a0 ++#define hfc_FIFO_DRX_F2 0x60a1 ++#define hfc_FIFO_DRX 0x4000 ++#define hfc_FIFO_DRX_ZOFF 0x4000 ++ ++#define hfc_FIFO_B1TX_Z1 0x2000 ++#define hfc_FIFO_B1TX_Z2 0x2002 ++#define hfc_FIFO_B1RX_Z1 0x6000 ++#define hfc_FIFO_B1RX_Z2 0x6002 ++ ++#define hfc_FIFO_B1TX_F1 0x2080 ++#define hfc_FIFO_B1TX_F2 0x2081 ++#define hfc_FIFO_B1RX_F1 0x6080 ++#define hfc_FIFO_B1RX_F2 0x6081 ++ ++#define hfc_FIFO_B1RX_ZOFF 0x4000 ++#define hfc_FIFO_B1TX_ZOFF 0x0000 ++ ++#define hfc_FIFO_B2TX_Z1 0x2100 ++#define hfc_FIFO_B2TX_Z2 0x2102 ++#define hfc_FIFO_B2RX_Z1 0x6100 ++#define hfc_FIFO_B2RX_Z2 0x6102 ++ ++#define hfc_FIFO_B2TX_F1 0x2180 ++#define hfc_FIFO_B2TX_F2 0x2181 ++#define hfc_FIFO_B2RX_F1 0x6180 ++#define hfc_FIFO_B2RX_F2 0x6181 ++ ++#define hfc_FIFO_B2RX_ZOFF 0x6000 ++#define hfc_FIFO_B2TX_ZOFF 0x2000 ++ ++#define hfc_BTRANS_THRESHOLD 128 ++#define hfc_BTRANS_THRESMASK 0x00 ++ ++/* Structures */ ++ ++typedef struct hfc_regs { ++ unsigned char fifo_en; ++ unsigned char ctmt; ++ unsigned char int_m1; ++ unsigned char int_m2; ++ unsigned char sctrl; ++ unsigned char sctrl_e; ++ unsigned char sctrl_r; ++ unsigned char connect; ++ unsigned char trm; ++ unsigned char mst_mode; ++ unsigned char bswapped; ++ unsigned char nt_mode; ++ unsigned char int_drec; ++} hfc_regs; ++ ++typedef struct hfc_card { ++ spinlock_t lock; ++ unsigned int irq; ++ unsigned int iomem; ++ int ticks; ++ int clicks; ++ unsigned char *pci_io; ++ void *fifomem; // start of the shared mem ++ volatile void *fifos; // 32k aligned mem for the fifos ++ struct hfc_regs regs; ++ unsigned int pcibus; ++ unsigned int pcidevfn; ++ struct pci_dev *pcidev; ++ struct dahdi_hfc *ztdev; ++ int drecinframe; ++ unsigned char drecbuf[hfc_D_FIFO_SIZE]; ++ unsigned char dtransbuf[hfc_D_FIFO_SIZE]; ++ unsigned char brecbuf[2][DAHDI_CHUNKSIZE]; ++ unsigned char btransbuf[2][DAHDI_CHUNKSIZE]; ++ unsigned char cardno; ++ struct hfc_card *next; ++} hfc_card; ++ ++typedef struct dahdi_hfc { ++ unsigned int usecount; ++ struct dahdi_span span; ++ struct dahdi_chan chans[3]; ++ struct dahdi_chan *_chans[3]; ++ struct hfc_card *card; ++} dahdi_hfc; ++ ++/* tune this */ ++#define hfc_BCHAN_BUFFER 8 ++#define hfc_MAX_CARDS 8 |