diff options
author | Andreas Eversberg <andreas@eversberg.eu> | 2009-05-22 07:04:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-05-25 03:51:34 -0400 |
commit | bc138ec4ac58bb83e2d9d5c12328d5452294c1f0 (patch) | |
tree | 059a02dfee5e813bdf21131aaa7c15085dd7f768 /drivers/isdn | |
parent | b5df5a5c3bf0f809d854ad7156ce26b709b533c0 (diff) |
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: Andreas Eversberg <andreas@eversberg.eu>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn')
-rw-r--r-- | drivers/isdn/mISDN/dsp.h | 11 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_cmx.c | 101 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_core.c | 17 |
3 files changed, 84 insertions, 45 deletions
diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index 41c6cfdca8c8..564ea3efd5e3 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h | |||
@@ -151,6 +151,15 @@ struct dsp_tone { | |||
151 | struct timer_list tl; | 151 | struct timer_list tl; |
152 | }; | 152 | }; |
153 | 153 | ||
154 | /*************** | ||
155 | * echo stuff * | ||
156 | ***************/ | ||
157 | |||
158 | struct dsp_echo { | ||
159 | int software; /* echo is generated by software */ | ||
160 | int hardware; /* echo is generated by hardware */ | ||
161 | }; | ||
162 | |||
154 | /***************** | 163 | /***************** |
155 | * general stuff * | 164 | * general stuff * |
156 | *****************/ | 165 | *****************/ |
@@ -161,7 +170,7 @@ struct dsp { | |||
161 | struct mISDNchannel *up; | 170 | struct mISDNchannel *up; |
162 | unsigned char name[64]; | 171 | unsigned char name[64]; |
163 | int b_active; | 172 | int b_active; |
164 | int echo; /* echo is enabled */ | 173 | struct dsp_echo echo; |
165 | int rx_disabled; /* what the user wants */ | 174 | int rx_disabled; /* what the user wants */ |
166 | int rx_is_off; /* what the card is */ | 175 | int rx_is_off; /* what the card is */ |
167 | int tx_mix; | 176 | int tx_mix; |
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index ac84146326e2..d19b4f6d7d87 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c | |||
@@ -163,8 +163,9 @@ dsp_cmx_debug(struct dsp *dsp) | |||
163 | 163 | ||
164 | printk(KERN_DEBUG "-----Current DSP\n"); | 164 | printk(KERN_DEBUG "-----Current DSP\n"); |
165 | list_for_each_entry(odsp, &dsp_ilist, list) { | 165 | list_for_each_entry(odsp, &dsp_ilist, list) { |
166 | printk(KERN_DEBUG "* %s echo=%d txmix=%d", | 166 | printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d", |
167 | odsp->name, odsp->echo, odsp->tx_mix); | 167 | odsp->name, odsp->echo.hardware, odsp->echo.software, |
168 | odsp->tx_mix); | ||
168 | if (odsp->conf) | 169 | if (odsp->conf) |
169 | printk(" (Conf %d)", odsp->conf->id); | 170 | printk(" (Conf %d)", odsp->conf->id); |
170 | if (dsp == odsp) | 171 | if (dsp == odsp) |
@@ -177,10 +178,12 @@ dsp_cmx_debug(struct dsp *dsp) | |||
177 | list_for_each_entry(member, &conf->mlist, list) { | 178 | list_for_each_entry(member, &conf->mlist, list) { |
178 | printk(KERN_DEBUG | 179 | printk(KERN_DEBUG |
179 | " - member = %s (slot_tx %d, bank_tx %d, " | 180 | " - member = %s (slot_tx %d, bank_tx %d, " |
180 | "slot_rx %d, bank_rx %d hfc_conf %d)%s\n", | 181 | "slot_rx %d, bank_rx %d hfc_conf %d " |
182 | "tx_data %d rx_is_off %d)%s\n", | ||
181 | member->dsp->name, member->dsp->pcm_slot_tx, | 183 | member->dsp->name, member->dsp->pcm_slot_tx, |
182 | member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, | 184 | member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, |
183 | member->dsp->pcm_bank_rx, member->dsp->hfc_conf, | 185 | member->dsp->pcm_bank_rx, member->dsp->hfc_conf, |
186 | member->dsp->tx_data, member->dsp->rx_is_off, | ||
184 | (member->dsp == dsp) ? " *this*" : ""); | 187 | (member->dsp == dsp) ? " *this*" : ""); |
185 | } | 188 | } |
186 | } | 189 | } |
@@ -385,7 +388,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) | |||
385 | int freeunits[8]; | 388 | int freeunits[8]; |
386 | u_char freeslots[256]; | 389 | u_char freeslots[256]; |
387 | int same_hfc = -1, same_pcm = -1, current_conf = -1, | 390 | int same_hfc = -1, same_pcm = -1, current_conf = -1, |
388 | all_conf = 1; | 391 | all_conf = 1, tx_data = 0; |
389 | 392 | ||
390 | /* dsp gets updated (no conf) */ | 393 | /* dsp gets updated (no conf) */ |
391 | if (!conf) { | 394 | if (!conf) { |
@@ -409,7 +412,7 @@ one_member: | |||
409 | /* process hw echo */ | 412 | /* process hw echo */ |
410 | if (dsp->features.pcm_banks < 1) | 413 | if (dsp->features.pcm_banks < 1) |
411 | return; | 414 | return; |
412 | if (!dsp->echo) { | 415 | if (!dsp->echo.software && !dsp->echo.hardware) { |
413 | /* NO ECHO: remove PCM slot if assigned */ | 416 | /* NO ECHO: remove PCM slot if assigned */ |
414 | if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { | 417 | if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { |
415 | if (dsp_debug & DEBUG_DSP_CMX) | 418 | if (dsp_debug & DEBUG_DSP_CMX) |
@@ -427,10 +430,15 @@ one_member: | |||
427 | } | 430 | } |
428 | return; | 431 | return; |
429 | } | 432 | } |
433 | /* echo is enabled, find out if we use soft or hardware */ | ||
434 | dsp->echo.software = dsp->tx_data; | ||
435 | dsp->echo.hardware = 0; | ||
430 | /* ECHO: already echo */ | 436 | /* ECHO: already echo */ |
431 | if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 && | 437 | if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 && |
432 | dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) | 438 | dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) { |
439 | dsp->echo.hardware = 1; | ||
433 | return; | 440 | return; |
441 | } | ||
434 | /* ECHO: if slot already assigned */ | 442 | /* ECHO: if slot already assigned */ |
435 | if (dsp->pcm_slot_tx >= 0) { | 443 | if (dsp->pcm_slot_tx >= 0) { |
436 | dsp->pcm_slot_rx = dsp->pcm_slot_tx; | 444 | dsp->pcm_slot_rx = dsp->pcm_slot_tx; |
@@ -443,6 +451,7 @@ one_member: | |||
443 | dsp->pcm_slot_tx); | 451 | dsp->pcm_slot_tx); |
444 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, | 452 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, |
445 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); | 453 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); |
454 | dsp->echo.hardware = 1; | ||
446 | return; | 455 | return; |
447 | } | 456 | } |
448 | /* ECHO: find slot */ | 457 | /* ECHO: find slot */ |
@@ -472,6 +481,7 @@ one_member: | |||
472 | "%s no slot available for echo\n", | 481 | "%s no slot available for echo\n", |
473 | __func__); | 482 | __func__); |
474 | /* no more slots available */ | 483 | /* no more slots available */ |
484 | dsp->echo.software = 1; | ||
475 | return; | 485 | return; |
476 | } | 486 | } |
477 | /* assign free slot */ | 487 | /* assign free slot */ |
@@ -485,6 +495,7 @@ one_member: | |||
485 | __func__, dsp->name, dsp->pcm_slot_tx); | 495 | __func__, dsp->name, dsp->pcm_slot_tx); |
486 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, | 496 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, |
487 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); | 497 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); |
498 | dsp->echo.hardware = 1; | ||
488 | return; | 499 | return; |
489 | } | 500 | } |
490 | 501 | ||
@@ -554,7 +565,7 @@ conf_software: | |||
554 | return; | 565 | return; |
555 | } | 566 | } |
556 | /* check if member has echo turned on */ | 567 | /* check if member has echo turned on */ |
557 | if (member->dsp->echo) { | 568 | if (member->dsp->echo.hardware || member->dsp->echo.software) { |
558 | if (dsp_debug & DEBUG_DSP_CMX) | 569 | if (dsp_debug & DEBUG_DSP_CMX) |
559 | printk(KERN_DEBUG | 570 | printk(KERN_DEBUG |
560 | "%s dsp %s cannot form a conf, because " | 571 | "%s dsp %s cannot form a conf, because " |
@@ -592,10 +603,9 @@ conf_software: | |||
592 | if (member->dsp->tx_data) { | 603 | if (member->dsp->tx_data) { |
593 | if (dsp_debug & DEBUG_DSP_CMX) | 604 | if (dsp_debug & DEBUG_DSP_CMX) |
594 | printk(KERN_DEBUG | 605 | printk(KERN_DEBUG |
595 | "%s dsp %s cannot form a conf, because " | 606 | "%s dsp %s tx_data is turned on\n", |
596 | "tx_data is turned on\n", | ||
597 | __func__, member->dsp->name); | 607 | __func__, member->dsp->name); |
598 | goto conf_software; | 608 | tx_data = 1; |
599 | } | 609 | } |
600 | /* check if pipeline exists */ | 610 | /* check if pipeline exists */ |
601 | if (member->dsp->pipeline.inuse) { | 611 | if (member->dsp->pipeline.inuse) { |
@@ -794,7 +804,7 @@ conf_software: | |||
794 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, | 804 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, |
795 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); | 805 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); |
796 | conf->hardware = 1; | 806 | conf->hardware = 1; |
797 | conf->software = 0; | 807 | conf->software = tx_data; |
798 | return; | 808 | return; |
799 | /* if members have one bank (or on the same chip) */ | 809 | /* if members have one bank (or on the same chip) */ |
800 | } else { | 810 | } else { |
@@ -904,7 +914,7 @@ conf_software: | |||
904 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, | 914 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, |
905 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); | 915 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); |
906 | conf->hardware = 1; | 916 | conf->hardware = 1; |
907 | conf->software = 0; | 917 | conf->software = tx_data; |
908 | return; | 918 | return; |
909 | } | 919 | } |
910 | } | 920 | } |
@@ -1295,17 +1305,25 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) | |||
1295 | int r, rr, t, tt, o_r, o_rr; | 1305 | int r, rr, t, tt, o_r, o_rr; |
1296 | int preload = 0; | 1306 | int preload = 0; |
1297 | struct mISDNhead *hh, *thh; | 1307 | struct mISDNhead *hh, *thh; |
1308 | int tx_data_only = 0; | ||
1298 | 1309 | ||
1299 | /* don't process if: */ | 1310 | /* don't process if: */ |
1300 | if (!dsp->b_active) { /* if not active */ | 1311 | if (!dsp->b_active) { /* if not active */ |
1301 | dsp->last_tx = 0; | 1312 | dsp->last_tx = 0; |
1302 | return; | 1313 | return; |
1303 | } | 1314 | } |
1304 | if (dsp->pcm_slot_tx >= 0 && /* connected to pcm slot */ | 1315 | if (((dsp->conf && dsp->conf->hardware) || /* hardware conf */ |
1316 | dsp->echo.hardware) && /* OR hardware echo */ | ||
1305 | dsp->tx_R == dsp->tx_W && /* AND no tx-data */ | 1317 | dsp->tx_R == dsp->tx_W && /* AND no tx-data */ |
1306 | !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ | 1318 | !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ |
1307 | dsp->last_tx = 0; | 1319 | if (!dsp->tx_data) { /* no tx_data for user space required */ |
1308 | return; | 1320 | dsp->last_tx = 0; |
1321 | return; | ||
1322 | } | ||
1323 | if (dsp->conf && dsp->conf->software && dsp->conf->hardware) | ||
1324 | tx_data_only = 1; | ||
1325 | if (dsp->conf->software && dsp->echo.hardware) | ||
1326 | tx_data_only = 1; | ||
1309 | } | 1327 | } |
1310 | 1328 | ||
1311 | #ifdef CMX_DEBUG | 1329 | #ifdef CMX_DEBUG |
@@ -1388,7 +1406,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) | |||
1388 | /* PROCESS DATA (one member / no conf) */ | 1406 | /* PROCESS DATA (one member / no conf) */ |
1389 | if (!conf || members <= 1) { | 1407 | if (!conf || members <= 1) { |
1390 | /* -> if echo is NOT enabled */ | 1408 | /* -> if echo is NOT enabled */ |
1391 | if (!dsp->echo) { | 1409 | if (!dsp->echo.software) { |
1392 | /* -> send tx-data if available or use 0-volume */ | 1410 | /* -> send tx-data if available or use 0-volume */ |
1393 | while (r != rr && t != tt) { | 1411 | while (r != rr && t != tt) { |
1394 | *d++ = p[t]; /* write tx_buff */ | 1412 | *d++ = p[t]; /* write tx_buff */ |
@@ -1438,7 +1456,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) | |||
1438 | o_r = (o_rr - rr + r) & CMX_BUFF_MASK; | 1456 | o_r = (o_rr - rr + r) & CMX_BUFF_MASK; |
1439 | /* start rx-pointer at current read position*/ | 1457 | /* start rx-pointer at current read position*/ |
1440 | /* -> if echo is NOT enabled */ | 1458 | /* -> if echo is NOT enabled */ |
1441 | if (!dsp->echo) { | 1459 | if (!dsp->echo.software) { |
1442 | /* | 1460 | /* |
1443 | * -> copy other member's rx-data, | 1461 | * -> copy other member's rx-data, |
1444 | * if tx-data is available, mix | 1462 | * if tx-data is available, mix |
@@ -1486,7 +1504,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) | |||
1486 | #endif | 1504 | #endif |
1487 | /* PROCESS DATA (three or more members) */ | 1505 | /* PROCESS DATA (three or more members) */ |
1488 | /* -> if echo is NOT enabled */ | 1506 | /* -> if echo is NOT enabled */ |
1489 | if (!dsp->echo) { | 1507 | if (!dsp->echo.software) { |
1490 | /* | 1508 | /* |
1491 | * -> substract rx-data from conf-data, | 1509 | * -> substract rx-data from conf-data, |
1492 | * if tx-data is available, mix | 1510 | * if tx-data is available, mix |
@@ -1550,27 +1568,40 @@ send_packet: | |||
1550 | * becuase we want what we send, not what we filtered | 1568 | * becuase we want what we send, not what we filtered |
1551 | */ | 1569 | */ |
1552 | if (dsp->tx_data) { | 1570 | if (dsp->tx_data) { |
1553 | /* PREPARE RESULT */ | 1571 | if (tx_data_only) { |
1554 | txskb = mI_alloc_skb(len, GFP_ATOMIC); | 1572 | hh->prim = DL_DATA_REQ; |
1555 | if (!txskb) { | 1573 | hh->id = 0; |
1556 | printk(KERN_ERR | 1574 | /* queue and trigger */ |
1557 | "FATAL ERROR in mISDN_dsp.o: " | 1575 | skb_queue_tail(&dsp->sendq, nskb); |
1558 | "cannot alloc %d bytes\n", len); | 1576 | schedule_work(&dsp->workq); |
1577 | /* exit because only tx_data is used */ | ||
1578 | return; | ||
1559 | } else { | 1579 | } else { |
1560 | thh = mISDN_HEAD_P(txskb); | 1580 | txskb = mI_alloc_skb(len, GFP_ATOMIC); |
1561 | thh->prim = DL_DATA_REQ; | 1581 | if (!txskb) { |
1562 | thh->id = 0; | 1582 | printk(KERN_ERR |
1563 | memcpy(skb_put(txskb, len), nskb->data+preload, len); | 1583 | "FATAL ERROR in mISDN_dsp.o: " |
1564 | /* queue (trigger later) */ | 1584 | "cannot alloc %d bytes\n", len); |
1565 | skb_queue_tail(&dsp->sendq, txskb); | 1585 | } else { |
1586 | thh = mISDN_HEAD_P(txskb); | ||
1587 | thh->prim = DL_DATA_REQ; | ||
1588 | thh->id = 0; | ||
1589 | memcpy(skb_put(txskb, len), nskb->data+preload, | ||
1590 | len); | ||
1591 | /* queue (trigger later) */ | ||
1592 | skb_queue_tail(&dsp->sendq, txskb); | ||
1593 | } | ||
1566 | } | 1594 | } |
1567 | } | 1595 | } |
1596 | |||
1597 | /* send data only to card, if we don't just calculated tx_data */ | ||
1568 | /* adjust volume */ | 1598 | /* adjust volume */ |
1569 | if (dsp->tx_volume) | 1599 | if (dsp->tx_volume) |
1570 | dsp_change_volume(nskb, dsp->tx_volume); | 1600 | dsp_change_volume(nskb, dsp->tx_volume); |
1571 | /* pipeline */ | 1601 | /* pipeline */ |
1572 | if (dsp->pipeline.inuse) | 1602 | if (dsp->pipeline.inuse) |
1573 | dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, nskb->len); | 1603 | dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, |
1604 | nskb->len); | ||
1574 | /* crypt */ | 1605 | /* crypt */ |
1575 | if (dsp->bf_enable) | 1606 | if (dsp->bf_enable) |
1576 | dsp_bf_encrypt(dsp, nskb->data, nskb->len); | 1607 | dsp_bf_encrypt(dsp, nskb->data, nskb->len); |
@@ -1891,10 +1922,8 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) | |||
1891 | 1922 | ||
1892 | /* no conf */ | 1923 | /* no conf */ |
1893 | if (!dsp->conf) { | 1924 | if (!dsp->conf) { |
1894 | /* in case of hardware (echo) */ | 1925 | /* in case of software echo */ |
1895 | if (dsp->pcm_slot_tx >= 0) | 1926 | if (dsp->echo.software) { |
1896 | return; | ||
1897 | if (dsp->echo) { | ||
1898 | nskb = skb_clone(skb, GFP_ATOMIC); | 1927 | nskb = skb_clone(skb, GFP_ATOMIC); |
1899 | if (nskb) { | 1928 | if (nskb) { |
1900 | hh = mISDN_HEAD_P(nskb); | 1929 | hh = mISDN_HEAD_P(nskb); |
@@ -1910,7 +1939,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) | |||
1910 | if (dsp->conf->hardware) | 1939 | if (dsp->conf->hardware) |
1911 | return; | 1940 | return; |
1912 | list_for_each_entry(member, &dsp->conf->mlist, list) { | 1941 | list_for_each_entry(member, &dsp->conf->mlist, list) { |
1913 | if (dsp->echo || member->dsp != dsp) { | 1942 | if (dsp->echo.software || member->dsp != dsp) { |
1914 | nskb = skb_clone(skb, GFP_ATOMIC); | 1943 | nskb = skb_clone(skb, GFP_ATOMIC); |
1915 | if (nskb) { | 1944 | if (nskb) { |
1916 | hh = mISDN_HEAD_P(nskb); | 1945 | hh = mISDN_HEAD_P(nskb); |
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 6b4939854306..a0e0af81eb2e 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c | |||
@@ -203,13 +203,13 @@ dsp_rx_off_member(struct dsp *dsp) | |||
203 | else if (dsp->dtmf.software) | 203 | else if (dsp->dtmf.software) |
204 | rx_off = 0; | 204 | rx_off = 0; |
205 | /* echo in software */ | 205 | /* echo in software */ |
206 | else if (dsp->echo && dsp->pcm_slot_tx < 0) | 206 | else if (dsp->echo.software) |
207 | rx_off = 0; | 207 | rx_off = 0; |
208 | /* bridge in software */ | 208 | /* bridge in software */ |
209 | else if (dsp->conf) { | 209 | else if (dsp->conf && dsp->conf->software) |
210 | if (dsp->conf->software) | 210 | rx_off = 0; |
211 | rx_off = 0; | 211 | /* data is not required by user space and not required |
212 | } | 212 | * for echo dtmf detection, soft-echo, soft-bridging */ |
213 | 213 | ||
214 | if (rx_off == dsp->rx_is_off) | 214 | if (rx_off == dsp->rx_is_off) |
215 | return; | 215 | return; |
@@ -415,7 +415,7 @@ tone_off: | |||
415 | dsp_rx_off(dsp); | 415 | dsp_rx_off(dsp); |
416 | break; | 416 | break; |
417 | case DSP_ECHO_ON: /* enable echo */ | 417 | case DSP_ECHO_ON: /* enable echo */ |
418 | dsp->echo = 1; /* soft echo */ | 418 | dsp->echo.software = 1; /* soft echo */ |
419 | if (dsp_debug & DEBUG_DSP_CORE) | 419 | if (dsp_debug & DEBUG_DSP_CORE) |
420 | printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__); | 420 | printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__); |
421 | dsp_cmx_hardware(dsp->conf, dsp); | 421 | dsp_cmx_hardware(dsp->conf, dsp); |
@@ -424,7 +424,8 @@ tone_off: | |||
424 | dsp_cmx_debug(dsp); | 424 | dsp_cmx_debug(dsp); |
425 | break; | 425 | break; |
426 | case DSP_ECHO_OFF: /* disable echo */ | 426 | case DSP_ECHO_OFF: /* disable echo */ |
427 | dsp->echo = 0; | 427 | dsp->echo.software = 0; |
428 | dsp->echo.hardware = 0; | ||
428 | if (dsp_debug & DEBUG_DSP_CORE) | 429 | if (dsp_debug & DEBUG_DSP_CORE) |
429 | printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__); | 430 | printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__); |
430 | dsp_cmx_hardware(dsp->conf, dsp); | 431 | dsp_cmx_hardware(dsp->conf, dsp); |
@@ -722,7 +723,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) | |||
722 | skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); | 723 | skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); |
723 | } | 724 | } |
724 | /* we need to process receive data if software */ | 725 | /* we need to process receive data if software */ |
725 | if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) { | 726 | if (dsp->conf && dsp->conf->software) { |
726 | /* process data from card at cmx */ | 727 | /* process data from card at cmx */ |
727 | dsp_cmx_receive(dsp, skb); | 728 | dsp_cmx_receive(dsp, skb); |
728 | } | 729 | } |