Commit bc138ec4ac58bb83e2d9d5c12328d5452294c1f0

Authored by Andreas Eversberg
Committed by David S. Miller
1 parent b5df5a5c3b

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 }