From 69e656cc16511719a89d83373c48172d3f39bc5f Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 7 Jan 2009 00:00:59 +0100 Subject: mISDN: Cleanup hfc multiport driver Remove references to external zaptel modules and some cosmetic cleanups. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfc_multi.h | 4 -- drivers/isdn/hardware/mISDN/hfcmulti.c | 109 +++++++------------------------- 2 files changed, 24 insertions(+), 89 deletions(-) diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index 7bbf7300593d..6d74951a1797 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 diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index c63e2f49da8a..ff5ec3cbeb77 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -140,7 +140,7 @@ * #define HFC_REGISTER_DEBUG */ -static const char *hfcmulti_revision = "2.02"; +#define HFC_MULTI_VERSION "2.03" #include #include @@ -165,10 +165,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) */ @@ -209,6 +205,7 @@ 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(timer, uint, S_IRUGO | S_IWUSR); @@ -1419,19 +1416,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; @@ -2583,7 +2567,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; @@ -2698,16 +2681,11 @@ hfcmulti_interrupt(int intno, void *dev_id) /* -> 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__); } } @@ -4945,9 +4923,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 +4942,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 */ @@ -5137,8 +5112,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 +5162,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 +5194,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 +5205,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 +5217,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; @@ -5301,17 +5251,6 @@ HFCmulti_init(void) 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; -- cgit v1.2.3 From 8dd2f36f317569665e454268a2677cfba3e848f1 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 2 Aug 2008 22:51:52 +0200 Subject: mISDN: Add feature via MISDN_CTRL_FILL_EMPTY to fill fifo if empty This prevents underrun of fifo when filled and in case of an underrun it prevents subsequent underruns due to jitter. Improve dsp, so buffers are kept filled with a certain delay, so moderate jitter will not cause underrun all the time -> the audio quality is highly improved. tones are not interrupted by gaps anymore, except when CPU is stalling or in high load. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfc_multi.h | 3 ++ drivers/isdn/hardware/mISDN/hfc_pci.h | 1 + drivers/isdn/hardware/mISDN/hfcmulti.c | 45 ++++++++++++++++++++------ drivers/isdn/hardware/mISDN/hfcpci.c | 41 ++++++++++++++++++++++-- drivers/isdn/mISDN/dsp.h | 1 + drivers/isdn/mISDN/dsp_cmx.c | 56 ++++++++++++++++++++++----------- drivers/isdn/mISDN/dsp_core.c | 37 ++++++++++++++++++++-- include/linux/mISDNhw.h | 25 ++++++++------- include/linux/mISDNif.h | 1 + 9 files changed, 165 insertions(+), 45 deletions(-) diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index 6d74951a1797..4aa6a8b41f50 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -9,6 +9,7 @@ #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 @@ -166,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)*/ diff --git a/drivers/isdn/hardware/mISDN/hfc_pci.h b/drivers/isdn/hardware/mISDN/hfc_pci.h index 5783d22a18fe..fd9241ab1802 100644 --- a/drivers/isdn/hardware/mISDN/hfc_pci.h +++ b/drivers/isdn/hardware/mISDN/hfc_pci.h @@ -27,6 +27,7 @@ */ #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 ff5ec3cbeb77..3fc2e9d95341 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -180,7 +180,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 */ @@ -1975,6 +1974,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) { @@ -2011,7 +2021,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; @@ -2050,7 +2059,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); } @@ -2932,7 +2941,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)); @@ -2947,7 +2956,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); @@ -3439,7 +3448,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; @@ -3454,6 +3463,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", @@ -3970,6 +3985,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; @@ -4806,6 +4822,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", @@ -4839,11 +4856,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]); @@ -4854,9 +4871,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); diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index cd8302af40eb..80c356e5dbe1 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -751,6 +751,36 @@ 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 */ @@ -1481,11 +1511,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) { case MISDN_CTRL_GETOP: - cq->op = 0; + cq->op = MISDN_CTRL_FILL_EMPTY; + break; + case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ + test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); + if (debug & DEBUG_HW_OPEN) + printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d " + "off=%d)\n", __func__, bch->nr, !!cq->p1); break; default: printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); @@ -1903,6 +1939,7 @@ open_bchannel(struct hfc_pci *hc, struct channel_req *rq) bch = &hc->bch[rq->adr.channel - 1]; 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; rq->ch = &bch->ch; /* TODO: E-channel */ if (!try_module_get(THIS_MODULE)) diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index 6c3fed6b8d4f..ded948069335 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -198,6 +198,7 @@ struct dsp { /* hardware stuff */ struct dsp_features features; int features_rx_off; /* set if rx_off is featured */ + int features_fill_empty; /* set if fill_empty is featured */ int pcm_slot_rx; /* current PCM slot (or -1) */ int pcm_bank_rx; int pcm_slot_tx; diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index c884511e2d49..fc8ea41ae6a2 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -1168,11 +1168,18 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) dsp->rx_init = 0; if (dsp->features.unordered) { dsp->rx_R = (hh->id & CMX_BUFF_MASK); - dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) - & CMX_BUFF_MASK; + if (dsp->cmx_delay) + dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) + & CMX_BUFF_MASK; + else + dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1)) + & CMX_BUFF_MASK; } else { dsp->rx_R = 0; - dsp->rx_W = dsp->cmx_delay; + if (dsp->cmx_delay) + dsp->rx_W = dsp->cmx_delay; + else + dsp->rx_W = dsp_poll >> 1; } } /* if frame contains time code, write directly */ @@ -1190,14 +1197,20 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) "cmx_receive(dsp=%lx): UNDERRUN (or overrun the " "maximum delay), adjusting read pointer! " "(inst %s)\n", (u_long)dsp, dsp->name); - /* flush buffer */ + /* flush rx buffer and set delay to dsp_poll / 2 */ if (dsp->features.unordered) { dsp->rx_R = (hh->id & CMX_BUFF_MASK); - dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) - & CMX_BUFF_MASK; + if (dsp->cmx_delay) + dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) + & CMX_BUFF_MASK; + dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1)) + & CMX_BUFF_MASK; } else { dsp->rx_R = 0; - dsp->rx_W = dsp->cmx_delay; + if (dsp->cmx_delay) + dsp->rx_W = dsp->cmx_delay; + else + dsp->rx_W = dsp_poll >> 1; } memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); } @@ -1360,8 +1373,11 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) t = (t+1) & CMX_BUFF_MASK; r = (r+1) & CMX_BUFF_MASK; } - if (r != rr) + if (r != rr) { + printk(KERN_DEBUG "%s: buffer empty\n", + __func__); memset(d, dsp_silence, (rr-r)&CMX_BUFF_MASK); + } /* -> if echo is enabled */ } else { /* @@ -1704,9 +1720,10 @@ dsp_cmx_send(void *arg) } /* * remove rx_delay only if we have delay AND we - * have not preset cmx_delay + * have not preset cmx_delay AND + * the delay is greater dsp_poll */ - if (delay && !dsp->cmx_delay) { + if (delay > dsp_poll && !dsp->cmx_delay) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG "%s lowest rx_delay of %d bytes for" @@ -1714,7 +1731,8 @@ dsp_cmx_send(void *arg) __func__, delay, dsp->name); r = dsp->rx_R; - rr = (r + delay) & CMX_BUFF_MASK; + rr = (r + delay - (dsp_poll >> 1)) + & CMX_BUFF_MASK; /* delete rx-data */ while (r != rr) { p[r] = dsp_silence; @@ -1736,7 +1754,7 @@ dsp_cmx_send(void *arg) * remove delay only if we have delay AND we * have enabled tx_dejitter */ - if (delay && dsp->tx_dejitter) { + if (delay > dsp_poll && dsp->tx_dejitter) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG "%s lowest tx_delay of %d bytes for" @@ -1744,7 +1762,8 @@ dsp_cmx_send(void *arg) __func__, delay, dsp->name); r = dsp->tx_R; - rr = (r + delay) & CMX_BUFF_MASK; + rr = (r + delay - (dsp_poll >> 1)) + & CMX_BUFF_MASK; /* delete tx-data */ while (r != rr) { q[r] = dsp_silence; @@ -1797,14 +1816,13 @@ dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) ww = dsp->tx_R; p = dsp->tx_buff; d = skb->data; - space = ww-w; - if (space <= 0) - space += CMX_BUFF_SIZE; + space = (ww - w - 1) & CMX_BUFF_MASK; /* write-pointer should not overrun nor reach read pointer */ - if (space-1 < skb->len) + if (space < skb->len) { /* write to the space we have left */ - ww = (ww - 1) & CMX_BUFF_MASK; - else + ww = (ww - 1) & CMX_BUFF_MASK; /* end one byte prior tx_R */ + printk(KERN_DEBUG "%s: buffer overflow\n", __func__); + } else /* write until all byte are copied */ ww = (w + skb->len) & CMX_BUFF_MASK; dsp->tx_W = ww; diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 1dc21d803410..1d504ba954f5 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -191,6 +191,8 @@ dsp_rx_off_member(struct dsp *dsp) struct mISDN_ctrl_req cq; int rx_off = 1; + memset(&cq, 0, sizeof(cq)); + if (!dsp->features_rx_off) return; @@ -249,6 +251,32 @@ dsp_rx_off(struct dsp *dsp) } } +/* enable "fill empty" feature */ +static void +dsp_fill_empty(struct dsp *dsp) +{ + struct mISDN_ctrl_req cq; + + memset(&cq, 0, sizeof(cq)); + + if (!dsp->ch.peer) { + if (dsp_debug & DEBUG_DSP_CORE) + printk(KERN_DEBUG "%s: no peer, no fill_empty\n", + __func__); + return; + } + cq.op = MISDN_CTRL_FILL_EMPTY; + cq.p1 = 1; + if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { + printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", + __func__); + return; + } + if (dsp_debug & DEBUG_DSP_CORE) + printk(KERN_DEBUG "%s: %s set fill_empty = 1\n", + __func__, dsp->name); +} + static int dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) { @@ -593,8 +621,6 @@ get_features(struct mISDNchannel *ch) struct dsp *dsp = container_of(ch, struct dsp, ch); struct mISDN_ctrl_req cq; - if (dsp_options & DSP_OPT_NOHARDWARE) - return; if (!ch->peer) { if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: no peer, no features\n", @@ -610,6 +636,10 @@ get_features(struct mISDNchannel *ch) } if (cq.op & MISDN_CTRL_RX_OFF) dsp->features_rx_off = 1; + if (cq.op & MISDN_CTRL_FILL_EMPTY) + dsp->features_fill_empty = 1; + if (dsp_options & DSP_OPT_NOHARDWARE) + return; if ((cq.op & MISDN_CTRL_HW_FEATURES_OP)) { cq.op = MISDN_CTRL_HW_FEATURES; *((u_long *)&cq.p1) = (u_long)&dsp->features; @@ -865,6 +895,9 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) if (dsp->dtmf.hardware || dsp->dtmf.software) dsp_dtmf_goertzel_init(dsp); get_features(ch); + /* enable fill_empty feature */ + if (dsp->features_fill_empty) + dsp_fill_empty(dsp); /* send ph_activate */ hh->prim = PH_ACTIVATE_REQ; if (ch->peer) diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h index e794dfb87504..9384b92dfc65 100644 --- a/include/linux/mISDNhw.h +++ b/include/linux/mISDNhw.h @@ -57,20 +57,21 @@ #define FLG_L2DATA 14 /* channel use L2 DATA primitivs */ #define FLG_ORIGIN 15 /* channel is on origin site */ /* channel specific stuff */ +#define FLG_FILLEMPTY 16 /* fill fifo on first frame (empty) */ /* arcofi specific */ -#define FLG_ARCOFI_TIMER 16 -#define FLG_ARCOFI_ERROR 17 +#define FLG_ARCOFI_TIMER 17 +#define FLG_ARCOFI_ERROR 18 /* isar specific */ -#define FLG_INITIALIZED 16 -#define FLG_DLEETX 17 -#define FLG_LASTDLE 18 -#define FLG_FIRST 19 -#define FLG_LASTDATA 20 -#define FLG_NMD_DATA 21 -#define FLG_FTI_RUN 22 -#define FLG_LL_OK 23 -#define FLG_LL_CONN 24 -#define FLG_DTMFSEND 25 +#define FLG_INITIALIZED 17 +#define FLG_DLEETX 18 +#define FLG_LASTDLE 19 +#define FLG_FIRST 20 +#define FLG_LASTDATA 21 +#define FLG_NMD_DATA 22 +#define FLG_FTI_RUN 23 +#define FLG_LL_OK 24 +#define FLG_LL_CONN 25 +#define FLG_DTMFSEND 26 /* workq events */ #define FLG_RECVQUEUE 30 diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index 8f2d60da04e7..74c903cd7a0a 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h @@ -312,6 +312,7 @@ clear_channelmap(u_int nr, u_char *map) #define MISDN_CTRL_SETPEER 0x0040 #define MISDN_CTRL_UNSETPEER 0x0080 #define MISDN_CTRL_RX_OFF 0x0100 +#define MISDN_CTRL_FILL_EMPTY 0x0200 #define MISDN_CTRL_HW_FEATURES_OP 0x2000 #define MISDN_CTRL_HW_FEATURES 0x2001 #define MISDN_CTRL_HFC_OP 0x4000 -- cgit v1.2.3 From 190f71d9d8516fea4db01ba86ddfad5738a92703 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 3 Aug 2008 10:36:53 +0200 Subject: mISDN: Add some debug option for clock problems Add a new debug bit for clock problems. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil --- drivers/isdn/mISDN/dsp.h | 1 + drivers/isdn/mISDN/dsp_cmx.c | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index ded948069335..98a33c58f091 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -15,6 +15,7 @@ #define DEBUG_DSP_TONE 0x0020 #define DEBUG_DSP_BLOWFISH 0x0040 #define DEBUG_DSP_DELAY 0x0100 +#define DEBUG_DSP_CLOCK 0x0200 #define DEBUG_DSP_DTMFCOEFF 0x8000 /* heavy output */ /* options may be: diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index fc8ea41ae6a2..93fb819c5203 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -1192,7 +1192,7 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) * we set our new read pointer, and write silence to buffer */ if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) { - if (dsp_debug & DEBUG_DSP_CMX) + if (dsp_debug & DEBUG_DSP_CLOCK) printk(KERN_DEBUG "cmx_receive(dsp=%lx): UNDERRUN (or overrun the " "maximum delay), adjusting read pointer! " @@ -1218,7 +1218,7 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) if (dsp->cmx_delay) if (((dsp->rx_W - dsp->rx_R) & CMX_BUFF_MASK) >= (dsp->cmx_delay << 1)) { - if (dsp_debug & DEBUG_DSP_CMX) + if (dsp_debug & DEBUG_DSP_CLOCK) printk(KERN_DEBUG "cmx_receive(dsp=%lx): OVERRUN (because " "twice the delay is reached), adjusting " @@ -1374,8 +1374,9 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) r = (r+1) & CMX_BUFF_MASK; } if (r != rr) { - printk(KERN_DEBUG "%s: buffer empty\n", - __func__); + if (dsp_debug & DEBUG_DSP_CLOCK) + printk(KERN_DEBUG "%s: RX empty\n", + __func__); memset(d, dsp_silence, (rr-r)&CMX_BUFF_MASK); } /* -> if echo is enabled */ @@ -1724,7 +1725,7 @@ dsp_cmx_send(void *arg) * the delay is greater dsp_poll */ if (delay > dsp_poll && !dsp->cmx_delay) { - if (dsp_debug & DEBUG_DSP_CMX) + if (dsp_debug & DEBUG_DSP_CLOCK) printk(KERN_DEBUG "%s lowest rx_delay of %d bytes for" " dsp %s are now removed.\n", @@ -1755,7 +1756,7 @@ dsp_cmx_send(void *arg) * have enabled tx_dejitter */ if (delay > dsp_poll && dsp->tx_dejitter) { - if (dsp_debug & DEBUG_DSP_CMX) + if (dsp_debug & DEBUG_DSP_CLOCK) printk(KERN_DEBUG "%s lowest tx_delay of %d bytes for" " dsp %s are now removed.\n", @@ -1821,7 +1822,8 @@ dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) if (space < skb->len) { /* write to the space we have left */ ww = (ww - 1) & CMX_BUFF_MASK; /* end one byte prior tx_R */ - printk(KERN_DEBUG "%s: buffer overflow\n", __func__); + if (dsp_debug & DEBUG_DSP_CLOCK) + printk(KERN_DEBUG "%s: TX overflow\n", __func__); } else /* write until all byte are copied */ ww = (w + skb->len) & CMX_BUFF_MASK; -- cgit v1.2.3 From 11618496d03d9e1ad70ac68afbfa7df9b5fc19d1 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 6 Aug 2008 19:13:07 +0200 Subject: mISDN: Fix queue limit counting problem If received frames are not handled in time, purge them. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil --- drivers/isdn/mISDN/hwchannel.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 2596fba4e614..535ceacc05b9 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -50,9 +50,6 @@ bchannel_bh(struct work_struct *ws) if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) { while ((skb = skb_dequeue(&bch->rqueue))) { - if (bch->rcount >= 64) - printk(KERN_WARNING "B-channel %p receive " - "queue if full, but empties...\n", bch); bch->rcount--; if (likely(bch->ch.peer)) { err = bch->ch.recv(bch->ch.peer, skb); @@ -177,8 +174,10 @@ recv_Bchannel(struct bchannel *bch) hh->prim = PH_DATA_IND; hh->id = MISDN_ID_ANY; if (bch->rcount >= 64) { - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; + printk(KERN_WARNING "B-channel %p receive queue overflow, " + "fushing!\n", bch); + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; return; } bch->rcount++; @@ -200,8 +199,10 @@ void recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb) { if (bch->rcount >= 64) { - dev_kfree_skb(skb); - return; + printk(KERN_WARNING "B-channel %p receive queue overflow, " + "fushing!\n", bch); + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; } bch->rcount++; skb_queue_tail(&bch->rqueue, skb); @@ -245,8 +246,12 @@ confirm_Bsend(struct bchannel *bch) { struct sk_buff *skb; - if (bch->rcount >= 64) - return; + if (bch->rcount >= 64) { + printk(KERN_WARNING "B-channel %p receive queue overflow, " + "fushing!\n", bch); + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; + } skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb), 0, NULL, GFP_ATOMIC); if (!skb) { -- cgit v1.2.3 From 9776ef0829ed33e8f36d9e7d859d00cc91c54ffd Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 11 Aug 2008 14:43:33 +0200 Subject: mISDN: Remove the local max-card limit This is not needed. Signed-off-by: Matthias Urlichs Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcpci.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 80c356e5dbe1..8461477a3ac0 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -34,7 +34,6 @@ static const char *hfcpci_revision = "2.0"; -#define MAX_CARDS 8 static int HFC_cnt; static uint debug; @@ -2077,9 +2076,6 @@ setup_card(struct hfc_pci *card) u_long flags; char name[MISDN_MAX_IDLEN]; - if (HFC_cnt >= MAX_CARDS) - return -EINVAL; /* maybe better value */ - card->dch.debug = debug; spin_lock_init(&card->lock); mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state); -- cgit v1.2.3 From 8b6015f736125050722dbe59c4f943e78cd626f0 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 12 Aug 2008 10:12:09 +0200 Subject: mISDN: Added an ioctl to change the device name To get persistent device names with hotplug we need to rename devices sometime. Signed-off-by: Matthias Urlichs Signed-off-by: Karsten Keil --- drivers/isdn/mISDN/socket.c | 15 +++++++++++++++ include/linux/mISDNif.h | 31 +++++++++++++++++++------------ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 37a2de18cfd0..98fa6c4a4bd6 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -645,6 +645,21 @@ base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } else err = -ENODEV; break; + case IMSETDEVNAME: + { + struct mISDN_devrename dn; + if (copy_from_user(&dn, (void __user *)arg, + sizeof(dn))) { + err = -EFAULT; + break; + } + dev = get_mdevice(dn.id); + if (dev) + strlcpy(dev->name, dn.name, MISDN_MAX_IDLEN); + else + err = -ENODEV; + } + break; default: err = -EINVAL; } diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index 74c903cd7a0a..be09476ed854 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h @@ -36,8 +36,8 @@ * - should be incremented on every checkin */ #define MISDN_MAJOR_VERSION 1 -#define MISDN_MINOR_VERSION 0 -#define MISDN_RELEASE 19 +#define MISDN_MINOR_VERSION 1 +#define MISDN_RELEASE 20 /* primitives for information exchange * generell format @@ -255,16 +255,6 @@ struct sockaddr_mISDN { unsigned char tei; }; -/* timer device ioctl */ -#define IMADDTIMER _IOR('I', 64, int) -#define IMDELTIMER _IOR('I', 65, int) -/* socket ioctls */ -#define IMGETVERSION _IOR('I', 66, int) -#define IMGETCOUNT _IOR('I', 67, int) -#define IMGETDEVINFO _IOR('I', 68, int) -#define IMCTRLREQ _IOR('I', 69, int) -#define IMCLEAR_L2 _IOR('I', 70, int) - struct mISDNversion { unsigned char major; unsigned char minor; @@ -281,6 +271,23 @@ struct mISDN_devinfo { char name[MISDN_MAX_IDLEN]; }; +struct mISDN_devrename { + u_int id; + char name[MISDN_MAX_IDLEN]; /* new name */ +}; + +/* timer device ioctl */ +#define IMADDTIMER _IOR('I', 64, int) +#define IMDELTIMER _IOR('I', 65, int) + +/* socket ioctls */ +#define IMGETVERSION _IOR('I', 66, int) +#define IMGETCOUNT _IOR('I', 67, int) +#define IMGETDEVINFO _IOR('I', 68, int) +#define IMCTRLREQ _IOR('I', 69, int) +#define IMCLEAR_L2 _IOR('I', 70, int) +#define IMSETDEVNAME _IOR('I', 71, struct mISDN_devrename) + static inline int test_channelmap(u_int nr, u_char *map) { -- cgit v1.2.3 From 837468d135dcc49cdabc9fa92fc9550479f60704 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Sat, 16 Aug 2008 00:04:33 +0200 Subject: mISDN: Use struct device name field struct device already has a 'name' member, use it. Signed-off-by: Matthias Urlichs Signed-off-by: Karsten Keil --- drivers/isdn/mISDN/core.c | 8 ++++---- drivers/isdn/mISDN/layer1.c | 2 +- drivers/isdn/mISDN/socket.c | 6 +++--- drivers/isdn/mISDN/stack.c | 43 ++++++++++++++++++++++++------------------- drivers/isdn/mISDN/tei.c | 6 +++--- include/linux/mISDNif.h | 1 - 6 files changed, 35 insertions(+), 31 deletions(-) diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index 751665c448d0..43fd97b0fe42 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c @@ -82,12 +82,12 @@ mISDN_register_device(struct mISDNdevice *dev, char *name) if (dev->id < 0) return -EBUSY; if (name && name[0]) - strcpy(dev->name, name); + dev_set_name(&dev->dev, "%s", name); else - sprintf(dev->name, "mISDN%d", dev->id); + dev_set_name(&dev->dev, "mISDN%d", dev->id); if (debug & DEBUG_CORE) printk(KERN_DEBUG "mISDN_register %s %d\n", - dev->name, dev->id); + dev_name(&dev->dev), dev->id); err = create_stack(dev); if (err) return err; @@ -104,7 +104,7 @@ mISDN_unregister_device(struct mISDNdevice *dev) { if (debug & DEBUG_CORE) printk(KERN_DEBUG "mISDN_unregister %s %d\n", - dev->name, dev->id); + dev_name(&dev->dev), dev->id); write_lock_irqsave(&device_lock, flags); list_del(&dev->D.list); write_unlock_irqrestore(&device_lock, flags); diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c index b73e952d12cf..e826eeb1ecec 100644 --- a/drivers/isdn/mISDN/layer1.c +++ b/drivers/isdn/mISDN/layer1.c @@ -101,7 +101,7 @@ l1m_debug(struct FsmInst *fi, char *fmt, ...) va_list va; va_start(va, fmt); - printk(KERN_DEBUG "%s: ", l1->dch->dev.name); + printk(KERN_DEBUG "%s: ", dev_name(&l1->dch->dev.dev)); vprintk(fmt, va); printk("\n"); va_end(va); diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 98fa6c4a4bd6..2f6d6e88ff2c 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -381,7 +381,7 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) memcpy(di.channelmap, dev->channelmap, sizeof(di.channelmap)); di.nrbchan = dev->nrbchan; - strcpy(di.name, dev->name); + strcpy(di.name, dev_name(&dev->dev)); if (copy_to_user((void __user *)arg, &di, sizeof(di))) err = -EFAULT; } else @@ -639,7 +639,7 @@ base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) memcpy(di.channelmap, dev->channelmap, sizeof(di.channelmap)); di.nrbchan = dev->nrbchan; - strcpy(di.name, dev->name); + strcpy(di.name, dev_name(&dev->dev)); if (copy_to_user((void __user *)arg, &di, sizeof(di))) err = -EFAULT; } else @@ -655,7 +655,7 @@ base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } dev = get_mdevice(dn.id); if (dev) - strlcpy(dev->name, dn.name, MISDN_MAX_IDLEN); + err = device_rename(&dev->dev, dn.name); else err = -ENODEV; } diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index d55b14ae4e99..9b9fab47cb2b 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -172,7 +172,8 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) else printk(KERN_WARNING "%s: dev(%s) prim(%x) id(%x) no channel\n", - __func__, st->dev->name, hh->prim, hh->id); + __func__, dev_name(&st->dev->dev), hh->prim, + hh->id); } else if (lm == 0x8) { WARN_ON(lm == 0x8); ch = get_channel4id(st, hh->id); @@ -181,11 +182,12 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) else printk(KERN_WARNING "%s: dev(%s) prim(%x) id(%x) no channel\n", - __func__, st->dev->name, hh->prim, hh->id); + __func__, dev_name(&st->dev->dev), hh->prim, + hh->id); } else { /* broadcast not handled yet */ printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n", - __func__, st->dev->name, hh->prim); + __func__, dev_name(&st->dev->dev), hh->prim); } return -ESRCH; } @@ -209,7 +211,8 @@ mISDNStackd(void *data) unlock_kernel(); #endif if (*debug & DEBUG_MSG_THREAD) - printk(KERN_DEBUG "mISDNStackd %s started\n", st->dev->name); + printk(KERN_DEBUG "mISDNStackd %s started\n", + dev_name(&st->dev->dev)); if (st->notify != NULL) { complete(st->notify); @@ -245,7 +248,7 @@ mISDNStackd(void *data) printk(KERN_DEBUG "%s: %s prim(%x) id(%x) " "send call(%d)\n", - __func__, st->dev->name, + __func__, dev_name(&st->dev->dev), mISDN_HEAD_PRIM(skb), mISDN_HEAD_ID(skb), err); dev_kfree_skb(skb); @@ -288,7 +291,7 @@ mISDNStackd(void *data) mISDN_STACK_ACTION_MASK)); if (*debug & DEBUG_MSG_THREAD) printk(KERN_DEBUG "%s: %s wake status %08lx\n", - __func__, st->dev->name, st->status); + __func__, dev_name(&st->dev->dev), st->status); test_and_set_bit(mISDN_STACK_ACTIVE, &st->status); test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status); @@ -303,15 +306,16 @@ mISDNStackd(void *data) #ifdef MISDN_MSG_STATS printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d " "msg %d sleep %d stopped\n", - st->dev->name, st->msg_cnt, st->sleep_cnt, st->stopped_cnt); + dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt, + st->stopped_cnt); printk(KERN_DEBUG "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", - st->dev->name, st->thread->utime, st->thread->stime); + dev_name(&st->dev->dev), st->thread->utime, st->thread->stime); printk(KERN_DEBUG "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", - st->dev->name, st->thread->nvcsw, st->thread->nivcsw); + dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw); printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n", - st->dev->name); + dev_name(&st->dev->dev)); #endif test_and_set_bit(mISDN_STACK_KILLED, &st->status); test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); @@ -401,15 +405,16 @@ create_stack(struct mISDNdevice *dev) newst->own.send = mISDN_queue_message; newst->own.recv = mISDN_queue_message; if (*debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: st(%s)\n", __func__, newst->dev->name); + printk(KERN_DEBUG "%s: st(%s)\n", __func__, + dev_name(&newst->dev->dev)); newst->notify = &done; newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s", - newst->dev->name); + dev_name(&newst->dev->dev)); if (IS_ERR(newst->thread)) { err = PTR_ERR(newst->thread); printk(KERN_ERR "mISDN:cannot create kernel thread for %s (%d)\n", - newst->dev->name, err); + dev_name(&newst->dev->dev), err); delete_teimanager(dev->teimgr); kfree(newst); } else @@ -428,8 +433,8 @@ connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch, if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev->name, protocol, adr->dev, adr->channel, - adr->sapi, adr->tei); + __func__, dev_name(&dev->dev), protocol, adr->dev, + adr->channel, adr->sapi, adr->tei); switch (protocol) { case ISDN_P_NT_S0: case ISDN_P_NT_E1: @@ -473,7 +478,7 @@ connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch, if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev->name, protocol, + __func__, dev_name(&dev->dev), protocol, adr->dev, adr->channel, adr->sapi, adr->tei); ch->st = dev->D.st; @@ -529,7 +534,7 @@ create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch, if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev->name, protocol, + __func__, dev_name(&dev->dev), protocol, adr->dev, adr->channel, adr->sapi, adr->tei); rq.protocol = ISDN_P_TE_S0; @@ -590,7 +595,7 @@ delete_channel(struct mISDNchannel *ch) } if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__, - ch->st->dev->name, ch->protocol); + dev_name(&ch->st->dev->dev), ch->protocol); if (ch->protocol >= ISDN_P_B_START) { if (ch->peer) { ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL); @@ -643,7 +648,7 @@ delete_stack(struct mISDNdevice *dev) if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: st(%s)\n", __func__, - st->dev->name); + dev_name(&st->dev->dev)); if (dev->teimgr) delete_teimanager(dev->teimgr); if (st->thread) { diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index 5c43d19e7c11..b452dead8fd0 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -968,9 +968,9 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) if (*debug & DEBUG_L2_TEI) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, mgr->ch.st->dev->name, crq->protocol, - crq->adr.dev, crq->adr.channel, crq->adr.sapi, - crq->adr.tei); + __func__, dev_name(&mgr->ch.st->dev->dev), + crq->protocol, crq->adr.dev, crq->adr.channel, + crq->adr.sapi, crq->adr.tei); if (crq->adr.sapi != 0) /* not supported yet */ return -EINVAL; if (crq->adr.tei > GROUP_TEI) diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index be09476ed854..a59febb6143a 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h @@ -431,7 +431,6 @@ struct mISDN_sock { struct mISDNdevice { struct mISDNchannel D; u_int id; - char name[MISDN_MAX_IDLEN]; u_int Dprotocols; u_int Bprotocols; u_int nrbchan; -- cgit v1.2.3 From e4cce225f05c1daf89d10565c654f4c11907a049 Mon Sep 17 00:00:00 2001 From: Peter Schlaile Date: Fri, 22 Aug 2008 19:44:21 +0200 Subject: mISDN: Fix HDLC DSP transmit Fix HDLC DSP transmit (DL_DATA frames were bounced back upwards instead of being sent down as PH_DATA frames) Thanks to Andreas Eversberg for the fix! Signed-off-by: Andreas Eversberg Signed-off-by: Peter Schlaile Signed-off-by: Karsten Keil --- drivers/isdn/mISDN/dsp_core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 1d504ba954f5..c16cb7ac3d2a 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -867,11 +867,14 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) } if (dsp->hdlc) { /* hdlc */ - spin_lock_irqsave(&dsp_lock, flags); - if (dsp->b_active) { - skb_queue_tail(&dsp->sendq, skb); - schedule_work(&dsp->workq); + if (!dsp->b_active) { + ret = -EIO; + break; } + hh->prim = PH_DATA_REQ; + spin_lock_irqsave(&dsp_lock, flags); + skb_queue_tail(&dsp->sendq, skb); + schedule_work(&dsp->workq); spin_unlock_irqrestore(&dsp_lock, flags); return 0; } -- cgit v1.2.3 From 0aafe75d5c9227f209c180012d799a9e19d7ee79 Mon Sep 17 00:00:00 2001 From: Peter Schlaile Date: Mon, 25 Aug 2008 17:55:53 +0200 Subject: mISDN: Make debug output a little bit more verbose Add usefull info to debug output. Signed-off-by: Peter Schlaile Signed-off-by: Karsten Keil --- drivers/isdn/mISDN/dsp_cmx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 93fb819c5203..b16f76c2d684 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -1823,7 +1823,9 @@ dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) /* write to the space we have left */ ww = (ww - 1) & CMX_BUFF_MASK; /* end one byte prior tx_R */ if (dsp_debug & DEBUG_DSP_CLOCK) - printk(KERN_DEBUG "%s: TX overflow\n", __func__); + printk(KERN_DEBUG "%s: TX overflow space=%d skb->len=" + "%d, w=0x%04x, ww=0x%04x\n", __func__, space, + skb->len, w, ww); } else /* write until all byte are copied */ ww = (w + skb->len) & CMX_BUFF_MASK; -- cgit v1.2.3 From 83a8a55b1deb07ac1ce546a8f230a8ef8f3c5ce5 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 30 Aug 2008 06:50:34 +0200 Subject: mISDN: Fixed more indexing bugs Fix more indexing bugs when checking free timeslots. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil --- drivers/isdn/mISDN/dsp_cmx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index b16f76c2d684..04dbb407f7a0 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -744,11 +744,11 @@ conf_software: if (dsp->pcm_slot_rx >= 0 && dsp->pcm_slot_rx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_tx] = 0; + freeslots[dsp->pcm_slot_rx] = 0; if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_tx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_rx] = 0; + freeslots[dsp->pcm_slot_tx] = 0; } } i = 0; @@ -836,11 +836,11 @@ conf_software: if (dsp->pcm_slot_rx >= 0 && dsp->pcm_slot_rx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_tx] = 0; + freeslots[dsp->pcm_slot_rx] = 0; if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_tx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_rx] = 0; + freeslots[dsp->pcm_slot_tx] = 0; } } i1 = 0; -- cgit v1.2.3 From a9b61830cd88a1d3d5e6d61adb737a3e20f7f0f5 Mon Sep 17 00:00:00 2001 From: Martin Bachem Date: Wed, 3 Sep 2008 18:08:30 +0200 Subject: mISDN: Use protocol to detect D-channel Use protocol to detect D-channel not the channel number 0 Signed-off-by: Martin Bachem Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcpci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 8461477a3ac0..37c2e19c3b00 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1964,7 +1964,8 @@ hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) switch (cmd) { case OPEN_CHANNEL: rq = arg; - if (rq->adr.channel == 0) + if ((rq->protocol == ISDN_P_TE_S0) || + (rq->protocol == ISDN_P_NT_S0)) err = open_dchannel(hc, ch, rq); else err = open_bchannel(hc, rq); -- cgit v1.2.3 From 1f28fa19d34c0d9186f274e61e4b3dcfc6428c5c Mon Sep 17 00:00:00 2001 From: Martin Bachem Date: Wed, 3 Sep 2008 15:17:45 +0200 Subject: mISDN: Add E-Channel logging features New prim PH_DATA_E_IND. - all E-ch frames are indicated by recv_Echannel(), which pushes E-Channel frames into dch's rqueue - if dchannel is opened with channel nr 0, no E-Channel logging is requested - if dchannel is opened with channel nr 1, E-Channel logging is requested. if layer1 does not support that, -EINVAL in return is appropriate Signed-off-by: Martin Bachem Signed-off-by: Karsten Keil --- drivers/isdn/mISDN/hwchannel.c | 19 +++++++++++++++++++ drivers/isdn/mISDN/stack.c | 2 +- include/linux/mISDNhw.h | 1 + include/linux/mISDNif.h | 1 + 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 535ceacc05b9..ab1168a110ae 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -165,6 +165,25 @@ recv_Dchannel(struct dchannel *dch) } EXPORT_SYMBOL(recv_Dchannel); +void +recv_Echannel(struct dchannel *ech, struct dchannel *dch) +{ + struct mISDNhead *hh; + + if (ech->rx_skb->len < 2) { /* at least 2 for sapi / tei */ + dev_kfree_skb(ech->rx_skb); + ech->rx_skb = NULL; + return; + } + hh = mISDN_HEAD_P(ech->rx_skb); + hh->prim = PH_DATA_E_IND; + hh->id = get_sapi_tei(ech->rx_skb->data); + skb_queue_tail(&dch->rqueue, ech->rx_skb); + ech->rx_skb = NULL; + schedule_event(dch, FLG_RECVQUEUE); +} +EXPORT_SYMBOL(recv_Echannel); + void recv_Bchannel(struct bchannel *bch) { diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index 9b9fab47cb2b..8cff570bb8df 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -453,7 +453,7 @@ connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch, ch->peer = &dev->D.st->own; ch->st = dev->D.st; rq.protocol = protocol; - rq.adr.channel = 0; + rq.adr.channel = adr->channel; err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); if (err) diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h index 9384b92dfc65..97ffdc1d3442 100644 --- a/include/linux/mISDNhw.h +++ b/include/linux/mISDNhw.h @@ -184,6 +184,7 @@ extern void queue_ch_frame(struct mISDNchannel *, u_int, extern int dchannel_senddata(struct dchannel *, struct sk_buff *); extern int bchannel_senddata(struct bchannel *, struct sk_buff *); extern void recv_Dchannel(struct dchannel *); +extern void recv_Echannel(struct dchannel *, struct dchannel *); extern void recv_Bchannel(struct bchannel *); extern void recv_Dchannel_skb(struct dchannel *, struct sk_buff *); extern void recv_Bchannel_skb(struct bchannel *, struct sk_buff *); diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index a59febb6143a..f75d596c5316 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h @@ -80,6 +80,7 @@ #define PH_DEACTIVATE_IND 0x0202 #define PH_DEACTIVATE_CNF 0x4202 #define PH_DATA_IND 0x2002 +#define PH_DATA_E_IND 0x3002 #define MPH_ACTIVATE_IND 0x0502 #define MPH_DEACTIVATE_IND 0x0602 #define MPH_INFORMATION_IND 0x0702 -- cgit v1.2.3 From 55a6af9749d6a31e087f304f2ea39db3bb7b3f3e Mon Sep 17 00:00:00 2001 From: Martin Bachem Date: Thu, 4 Sep 2008 12:42:39 +0200 Subject: mISDN: Return error on E-channel access Return error on D-channel access with E-channel data requested Signed-off-by: Martin Bachem Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcpci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 37c2e19c3b00..ea69d5862f6d 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1894,6 +1894,10 @@ open_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch, hc->dch.dev.id, __builtin_return_address(0)); if (rq->protocol == ISDN_P_NONE) return -EINVAL; + if (rq->adr.channel == 1) { + /* TODO: E-Channel */ + return -EINVAL; + } if (!hc->initdone) { if (rq->protocol == ISDN_P_TE_S0) { err = create_l1(&hc->dch, hfc_l1callback); -- cgit v1.2.3 From 3bd69ad197a4a3d0085a5dc3b5796111bf176b12 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 6 Sep 2008 09:03:46 +0200 Subject: mISDN: Add ISDN sample clock API to mISDN core Add ISDN sample clock API to mISDN core (new file clock.c) hfcmulti and mISDNdsp use clock API. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfc_multi.h | 3 + drivers/isdn/hardware/mISDN/hfcmulti.c | 45 +++++-- drivers/isdn/mISDN/Makefile | 2 +- drivers/isdn/mISDN/clock.c | 216 ++++++++++++++++++++++++++++++++ drivers/isdn/mISDN/core.c | 1 + drivers/isdn/mISDN/core.h | 2 + drivers/isdn/mISDN/dsp_cmx.c | 40 +++--- include/linux/mISDNif.h | 17 +++ 8 files changed, 294 insertions(+), 32 deletions(-) create mode 100644 drivers/isdn/mISDN/clock.c diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index 4aa6a8b41f50..663b77f578be 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -197,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/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 3fc2e9d95341..592db93105f9 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 clockdelay_te 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. */ /* @@ -190,12 +196,13 @@ static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 }; */ 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; @@ -207,12 +214,13 @@ 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); @@ -2629,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))) { @@ -2683,11 +2692,13 @@ 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); } if (r_irq_misc & V_IRQ_PROC) { @@ -4075,6 +4086,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 */ @@ -4489,10 +4509,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 */ @@ -5003,6 +5027,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) { @@ -5273,6 +5301,9 @@ 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); diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile index 1cb5e633cf75..0a6bd2a9e730 100644 --- a/drivers/isdn/mISDN/Makefile +++ b/drivers/isdn/mISDN/Makefile @@ -8,6 +8,6 @@ obj-$(CONFIG_MISDN_L1OIP) += l1oip.o # multi objects -mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o +mISDN_core-objs := core.o fsm.o socket.o clock.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_pipeline.o dsp_hwec.o l1oip-objs := l1oip_core.o l1oip_codec.o diff --git a/drivers/isdn/mISDN/clock.c b/drivers/isdn/mISDN/clock.c new file mode 100644 index 000000000000..44d9c3d5d33d --- /dev/null +++ b/drivers/isdn/mISDN/clock.c @@ -0,0 +1,216 @@ +/* + * Copyright 2008 by Andreas Eversberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * Quick API description: + * + * A clock source registers using mISDN_register_clock: + * name = text string to name clock source + * priority = value to priorize clock sources (0 = default) + * ctl = callback function to enable/disable clock source + * priv = private pointer of clock source + * return = pointer to clock source structure; + * + * Note: Callback 'ctl' can be called before mISDN_register_clock returns! + * Also it can be called during mISDN_unregister_clock. + * + * A clock source calls mISDN_clock_update with given samples elapsed, if + * enabled. If function call is delayed, tv must be set with the timestamp + * of the actual event. + * + * A clock source unregisters using mISDN_unregister_clock. + * + * To get current clock, call mISDN_clock_get. The signed short value + * counts the number of samples since. Time since last clock event is added. + * + */ + +#include +#include +#include +#include +#include "core.h" + +static u_int *debug; +static LIST_HEAD(iclock_list); +DEFINE_RWLOCK(iclock_lock); +u16 iclock_count; /* counter of last clock */ +struct timeval iclock_tv; /* time stamp of last clock */ +int iclock_tv_valid; /* already received one timestamp */ +struct mISDNclock *iclock_current; + +void +mISDN_init_clock(u_int *dp) +{ + debug = dp; + do_gettimeofday(&iclock_tv); +} + +static void +select_iclock(void) +{ + struct mISDNclock *iclock, *bestclock = NULL, *lastclock = NULL; + int pri = -128; + + list_for_each_entry(iclock, &iclock_list, list) { + if (iclock->pri > pri) { + pri = iclock->pri; + bestclock = iclock; + } + if (iclock_current == iclock) + lastclock = iclock; + } + if (lastclock && bestclock != lastclock) { + /* last used clock source still exists but changes, disable */ + if (*debug & DEBUG_CLOCK) + printk(KERN_DEBUG "Old clock source '%s' disable.\n", + lastclock->name); + lastclock->ctl(lastclock->priv, 0); + } + if (bestclock && bestclock != iclock_current) { + /* new clock source selected, enable */ + if (*debug & DEBUG_CLOCK) + printk(KERN_DEBUG "New clock source '%s' enable.\n", + bestclock->name); + bestclock->ctl(bestclock->priv, 1); + } + if (bestclock != iclock_current) { + /* no clock received yet */ + iclock_tv_valid = 0; + } + iclock_current = bestclock; +} + +struct mISDNclock +*mISDN_register_clock(char *name, int pri, clockctl_func_t *ctl, void *priv) +{ + u_long flags; + struct mISDNclock *iclock; + + if (*debug & (DEBUG_CORE | DEBUG_CLOCK)) + printk(KERN_DEBUG "%s: %s %d\n", __func__, name, pri); + iclock = kzalloc(sizeof(struct mISDNclock), GFP_ATOMIC); + if (!iclock) { + printk(KERN_ERR "%s: No memory for clock entry.\n", __func__); + return NULL; + } + strncpy(iclock->name, name, sizeof(iclock->name)-1); + iclock->pri = pri; + iclock->priv = priv; + iclock->ctl = ctl; + write_lock_irqsave(&iclock_lock, flags); + list_add_tail(&iclock->list, &iclock_list); + select_iclock(); + w