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

mISDN: Hardware acceleration is now possible in conjunction with audio recording

Audio recording requires software audio processing.
Both hardware and software processing is simultaniously possible now.
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 b5df5a5c
...@@ -151,6 +151,15 @@ struct dsp_tone { ...@@ -151,6 +151,15 @@ struct dsp_tone {
struct timer_list tl; struct timer_list tl;
}; };
/***************
* echo stuff *
***************/
struct dsp_echo {
int software; /* echo is generated by software */
int hardware; /* echo is generated by hardware */
};
/***************** /*****************
* general stuff * * general stuff *
*****************/ *****************/
...@@ -161,7 +170,7 @@ struct dsp { ...@@ -161,7 +170,7 @@ struct dsp {
struct mISDNchannel *up; struct mISDNchannel *up;
unsigned char name[64]; unsigned char name[64];
int b_active; int b_active;
int echo; /* echo is enabled */ struct dsp_echo echo;
int rx_disabled; /* what the user wants */ int rx_disabled; /* what the user wants */
int rx_is_off; /* what the card is */ int rx_is_off; /* what the card is */
int tx_mix; int tx_mix;
......
...@@ -163,8 +163,9 @@ dsp_cmx_debug(struct dsp *dsp) ...@@ -163,8 +163,9 @@ dsp_cmx_debug(struct dsp *dsp)
printk(KERN_DEBUG "-----Current DSP\n"); printk(KERN_DEBUG "-----Current DSP\n");
list_for_each_entry(odsp, &dsp_ilist, list) { list_for_each_entry(odsp, &dsp_ilist, list) {
printk(KERN_DEBUG "* %s echo=%d txmix=%d", printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d",
odsp->name, odsp->echo, odsp->tx_mix); odsp->name, odsp->echo.hardware, odsp->echo.software,
odsp->tx_mix);
if (odsp->conf) if (odsp->conf)
printk(" (Conf %d)", odsp->conf->id); printk(" (Conf %d)", odsp->conf->id);
if (dsp == odsp) if (dsp == odsp)
...@@ -177,10 +178,12 @@ dsp_cmx_debug(struct dsp *dsp) ...@@ -177,10 +178,12 @@ dsp_cmx_debug(struct dsp *dsp)
list_for_each_entry(member, &conf->mlist, list) { list_for_each_entry(member, &conf->mlist, list) {
printk(KERN_DEBUG printk(KERN_DEBUG
" - member = %s (slot_tx %d, bank_tx %d, " " - member = %s (slot_tx %d, bank_tx %d, "
"slot_rx %d, bank_rx %d hfc_conf %d)%s\n", "slot_rx %d, bank_rx %d hfc_conf %d "
"tx_data %d rx_is_off %d)%s\n",
member->dsp->name, member->dsp->pcm_slot_tx, member->dsp->name, member->dsp->pcm_slot_tx,
member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx,
member->dsp->pcm_bank_rx, member->dsp->hfc_conf, member->dsp->pcm_bank_rx, member->dsp->hfc_conf,
member->dsp->tx_data, member->dsp->rx_is_off,
(member->dsp == dsp) ? " *this*" : ""); (member->dsp == dsp) ? " *this*" : "");
} }
} }
...@@ -385,7 +388,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) ...@@ -385,7 +388,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
int freeunits[8]; int freeunits[8];
u_char freeslots[256]; u_char freeslots[256];
int same_hfc = -1, same_pcm = -1, current_conf = -1, int same_hfc = -1, same_pcm = -1, current_conf = -1,
all_conf = 1; all_conf = 1, tx_data = 0;
/* dsp gets updated (no conf) */ /* dsp gets updated (no conf) */
if (!conf) { if (!conf) {
...@@ -409,7 +412,7 @@ one_member: ...@@ -409,7 +412,7 @@ one_member:
/* process hw echo */ /* process hw echo */
if (dsp->features.pcm_banks < 1) if (dsp->features.pcm_banks < 1)
return; return;
if (!dsp->echo) { if (!dsp->echo.software && !dsp->echo.hardware) {
/* NO ECHO: remove PCM slot if assigned */ /* NO ECHO: remove PCM slot if assigned */
if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) {
if (dsp_debug & DEBUG_DSP_CMX) if (dsp_debug & DEBUG_DSP_CMX)
...@@ -427,10 +430,15 @@ one_member: ...@@ -427,10 +430,15 @@ one_member:
} }
return; return;
} }
/* echo is enabled, find out if we use soft or hardware */
dsp->echo.software = dsp->tx_data;
dsp->echo.hardware = 0;
/* ECHO: already echo */ /* ECHO: already echo */
if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 && if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 &&
dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) {
dsp->echo.hardware = 1;
return; return;
}
/* ECHO: if slot already assigned */ /* ECHO: if slot already assigned */
if (dsp->pcm_slot_tx >= 0) { if (dsp->pcm_slot_tx >= 0) {
dsp->pcm_slot_rx = dsp->pcm_slot_tx; dsp->pcm_slot_rx = dsp->pcm_slot_tx;
...@@ -443,6 +451,7 @@ one_member: ...@@ -443,6 +451,7 @@ one_member:
dsp->pcm_slot_tx); dsp->pcm_slot_tx);
dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN,
dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);
dsp->echo.hardware = 1;
return; return;
} }
/* ECHO: find slot */ /* ECHO: find slot */
...@@ -472,6 +481,7 @@ one_member: ...@@ -472,6 +481,7 @@ one_member:
"%s no slot available for echo\n", "%s no slot available for echo\n",
__func__); __func__);
/* no more slots available */ /* no more slots available */
dsp->echo.software = 1;
return; return;
} }
/* assign free slot */ /* assign free slot */
...@@ -485,6 +495,7 @@ one_member: ...@@ -485,6 +495,7 @@ one_member:
__func__, dsp->name, dsp->pcm_slot_tx); __func__, dsp->name, dsp->pcm_slot_tx);
dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN,
dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);
dsp->echo.hardware = 1;
return; return;
} }
...@@ -554,7 +565,7 @@ conf_software: ...@@ -554,7 +565,7 @@ conf_software:
return; return;
} }
/* check if member has echo turned on */ /* check if member has echo turned on */
if (member->dsp->echo) { if (member->dsp->echo.hardware || member->dsp->echo.software) {
if (dsp_debug & DEBUG_DSP_CMX) if (dsp_debug & DEBUG_DSP_CMX)
printk(KERN_DEBUG printk(KERN_DEBUG
"%s dsp %s cannot form a conf, because " "%s dsp %s cannot form a conf, because "
...@@ -592,10 +603,9 @@ conf_software: ...@@ -592,10 +603,9 @@ conf_software:
if (member->dsp->tx_data) { if (member->dsp->tx_data) {
if (dsp_debug & DEBUG_DSP_CMX) if (dsp_debug & DEBUG_DSP_CMX)
printk(KERN_DEBUG printk(KERN_DEBUG
"%s dsp %s cannot form a conf, because " "%s dsp %s tx_data is turned on\n",
"tx_data is turned on\n",
__func__, member->dsp->name); __func__, member->dsp->name);
goto conf_software; tx_data = 1;
} }
/* check if pipeline exists */ /* check if pipeline exists */
if (member->dsp->pipeline.inuse) { if (member->dsp->pipeline.inuse) {
...@@ -794,7 +804,7 @@ conf_software: ...@@ -794,7 +804,7 @@ conf_software:
nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx,
nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);
conf->hardware = 1; conf->hardware = 1;
conf->software = 0; conf->software = tx_data;
return; return;
/* if members have one bank (or on the same chip) */ /* if members have one bank (or on the same chip) */
} else { } else {
...@@ -904,7 +914,7 @@ conf_software: ...@@ -904,7 +914,7 @@ conf_software:
nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx,
nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);
conf->hardware = 1; conf->hardware = 1;
conf->software = 0; conf->software = tx_data;
return; return;
} }
} }
...@@ -1295,17 +1305,25 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) ...@@ -1295,17 +1305,25 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
int r, rr, t, tt, o_r, o_rr; int r, rr, t, tt, o_r, o_rr;
int preload = 0; int preload = 0;
struct mISDNhead *hh, *thh; struct mISDNhead *hh, *thh;
int tx_data_only = 0;
/* don't process if: */ /* don't process if: */
if (!dsp->b_active) { /* if not active */ if (!dsp->b_active) { /* if not active */
dsp->last_tx = 0; dsp->last_tx = 0;
return; return;
} }
if (dsp->pcm_slot_tx >= 0 && /* connected to pcm slot */ if (((dsp->conf && dsp->conf->hardware) || /* hardware conf */
dsp->echo.hardware) && /* OR hardware echo */
dsp->tx_R == dsp->tx_W && /* AND no tx-data */ dsp->tx_R == dsp->tx_W && /* AND no tx-data */
!(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */
dsp->last_tx = 0; if (!dsp->tx_data) { /* no tx_data for user space required */
return; dsp->last_tx = 0;
return;
}
if (dsp->conf && dsp->conf->software && dsp->conf->hardware)
tx_data_only = 1;
if (dsp->conf->software && dsp->echo.hardware)
tx_data_only = 1;
} }
#ifdef CMX_DEBUG #ifdef CMX_DEBUG
...@@ -1388,7 +1406,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) ...@@ -1388,7 +1406,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
/* PROCESS DATA (one member / no conf) */ /* PROCESS DATA (one member / no conf) */
if (!conf || members <= 1) { if (!conf || members <= 1) {
/* -> if echo is NOT enabled */ /* -> if echo is NOT enabled */
if (!dsp->echo) { if (!dsp->echo.software) {
/* -> send tx-data if available or use 0-volume */ /* -> send tx-data if available or use 0-volume */
while (r != rr && t != tt) { while (r != rr && t != tt) {
*d++ = p[t]; /* write tx_buff */ *d++ = p[t]; /* write tx_buff */
...@@ -1438,7 +1456,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) ...@@ -1438,7 +1456,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
o_r = (o_rr - rr + r) & CMX_BUFF_MASK; o_r = (o_rr - rr + r) & CMX_BUFF_MASK;
/* start rx-pointer at current read position*/ /* start rx-pointer at current read position*/
/* -> if echo is NOT enabled */ /* -> if echo is NOT enabled */
if (!dsp->echo) { if (!dsp->echo.software) {
/* /*
* -> copy other member's rx-data, * -> copy other member's rx-data,
* if tx-data is available, mix * if tx-data is available, mix
...@@ -1486,7 +1504,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) ...@@ -1486,7 +1504,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
#endif #endif
/* PROCESS DATA (three or more members) */ /* PROCESS DATA (three or more members) */
/* -> if echo is NOT enabled */ /* -> if echo is NOT enabled */
if (!dsp->echo) { if (!dsp->echo.software) {
/* /*
* -> substract rx-data from conf-data, * -> substract rx-data from conf-data,
* if tx-data is available, mix * if tx-data is available, mix
...@@ -1550,27 +1568,40 @@ send_packet: ...@@ -1550,27 +1568,40 @@ send_packet:
* becuase we want what we send, not what we filtered * becuase we want what we send, not what we filtered
*/ */
if (dsp->tx_data) { if (dsp->tx_data) {
/* PREPARE RESULT */ if (tx_data_only) {
txskb = mI_alloc_skb(len, GFP_ATOMIC); hh->prim = DL_DATA_REQ;
if (!txskb) { hh->id = 0;
printk(KERN_ERR /* queue and trigger */
"FATAL ERROR in mISDN_dsp.o: " skb_queue_tail(&dsp->sendq, nskb);
"cannot alloc %d bytes\n", len); schedule_work(&dsp->workq);
/* exit because only tx_data is used */
return;
} else { } else {
thh = mISDN_HEAD_P(txskb); txskb = mI_alloc_skb(len, GFP_ATOMIC);
thh->prim = DL_DATA_REQ; if (!txskb) {
thh->id = 0; printk(KERN_ERR
memcpy(skb_put(txskb, len), nskb->data+preload, len); "FATAL ERROR in mISDN_dsp.o: "
/* queue (trigger later) */ "cannot alloc %d bytes\n", len);
skb_queue_tail(&dsp->sendq, txskb); } else {
thh = mISDN_HEAD_P(txskb);
thh->prim = DL_DATA_REQ;
thh->id = 0;
memcpy(skb_put(txskb, len), nskb->data+preload,
len);
/* queue (trigger later) */
skb_queue_tail(&dsp->sendq, txskb);
}
} }
} }
/* send data only to card, if we don't just calculated tx_data */
/* adjust volume */ /* adjust volume */
if (dsp->tx_volume) if (dsp->tx_volume)
dsp_change_volume(nskb, dsp->tx_volume); dsp_change_volume(nskb, dsp->tx_volume);
/* pipeline */ /* pipeline */
if (dsp->pipeline.inuse) if (dsp->pipeline.inuse)
dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, nskb->len); dsp_pipeline_process_tx(&dsp->pipeline, nskb->data,
nskb->len);
/* crypt */ /* crypt */
if (dsp->bf_enable) if (dsp->bf_enable)
dsp_bf_encrypt(dsp, nskb->data, nskb->len); dsp_bf_encrypt(dsp, nskb->data, nskb->len);
...@@ -1891,10 +1922,8 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) ...@@ -1891,10 +1922,8 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb)
/* no conf */ /* no conf */
if (!dsp->conf) { if (!dsp->conf) {
/* in case of hardware (echo) */ /* in case of software echo */
if (dsp->pcm_slot_tx >= 0) if (dsp->echo.software) {
return;
if (dsp->echo) {
nskb = skb_clone(skb, GFP_ATOMIC); nskb = skb_clone(skb, GFP_ATOMIC);
if (nskb) { if (nskb) {
hh = mISDN_HEAD_P(nskb); hh = mISDN_HEAD_P(nskb);
...@@ -1910,7 +1939,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) ...@@ -1910,7 +1939,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb)
if (dsp->conf->hardware) if (dsp->conf->hardware)
return; return;
list_for_each_entry(member, &dsp->conf->mlist, list) { list_for_each_entry(member, &dsp->conf->mlist, list) {
if (dsp->echo || member->dsp != dsp) { if (dsp->echo.software || member->dsp != dsp) {
nskb = skb_clone(skb, GFP_ATOMIC); nskb = skb_clone(skb, GFP_ATOMIC);
if (nskb) { if (nskb) {
hh = mISDN_HEAD_P(nskb); hh = mISDN_HEAD_P(nskb);
......
...@@ -203,13 +203,13 @@ dsp_rx_off_member(struct dsp *dsp) ...@@ -203,13 +203,13 @@ dsp_rx_off_member(struct dsp *dsp)
else if (dsp->dtmf.software) else if (dsp->dtmf.software)
rx_off = 0; rx_off = 0;
/* echo in software */ /* echo in software */
else if (dsp->echo && dsp->pcm_slot_tx < 0) else if (dsp->echo.software)
rx_off = 0; rx_off = 0;
/* bridge in software */ /* bridge in software */
else if (dsp->conf) { else if (dsp->conf && dsp->conf->software)
if (dsp->conf->software) rx_off = 0;
rx_off = 0; /* data is not required by user space and not required
} * for echo dtmf detection, soft-echo, soft-bridging */
if (rx_off == dsp->rx_is_off) if (rx_off == dsp->rx_is_off)
return; return;
...@@ -415,7 +415,7 @@ tone_off: ...@@ -415,7 +415,7 @@ tone_off:
dsp_rx_off(dsp); dsp_rx_off(dsp);
break; break;
case DSP_ECHO_ON: /* enable echo */ case DSP_ECHO_ON: /* enable echo */
dsp->echo = 1; /* soft echo */ dsp->echo.software = 1; /* soft echo */
if (dsp_debug & DEBUG_DSP_CORE) if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__); printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__);
dsp_cmx_hardware(dsp->conf, dsp); dsp_cmx_hardware(dsp->conf, dsp);
...@@ -424,7 +424,8 @@ tone_off: ...@@ -424,7 +424,8 @@ tone_off:
dsp_cmx_debug(dsp); dsp_cmx_debug(dsp);
break; break;
case DSP_ECHO_OFF: /* disable echo */ case DSP_ECHO_OFF: /* disable echo */
dsp->echo = 0; dsp->echo.software = 0;
dsp->echo.hardware = 0;
if (dsp_debug & DEBUG_DSP_CORE) if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__); printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__);
dsp_cmx_hardware(dsp->conf, dsp); dsp_cmx_hardware(dsp->conf, dsp);
...@@ -722,7 +723,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) ...@@ -722,7 +723,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb)
skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); skb->len, (dsp_options&DSP_OPT_ULAW)?1:0);
} }
/* we need to process receive data if software */ /* we need to process receive data if software */
if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) { if (dsp->conf && dsp->conf->software) {
/* process data from card at cmx */ /* process data from card at cmx */
dsp_cmx_receive(dsp, skb); dsp_cmx_receive(dsp, skb);
} }
......
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