diff options
Diffstat (limited to 'drivers/isdn/mISDN')
-rw-r--r-- | drivers/isdn/mISDN/dsp.h | 1 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_cmx.c | 56 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_core.c | 37 |
3 files changed, 73 insertions, 21 deletions
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) |