mISDN: Echo canceler now gets delay information from hardware
Added tx-fifo information for calculation of current delay to sync tx and rx streams for echo canceler. Signed-off-by: Andreas Eversberg <andreas@eversberg.eu> Signed-off-by: Karsten Keil <keil@b1-systems.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a5355c27d2
commit
7cfa153dd7
10 changed files with 60 additions and 41 deletions
|
@ -44,6 +44,7 @@ struct hfc_chan {
|
|||
int conf; /* conference setting of TX slot */
|
||||
int txpending; /* if there is currently data in */
|
||||
/* the FIFO 0=no, 1=yes, 2=splloop */
|
||||
int Zfill; /* rx-fifo level on last hfcmulti_tx */
|
||||
int rx_off; /* set to turn fifo receive off */
|
||||
int coeff_count; /* curren coeff block */
|
||||
s32 *coeff; /* memory pointer to 8 coeff blocks */
|
||||
|
|
|
@ -1945,6 +1945,9 @@ next_frame:
|
|||
"%d!=%d\n", __func__, hc->id + 1, temp, z2);
|
||||
z2 = temp; /* repeat unti Z2 is equal */
|
||||
}
|
||||
hc->chan[ch].Zfill = z1 - z2;
|
||||
if (hc->chan[ch].Zfill < 0)
|
||||
hc->chan[ch].Zfill += hc->Zlen;
|
||||
Zspace = z2 - z1;
|
||||
if (Zspace <= 0)
|
||||
Zspace += hc->Zlen;
|
||||
|
@ -2031,6 +2034,7 @@ next_frame:
|
|||
|
||||
/* Have to prep the audio data */
|
||||
hc->write_fifo(hc, d, ii - i);
|
||||
hc->chan[ch].Zfill += ii - i;
|
||||
*idxp = ii;
|
||||
|
||||
/* if not all data has been written */
|
||||
|
@ -2226,7 +2230,7 @@ next_frame:
|
|||
if (dch)
|
||||
recv_Dchannel(dch);
|
||||
else
|
||||
recv_Bchannel(bch);
|
||||
recv_Bchannel(bch, MISDN_ID_ANY);
|
||||
*sp = skb;
|
||||
again++;
|
||||
goto next_frame;
|
||||
|
@ -2258,7 +2262,7 @@ next_frame:
|
|||
"(z1=%04x, z2=%04x) TRANS\n",
|
||||
__func__, hc->id + 1, ch, Zsize, z1, z2);
|
||||
/* only bch is transparent */
|
||||
recv_Bchannel(bch);
|
||||
recv_Bchannel(bch, hc->chan[ch].Zfill);
|
||||
*sp = skb;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -452,7 +452,7 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz,
|
|||
}
|
||||
bz->za[new_f2].z2 = cpu_to_le16(new_z2);
|
||||
bz->f2 = new_f2; /* next buffer */
|
||||
recv_Bchannel(bch);
|
||||
recv_Bchannel(bch, MISDN_ID_ANY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -541,35 +541,45 @@ receive_dmsg(struct hfc_pci *hc)
|
|||
* check for transparent receive data and read max one 'poll' size if avail
|
||||
*/
|
||||
static void
|
||||
hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata)
|
||||
hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
|
||||
struct bzfifo *txbz, u_char *bdata)
|
||||
{
|
||||
__le16 *z1r, *z2r;
|
||||
int new_z2, fcnt, maxlen;
|
||||
u_char *ptr, *ptr1;
|
||||
__le16 *z1r, *z2r, *z1t, *z2t;
|
||||
int new_z2, fcnt_rx, fcnt_tx, maxlen;
|
||||
u_char *ptr, *ptr1;
|
||||
|
||||
z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */
|
||||
z1r = &rxbz->za[MAX_B_FRAMES].z1; /* pointer to z reg */
|
||||
z2r = z1r + 1;
|
||||
z1t = &txbz->za[MAX_B_FRAMES].z1;
|
||||
z2t = z1t + 1;
|
||||
|
||||
fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r);
|
||||
if (!fcnt)
|
||||
fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r);
|
||||
if (!fcnt_rx)
|
||||
return; /* no data avail */
|
||||
|
||||
if (fcnt <= 0)
|
||||
fcnt += B_FIFO_SIZE; /* bytes actually buffered */
|
||||
new_z2 = le16_to_cpu(*z2r) + fcnt; /* new position in fifo */
|
||||
if (fcnt_rx <= 0)
|
||||
fcnt_rx += B_FIFO_SIZE; /* bytes actually buffered */
|
||||
new_z2 = le16_to_cpu(*z2r) + fcnt_rx; /* 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 */
|
||||
if (fcnt_rx > MAX_DATA_SIZE) { /* flush, if oversized */
|
||||
*z2r = cpu_to_le16(new_z2); /* new position */
|
||||
return;
|
||||
}
|
||||
|
||||
bch->rx_skb = mI_alloc_skb(fcnt, GFP_ATOMIC);
|
||||
fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
|
||||
if (fcnt_tx <= 0)
|
||||
fcnt_tx += B_FIFO_SIZE;
|
||||
/* fcnt_tx contains available bytes in tx-fifo */
|
||||
fcnt_tx = B_FIFO_SIZE - fcnt_tx;
|
||||
/* remaining bytes to send (bytes in tx-fifo) */
|
||||
|
||||
bch->rx_skb = mI_alloc_skb(fcnt_rx, GFP_ATOMIC);
|
||||
if (bch->rx_skb) {
|
||||
ptr = skb_put(bch->rx_skb, fcnt);
|
||||
if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
|
||||
maxlen = fcnt; /* complete transfer */
|
||||
ptr = skb_put(bch->rx_skb, fcnt_rx);
|
||||
if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL)
|
||||
maxlen = fcnt_rx; /* complete transfer */
|
||||
else
|
||||
maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r);
|
||||
/* maximum */
|
||||
|
@ -577,14 +587,14 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata)
|
|||
ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL);
|
||||
/* start of data */
|
||||
memcpy(ptr, ptr1, maxlen); /* copy data */
|
||||
fcnt -= maxlen;
|
||||
fcnt_rx -= maxlen;
|
||||
|
||||
if (fcnt) { /* rest remaining */
|
||||
if (fcnt_rx) { /* rest remaining */
|
||||
ptr += maxlen;
|
||||
ptr1 = bdata; /* start of buffer */
|
||||
memcpy(ptr, ptr1, fcnt); /* rest */
|
||||
memcpy(ptr, ptr1, fcnt_rx); /* rest */
|
||||
}
|
||||
recv_Bchannel(bch);
|
||||
recv_Bchannel(bch, fcnt_tx); /* bch, id */
|
||||
} else
|
||||
printk(KERN_WARNING "HFCPCI: receive out of memory\n");
|
||||
|
||||
|
@ -600,26 +610,28 @@ main_rec_hfcpci(struct bchannel *bch)
|
|||
struct hfc_pci *hc = bch->hw;
|
||||
int rcnt, real_fifo;
|
||||
int receive = 0, count = 5;
|
||||
struct bzfifo *bz;
|
||||
struct bzfifo *txbz, *rxbz;
|
||||
u_char *bdata;
|
||||
struct zt *zp;
|
||||
|
||||
if ((bch->nr & 2) && (!hc->hw.bswapped)) {
|
||||
bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
|
||||
rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
|
||||
txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
|
||||
bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2;
|
||||
real_fifo = 1;
|
||||
} else {
|
||||
bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
|
||||
rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
|
||||
txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
|
||||
bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1;
|
||||
real_fifo = 0;
|
||||
}
|
||||
Begin:
|
||||
count--;
|
||||
if (bz->f1 != bz->f2) {
|
||||
if (rxbz->f1 != rxbz->f2) {
|
||||
if (bch->debug & DEBUG_HW_BCHANNEL)
|
||||
printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n",
|
||||
bch->nr, bz->f1, bz->f2);
|
||||
zp = &bz->za[bz->f2];
|
||||
bch->nr, rxbz->f1, rxbz->f2);
|
||||
zp = &rxbz->za[rxbz->f2];
|
||||
|
||||
rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
|
||||
if (rcnt < 0)
|
||||
|
@ -630,8 +642,8 @@ Begin:
|
|||
"hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n",
|
||||
bch->nr, le16_to_cpu(zp->z1),
|
||||
le16_to_cpu(zp->z2), rcnt);
|
||||
hfcpci_empty_bfifo(bch, bz, bdata, rcnt);
|
||||
rcnt = bz->f1 - bz->f2;
|
||||
hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt);
|
||||
rcnt = rxbz->f1 - rxbz->f2;
|
||||
if (rcnt < 0)
|
||||
rcnt += MAX_B_FRAMES + 1;
|
||||
if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) {
|
||||
|
@ -644,7 +656,7 @@ Begin:
|
|||
else
|
||||
receive = 0;
|
||||
} else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
|
||||
hfcpci_empty_fifo_trans(bch, bz, bdata);
|
||||
hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata);
|
||||
return;
|
||||
} else
|
||||
receive = 0;
|
||||
|
|
|
@ -947,7 +947,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
|
|||
if (fifo->dch)
|
||||
recv_Dchannel(fifo->dch);
|
||||
if (fifo->bch)
|
||||
recv_Bchannel(fifo->bch);
|
||||
recv_Bchannel(fifo->bch, MISDN_ID_ANY);
|
||||
if (fifo->ech)
|
||||
recv_Echannel(fifo->ech,
|
||||
&hw->dch);
|
||||
|
@ -969,7 +969,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
|
|||
} else {
|
||||
/* deliver transparent data to layer2 */
|
||||
if (rx_skb->len >= poll)
|
||||
recv_Bchannel(fifo->bch);
|
||||
recv_Bchannel(fifo->bch, MISDN_ID_ANY);
|
||||
}
|
||||
spin_unlock(&hw->lock);
|
||||
}
|
||||
|
|
|
@ -262,5 +262,5 @@ extern int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg);
|
|||
extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data,
|
||||
int len);
|
||||
extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data,
|
||||
int len);
|
||||
int len, unsigned int txlen);
|
||||
|
||||
|
|
|
@ -710,7 +710,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb)
|
|||
/* pipeline */
|
||||
if (dsp->pipeline.inuse)
|
||||
dsp_pipeline_process_rx(&dsp->pipeline, skb->data,
|
||||
skb->len);
|
||||
skb->len, hh->id);
|
||||
/* change volume if requested */
|
||||
if (dsp->rx_volume)
|
||||
dsp_change_volume(skb, dsp->rx_volume);
|
||||
|
|
|
@ -347,7 +347,8 @@ void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len)
|
|||
entry->elem->process_tx(entry->p, data, len);
|
||||
}
|
||||
|
||||
void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len)
|
||||
void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len,
|
||||
unsigned int txlen)
|
||||
{
|
||||
struct dsp_pipeline_entry *entry;
|
||||
|
||||
|
@ -356,7 +357,7 @@ void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len)
|
|||
|
||||
list_for_each_entry_reverse(entry, &pipeline->list, list)
|
||||
if (entry->elem->process_rx)
|
||||
entry->elem->process_rx(entry->p, data, len);
|
||||
entry->elem->process_rx(entry->p, data, len, txlen);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -185,13 +185,13 @@ recv_Echannel(struct dchannel *ech, struct dchannel *dch)
|
|||
EXPORT_SYMBOL(recv_Echannel);
|
||||
|
||||
void
|
||||
recv_Bchannel(struct bchannel *bch)
|
||||
recv_Bchannel(struct bchannel *bch, unsigned int id)
|
||||
{
|
||||
struct mISDNhead *hh;
|
||||
|
||||
hh = mISDN_HEAD_P(bch->rx_skb);
|
||||
hh->prim = PH_DATA_IND;
|
||||
hh->id = MISDN_ID_ANY;
|
||||
hh->id = id;
|
||||
if (bch->rcount >= 64) {
|
||||
printk(KERN_WARNING "B-channel %p receive queue overflow, "
|
||||
"fushing!\n", bch);
|
||||
|
|
|
@ -12,7 +12,8 @@ struct mISDN_dsp_element {
|
|||
void *(*new)(const char *arg);
|
||||
void (*free)(void *p);
|
||||
void (*process_tx)(void *p, unsigned char *data, int len);
|
||||
void (*process_rx)(void *p, unsigned char *data, int len);
|
||||
void (*process_rx)(void *p, unsigned char *data, int len,
|
||||
unsigned int txlen);
|
||||
int num_args;
|
||||
struct mISDN_dsp_element_arg
|
||||
*args;
|
||||
|
|
|
@ -185,7 +185,7 @@ 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_Bchannel(struct bchannel *, unsigned int id);
|
||||
extern void recv_Dchannel_skb(struct dchannel *, struct sk_buff *);
|
||||
extern void recv_Bchannel_skb(struct bchannel *, struct sk_buff *);
|
||||
extern void confirm_Bsend(struct bchannel *bch);
|
||||
|
|
Loading…
Reference in a new issue