Commit 7cfa153d authored by Andreas Eversberg's avatar Andreas Eversberg Committed by David S. Miller

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: default avatarAndreas Eversberg <andreas@eversberg.eu>
Signed-off-by: default avatarKarsten Keil <keil@b1-systems.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a5355c27
...@@ -44,6 +44,7 @@ struct hfc_chan { ...@@ -44,6 +44,7 @@ struct hfc_chan {
int conf; /* conference setting of TX slot */ int conf; /* conference setting of TX slot */
int txpending; /* if there is currently data in */ int txpending; /* if there is currently data in */
/* the FIFO 0=no, 1=yes, 2=splloop */ /* 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 rx_off; /* set to turn fifo receive off */
int coeff_count; /* curren coeff block */ int coeff_count; /* curren coeff block */
s32 *coeff; /* memory pointer to 8 coeff blocks */ s32 *coeff; /* memory pointer to 8 coeff blocks */
......
...@@ -1945,6 +1945,9 @@ hfcmulti_tx(struct hfc_multi *hc, int ch) ...@@ -1945,6 +1945,9 @@ hfcmulti_tx(struct hfc_multi *hc, int ch)
"%d!=%d\n", __func__, hc->id + 1, temp, z2); "%d!=%d\n", __func__, hc->id + 1, temp, z2);
z2 = temp; /* repeat unti Z2 is equal */ 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; Zspace = z2 - z1;
if (Zspace <= 0) if (Zspace <= 0)
Zspace += hc->Zlen; Zspace += hc->Zlen;
...@@ -2031,6 +2034,7 @@ hfcmulti_tx(struct hfc_multi *hc, int ch) ...@@ -2031,6 +2034,7 @@ hfcmulti_tx(struct hfc_multi *hc, int ch)
/* Have to prep the audio data */ /* Have to prep the audio data */
hc->write_fifo(hc, d, ii - i); hc->write_fifo(hc, d, ii - i);
hc->chan[ch].Zfill += ii - i;
*idxp = ii; *idxp = ii;
/* if not all data has been written */ /* if not all data has been written */
...@@ -2226,7 +2230,7 @@ hfcmulti_rx(struct hfc_multi *hc, int ch) ...@@ -2226,7 +2230,7 @@ hfcmulti_rx(struct hfc_multi *hc, int ch)
if (dch) if (dch)
recv_Dchannel(dch); recv_Dchannel(dch);
else else
recv_Bchannel(bch); recv_Bchannel(bch, MISDN_ID_ANY);
*sp = skb; *sp = skb;
again++; again++;
goto next_frame; goto next_frame;
...@@ -2258,7 +2262,7 @@ hfcmulti_rx(struct hfc_multi *hc, int ch) ...@@ -2258,7 +2262,7 @@ hfcmulti_rx(struct hfc_multi *hc, int ch)
"(z1=%04x, z2=%04x) TRANS\n", "(z1=%04x, z2=%04x) TRANS\n",
__func__, hc->id + 1, ch, Zsize, z1, z2); __func__, hc->id + 1, ch, Zsize, z1, z2);
/* only bch is transparent */ /* only bch is transparent */
recv_Bchannel(bch); recv_Bchannel(bch, hc->chan[ch].Zfill);
*sp = skb; *sp = skb;
} }
} }
......
...@@ -452,7 +452,7 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, ...@@ -452,7 +452,7 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz,
} }
bz->za[new_f2].z2 = cpu_to_le16(new_z2); bz->za[new_f2].z2 = cpu_to_le16(new_z2);
bz->f2 = new_f2; /* next buffer */ 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) ...@@ -541,35 +541,45 @@ receive_dmsg(struct hfc_pci *hc)
* check for transparent receive data and read max one 'poll' size if avail * check for transparent receive data and read max one 'poll' size if avail
*/ */
static void 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; __le16 *z1r, *z2r, *z1t, *z2t;
int new_z2, fcnt, maxlen; int new_z2, fcnt_rx, fcnt_tx, maxlen;
u_char *ptr, *ptr1; 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; z2r = z1r + 1;
z1t = &txbz->za[MAX_B_FRAMES].z1;
z2t = z1t + 1;
fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r);
if (!fcnt) if (!fcnt_rx)
return; /* no data avail */ return; /* no data avail */
if (fcnt <= 0) if (fcnt_rx <= 0)
fcnt += B_FIFO_SIZE; /* bytes actually buffered */ fcnt_rx += B_FIFO_SIZE; /* bytes actually buffered */
new_z2 = le16_to_cpu(*z2r) + fcnt; /* new position in fifo */ new_z2 = le16_to_cpu(*z2r) + fcnt_rx; /* new position in fifo */
if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
new_z2 -= B_FIFO_SIZE; /* buffer wrap */ 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 */ *z2r = cpu_to_le16(new_z2); /* new position */
return; 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) { if (bch->rx_skb) {
ptr = skb_put(bch->rx_skb, fcnt); ptr = skb_put(bch->rx_skb, fcnt_rx);
if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL) if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL)
maxlen = fcnt; /* complete transfer */ maxlen = fcnt_rx; /* complete transfer */
else else
maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r); maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r);
/* maximum */ /* maximum */
...@@ -577,14 +587,14 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) ...@@ -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); ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL);
/* start of data */ /* start of data */
memcpy(ptr, ptr1, maxlen); /* copy data */ memcpy(ptr, ptr1, maxlen); /* copy data */
fcnt -= maxlen; fcnt_rx -= maxlen;
if (fcnt) { /* rest remaining */ if (fcnt_rx) { /* rest remaining */
ptr += maxlen; ptr += maxlen;
ptr1 = bdata; /* start of buffer */ 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 } else
printk(KERN_WARNING "HFCPCI: receive out of memory\n"); printk(KERN_WARNING "HFCPCI: receive out of memory\n");
...@@ -600,26 +610,28 @@ main_rec_hfcpci(struct bchannel *bch) ...@@ -600,26 +610,28 @@ main_rec_hfcpci(struct bchannel *bch)
struct hfc_pci *hc = bch->hw; struct hfc_pci *hc = bch->hw;
int rcnt, real_fifo; int rcnt, real_fifo;
int receive = 0, count = 5; int receive = 0, count = 5;
struct bzfifo *bz; struct bzfifo *txbz, *rxbz;
u_char *bdata; u_char *bdata;
struct zt *zp; struct zt *zp;
if ((bch->nr & 2) && (!hc->hw.bswapped)) { 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; bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2;
real_fifo = 1; real_fifo = 1;
} else { } 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; bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1;
real_fifo = 0; real_fifo = 0;
} }
Begin: Begin:
count--; count--;
if (bz->f1 != bz->f2) { if (rxbz->f1 != rxbz->f2) {
if (bch->debug & DEBUG_HW_BCHANNEL) if (bch->debug & DEBUG_HW_BCHANNEL)
printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n", printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n",
bch->nr, bz->f1, bz->f2); bch->nr, rxbz->f1, rxbz->f2);
zp = &bz->za[bz->f2]; zp = &rxbz->za[rxbz->f2];
rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
if (rcnt < 0) if (rcnt < 0)
...@@ -630,8 +642,8 @@ main_rec_hfcpci(struct bchannel *bch) ...@@ -630,8 +642,8 @@ main_rec_hfcpci(struct bchannel *bch)
"hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n", "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n",
bch->nr, le16_to_cpu(zp->z1), bch->nr, le16_to_cpu(zp->z1),
le16_to_cpu(zp->z2), rcnt); le16_to_cpu(zp->z2), rcnt);
hfcpci_empty_bfifo(bch, bz, bdata, rcnt); hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt);
rcnt = bz->f1 - bz->f2; rcnt = rxbz->f1 - rxbz->f2;
if (rcnt < 0) if (rcnt < 0)
rcnt += MAX_B_FRAMES + 1; rcnt += MAX_B_FRAMES + 1;
if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) { if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) {
...@@ -644,7 +656,7 @@ main_rec_hfcpci(struct bchannel *bch) ...@@ -644,7 +656,7 @@ main_rec_hfcpci(struct bchannel *bch)
else else
receive = 0; receive = 0;
} else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
hfcpci_empty_fifo_trans(bch, bz, bdata); hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata);
return; return;
} else } else
receive = 0; receive = 0;
......
...@@ -947,7 +947,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, ...@@ -947,7 +947,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
if (fifo->dch) if (fifo->dch)
recv_Dchannel(fifo->dch); recv_Dchannel(fifo->dch);
if (fifo->bch) if (fifo->bch)
recv_Bchannel(fifo->bch); recv_Bchannel(fifo->bch, MISDN_ID_ANY);
if (fifo->ech) if (fifo->ech)
recv_Echannel(fifo->ech, recv_Echannel(fifo->ech,
&hw->dch); &hw->dch);
...@@ -969,7 +969,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, ...@@ -969,7 +969,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
} else { } else {
/* deliver transparent data to layer2 */ /* deliver transparent data to layer2 */
if (rx_skb->len >= poll) if (rx_skb->len >= poll)
recv_Bchannel(fifo->bch); recv_Bchannel(fifo->bch, MISDN_ID_ANY);
} }
spin_unlock(&hw->lock); spin_unlock(&hw->lock);
} }
......
...@@ -262,5 +262,5 @@ extern int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg); ...@@ -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, extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data,
int len); int len);
extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, 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) ...@@ -710,7 +710,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb)
/* pipeline */ /* pipeline */
if (dsp->pipeline.inuse) if (dsp->pipeline.inuse)
dsp_pipeline_process_rx(&dsp->pipeline, skb->data, dsp_pipeline_process_rx(&dsp->pipeline, skb->data,
skb->len); skb->len, hh->id);
/* change volume if requested */ /* change volume if requested */
if (dsp->rx_volume) if (dsp->rx_volume)
dsp_change_volume(skb, 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) ...@@ -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); 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; struct dsp_pipeline_entry *entry;
...@@ -356,7 +357,7 @@ void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len) ...@@ -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) list_for_each_entry_reverse(entry, &pipeline->list, list)
if (entry->elem->process_rx) 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) ...@@ -185,13 +185,13 @@ recv_Echannel(struct dchannel *ech, struct dchannel *dch)
EXPORT_SYMBOL(recv_Echannel); EXPORT_SYMBOL(recv_Echannel);
void void
recv_Bchannel(struct bchannel *bch) recv_Bchannel(struct bchannel *bch, unsigned int id)
{ {
struct mISDNhead *hh; struct mISDNhead *hh;
hh = mISDN_HEAD_P(bch->rx_skb); hh = mISDN_HEAD_P(bch->rx_skb);
hh->prim = PH_DATA_IND; hh->prim = PH_DATA_IND;
hh->id = MISDN_ID_ANY; hh->id = id;
if (bch->rcount >= 64) { if (bch->rcount >= 64) {
printk(KERN_WARNING "B-channel %p receive queue overflow, " printk(KERN_WARNING "B-channel %p receive queue overflow, "
"fushing!\n", bch); "fushing!\n", bch);
......
...@@ -12,7 +12,8 @@ struct mISDN_dsp_element { ...@@ -12,7 +12,8 @@ struct mISDN_dsp_element {
void *(*new)(const char *arg); void *(*new)(const char *arg);
void (*free)(void *p); void (*free)(void *p);
void (*process_tx)(void *p, unsigned char *data, int len); 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; int num_args;
struct mISDN_dsp_element_arg struct mISDN_dsp_element_arg
*args; *args;
......
...@@ -185,7 +185,7 @@ extern int dchannel_senddata(struct dchannel *, struct sk_buff *); ...@@ -185,7 +185,7 @@ extern int dchannel_senddata(struct dchannel *, struct sk_buff *);
extern int bchannel_senddata(struct bchannel *, struct sk_buff *); extern int bchannel_senddata(struct bchannel *, struct sk_buff *);
extern void recv_Dchannel(struct dchannel *); extern void recv_Dchannel(struct dchannel *);
extern void recv_Echannel(struct 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_Dchannel_skb(struct dchannel *, struct sk_buff *);
extern void recv_Bchannel_skb(struct bchannel *, struct sk_buff *); extern void recv_Bchannel_skb(struct bchannel *, struct sk_buff *);
extern void confirm_Bsend(struct bchannel *bch); extern void confirm_Bsend(struct bchannel *bch);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment