Skip to content

Commit

Permalink
mISDN: Hardware acceleration is now possible in conjunction with audi…
Browse files Browse the repository at this point in the history
…o recording

Audio recording requires software audio processing.
Both hardware and software processing is simultaniously possible now.

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>
  • Loading branch information
Andreas Eversberg authored and David S. Miller committed May 25, 2009
1 parent b5df5a5 commit bc138ec
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 45 deletions.
11 changes: 10 additions & 1 deletion drivers/isdn/mISDN/dsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ struct dsp_tone {
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 *
*****************/
Expand All @@ -161,7 +170,7 @@ struct dsp {
struct mISDNchannel *up;
unsigned char name[64];
int b_active;
int echo; /* echo is enabled */
struct dsp_echo echo;
int rx_disabled; /* what the user wants */
int rx_is_off; /* what the card is */
int tx_mix;
Expand Down
101 changes: 65 additions & 36 deletions drivers/isdn/mISDN/dsp_cmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,9 @@ dsp_cmx_debug(struct dsp *dsp)

printk(KERN_DEBUG "-----Current DSP\n");
list_for_each_entry(odsp, &dsp_ilist, list) {
printk(KERN_DEBUG "* %s echo=%d txmix=%d",
odsp->name, odsp->echo, odsp->tx_mix);
printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d",
odsp->name, odsp->echo.hardware, odsp->echo.software,
odsp->tx_mix);
if (odsp->conf)
printk(" (Conf %d)", odsp->conf->id);
if (dsp == odsp)
Expand All @@ -177,10 +178,12 @@ dsp_cmx_debug(struct dsp *dsp)
list_for_each_entry(member, &conf->mlist, list) {
printk(KERN_DEBUG
" - 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->pcm_bank_tx, member->dsp->pcm_slot_rx,
member->dsp->pcm_bank_rx, member->dsp->hfc_conf,
member->dsp->tx_data, member->dsp->rx_is_off,
(member->dsp == dsp) ? " *this*" : "");
}
}
Expand Down Expand Up @@ -385,7 +388,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
int freeunits[8];
u_char freeslots[256];
int same_hfc = -1, same_pcm = -1, current_conf = -1,
all_conf = 1;
all_conf = 1, tx_data = 0;

/* dsp gets updated (no conf) */
if (!conf) {
Expand All @@ -409,7 +412,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
/* process hw echo */
if (dsp->features.pcm_banks < 1)
return;
if (!dsp->echo) {
if (!dsp->echo.software && !dsp->echo.hardware) {
/* NO ECHO: remove PCM slot if assigned */
if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) {
if (dsp_debug & DEBUG_DSP_CMX)
Expand All @@ -427,10 +430,15 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
}
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 */
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;
}
/* ECHO: if slot already assigned */
if (dsp->pcm_slot_tx >= 0) {
dsp->pcm_slot_rx = dsp->pcm_slot_tx;
Expand All @@ -443,6 +451,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
dsp->pcm_slot_tx);
dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN,
dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);
dsp->echo.hardware = 1;
return;
}
/* ECHO: find slot */
Expand Down Expand Up @@ -472,6 +481,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
"%s no slot available for echo\n",
__func__);
/* no more slots available */
dsp->echo.software = 1;
return;
}
/* assign free slot */
Expand All @@ -485,6 +495,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
__func__, dsp->name, dsp->pcm_slot_tx);
dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN,
dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);
dsp->echo.hardware = 1;
return;
}

Expand Down Expand Up @@ -554,7 +565,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
return;
}
/* 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)
printk(KERN_DEBUG
"%s dsp %s cannot form a conf, because "
Expand Down Expand Up @@ -592,10 +603,9 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
if (member->dsp->tx_data) {
if (dsp_debug & DEBUG_DSP_CMX)
printk(KERN_DEBUG
"%s dsp %s cannot form a conf, because "
"tx_data is turned on\n",
"%s dsp %s tx_data is turned on\n",
__func__, member->dsp->name);
goto conf_software;
tx_data = 1;
}
/* check if pipeline exists */
if (member->dsp->pipeline.inuse) {
Expand Down Expand Up @@ -794,7 +804,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx,
nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);
conf->hardware = 1;
conf->software = 0;
conf->software = tx_data;
return;
/* if members have one bank (or on the same chip) */
} else {
Expand Down Expand Up @@ -904,7 +914,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx,
nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);
conf->hardware = 1;
conf->software = 0;
conf->software = tx_data;
return;
}
}
Expand Down Expand Up @@ -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 preload = 0;
struct mISDNhead *hh, *thh;
int tx_data_only = 0;

/* don't process if: */
if (!dsp->b_active) { /* if not active */
dsp->last_tx = 0;
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->tone.tone && dsp->tone.software)) { /* AND not soft tones */
dsp->last_tx = 0;
return;
if (!dsp->tx_data) { /* no tx_data for user space required */
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
Expand Down Expand Up @@ -1388,7 +1406,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
/* PROCESS DATA (one member / no conf) */
if (!conf || members <= 1) {
/* -> if echo is NOT enabled */
if (!dsp->echo) {
if (!dsp->echo.software) {
/* -> send tx-data if available or use 0-volume */
while (r != rr && t != tt) {
*d++ = p[t]; /* write tx_buff */
Expand Down Expand Up @@ -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;
/* start rx-pointer at current read position*/
/* -> if echo is NOT enabled */
if (!dsp->echo) {
if (!dsp->echo.software) {
/*
* -> copy other member's rx-data,
* if tx-data is available, mix
Expand Down Expand Up @@ -1486,7 +1504,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
#endif
/* PROCESS DATA (three or more members) */
/* -> if echo is NOT enabled */
if (!dsp->echo) {
if (!dsp->echo.software) {
/*
* -> substract rx-data from conf-data,
* if tx-data is available, mix
Expand Down Expand Up @@ -1550,27 +1568,40 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
* becuase we want what we send, not what we filtered
*/
if (dsp->tx_data) {
/* PREPARE RESULT */
txskb = mI_alloc_skb(len, GFP_ATOMIC);
if (!txskb) {
printk(KERN_ERR
"FATAL ERROR in mISDN_dsp.o: "
"cannot alloc %d bytes\n", len);
if (tx_data_only) {
hh->prim = DL_DATA_REQ;
hh->id = 0;
/* queue and trigger */
skb_queue_tail(&dsp->sendq, nskb);
schedule_work(&dsp->workq);
/* exit because only tx_data is used */
return;
} 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);
txskb = mI_alloc_skb(len, GFP_ATOMIC);
if (!txskb) {
printk(KERN_ERR
"FATAL ERROR in mISDN_dsp.o: "
"cannot alloc %d bytes\n", len);
} 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 */
if (dsp->tx_volume)
dsp_change_volume(nskb, dsp->tx_volume);
/* pipeline */
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 */
if (dsp->bf_enable)
dsp_bf_encrypt(dsp, nskb->data, nskb->len);
Expand Down Expand Up @@ -1891,10 +1922,8 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb)

/* no conf */
if (!dsp->conf) {
/* in case of hardware (echo) */
if (dsp->pcm_slot_tx >= 0)
return;
if (dsp->echo) {
/* in case of software echo */
if (dsp->echo.software) {
nskb = skb_clone(skb, GFP_ATOMIC);
if (nskb) {
hh = mISDN_HEAD_P(nskb);
Expand All @@ -1910,7 +1939,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb)
if (dsp->conf->hardware)
return;
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);
if (nskb) {
hh = mISDN_HEAD_P(nskb);
Expand Down
17 changes: 9 additions & 8 deletions drivers/isdn/mISDN/dsp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,13 @@ dsp_rx_off_member(struct dsp *dsp)
else if (dsp->dtmf.software)
rx_off = 0;
/* echo in software */
else if (dsp->echo && dsp->pcm_slot_tx < 0)
else if (dsp->echo.software)
rx_off = 0;
/* bridge in software */
else if (dsp->conf) {
if (dsp->conf->software)
rx_off = 0;
}
else if (dsp->conf && dsp->conf->software)
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)
return;
Expand Down Expand Up @@ -415,7 +415,7 @@ dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb)
dsp_rx_off(dsp);
break;
case DSP_ECHO_ON: /* enable echo */
dsp->echo = 1; /* soft echo */
dsp->echo.software = 1; /* soft echo */
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__);
dsp_cmx_hardware(dsp->conf, dsp);
Expand All @@ -424,7 +424,8 @@ dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb)
dsp_cmx_debug(dsp);
break;
case DSP_ECHO_OFF: /* disable echo */
dsp->echo = 0;
dsp->echo.software = 0;
dsp->echo.hardware = 0;
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__);
dsp_cmx_hardware(dsp->conf, dsp);
Expand Down Expand Up @@ -722,7 +723,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb)
skb->len, (dsp_options&DSP_OPT_ULAW)?1:0);
}
/* 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 */
dsp_cmx_receive(dsp, skb);
}
Expand Down

0 comments on commit bc138ec

Please sign in to comment.