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/hfcpci.c | 41 ++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'drivers/isdn/hardware/mISDN/hfcpci.c') diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index cd8302a..80c356e 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)) -- cgit v1.1 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(-) (limited to 'drivers/isdn/hardware/mISDN/hfcpci.c') diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 80c356e..8461477 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.1 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(-) (limited to 'drivers/isdn/hardware/mISDN/hfcpci.c') diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 8461477..37c2e19 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.1 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(+) (limited to 'drivers/isdn/hardware/mISDN/hfcpci.c') diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 37c2e19..ea69d58 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.1 From 87c5fa1bb42624254a2013cbbc3b170d6017f5d6 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 28 Sep 2008 13:01:01 +0200 Subject: mISDN: Add different different timer settings for hfc-pci - Poll-timer can now be set from 8 to 256 samples, depending on your kernel. - If default or 128 is used, the normal controller's clock is used as before. Usage: modprobe hfcpci poll=XXX - Added some debug code for dsp buffer size. (CMX_DELAY_DEBUG) Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcpci.c | 152 ++++++++++++++++++++++++++++------- 1 file changed, 125 insertions(+), 27 deletions(-) (limited to 'drivers/isdn/hardware/mISDN/hfcpci.c') diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index ea69d58..cd5d26c 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 @@ -36,10 +55,14 @@ static const char *hfcpci_revision = "2.0"; 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); +module_param(poll, uint, S_IRUGO | S_IWUSR); static LIST_HEAD(HFClist); static DEFINE_RWLOCK(HFClock); @@ -519,9 +542,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; @@ -533,17 +556,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); @@ -568,7 +593,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; } /* @@ -579,12 +603,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; @@ -624,9 +647,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; @@ -782,9 +806,9 @@ hfcpci_fill_fifo(struct bchannel *bch) 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 */ @@ -1164,37 +1188,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); @@ -1203,6 +1227,41 @@ hfcpci_int(int intno, void *dev_id) return IRQ_HANDLED; } +static void +hfcpci_softirq(void *arg) +{ + u_long flags; + struct bchannel *bch; + struct hfc_pci *hc; + + write_lock_irqsave(&HFClock, flags); + list_for_each_entry(hc, &HFClist, list) { + if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) { + spin_lock(&hc->lock); + bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); + if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */ + main_rec_hfcpci(bch); + tx_birq(bch); + } + bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2); + if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */ + main_rec_hfcpci(bch); + tx_birq(bch); + } + spin_unlock(&hc->lock); + } + } + write_unlock_irqrestore(&HFClock, flags); + + /* if next event would be in the past ... */ + if ((s32)(hfc_jiffies + tics - jiffies) <= 0) + hfc_jiffies = jiffies + 1; + else + hfc_jiffies += tics; + hfc_tl.expires = hfc_jiffies; + add_timer(&hfc_tl); +} + /* * timer callback for D-chan busy resolution. Currently no function */ @@ -1312,14 +1371,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; } @@ -1427,7 +1488,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 @@ -1436,7 +1498,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 @@ -2273,7 +2336,39 @@ HFC_init(void) { int err; + if (!poll) + poll = HFCPCI_BTRANS_THRESHOLD; + + if (poll != HFCPCI_BTRANS_THRESHOLD) { + tics = poll * HZ / 8000; + if (tics < 1) + tics = 1; + poll = tics * 8000 / HZ; + if (poll > 256 || poll < 8) { + printk(KERN_ERR "%s: Wrong poll value %d not in range " + "of 8..256.\n", __func__, poll); + err = -EINVAL; + return err; + } + } + if (poll != HFCPCI_BTRANS_THRESHOLD) { + printk(KERN_INFO "%s: Using alternative poll value of %d\n", + __func__, poll); + hfc_tl.function = (void *)hfcpci_softirq; + hfc_tl.data = 0; + init_timer(&hfc_tl); + hfc_tl.expires = jiffies + tics; + hfc_jiffies = hfc_tl.expires; + add_timer(&hfc_tl); + } else + tics = 0; /* indicate the use of controller's timer */ + err = pci_register_driver(&hfc_driver); + if (err) { + if (timer_pending(&hfc_tl)) + del_timer(&hfc_tl); + } + return err; } @@ -2282,6 +2377,9 @@ HFC_cleanup(void) { struct hfc_pci *card, *next; + if (timer_pending(&hfc_tl)) + del_timer(&hfc_tl); + list_for_each_entry_safe(card, next, &HFClist, list) { release_card(card); } -- cgit v1.1 From b36b654a7e82308cea063cdf909a7f246105c2a3 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Sat, 16 Aug 2008 00:09:24 +0200 Subject: mISDN: Create /sys/class/mISDN Create /sys/class/mISDN and implement functions to handle device renames. Signed-Off-By: Matthias Urlichs Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcpci.c | 100 +++++++++++++++-------------------- 1 file changed, 44 insertions(+), 56 deletions(-) (limited to 'drivers/isdn/hardware/mISDN/hfcpci.c') diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index cd5d26c..8df12bf 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -64,9 +64,6 @@ MODULE_LICENSE("GPL"); module_param(debug, uint, 0); module_param(poll, uint, S_IRUGO | S_IWUSR); -static LIST_HEAD(HFClist); -static DEFINE_RWLOCK(HFClock); - enum { HFC_CCD_2BD0, HFC_CCD_B000, @@ -136,7 +133,6 @@ struct hfcPCI_hw { struct hfc_pci { - struct list_head list; u_char subtype; u_char chanlimit; u_char initdone; @@ -1227,41 +1223,6 @@ hfcpci_int(int intno, void *dev_id) return IRQ_HANDLED; } -static void -hfcpci_softirq(void *arg) -{ - u_long flags; - struct bchannel *bch; - struct hfc_pci *hc; - - write_lock_irqsave(&HFClock, flags); - list_for_each_entry(hc, &HFClist, list) { - if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) { - spin_lock(&hc->lock); - bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); - if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */ - main_rec_hfcpci(bch); - tx_birq(bch); - } - bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2); - if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */ - main_rec_hfcpci(bch); - tx_birq(bch); - } - spin_unlock(&hc->lock); - } - } - write_unlock_irqrestore(&HFClock, flags); - - /* if next event would be in the past ... */ - if ((s32)(hfc_jiffies + tics - jiffies) <= 0) - hfc_jiffies = jiffies + 1; - else - hfc_jiffies += tics; - hfc_tl.expires = hfc_jiffies; - add_timer(&hfc_tl); -} - /* * timer callback for D-chan busy resolution. Currently no function */ @@ -2131,7 +2092,6 @@ release_card(struct hfc_pci *hc) { mISDN_freebchannel(&hc->bch[1]); mISDN_freebchannel(&hc->bch[0]); mISDN_freedchannel(&hc->dch); - list_del(&hc->list); pci_set_drvdata(hc->pdev, NULL); kfree(hc); } @@ -2141,7 +2101,6 @@ setup_card(struct hfc_pci *card) { int err = -EINVAL; u_int i; - u_long flags; char name[MISDN_MAX_IDLEN]; card->dch.debug = debug; @@ -2169,13 +2128,10 @@ setup_card(struct hfc_pci *card) if (err) goto error; snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1); - err = mISDN_register_device(&card->dch.dev, name); + err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name); if (err) goto error; HFC_cnt++; - write_lock_irqsave(&HFClock, flags); - list_add_tail(&card->list, &HFClist); - write_unlock_irqrestore(&HFClock, flags); printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt); return 0; error: @@ -2311,15 +2267,12 @@ static void __devexit hfc_remove_pci(struct pci_dev *pdev) { struct hfc_pci *card = pci_get_drvdata(pdev); - u_long flags; - if (card) { - write_lock_irqsave(&HFClock, flags); + if (card) release_card(card); - write_unlock_irqrestore(&HFClock, flags); - } else + else if (debug) - printk(KERN_WARNING "%s: drvdata allready removed\n", + printk(KERN_WARNING "%s: drvdata already removed\n", __func__); } @@ -2331,6 +2284,46 @@ static struct pci_driver hfc_driver = { .id_table = hfc_ids, }; +static int +_hfcpci_softirq(struct device *dev, void *arg) +{ + struct hfc_pci *hc = dev_get_drvdata(dev); + struct bchannel *bch; + if (hc == NULL) + return 0; + + if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) { + spin_lock(&hc->lock); + bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); + if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */ + main_rec_hfcpci(bch); + tx_birq(bch); + } + bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2); + if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */ + main_rec_hfcpci(bch); + tx_birq(bch); + } + spin_unlock(&hc->lock); + } + return 0; +} + +static void +hfcpci_softirq(void *arg) +{ + (void) driver_for_each_device(&hfc_driver.driver, NULL, arg, + _hfcpci_softirq); + + /* if next event would be in the past ... */ + if ((s32)(hfc_jiffies + tics - jiffies) <= 0) + hfc_jiffies = jiffies + 1; + else + hfc_jiffies += tics; + hfc_tl.expires = hfc_jiffies; + add_timer(&hfc_tl); +} + static int __init HFC_init(void) { @@ -2375,14 +2368,9 @@ HFC_init(void) static void __exit HFC_cleanup(void) { - struct hfc_pci *card, *next; - if (timer_pending(&hfc_tl)) del_timer(&hfc_tl); - list_for_each_entry_safe(card, next, &HFClist, list) { - release_card(card); - } pci_unregister_driver(&hfc_driver); } -- cgit v1.1 From 400fd9783e7374bdf73b9cee9d7b90e35e3007da Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 11 Oct 2008 08:13:29 +0200 Subject: mISDN: Minor cleanups Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcpci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/isdn/hardware/mISDN/hfcpci.c') diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 8df12bf..2db0649 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -2333,10 +2333,10 @@ HFC_init(void) poll = HFCPCI_BTRANS_THRESHOLD; if (poll != HFCPCI_BTRANS_THRESHOLD) { - tics = poll * HZ / 8000; + tics = (poll * HZ) / 8000; if (tics < 1) tics = 1; - poll = tics * 8000 / HZ; + poll = (tics * 8000) / HZ; if (poll > 256 || poll < 8) { printk(KERN_ERR "%s: Wrong poll value %d not in range " "of 8..256.\n", __func__, poll); -- cgit v1.1 From e314f89a62c1d74380455690325b1336ea0dca9d Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 16 Oct 2008 13:58:54 +0200 Subject: mISDN: Add MODULE_DEVICE_TABLE() to hfcpci Add missed table. Signed-off-by: Matthias Urlichs Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcpci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/isdn/hardware/mISDN/hfcpci.c') diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 2db0649..019dbe9 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -2376,3 +2376,5 @@ HFC_cleanup(void) module_init(HFC_init); module_exit(HFC_cleanup); + +MODULE_DEVICE_TABLE(pci, hfc_ids); -- cgit v1.1 From c3b3cdeba5a671ce5d0064c52c8a85f5b1e72e92 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 9 Nov 2008 10:23:19 +0100 Subject: mISDN: Added missing create_l1() call create_l1() was missed when changing mode to TE. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcpci.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/isdn/hardware/mISDN/hfcpci.c') diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 019dbe9..917bf41 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1937,6 +1937,11 @@ open_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch, if (rq->protocol != ch->protocol) { if (hc->hw.protocol == ISDN_P_TE_S0) l1_event(hc->dch.l1, CLOSE_CHANNEL); + if (rq->protocol == ISDN_P_TE_S0) { + err = create_l1(&hc->dch, hfc_l1callback); + if (err) + return err; + } hc->hw.protocol = rq->protocol; ch->protocol = rq->protocol; hfcpci_setmode(hc); -- cgit v1.1 From 9785a8f8db3df0605fa680f44185957aff9d8776 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Sun, 11 Jan 2009 17:58:13 +0100 Subject: Make parameter debug writable Overseen in the last patch series. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcpci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/isdn/hardware/mISDN/hfcpci.c') diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 917bf41..f0e14df 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -61,7 +61,7 @@ u32 hfc_jiffies; MODULE_AUTHOR("Karsten Keil"); MODULE_LICENSE("GPL"); -module_param(debug, uint, 0); +module_param(debug, uint, S_IRUGO | S_IWUSR); module_param(poll, uint, S_IRUGO | S_IWUSR); enum { -- cgit v1.1