Commit bc138ec4ac58bb83e2d9d5c12328d5452294c1f0
Committed by
David S. Miller
1 parent
b5df5a5c3b
Exists in
master
and in
7 other branches
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>
Showing 3 changed files with 84 additions and 45 deletions Side-by-side Diff
drivers/isdn/mISDN/dsp.h
... | ... | @@ -151,6 +151,15 @@ |
151 | 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 | 164 | * general stuff * |
156 | 165 | *****************/ |
... | ... | @@ -161,7 +170,7 @@ |
161 | 170 | struct mISDNchannel *up; |
162 | 171 | unsigned char name[64]; |
163 | 172 | int b_active; |
164 | - int echo; /* echo is enabled */ | |
173 | + struct dsp_echo echo; | |
165 | 174 | int rx_disabled; /* what the user wants */ |
166 | 175 | int rx_is_off; /* what the card is */ |
167 | 176 | int tx_mix; |
drivers/isdn/mISDN/dsp_cmx.c
... | ... | @@ -163,8 +163,9 @@ |
163 | 163 | |
164 | 164 | printk(KERN_DEBUG "-----Current DSP\n"); |
165 | 165 | list_for_each_entry(odsp, &dsp_ilist, list) { |
166 | - printk(KERN_DEBUG "* %s echo=%d txmix=%d", | |
167 | - odsp->name, odsp->echo, odsp->tx_mix); | |
166 | + printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d", | |
167 | + odsp->name, odsp->echo.hardware, odsp->echo.software, | |
168 | + odsp->tx_mix); | |
168 | 169 | if (odsp->conf) |
169 | 170 | printk(" (Conf %d)", odsp->conf->id); |
170 | 171 | if (dsp == odsp) |
171 | 172 | |
... | ... | @@ -177,10 +178,12 @@ |
177 | 178 | list_for_each_entry(member, &conf->mlist, list) { |
178 | 179 | printk(KERN_DEBUG |
179 | 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 | 183 | member->dsp->name, member->dsp->pcm_slot_tx, |
182 | 184 | member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, |
183 | 185 | member->dsp->pcm_bank_rx, member->dsp->hfc_conf, |
186 | + member->dsp->tx_data, member->dsp->rx_is_off, | |
184 | 187 | (member->dsp == dsp) ? " *this*" : ""); |
185 | 188 | } |
186 | 189 | } |
... | ... | @@ -385,7 +388,7 @@ |
385 | 388 | int freeunits[8]; |
386 | 389 | u_char freeslots[256]; |
387 | 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 | 393 | /* dsp gets updated (no conf) */ |
391 | 394 | if (!conf) { |
... | ... | @@ -409,7 +412,7 @@ |
409 | 412 | /* process hw echo */ |
410 | 413 | if (dsp->features.pcm_banks < 1) |
411 | 414 | return; |
412 | - if (!dsp->echo) { | |
415 | + if (!dsp->echo.software && !dsp->echo.hardware) { | |
413 | 416 | /* NO ECHO: remove PCM slot if assigned */ |
414 | 417 | if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { |
415 | 418 | if (dsp_debug & DEBUG_DSP_CMX) |
416 | 419 | |
417 | 420 | |
... | ... | @@ -427,10 +430,15 @@ |
427 | 430 | } |
428 | 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 | 436 | /* ECHO: already echo */ |
431 | 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 | 440 | return; |
441 | + } | |
434 | 442 | /* ECHO: if slot already assigned */ |
435 | 443 | if (dsp->pcm_slot_tx >= 0) { |
436 | 444 | dsp->pcm_slot_rx = dsp->pcm_slot_tx; |
... | ... | @@ -443,6 +451,7 @@ |
443 | 451 | dsp->pcm_slot_tx); |
444 | 452 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, |
445 | 453 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); |
454 | + dsp->echo.hardware = 1; | |
446 | 455 | return; |
447 | 456 | } |
448 | 457 | /* ECHO: find slot */ |
... | ... | @@ -472,6 +481,7 @@ |
472 | 481 | "%s no slot available for echo\n", |
473 | 482 | __func__); |
474 | 483 | /* no more slots available */ |
484 | + dsp->echo.software = 1; | |
475 | 485 | return; |
476 | 486 | } |
477 | 487 | /* assign free slot */ |
... | ... | @@ -485,6 +495,7 @@ |
485 | 495 | __func__, dsp->name, dsp->pcm_slot_tx); |
486 | 496 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, |
487 | 497 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); |
498 | + dsp->echo.hardware = 1; | |
488 | 499 | return; |
489 | 500 | } |
490 | 501 | |
... | ... | @@ -554,7 +565,7 @@ |
554 | 565 | return; |
555 | 566 | } |
556 | 567 | /* check if member has echo turned on */ |
557 | - if (member->dsp->echo) { | |
568 | + if (member->dsp->echo.hardware || member->dsp->echo.software) { | |
558 | 569 | if (dsp_debug & DEBUG_DSP_CMX) |
559 | 570 | printk(KERN_DEBUG |
560 | 571 | "%s dsp %s cannot form a conf, because " |
561 | 572 | |
... | ... | @@ -592,10 +603,9 @@ |
592 | 603 | if (member->dsp->tx_data) { |
593 | 604 | if (dsp_debug & DEBUG_DSP_CMX) |
594 | 605 | printk(KERN_DEBUG |
595 | - "%s dsp %s cannot form a conf, because " | |
596 | - "tx_data is turned on\n", | |
606 | + "%s dsp %s tx_data is turned on\n", | |
597 | 607 | __func__, member->dsp->name); |
598 | - goto conf_software; | |
608 | + tx_data = 1; | |
599 | 609 | } |
600 | 610 | /* check if pipeline exists */ |
601 | 611 | if (member->dsp->pipeline.inuse) { |
... | ... | @@ -794,7 +804,7 @@ |
794 | 804 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, |
795 | 805 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); |
796 | 806 | conf->hardware = 1; |
797 | - conf->software = 0; | |
807 | + conf->software = tx_data; | |
798 | 808 | return; |
799 | 809 | /* if members have one bank (or on the same chip) */ |
800 | 810 | } else { |
... | ... | @@ -904,7 +914,7 @@ |
904 | 914 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, |
905 | 915 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); |
906 | 916 | conf->hardware = 1; |
907 | - conf->software = 0; | |
917 | + conf->software = tx_data; | |
908 | 918 | return; |
909 | 919 | } |
910 | 920 | } |
911 | 921 | |
912 | 922 | |
... | ... | @@ -1295,17 +1305,25 @@ |
1295 | 1305 | int r, rr, t, tt, o_r, o_rr; |
1296 | 1306 | int preload = 0; |
1297 | 1307 | struct mISDNhead *hh, *thh; |
1308 | + int tx_data_only = 0; | |
1298 | 1309 | |
1299 | 1310 | /* don't process if: */ |
1300 | 1311 | if (!dsp->b_active) { /* if not active */ |
1301 | 1312 | dsp->last_tx = 0; |
1302 | 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 | 1317 | dsp->tx_R == dsp->tx_W && /* AND no tx-data */ |
1306 | 1318 | !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ |
1307 | - dsp->last_tx = 0; | |
1308 | - return; | |
1319 | + if (!dsp->tx_data) { /* no tx_data for user space required */ | |
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 | 1329 | #ifdef CMX_DEBUG |
... | ... | @@ -1388,7 +1406,7 @@ |
1388 | 1406 | /* PROCESS DATA (one member / no conf) */ |
1389 | 1407 | if (!conf || members <= 1) { |
1390 | 1408 | /* -> if echo is NOT enabled */ |
1391 | - if (!dsp->echo) { | |
1409 | + if (!dsp->echo.software) { | |
1392 | 1410 | /* -> send tx-data if available or use 0-volume */ |
1393 | 1411 | while (r != rr && t != tt) { |
1394 | 1412 | *d++ = p[t]; /* write tx_buff */ |
... | ... | @@ -1438,7 +1456,7 @@ |
1438 | 1456 | o_r = (o_rr - rr + r) & CMX_BUFF_MASK; |
1439 | 1457 | /* start rx-pointer at current read position*/ |
1440 | 1458 | /* -> if echo is NOT enabled */ |
1441 | - if (!dsp->echo) { | |
1459 | + if (!dsp->echo.software) { | |
1442 | 1460 | /* |
1443 | 1461 | * -> copy other member's rx-data, |
1444 | 1462 | * if tx-data is available, mix |
... | ... | @@ -1486,7 +1504,7 @@ |
1486 | 1504 | #endif |
1487 | 1505 | /* PROCESS DATA (three or more members) */ |
1488 | 1506 | /* -> if echo is NOT enabled */ |
1489 | - if (!dsp->echo) { | |
1507 | + if (!dsp->echo.software) { | |
1490 | 1508 | /* |
1491 | 1509 | * -> substract rx-data from conf-data, |
1492 | 1510 | * if tx-data is available, mix |
1493 | 1511 | |
1494 | 1512 | |
1495 | 1513 | |
... | ... | @@ -1550,27 +1568,40 @@ |
1550 | 1568 | * becuase we want what we send, not what we filtered |
1551 | 1569 | */ |
1552 | 1570 | if (dsp->tx_data) { |
1553 | - /* PREPARE RESULT */ | |
1554 | - txskb = mI_alloc_skb(len, GFP_ATOMIC); | |
1555 | - if (!txskb) { | |
1556 | - printk(KERN_ERR | |
1557 | - "FATAL ERROR in mISDN_dsp.o: " | |
1558 | - "cannot alloc %d bytes\n", len); | |
1571 | + if (tx_data_only) { | |
1572 | + hh->prim = DL_DATA_REQ; | |
1573 | + hh->id = 0; | |
1574 | + /* queue and trigger */ | |
1575 | + skb_queue_tail(&dsp->sendq, nskb); | |
1576 | + schedule_work(&dsp->workq); | |
1577 | + /* exit because only tx_data is used */ | |
1578 | + return; | |
1559 | 1579 | } else { |
1560 | - thh = mISDN_HEAD_P(txskb); | |
1561 | - thh->prim = DL_DATA_REQ; | |
1562 | - thh->id = 0; | |
1563 | - memcpy(skb_put(txskb, len), nskb->data+preload, len); | |
1564 | - /* queue (trigger later) */ | |
1565 | - skb_queue_tail(&dsp->sendq, txskb); | |
1580 | + txskb = mI_alloc_skb(len, GFP_ATOMIC); | |
1581 | + if (!txskb) { | |
1582 | + printk(KERN_ERR | |
1583 | + "FATAL ERROR in mISDN_dsp.o: " | |
1584 | + "cannot alloc %d bytes\n", len); | |
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 | 1598 | /* adjust volume */ |
1569 | 1599 | if (dsp->tx_volume) |
1570 | 1600 | dsp_change_volume(nskb, dsp->tx_volume); |
1571 | 1601 | /* pipeline */ |
1572 | 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 | 1605 | /* crypt */ |
1575 | 1606 | if (dsp->bf_enable) |
1576 | 1607 | dsp_bf_encrypt(dsp, nskb->data, nskb->len); |
... | ... | @@ -1891,10 +1922,8 @@ |
1891 | 1922 | |
1892 | 1923 | /* no conf */ |
1893 | 1924 | if (!dsp->conf) { |
1894 | - /* in case of hardware (echo) */ | |
1895 | - if (dsp->pcm_slot_tx >= 0) | |
1896 | - return; | |
1897 | - if (dsp->echo) { | |
1925 | + /* in case of software echo */ | |
1926 | + if (dsp->echo.software) { | |
1898 | 1927 | nskb = skb_clone(skb, GFP_ATOMIC); |
1899 | 1928 | if (nskb) { |
1900 | 1929 | hh = mISDN_HEAD_P(nskb); |
... | ... | @@ -1910,7 +1939,7 @@ |
1910 | 1939 | if (dsp->conf->hardware) |
1911 | 1940 | return; |
1912 | 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 | 1943 | nskb = skb_clone(skb, GFP_ATOMIC); |
1915 | 1944 | if (nskb) { |
1916 | 1945 | hh = mISDN_HEAD_P(nskb); |
drivers/isdn/mISDN/dsp_core.c
... | ... | @@ -203,13 +203,13 @@ |
203 | 203 | else if (dsp->dtmf.software) |
204 | 204 | rx_off = 0; |
205 | 205 | /* echo in software */ |
206 | - else if (dsp->echo && dsp->pcm_slot_tx < 0) | |
206 | + else if (dsp->echo.software) | |
207 | 207 | rx_off = 0; |
208 | 208 | /* bridge in software */ |
209 | - else if (dsp->conf) { | |
210 | - if (dsp->conf->software) | |
211 | - rx_off = 0; | |
212 | - } | |
209 | + else if (dsp->conf && dsp->conf->software) | |
210 | + rx_off = 0; | |
211 | + /* data is not required by user space and not required | |
212 | + * for echo dtmf detection, soft-echo, soft-bridging */ | |
213 | 213 | |
214 | 214 | if (rx_off == dsp->rx_is_off) |
215 | 215 | return; |
... | ... | @@ -415,7 +415,7 @@ |
415 | 415 | dsp_rx_off(dsp); |
416 | 416 | break; |
417 | 417 | case DSP_ECHO_ON: /* enable echo */ |
418 | - dsp->echo = 1; /* soft echo */ | |
418 | + dsp->echo.software = 1; /* soft echo */ | |
419 | 419 | if (dsp_debug & DEBUG_DSP_CORE) |
420 | 420 | printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__); |
421 | 421 | dsp_cmx_hardware(dsp->conf, dsp); |
... | ... | @@ -424,7 +424,8 @@ |
424 | 424 | dsp_cmx_debug(dsp); |
425 | 425 | break; |
426 | 426 | case DSP_ECHO_OFF: /* disable echo */ |
427 | - dsp->echo = 0; | |
427 | + dsp->echo.software = 0; | |
428 | + dsp->echo.hardware = 0; | |
428 | 429 | if (dsp_debug & DEBUG_DSP_CORE) |
429 | 430 | printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__); |
430 | 431 | dsp_cmx_hardware(dsp->conf, dsp); |
... | ... | @@ -722,7 +723,7 @@ |
722 | 723 | skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); |
723 | 724 | } |
724 | 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 | 727 | /* process data from card at cmx */ |
727 | 728 | dsp_cmx_receive(dsp, skb); |
728 | 729 | } |