diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-09 15:27:39 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-09 15:27:39 -0800 |
commit | 2fb585a10e421b4eeae066eb99080bd7e4512079 (patch) | |
tree | b8ca32933de26e9198490acfb5a4df093fdd8ef9 | |
parent | 31aeb6c815549948571eec988ad9728c27d7a68d (diff) | |
parent | 69f52adb2d534afc41fcc658f155e01f0b322f9e (diff) |
Merge branch 'for_2.6.29' of git://git.kernel.org/pub/scm/linux/kernel/git/kkeil/ISDN-2.6
* 'for_2.6.29' of git://git.kernel.org/pub/scm/linux/kernel/git/kkeil/ISDN-2.6: (28 commits)
mISDN: Add HFC USB driver
mISDN: Add layer1 prim MPH_INFORMATION_REQ
mISDN: Fix kernel crash when doing hardware conference with more than two members
mISDN: Added missing create_l1() call
mISDN: Add MODULE_DEVICE_TABLE() to hfcpci
mISDN: Minor cleanups
mISDN: Create /sys/class/mISDN
mISDN: Add missing release functions
mISDN: Add different different timer settings for hfc-pci
mISDN: Minor fixes
mISDN: Correct busy device detection
mISDN: Fix deactivation, if peer IP is removed from l1oip instance.
mISDN: Add ISDN_P_TE_UP0 / ISDN_P_NT_UP0
mISDN: Fix irq detection
mISDN: Add ISDN sample clock API to mISDN core
mISDN: Return error on E-channel access
mISDN: Add E-Channel logging features
mISDN: Use protocol to detect D-channel
mISDN: Fixed more indexing bugs
mISDN: Make debug output a little bit more verbose
...
24 files changed, 3734 insertions, 379 deletions
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index 14793480c45..fd112ae252c 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -23,3 +23,10 @@ config MISDN_HFCMULTI * HFC-8S (8 S/T interfaces on one chip) * HFC-E1 (E1 interface for 2Mbit ISDN) +config MISDN_HFCUSB + tristate "Support for HFC-S USB based TAs" + depends on USB + help + Enable support for USB ISDN TAs with Cologne Chip AG's + HFC-S USB ISDN Controller + diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 1e7ca5332ad..b0403526bbb 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o +obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index 7bbf7300593..663b77f578b 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -2,10 +2,6 @@ * see notice in hfc_multi.c */ -extern void ztdummy_extern_interrupt(void); -extern void ztdummy_register_interrupt(void); -extern int ztdummy_unregister_interrupt(void); - #define DEBUG_HFCMULTI_FIFO 0x00010000 #define DEBUG_HFCMULTI_CRC 0x00020000 #define DEBUG_HFCMULTI_INIT 0x00040000 @@ -13,6 +9,7 @@ extern int ztdummy_unregister_interrupt(void); #define DEBUG_HFCMULTI_MODE 0x00100000 #define DEBUG_HFCMULTI_MSG 0x00200000 #define DEBUG_HFCMULTI_STATE 0x00400000 +#define DEBUG_HFCMULTI_FILL 0x00800000 #define DEBUG_HFCMULTI_SYNC 0x01000000 #define DEBUG_HFCMULTI_DTMF 0x02000000 #define DEBUG_HFCMULTI_LOCK 0x80000000 @@ -170,6 +167,8 @@ struct hfc_multi { u_long chip; /* chip configuration */ int masterclk; /* port that provides master clock -1=off */ + unsigned char silence;/* silence byte */ + unsigned char silence_data[128];/* silence block */ int dtmf; /* flag that dtmf is currently in process */ int Flen; /* F-buffer size */ int Zlen; /* Z-buffer size (must be int for calculation)*/ @@ -198,6 +197,9 @@ struct hfc_multi { spinlock_t lock; /* the lock */ + struct mISDNclock *iclock; /* isdn clock support */ + int iclock_on; + /* * the channel index is counted from 0, regardless where the channel * is located on the hfc-channel. diff --git a/drivers/isdn/hardware/mISDN/hfc_pci.h b/drivers/isdn/hardware/mISDN/hfc_pci.h index 5783d22a18f..3132ddc99fc 100644 --- a/drivers/isdn/hardware/mISDN/hfc_pci.h +++ b/drivers/isdn/hardware/mISDN/hfc_pci.h @@ -26,7 +26,7 @@ * change mask and threshold simultaneously */ #define HFCPCI_BTRANS_THRESHOLD 128 -#define HFCPCI_BTRANS_MAX 256 +#define HFCPCI_FILLEMPTY 64 #define HFCPCI_BTRANS_THRESMASK 0x00 /* defines for PCI config */ diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index c63e2f49da8..97f4708b387 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -133,6 +133,12 @@ * Give the value of the clock control register (A_ST_CLK_DLY) * of the S/T interfaces in TE mode. * This register is needed for the TBR3 certification, so don't change it. + * + * clock: + * NOTE: only one clock value must be given once + * Selects interface with clock source for mISDN and applications. + * Set to card number starting with 1. Set to -1 to disable. + * By default, the first card is used as clock source. */ /* @@ -140,7 +146,7 @@ * #define HFC_REGISTER_DEBUG */ -static const char *hfcmulti_revision = "2.02"; +#define HFC_MULTI_VERSION "2.03" #include <linux/module.h> #include <linux/pci.h> @@ -165,10 +171,6 @@ static LIST_HEAD(HFClist); static spinlock_t HFClock; /* global hfc list lock */ static void ph_state_change(struct dchannel *); -static void (*hfc_interrupt)(void); -static void (*register_interrupt)(void); -static int (*unregister_interrupt)(void); -static int interrupt_registered; static struct hfc_multi *syncmaster; static int plxsd_master; /* if we have a master card (yet) */ @@ -184,7 +186,6 @@ static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 }; #define CLKDEL_TE 0x0f /* CLKDEL in TE mode */ #define CLKDEL_NT 0x6c /* CLKDEL in NT mode (0x60 MUST be included!) */ -static u_char silence = 0xff; /* silence by LAW */ #define DIP_4S 0x1 /* DIP Switches for Beronet 1S/2S/4S cards */ #define DIP_8S 0x2 /* DIP Switches for Beronet 8S+ cards */ @@ -195,12 +196,13 @@ static u_char silence = 0xff; /* silence by LAW */ */ static uint type[MAX_CARDS]; -static uint pcm[MAX_CARDS]; -static uint dslot[MAX_CARDS]; +static int pcm[MAX_CARDS]; +static int dslot[MAX_CARDS]; static uint iomode[MAX_CARDS]; static uint port[MAX_PORTS]; static uint debug; static uint poll; +static int clock; static uint timer; static uint clockdelay_te = CLKDEL_TE; static uint clockdelay_nt = CLKDEL_NT; @@ -209,14 +211,16 @@ static int HFC_cnt, Port_cnt, PCM_cnt = 99; MODULE_AUTHOR("Andreas Eversberg"); MODULE_LICENSE("GPL"); +MODULE_VERSION(HFC_MULTI_VERSION); module_param(debug, uint, S_IRUGO | S_IWUSR); module_param(poll, uint, S_IRUGO | S_IWUSR); +module_param(clock, int, S_IRUGO | S_IWUSR); module_param(timer, uint, S_IRUGO | S_IWUSR); module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(pcm, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(dslot, uint, NULL, S_IRUGO | S_IWUSR); +module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR); +module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR); module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); @@ -1419,19 +1423,6 @@ controller_fail: HFC_outb(hc, R_TI_WD, poll_timer); hc->hw.r_irqmsk_misc |= V_TI_IRQMSK; - /* - * set up 125us interrupt, only if function pointer is available - * and module parameter timer is set - */ - if (timer && hfc_interrupt && register_interrupt) { - /* only one chip should use this interrupt */ - timer = 0; - interrupt_registered = 1; - hc->hw.r_irqmsk_misc |= V_PROC_IRQMSK; - /* deactivate other interrupts in ztdummy */ - register_interrupt(); - } - /* set E1 state machine IRQ */ if (hc->type == 1) hc->hw.r_irqmsk_misc |= V_STA_IRQMSK; @@ -1991,6 +1982,17 @@ next_frame: return; /* no data */ } + /* "fill fifo if empty" feature */ + if (bch && test_bit(FLG_FILLEMPTY, &bch->Flags) + && !test_bit(FLG_HDLC, &bch->Flags) && z2 == z1) { + if (debug & DEBUG_HFCMULTI_FILL) + printk(KERN_DEBUG "%s: buffer empty, so we have " + "underrun\n", __func__); + /* fill buffer, to prevent future underrun */ + hc->write_fifo(hc, hc->silence_data, poll >> 1); + Zspace -= (poll >> 1); + } + /* if audio data and connected slot */ if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending) && slot_tx >= 0) { @@ -2027,7 +2029,6 @@ next_frame: __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i, temp ? "HDLC":"TRANS"); - /* Have to prep the audio data */ hc->write_fifo(hc, d, ii - i); *idxp = ii; @@ -2066,7 +2067,7 @@ next_frame: * no more data at all. this prevents sending an undefined value. */ if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) - HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); + HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); } @@ -2583,7 +2584,6 @@ hfcmulti_interrupt(int intno, void *dev_id) static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0, iq5 = 0, iq6 = 0, iqcnt = 0; #endif - static int count; struct hfc_multi *hc = dev_id; struct dchannel *dch; u_char r_irq_statech, status, r_irq_misc, r_irq_oview; @@ -2637,6 +2637,7 @@ hfcmulti_interrupt(int intno, void *dev_id) iqcnt = 0; } #endif + if (!r_irq_statech && !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | V_MISC_IRQSTA | V_FR_IRQSTA))) { @@ -2657,6 +2658,7 @@ hfcmulti_interrupt(int intno, void *dev_id) if (status & V_MISC_IRQSTA) { /* misc IRQ */ r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC); + r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */ if (r_irq_misc & V_STA_IRQ) { if (hc->type == 1) { /* state machine */ @@ -2691,23 +2693,20 @@ hfcmulti_interrupt(int intno, void *dev_id) plxsd_checksync(hc, 0); } } - if (r_irq_misc & V_TI_IRQ) + if (r_irq_misc & V_TI_IRQ) { + if (hc->iclock_on) + mISDN_clock_update(hc->iclock, poll, NULL); handle_timer_irq(hc); + } if (r_irq_misc & V_DTMF_IRQ) { - /* -> DTMF IRQ */ hfcmulti_dtmf(hc); } - /* TODO: REPLACE !!!! 125 us Interrupts are not acceptable */ if (r_irq_misc & V_IRQ_PROC) { - /* IRQ every 125us */ - count++; - /* generate 1kHz signal */ - if (count == 8) { - if (hfc_interrupt) - hfc_interrupt(); - count = 0; - } + static int irq_proc_cnt; + if (!irq_proc_cnt++) + printk(KERN_WARNING "%s: got V_IRQ_PROC -" + " this should not happen\n", __func__); } } @@ -2954,7 +2953,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); HFC_wait(hc); /* tx silence */ - HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); + HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + ((ch % 4) * 4)) << 1); HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1)); @@ -2969,7 +2968,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); HFC_wait(hc); /* tx silence */ - HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); + HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); /* enable RX fifo */ HFC_outb(hc, R_FIFO, (ch<<1)|1); HFC_wait(hc); @@ -3461,7 +3460,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP - | MISDN_CTRL_RX_OFF; + | MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY; break; case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ hc->chan[bch->slot].rx_off = !!cq->p1; @@ -3476,6 +3475,12 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n", __func__, bch->nr, hc->chan[bch->slot].rx_off); break; + case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ + test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d " + "off=%d)\n", __func__, bch->nr, !!cq->p1); + break; case MISDN_CTRL_HW_FEATURES: /* fill features structure */ if (debug & DEBUG_HFCMULTI_MSG) printk(KERN_DEBUG "%s: HW_FEATURE request\n", @@ -3992,6 +3997,7 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch, } if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; hc->chan[ch].rx_off = 0; rq->ch = &bch->ch; @@ -4081,6 +4087,15 @@ hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) return err; } +static int +clockctl(void *priv, int enable) +{ + struct hfc_multi *hc = priv; + + hc->iclock_on = enable; + return 0; +} + /* * initialize the card */ @@ -4495,10 +4510,14 @@ release_card(struct hfc_multi *hc) printk(KERN_WARNING "%s: release card (%d) entered\n", __func__, hc->id); + /* unregister clock source */ + if (hc->iclock) + mISDN_unregister_clock(hc->iclock); + + /* disable irq */ spin_lock_irqsave(&hc->lock, flags); disable_hwirq(hc); spin_unlock_irqrestore(&hc->lock, flags); - udelay(1000); /* dimm leds */ @@ -4699,7 +4718,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) } else hc->chan[hc->dslot].jitter = 2; /* default */ snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); - ret = mISDN_register_device(&dch->dev, name); + ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); if (ret) goto free_chan; hc->created[0] = 1; @@ -4807,9 +4826,9 @@ init_multi_port(struct hfc_multi *hc, int pt) test_and_set_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i + 2].cfg); } - snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d/%d", + snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d", hc->type, HFC_cnt + 1, pt + 1); - ret = mISDN_register_device(&dch->dev, name); + ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); if (ret) goto free_chan; hc->created[pt] = 1; @@ -4828,6 +4847,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) struct hfc_multi *hc; u_long flags; u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */ + int i; if (HFC_cnt >= MAX_CARDS) { printk(KERN_ERR "too many cards (max=%d).\n", @@ -4861,11 +4881,11 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) hc->id = HFC_cnt; hc->pcm = pcm[HFC_cnt]; hc->io_mode = iomode[HFC_cnt]; - if (dslot[HFC_cnt] < 0) { + if (dslot[HFC_cnt] < 0 && hc->type == 1) { hc->dslot = 0; printk(KERN_INFO "HFC-E1 card has disabled D-channel, but " "31 B-channels\n"); - } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32) { + } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 && hc->type == 1) { hc->dslot = dslot[HFC_cnt]; printk(KERN_INFO "HFC-E1 card has alternating D-channel on " "time slot %d\n", dslot[HFC_cnt]); @@ -4876,9 +4896,17 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) hc->masterclk = -1; if (type[HFC_cnt] & 0x100) { test_and_set_bit(HFC_CHIP_ULAW, &hc->chip); - silence = 0xff; /* ulaw silence */ + hc->silence = 0xff; /* ulaw silence */ } else - silence = 0x2a; /* alaw silence */ + hc->silence = 0x2a; /* alaw silence */ + if ((poll >> 1) > sizeof(hc->silence_data)) { + printk(KERN_ERR "HFCMULTI error: silence_data too small, " + "please fix\n"); + return -EINVAL; + } + for (i = 0; i < (poll >> 1); i++) + hc->silence_data[i] = hc->silence; + if (!(type[HFC_cnt] & 0x200)) test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); @@ -4945,9 +4973,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) switch (m->dip_type) { case DIP_4S: /* - * get DIP Setting for beroNet 1S/2S/4S cards - * check if Port Jumper config matches - * module param 'protocol' + * Get DIP setting for beroNet 1S/2S/4S cards * DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) + * GPI 19/23 (R_GPI_IN2)) */ @@ -4966,9 +4992,8 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) break; case DIP_8S: /* - * get DIP Setting for beroNet 8S0+ cards - * - * enable PCI auxbridge function + * Get DIP Setting for beroNet 8S0+ cards + * Enable PCI auxbridge function */ HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); /* prepare access to auxport */ @@ -5003,6 +5028,10 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) list_add_tail(&hc->list, &HFClist); spin_unlock_irqrestore(&HFClock, flags); + /* use as clock source */ + if (clock == HFC_cnt + 1) + hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc); + /* initialize hardware */ ret_err = init_card(hc); if (ret_err) { @@ -5137,8 +5166,7 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = { { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */ { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, - /* IOB8ST Recording */ + PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, /* IOB8ST Recording */ { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST */ { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, @@ -5188,18 +5216,16 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct hm_map *m = (struct hm_map *)ent->driver_data; int ret; - if (m == NULL) { - if (ent->vendor == PCI_VENDOR_ID_CCD) - if (ent->device == PCI_DEVICE_ID_CCD_HFC4S || - ent->device == PCI_DEVICE_ID_CCD_HFC8S || - ent->device == PCI_DEVICE_ID_CCD_HFCE1) - printk(KERN_ERR - "unknown HFC multiport controller " - "(vendor:%x device:%x subvendor:%x " - "subdevice:%x) Please contact the " - "driver maintainer for support.\n", - ent->vendor, ent->device, - ent->subvendor, ent->subdevice); + if (m == NULL && ent->vendor == PCI_VENDOR_ID_CCD && ( + ent->device == PCI_DEVICE_ID_CCD_HFC4S || + ent->device == PCI_DEVICE_ID_CCD_HFC8S || + ent->device == PCI_DEVICE_ID_CCD_HFCE1)) { + printk(KERN_ERR + "Unknown HFC multiport controller (vendor:%x device:%x " + "subvendor:%x subdevice:%x)\n", ent->vendor, ent->device, + ent->subvendor, ent->subdevice); + printk(KERN_ERR + "Please contact the driver maintainer for support.\n"); return -ENODEV; } ret = hfcmulti_init(pdev, ent); @@ -5222,22 +5248,9 @@ HFCmulti_cleanup(void) { struct hfc_multi *card, *next; - /* unload interrupt function symbol */ - if (hfc_interrupt) - symbol_put(ztdummy_extern_interrupt); - if (register_interrupt) - symbol_put(ztdummy_register_interrupt); - if (unregister_interrupt) { - if (interrupt_registered) { - interrupt_registered = 0; - unregister_interrupt(); - } - symbol_put(ztdummy_unregister_interrupt); - } - + /* get rid of all devices of this driver */ list_for_each_entry_safe(card, next, &HFClist, list) release_card(card); - /* get rid of all devices of this driver */ pci_unregister_driver(&hfcmultipci_driver); } @@ -5246,8 +5259,10 @@ HFCmulti_init(void) { int err; + printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION); + #ifdef IRQ_DEBUG - printk(KERN_ERR "%s: IRQ_DEBUG IS ENABLED!\n", __func__); + printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__); #endif spin_lock_init(&HFClock); @@ -5256,22 +5271,11 @@ HFCmulti_init(void) if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: init entered\n", __func__); - hfc_interrupt = symbol_get(ztdummy_extern_interrupt); - register_interrupt = symbol_get(ztdummy_register_interrupt); - unregister_interrupt = symbol_get(ztdummy_unregister_interrupt); - printk(KERN_INFO "mISDN: HFC-multi driver %s\n", - hfcmulti_revision); - switch (poll) { case 0: poll_timer = 6; poll = 128; break; - /* - * wenn dieses break nochmal verschwindet, - * gibt es heisse ohren :-) - * "without the break you will get hot ears ???" - */ case 8: poll_timer = 2; break; @@ -5298,20 +5302,12 @@ HFCmulti_init(void) } + if (!clock) + clock = 1; + err = pci_register_driver(&hfcmultipci_driver); if (err < 0) { printk(KERN_ERR "error registering pci driver: %x\n", err); - if (hfc_interrupt) - symbol_put(ztdummy_extern_interrupt); - if (register_interrupt) - symbol_put(ztdummy_register_interrupt); - if (unregister_interrupt) { - if (interrupt_registered) { - interrupt_registered = 0; - unregister_interrupt(); - } - symbol_put(ztdummy_unregister_interrupt); - } return err; } return 0; diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index cd8302af40e..917bf41a293 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -23,6 +23,25 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * Module options: + * + * debug: + * NOTE: only one poll value must be given for all cards + * See hfc_pci.h for debug flags. + * + * poll: + * NOTE: only one poll value must be given for all cards + * Give the number of samples for each fifo process. + * By default 128 is used. Decrease to reduce delay, increase to + * reduce cpu load. If unsure, don't mess with it! + * A value of 128 will use controller's interrupt. Other values will + * use kernel timer, because the controller will not allow lower values + * than 128. + * Also note that the value depends on the kernel timer frequency. + * If kernel uses a frequency of 1000 Hz, steps of 8 samples are possible. + * If the kernel uses 100 Hz, steps of 80 samples are possible. + * If the kernel uses 300 Hz, steps of about 26 samples are possible. + * */ #include <linux/module.h> @@ -34,16 +53,16 @@ static const char *hfcpci_revision = "2.0"; -#define MAX_CARDS 8 static int HFC_cnt; static uint debug; +static uint poll, tics; +struct timer_list hfc_tl; +u32 hfc_jiffies; MODULE_AUTHOR("Karsten Keil"); MODULE_LICENSE("GPL"); module_param(debug, uint, 0); - -static LIST_HEAD(HFClist); -static DEFINE_RWLOCK(HFClock); +module_param(poll, uint, S_IRUGO | S_IWUSR); enum { HFC_CCD_2BD0, @@ -114,7 +133,6 @@ struct hfcPCI_hw { struct hfc_pci { - struct list_head list; u_char subtype; u_char chanlimit; u_char initdone; @@ -520,9 +538,9 @@ receive_dmsg(struct hfc_pci *hc) } /* - * check for transparent receive data and read max one threshold size if avail + * check for transparent receive data and read max one 'poll' size if avail */ -static int +static void hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) { __le16 *z1r, *z2r; @@ -534,17 +552,19 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); if (!fcnt) - return 0; /* no data avail */ + return; /* no data avail */ if (fcnt <= 0) fcnt += B_FIFO_SIZE; /* bytes actually buffered */ - if (fcnt > HFCPCI_BTRANS_THRESHOLD) - fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */ - new_z2 = le16_to_cpu(*z2r) + fcnt; /* new position in fifo */ if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z2 -= B_FIFO_SIZE; /* buffer wrap */ + if (fcnt > MAX_DATA_SIZE) { /* flush, if oversized */ + *z2r = cpu_to_le16(new_z2); /* new position */ + return; + } + bch->rx_skb = mI_alloc_skb(fcnt, GFP_ATOMIC); if (bch->rx_skb) { ptr = skb_put(bch->rx_skb, fcnt); @@ -569,7 +589,6 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) printk(KERN_WARNING "HFCPCI: receive out of memory\n"); *z2r = cpu_to_le16(new_z2); /* new position */ - return 1; } /* @@ -580,12 +599,11 @@ main_rec_hfcpci(struct bchannel *bch) { struct hfc_pci *hc = bch->hw; int rcnt, real_fifo; - int receive, count = 5; + int receive = 0, count = 5; struct bzfifo *bz; u_char *bdata; struct zt *zp; - if ((bch->nr & 2) && (!hc->hw.bswapped)) { bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2; @@ -625,9 +643,10 @@ Begin: receive = 1; else receive = 0; - } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) - receive = hfcpci_empty_fifo_trans(bch, bz, bdata); - else + } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + hfcpci_empty_fifo_trans(bch, bz, bdata); + return; + } else receive = 0; if (count && receive) goto Begin; @@ -751,11 +770,41 @@ hfcpci_fill_fifo(struct bchannel *bch) /* fcnt contains available bytes in fifo */ fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send (bytes in fifo) */ + + /* "fill fifo if empty" feature */ + if (test_bit(FLG_FILLEMPTY, &bch->Flags) && !fcnt) { + /* printk(KERN_DEBUG "%s: buffer empty, so we have " + "underrun\n", __func__); */ + /* fill buffer, to prevent future underrun */ + count = HFCPCI_FILLEMPTY; + new_z1 = le16_to_cpu(*z1t) + count; + /* new buffer Position */ + if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) + new_z1 -= B_FIFO_SIZE; /* buffer wrap */ + dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); + maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); + /* end of fifo */ + if (bch->debug & DEBUG_HW_BFIFO) + printk(KERN_DEBUG "hfcpci_FFt fillempty " + "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n", + fcnt, maxlen, new_z1, dst); + fcnt += count; + if (maxlen > count) + maxlen = count; /* limit size */ + memset(dst, 0x2a, maxlen); /* first copy */ + count -= maxlen; /* remaining bytes */ + if (count) { + dst = bdata; /* start of buffer */ + memset(dst, 0x2a, count); + } + *z1t = cpu_to_le16(new_z1); /* now send data */ + } + next_t_frame: count = bch->tx_skb->len - bch->tx_idx; - /* maximum fill shall be HFCPCI_BTRANS_MAX */ - if (count > HFCPCI_BTRANS_MAX - fcnt) - count = HFCPCI_BTRANS_MAX - fcnt; + /* maximum fill shall be poll*2 */ + if (count > (poll << 1) - fcnt) + count = (poll << 1) - fcnt; if (count <= 0) return; /* data is suitable for fifo */ @@ -1135,37 +1184,37 @@ hfcpci_int(int intno, void *dev_id) val &= ~0x80; Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); } - if (val & 0x08) { + if (val & 0x08) { /* B1 rx */ bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); if (bch) main_rec_hfcpci(bch); else if (hc->dch.debug) printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n"); } - if (val & 0x10) { + if (val & 0x10) { /* B2 rx */ bch = Sel_BCS(hc, 2); if (bch) main_rec_hfcpci(bch); else if (hc->dch.debug) printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n"); } - if (val & 0x01) { + if (val & 0x01) { /* B1 tx */ bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); if (bch) tx_birq(bch); else if (hc->dch.debug) printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n"); } - if (val & 0x02) { + if (val & 0x02) { /* B2 tx */ bch = Sel_BCS(hc, 2); if (bch) tx_birq(bch); else if (hc->dch.debug) printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n"); } - if (val & 0x20) + if (val & 0x20) /* D rx */ receive_dmsg(hc); - if (val & 0x04) { /* dframe transmitted */ + if (val & 0x04) { /* D tx */ if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags)) del_timer(&hc->dch.timer); tx_dirq(&hc->dch); @@ -1283,14 +1332,16 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol) } if (fifo2 & 2) { hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; - hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + - HFCPCI_INTS_B2REC); + if (!tics) + hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + + HFCPCI_INTS_B2REC); hc->hw.ctmt |= 2; hc->hw.conn &= ~0x18; } else { hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; - hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + - HFCPCI_INTS_B1REC); + if (!tics) + hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + + HFCPCI_INTS_B1REC); hc->hw.ctmt |= 1; hc->hw.conn &= ~0x03; } @@ -1398,7 +1449,8 @@ set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) if (chan & 2) { hc->hw.sctrl_r |= SCTRL_B2_ENA; hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; - hc->hw.int_m1 |= HFCPCI_INTS_B2REC; + if (!tics) + hc->hw.int_m1 |= HFCPCI_INTS_B2REC; hc->hw.ctmt |= 2; hc->hw.conn &= ~0x18; #ifdef REVERSE_BITORDER @@ -1407,7 +1459,8 @@ set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) } else { hc->hw.sctrl_r |= SCTRL_B1_ENA; hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; - hc->hw.int_m1 |= HFCPCI_INTS_B1REC; + if (!tics) + hc->hw.int_m1 |= HFCPCI_INTS_B1REC; hc->hw.ctmt |= 1; hc->hw.conn &= ~0x03; #ifdef REVERSE_BITORDER @@ -1481,11 +1534,17 @@ deactivate_bchannel(struct bchannel *bch) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; + int ret = 0; switch (cq->op) { < |