diff options
Diffstat (limited to 'drivers/isdn/hardware/mISDN/hfcmulti.c')
-rw-r--r-- | drivers/isdn/hardware/mISDN/hfcmulti.c | 45 |
1 files changed, 35 insertions, 10 deletions
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); |