1950 lines · c
1/*2 * Audio crossconnecting/conferrencing (hardware level).3 *4 * Copyright 2002 by Andreas Eversberg (jolly@eversberg.eu)5 *6 * This software may be used and distributed according to the terms7 * of the GNU General Public License, incorporated herein by reference.8 *9 */10 11/*12 * The process of adding and removing parties to/from a conference:13 *14 * There is a chain of struct dsp_conf which has one or more members in a chain15 * of struct dsp_conf_member.16 *17 * After a party is added, the conference is checked for hardware capability.18 * Also if a party is removed, the conference is checked again.19 *20 * There are 3 different solutions: -1 = software, 0 = hardware-crossconnect21 * 1-n = hardware-conference. The n will give the conference number.22 *23 * Depending on the change after removal or insertion of a party, hardware24 * commands are given.25 *26 * The current solution is stored within the struct dsp_conf entry.27 */28 29/*30 * HOW THE CMX WORKS:31 *32 * There are 3 types of interaction: One member is alone, in this case only33 * data flow from upper to lower layer is done.34 * Two members will also exchange their data so they are crossconnected.35 * Three or more members will be added in a conference and will hear each36 * other but will not receive their own speech (echo) if not enabled.37 *38 * Features of CMX are:39 * - Crossconnecting or even conference, if more than two members are together.40 * - Force mixing of transmit data with other crossconnect/conference members.41 * - Echo generation to benchmark the delay of audio processing.42 * - Use hardware to minimize cpu load, disable FIFO load and minimize delay.43 * - Dejittering and clock generation.44 *45 * There are 2 buffers:46 *47 *48 * RX-Buffer49 * R W50 * | |51 * ----------------+-------------+-------------------52 *53 * The rx-buffer is a ring buffer used to store the received data for each54 * individual member. This is only the case if data needs to be dejittered55 * or in case of a conference where different clocks require reclocking.56 * The transmit-clock (R) will read the buffer.57 * If the clock overruns the write-pointer, we will have a buffer underrun.58 * If the write pointer always has a certain distance from the transmit-59 * clock, we will have a delay. The delay will dynamically be increased and60 * reduced.61 *62 *63 * TX-Buffer64 * R W65 * | |66 * -----------------+--------+-----------------------67 *68 * The tx-buffer is a ring buffer to queue the transmit data from user space69 * until it will be mixed or sent. There are two pointers, R and W. If the write70 * pointer W would reach or overrun R, the buffer would overrun. In this case71 * (some) data is dropped so that it will not overrun.72 * Additionally a dynamic dejittering can be enabled. this allows data from73 * user space that have jitter and different clock source.74 *75 *76 * Clock:77 *78 * A Clock is not required, if the data source has exactly one clock. In this79 * case the data source is forwarded to the destination.80 *81 * A Clock is required, because the data source82 * - has multiple clocks.83 * - has no usable clock due to jitter or packet loss (VoIP).84 * In this case the system's clock is used. The clock resolution depends on85 * the jiffy resolution.86 *87 * If a member joins a conference:88 *89 * - If a member joins, its rx_buff is set to silence and change read pointer90 * to transmit clock.91 *92 * The procedure of received data from card is explained in cmx_receive.93 * The procedure of received data from user space is explained in cmx_transmit.94 * The procedure of transmit data to card is cmx_send.95 *96 *97 * Interaction with other features:98 *99 * DTMF:100 * DTMF decoding is done before the data is crossconnected.101 *102 * Volume change:103 * Changing rx-volume is done before the data is crossconnected. The tx-volume104 * must be changed whenever data is transmitted to the card by the cmx.105 *106 * Tones:107 * If a tone is enabled, it will be processed whenever data is transmitted to108 * the card. It will replace the tx-data from the user space.109 * If tones are generated by hardware, this conference member is removed for110 * this time.111 *112 * Disable rx-data:113 * If cmx is realized in hardware, rx data will be disabled if requested by114 * the upper layer. If dtmf decoding is done by software and enabled, rx data115 * will not be disabled but blocked to the upper layer.116 *117 * HFC conference engine:118 * If it is possible to realize all features using hardware, hardware will be119 * used if not forbidden by control command. Disabling rx-data provides120 * absolutely traffic free audio processing. (except for the quick 1-frame121 * upload of a tone loop, only once for a new tone)122 *123 */124 125/* delay.h is required for hw_lock.h */126 127#include <linux/slab.h>128#include <linux/delay.h>129#include <linux/mISDNif.h>130#include <linux/mISDNdsp.h>131#include "core.h"132#include "dsp.h"133/*134 * debugging of multi party conference,135 * by using conference even with two members136 */137 138/* #define CMX_CONF_DEBUG */139 140/*#define CMX_DEBUG * massive read/write pointer output */141/*#define CMX_DELAY_DEBUG * gives rx-buffer delay overview */142/*#define CMX_TX_DEBUG * massive read/write on tx-buffer with content */143 144/*145 * debug cmx memory structure146 */147void148dsp_cmx_debug(struct dsp *dsp)149{150 struct dsp_conf *conf;151 struct dsp_conf_member *member;152 struct dsp *odsp;153 154 printk(KERN_DEBUG "-----Current DSP\n");155 list_for_each_entry(odsp, &dsp_ilist, list) {156 printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d",157 odsp->name, odsp->echo.hardware, odsp->echo.software,158 odsp->tx_mix);159 if (odsp->conf)160 printk(" (Conf %d)", odsp->conf->id);161 if (dsp == odsp)162 printk(" *this*");163 printk("\n");164 }165 printk(KERN_DEBUG "-----Current Conf:\n");166 list_for_each_entry(conf, &conf_ilist, list) {167 printk(KERN_DEBUG "* Conf %d (%p)\n", conf->id, conf);168 list_for_each_entry(member, &conf->mlist, list) {169 printk(KERN_DEBUG170 " - member = %s (slot_tx %d, bank_tx %d, "171 "slot_rx %d, bank_rx %d hfc_conf %d "172 "tx_data %d rx_is_off %d)%s\n",173 member->dsp->name, member->dsp->pcm_slot_tx,174 member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx,175 member->dsp->pcm_bank_rx, member->dsp->hfc_conf,176 member->dsp->tx_data, member->dsp->rx_is_off,177 (member->dsp == dsp) ? " *this*" : "");178 }179 }180 printk(KERN_DEBUG "-----end\n");181}182 183/*184 * search conference185 */186static struct dsp_conf *187dsp_cmx_search_conf(u32 id)188{189 struct dsp_conf *conf;190 191 if (!id) {192 printk(KERN_WARNING "%s: conference ID is 0.\n", __func__);193 return NULL;194 }195 196 /* search conference */197 list_for_each_entry(conf, &conf_ilist, list)198 if (conf->id == id)199 return conf;200 201 return NULL;202}203 204 205/*206 * add member to conference207 */208static int209dsp_cmx_add_conf_member(struct dsp *dsp, struct dsp_conf *conf)210{211 struct dsp_conf_member *member;212 213 if (!conf || !dsp) {214 printk(KERN_WARNING "%s: conf or dsp is 0.\n", __func__);215 return -EINVAL;216 }217 if (dsp->member) {218 printk(KERN_WARNING "%s: dsp is already member in a conf.\n",219 __func__);220 return -EINVAL;221 }222 223 if (dsp->conf) {224 printk(KERN_WARNING "%s: dsp is already in a conf.\n",225 __func__);226 return -EINVAL;227 }228 229 member = kzalloc(sizeof(struct dsp_conf_member), GFP_ATOMIC);230 if (!member) {231 printk(KERN_ERR "kzalloc struct dsp_conf_member failed\n");232 return -ENOMEM;233 }234 member->dsp = dsp;235 /* clear rx buffer */236 memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));237 dsp->rx_init = 1; /* rx_W and rx_R will be adjusted on first frame */238 dsp->rx_W = 0;239 dsp->rx_R = 0;240 241 list_add_tail(&member->list, &conf->mlist);242 243 dsp->conf = conf;244 dsp->member = member;245 246 return 0;247}248 249 250/*251 * del member from conference252 */253int254dsp_cmx_del_conf_member(struct dsp *dsp)255{256 struct dsp_conf_member *member;257 258 if (!dsp) {259 printk(KERN_WARNING "%s: dsp is 0.\n",260 __func__);261 return -EINVAL;262 }263 264 if (!dsp->conf) {265 printk(KERN_WARNING "%s: dsp is not in a conf.\n",266 __func__);267 return -EINVAL;268 }269 270 if (list_empty(&dsp->conf->mlist)) {271 printk(KERN_WARNING "%s: dsp has linked an empty conf.\n",272 __func__);273 return -EINVAL;274 }275 276 /* find us in conf */277 list_for_each_entry(member, &dsp->conf->mlist, list) {278 if (member->dsp == dsp) {279 list_del(&member->list);280 dsp->conf = NULL;281 dsp->member = NULL;282 kfree(member);283 return 0;284 }285 }286 printk(KERN_WARNING287 "%s: dsp is not present in its own conf_member list.\n",288 __func__);289 290 return -EINVAL;291}292 293 294/*295 * new conference296 */297static struct dsp_conf298*dsp_cmx_new_conf(u32 id)299{300 struct dsp_conf *conf;301 302 if (!id) {303 printk(KERN_WARNING "%s: id is 0.\n",304 __func__);305 return NULL;306 }307 308 conf = kzalloc(sizeof(struct dsp_conf), GFP_ATOMIC);309 if (!conf) {310 printk(KERN_ERR "kzalloc struct dsp_conf failed\n");311 return NULL;312 }313 INIT_LIST_HEAD(&conf->mlist);314 conf->id = id;315 316 list_add_tail(&conf->list, &conf_ilist);317 318 return conf;319}320 321 322/*323 * del conference324 */325int326dsp_cmx_del_conf(struct dsp_conf *conf)327{328 if (!conf) {329 printk(KERN_WARNING "%s: conf is null.\n",330 __func__);331 return -EINVAL;332 }333 334 if (!list_empty(&conf->mlist)) {335 printk(KERN_WARNING "%s: conf not empty.\n",336 __func__);337 return -EINVAL;338 }339 list_del(&conf->list);340 kfree(conf);341 342 return 0;343}344 345 346/*347 * send HW message to hfc card348 */349static void350dsp_cmx_hw_message(struct dsp *dsp, u32 message, u32 param1, u32 param2,351 u32 param3, u32 param4)352{353 struct mISDN_ctrl_req cq;354 355 memset(&cq, 0, sizeof(cq));356 cq.op = message;357 cq.p1 = param1 | (param2 << 8);358 cq.p2 = param3 | (param4 << 8);359 if (dsp->ch.peer)360 dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq);361}362 363 364/*365 * do hardware update and set the software/hardware flag366 *367 * either a conference or a dsp instance can be given368 * if only dsp instance is given, the instance is not associated with a conf369 * and therefore removed. if a conference is given, the dsp is expected to370 * be member of that conference.371 */372void373dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)374{375 struct dsp_conf_member *member, *nextm;376 struct dsp *finddsp;377 int memb = 0, i, ii, i1, i2;378 int freeunits[8];379 u_char freeslots[256];380 int same_hfc = -1, same_pcm = -1, current_conf = -1,381 all_conf = 1, tx_data = 0;382 383 /* dsp gets updated (no conf) */384 if (!conf) {385 if (!dsp)386 return;387 if (dsp_debug & DEBUG_DSP_CMX)388 printk(KERN_DEBUG "%s checking dsp %s\n",389 __func__, dsp->name);390 one_member:391 /* remove HFC conference if enabled */392 if (dsp->hfc_conf >= 0) {393 if (dsp_debug & DEBUG_DSP_CMX)394 printk(KERN_DEBUG395 "%s removing %s from HFC conf %d "396 "because dsp is split\n", __func__,397 dsp->name, dsp->hfc_conf);398 dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_CONF_SPLIT,399 0, 0, 0, 0);400 dsp->hfc_conf = -1;401 }402 /* process hw echo */403 if (dsp->features.pcm_banks < 1)404 return;405 if (!dsp->echo.software && !dsp->echo.hardware) {406 /* NO ECHO: remove PCM slot if assigned */407 if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) {408 if (dsp_debug & DEBUG_DSP_CMX)409 printk(KERN_DEBUG "%s removing %s from"410 " PCM slot %d (TX) %d (RX) because"411 " dsp is split (no echo)\n",412 __func__, dsp->name,413 dsp->pcm_slot_tx, dsp->pcm_slot_rx);414 dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_DISC,415 0, 0, 0, 0);416 dsp->pcm_slot_tx = -1;417 dsp->pcm_bank_tx = -1;418 dsp->pcm_slot_rx = -1;419 dsp->pcm_bank_rx = -1;420 }421 return;422 }423 /* echo is enabled, find out if we use soft or hardware */424 dsp->echo.software = dsp->tx_data;425 dsp->echo.hardware = 0;426 /* ECHO: already echo */427 if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 &&428 dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) {429 dsp->echo.hardware = 1;430 return;431 }432 /* ECHO: if slot already assigned */433 if (dsp->pcm_slot_tx >= 0) {434 dsp->pcm_slot_rx = dsp->pcm_slot_tx;435 dsp->pcm_bank_tx = 2; /* 2 means loop */436 dsp->pcm_bank_rx = 2;437 if (dsp_debug & DEBUG_DSP_CMX)438 printk(KERN_DEBUG439 "%s refresh %s for echo using slot %d\n",440 __func__, dsp->name,441 dsp->pcm_slot_tx);442 dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN,443 dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);444 dsp->echo.hardware = 1;445 return;446 }447 /* ECHO: find slot */448 dsp->pcm_slot_tx = -1;449 dsp->pcm_slot_rx = -1;450 memset(freeslots, 1, sizeof(freeslots));451 list_for_each_entry(finddsp, &dsp_ilist, list) {452 if (finddsp->features.pcm_id == dsp->features.pcm_id) {453 if (finddsp->pcm_slot_rx >= 0 &&454 finddsp->pcm_slot_rx < sizeof(freeslots))455 freeslots[finddsp->pcm_slot_rx] = 0;456 if (finddsp->pcm_slot_tx >= 0 &&457 finddsp->pcm_slot_tx < sizeof(freeslots))458 freeslots[finddsp->pcm_slot_tx] = 0;459 }460 }461 i = 0;462 ii = dsp->features.pcm_slots;463 while (i < ii) {464 if (freeslots[i])465 break;466 i++;467 }468 if (i == ii) {469 if (dsp_debug & DEBUG_DSP_CMX)470 printk(KERN_DEBUG471 "%s no slot available for echo\n",472 __func__);473 /* no more slots available */474 dsp->echo.software = 1;475 return;476 }477 /* assign free slot */478 dsp->pcm_slot_tx = i;479 dsp->pcm_slot_rx = i;480 dsp->pcm_bank_tx = 2; /* loop */481 dsp->pcm_bank_rx = 2;482 if (dsp_debug & DEBUG_DSP_CMX)483 printk(KERN_DEBUG484 "%s assign echo for %s using slot %d\n",485 __func__, dsp->name, dsp->pcm_slot_tx);486 dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN,487 dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);488 dsp->echo.hardware = 1;489 return;490 }491 492 /* conf gets updated (all members) */493 if (dsp_debug & DEBUG_DSP_CMX)494 printk(KERN_DEBUG "%s checking conference %d\n",495 __func__, conf->id);496 497 if (list_empty(&conf->mlist)) {498 printk(KERN_ERR "%s: conference without members\n",499 __func__);500 return;501 }502 member = list_entry(conf->mlist.next, struct dsp_conf_member, list);503 same_hfc = member->dsp->features.hfc_id;504 same_pcm = member->dsp->features.pcm_id;505 /* check all members in our conference */506 list_for_each_entry(member, &conf->mlist, list) {507 /* check if member uses mixing */508 if (member->dsp->tx_mix) {509 if (dsp_debug & DEBUG_DSP_CMX)510 printk(KERN_DEBUG511 "%s dsp %s cannot form a conf, because "512 "tx_mix is turned on\n", __func__,513 member->dsp->name);514 conf_software:515 list_for_each_entry(member, &conf->mlist, list) {516 dsp = member->dsp;517 /* remove HFC conference if enabled */518 if (dsp->hfc_conf >= 0) {519 if (dsp_debug & DEBUG_DSP_CMX)520 printk(KERN_DEBUG521 "%s removing %s from HFC "522 "conf %d because not "523 "possible with hardware\n",524 __func__,525 dsp->name,526 dsp->hfc_conf);527 dsp_cmx_hw_message(dsp,528 MISDN_CTRL_HFC_CONF_SPLIT,529 0, 0, 0, 0);530 dsp->hfc_conf = -1;531 }532 /* remove PCM slot if assigned */533 if (dsp->pcm_slot_tx >= 0 ||534 dsp->pcm_slot_rx >= 0) {535 if (dsp_debug & DEBUG_DSP_CMX)536 printk(KERN_DEBUG "%s removing "537 "%s from PCM slot %d (TX)"538 " slot %d (RX) because not"539 " possible with hardware\n",540 __func__,541 dsp->name,542 dsp->pcm_slot_tx,543 dsp->pcm_slot_rx);544 dsp_cmx_hw_message(dsp,545 MISDN_CTRL_HFC_PCM_DISC,546 0, 0, 0, 0);547 dsp->pcm_slot_tx = -1;548 dsp->pcm_bank_tx = -1;549 dsp->pcm_slot_rx = -1;550 dsp->pcm_bank_rx = -1;551 }552 }553 conf->hardware = 0;554 conf->software = 1;555 return;556 }557 /* check if member has echo turned on */558 if (member->dsp->echo.hardware || member->dsp->echo.software) {559 if (dsp_debug & DEBUG_DSP_CMX)560 printk(KERN_DEBUG561 "%s dsp %s cannot form a conf, because "562 "echo is turned on\n", __func__,563 member->dsp->name);564 goto conf_software;565 }566 /* check if member has tx_mix turned on */567 if (member->dsp->tx_mix) {568 if (dsp_debug & DEBUG_DSP_CMX)569 printk(KERN_DEBUG570 "%s dsp %s cannot form a conf, because "571 "tx_mix is turned on\n",572 __func__, member->dsp->name);573 goto conf_software;574 }575 /* check if member changes volume at an not suppoted level */576 if (member->dsp->tx_volume) {577 if (dsp_debug & DEBUG_DSP_CMX)578 printk(KERN_DEBUG579 "%s dsp %s cannot form a conf, because "580 "tx_volume is changed\n",581 __func__, member->dsp->name);582 goto conf_software;583 }584 if (member->dsp->rx_volume) {585 if (dsp_debug & DEBUG_DSP_CMX)586 printk(KERN_DEBUG587 "%s dsp %s cannot form a conf, because "588 "rx_volume is changed\n",589 __func__, member->dsp->name);590 goto conf_software;591 }592 /* check if tx-data turned on */593 if (member->dsp->tx_data) {594 if (dsp_debug & DEBUG_DSP_CMX)595 printk(KERN_DEBUG596 "%s dsp %s tx_data is turned on\n",597 __func__, member->dsp->name);598 tx_data = 1;599 }600 /* check if pipeline exists */601 if (member->dsp->pipeline.inuse) {602 if (dsp_debug & DEBUG_DSP_CMX)603 printk(KERN_DEBUG604 "%s dsp %s cannot form a conf, because "605 "pipeline exists\n", __func__,606 member->dsp->name);607 goto conf_software;608 }609 /* check if encryption is enabled */610 if (member->dsp->bf_enable) {611 if (dsp_debug & DEBUG_DSP_CMX)612 printk(KERN_DEBUG "%s dsp %s cannot form a "613 "conf, because encryption is enabled\n",614 __func__, member->dsp->name);615 goto conf_software;616 }617 /* check if member is on a card with PCM support */618 if (member->dsp->features.pcm_id < 0) {619 if (dsp_debug & DEBUG_DSP_CMX)620 printk(KERN_DEBUG621 "%s dsp %s cannot form a conf, because "622 "dsp has no PCM bus\n",623 __func__, member->dsp->name);624 goto conf_software;625 }626 /* check if relations are on the same PCM bus */627 if (member->dsp->features.pcm_id != same_pcm) {628 if (dsp_debug & DEBUG_DSP_CMX)629 printk(KERN_DEBUG630 "%s dsp %s cannot form a conf, because "631 "dsp is on a different PCM bus than the "632 "first dsp\n",633 __func__, member->dsp->name);634 goto conf_software;635 }636 /* determine if members are on the same hfc chip */637 if (same_hfc != member->dsp->features.hfc_id)638 same_hfc = -1;639 /* if there are members already in a conference */640 if (current_conf < 0 && member->dsp->hfc_conf >= 0)641 current_conf = member->dsp->hfc_conf;642 /* if any member is not in a conference */643 if (member->dsp->hfc_conf < 0)644 all_conf = 0;645 646 memb++;647 }648 649 /* if no member, this is an error */650 if (memb < 1)651 return;652 653 /* one member */654 if (memb == 1) {655 if (dsp_debug & DEBUG_DSP_CMX)656 printk(KERN_DEBUG657 "%s conf %d cannot form a HW conference, "658 "because dsp is alone\n", __func__, conf->id);659 conf->hardware = 0;660 conf->software = 0;661 member = list_entry(conf->mlist.next, struct dsp_conf_member,662 list);663 dsp = member->dsp;664 goto one_member;665 }666 667 /*668 * ok, now we are sure that all members are on the same pcm.669 * now we will see if we have only two members, so we can do670 * crossconnections, which don't have any limitations.671 */672 673 /* if we have only two members */674 if (memb == 2) {675 member = list_entry(conf->mlist.next, struct dsp_conf_member,676 list);677 nextm = list_entry(member->list.next, struct dsp_conf_member,678 list);679 /* remove HFC conference if enabled */680 if (member->dsp->hfc_conf >= 0) {681 if (dsp_debug & DEBUG_DSP_CMX)682 printk(KERN_DEBUG683 "%s removing %s from HFC conf %d because "684 "two parties require only a PCM slot\n",685 __func__, member->dsp->name,686 member->dsp->hfc_conf);687 dsp_cmx_hw_message(member->dsp,688 MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0);689 member->dsp->hfc_conf = -1;690 }691 if (nextm->dsp->hfc_conf >= 0) {692 if (dsp_debug & DEBUG_DSP_CMX)693 printk(KERN_DEBUG694 "%s removing %s from HFC conf %d because "695 "two parties require only a PCM slot\n",696 __func__, nextm->dsp->name,697 nextm->dsp->hfc_conf);698 dsp_cmx_hw_message(nextm->dsp,699 MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0);700 nextm->dsp->hfc_conf = -1;701 }702 /* if members have two banks (and not on the same chip) */703 if (member->dsp->features.pcm_banks > 1 &&704 nextm->dsp->features.pcm_banks > 1 &&705 member->dsp->features.hfc_id !=706 nextm->dsp->features.hfc_id) {707 /* if both members have same slots with crossed banks */708 if (member->dsp->pcm_slot_tx >= 0 &&709 member->dsp->pcm_slot_rx >= 0 &&710 nextm->dsp->pcm_slot_tx >= 0 &&711 nextm->dsp->pcm_slot_rx >= 0 &&712 nextm->dsp->pcm_slot_tx ==713 member->dsp->pcm_slot_rx &&714 nextm->dsp->pcm_slot_rx ==715 member->dsp->pcm_slot_tx &&716 nextm->dsp->pcm_slot_tx ==717 member->dsp->pcm_slot_tx &&718 member->dsp->pcm_bank_tx !=719 member->dsp->pcm_bank_rx &&720 nextm->dsp->pcm_bank_tx !=721 nextm->dsp->pcm_bank_rx) {722 /* all members have same slot */723 if (dsp_debug & DEBUG_DSP_CMX)724 printk(KERN_DEBUG725 "%s dsp %s & %s stay joined on "726 "PCM slot %d bank %d (TX) bank %d "727 "(RX) (on different chips)\n",728 __func__,729 member->dsp->name,730 nextm->dsp->name,731 member->dsp->pcm_slot_tx,732 member->dsp->pcm_bank_tx,733 member->dsp->pcm_bank_rx);734 conf->hardware = 1;735 conf->software = tx_data;736 return;737 }738 /* find a new slot */739 memset(freeslots, 1, sizeof(freeslots));740 list_for_each_entry(dsp, &dsp_ilist, list) {741 if (dsp != member->dsp &&742 dsp != nextm->dsp &&743 member->dsp->features.pcm_id ==744 dsp->features.pcm_id) {745 if (dsp->pcm_slot_rx >= 0 &&746 dsp->pcm_slot_rx <747 sizeof(freeslots))748 freeslots[dsp->pcm_slot_rx] = 0;749 if (dsp->pcm_slot_tx >= 0 &&750 dsp->pcm_slot_tx <751 sizeof(freeslots))752 freeslots[dsp->pcm_slot_tx] = 0;753 }754 }755 i = 0;756 ii = member->dsp->features.pcm_slots;757 while (i < ii) {758 if (freeslots[i])759 break;760 i++;761 }762 if (i == ii) {763 if (dsp_debug & DEBUG_DSP_CMX)764 printk(KERN_DEBUG765 "%s no slot available for "766 "%s & %s\n", __func__,767 member->dsp->name,768 nextm->dsp->name);769 /* no more slots available */770 goto conf_software;771 }772 /* assign free slot */773 member->dsp->pcm_slot_tx = i;774 member->dsp->pcm_slot_rx = i;775 nextm->dsp->pcm_slot_tx = i;776 nextm->dsp->pcm_slot_rx = i;777 member->dsp->pcm_bank_rx = 0;778 member->dsp->pcm_bank_tx = 1;779 nextm->dsp->pcm_bank_rx = 1;780 nextm->dsp->pcm_bank_tx = 0;781 if (dsp_debug & DEBUG_DSP_CMX)782 printk(KERN_DEBUG783 "%s adding %s & %s to new PCM slot %d "784 "(TX and RX on different chips) because "785 "both members have not same slots\n",786 __func__,787 member->dsp->name,788 nextm->dsp->name,789 member->dsp->pcm_slot_tx);790 dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN,791 member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx,792 member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx);793 dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN,794 nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx,795 nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);796 conf->hardware = 1;797 conf->software = tx_data;798 return;799 /* if members have one bank (or on the same chip) */800 } else {801 /* if both members have different crossed slots */802 if (member->dsp->pcm_slot_tx >= 0 &&803 member->dsp->pcm_slot_rx >= 0 &&804 nextm->dsp->pcm_slot_tx >= 0 &&805 nextm->dsp->pcm_slot_rx >= 0 &&806 nextm->dsp->pcm_slot_tx ==807 member->dsp->pcm_slot_rx &&808 nextm->dsp->pcm_slot_rx ==809 member->dsp->pcm_slot_tx &&810 member->dsp->pcm_slot_tx !=811 member->dsp->pcm_slot_rx &&812 member->dsp->pcm_bank_tx == 0 &&813 member->dsp->pcm_bank_rx == 0 &&814 nextm->dsp->pcm_bank_tx == 0 &&815 nextm->dsp->pcm_bank_rx == 0) {816 /* all members have same slot */817 if (dsp_debug & DEBUG_DSP_CMX)818 printk(KERN_DEBUG819 "%s dsp %s & %s stay joined on PCM "820 "slot %d (TX) %d (RX) on same chip "821 "or one bank PCM)\n", __func__,822 member->dsp->name,823 nextm->dsp->name,824 member->dsp->pcm_slot_tx,825 member->dsp->pcm_slot_rx);826 conf->hardware = 1;827 conf->software = tx_data;828 return;829 }830 /* find two new slot */831 memset(freeslots, 1, sizeof(freeslots));832 list_for_each_entry(dsp, &dsp_ilist, list) {833 if (dsp != member->dsp &&834 dsp != nextm->dsp &&835 member->dsp->features.pcm_id ==836 dsp->features.pcm_id) {837 if (dsp->pcm_slot_rx >= 0 &&838 dsp->pcm_slot_rx <839 sizeof(freeslots))840 freeslots[dsp->pcm_slot_rx] = 0;841 if (dsp->pcm_slot_tx >= 0 &&842 dsp->pcm_slot_tx <843 sizeof(freeslots))844 freeslots[dsp->pcm_slot_tx] = 0;845 }846 }847 i1 = 0;848 ii = member->dsp->features.pcm_slots;849 while (i1 < ii) {850 if (freeslots[i1])851 break;852 i1++;853 }854 if (i1 == ii) {855 if (dsp_debug & DEBUG_DSP_CMX)856 printk(KERN_DEBUG857 "%s no slot available "858 "for %s & %s\n", __func__,859 member->dsp->name,860 nextm->dsp->name);861 /* no more slots available */862 goto conf_software;863 }864 i2 = i1 + 1;865 while (i2 < ii) {866 if (freeslots[i2])867 break;868 i2++;869 }870 if (i2 == ii) {871 if (dsp_debug & DEBUG_DSP_CMX)872 printk(KERN_DEBUG873 "%s no slot available "874 "for %s & %s\n",875 __func__,876 member->dsp->name,877 nextm->dsp->name);878 /* no more slots available */879 goto conf_software;880 }881 /* assign free slots */882 member->dsp->pcm_slot_tx = i1;883 member->dsp->pcm_slot_rx = i2;884 nextm->dsp->pcm_slot_tx = i2;885 nextm->dsp->pcm_slot_rx = i1;886 member->dsp->pcm_bank_rx = 0;887 member->dsp->pcm_bank_tx = 0;888 nextm->dsp->pcm_bank_rx = 0;889 nextm->dsp->pcm_bank_tx = 0;890 if (dsp_debug & DEBUG_DSP_CMX)891 printk(KERN_DEBUG892 "%s adding %s & %s to new PCM slot %d "893 "(TX) %d (RX) on same chip or one bank "894 "PCM, because both members have not "895 "crossed slots\n", __func__,896 member->dsp->name,897 nextm->dsp->name,898 member->dsp->pcm_slot_tx,899 member->dsp->pcm_slot_rx);900 dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN,901 member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx,902 member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx);903 dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN,904 nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx,905 nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);906 conf->hardware = 1;907 conf->software = tx_data;908 return;909 }910 }911 912 /*913 * if we have more than two, we may check if we have a conference914 * unit available on the chip. also all members must be on the same915 */916 917 /* if not the same HFC chip */918 if (same_hfc < 0) {919 if (dsp_debug & DEBUG_DSP_CMX)920 printk(KERN_DEBUG921 "%s conference %d cannot be formed, because "922 "members are on different chips or not "923 "on HFC chip\n",924 __func__, conf->id);925 goto conf_software;926 }927 928 /* for more than two members.. */929 930 /* if all members already have the same conference */931 if (all_conf) {932 conf->hardware = 1;933 conf->software = tx_data;934 return;935 }936 937 /*938 * if there is an existing conference, but not all members have joined939 */940 if (current_conf >= 0) {941 join_members:942 list_for_each_entry(member, &conf->mlist, list) {943 /* if no conference engine on our chip, change to944 * software */945 if (!member->dsp->features.hfc_conf)946 goto conf_software;947 /* in case of hdlc, change to software */948 if (member->dsp->hdlc)949 goto conf_software;950 /* join to current conference */951 if (member->dsp->hfc_conf == current_conf)952 continue;953 /* get a free timeslot first */954 memset(freeslots, 1, sizeof(freeslots));955 list_for_each_entry(dsp, &dsp_ilist, list) {956 /*957 * not checking current member, because958 * slot will be overwritten.959 */960 if (961 dsp != member->dsp &&962 /* dsp must be on the same PCM */963 member->dsp->features.pcm_id ==964 dsp->features.pcm_id) {965 /* dsp must be on a slot */966 if (dsp->pcm_slot_tx >= 0 &&967 dsp->pcm_slot_tx <968 sizeof(freeslots))969 freeslots[dsp->pcm_slot_tx] = 0;970 if (dsp->pcm_slot_rx >= 0 &&971 dsp->pcm_slot_rx <972 sizeof(freeslots))973 freeslots[dsp->pcm_slot_rx] = 0;974 }975 }976 i = 0;977 ii = member->dsp->features.pcm_slots;978 while (i < ii) {979 if (freeslots[i])980 break;981 i++;982 }983 if (i == ii) {984 /* no more slots available */985 if (dsp_debug & DEBUG_DSP_CMX)986 printk(KERN_DEBUG987 "%s conference %d cannot be formed,"988 " because no slot free\n",989 __func__, conf->id);990 goto conf_software;991 }992 if (dsp_debug & DEBUG_DSP_CMX)993 printk(KERN_DEBUG994 "%s changing dsp %s to HW conference "995 "%d slot %d\n", __func__,996 member->dsp->name, current_conf, i);997 /* assign free slot & set PCM & join conf */998 member->dsp->pcm_slot_tx = i;999 member->dsp->pcm_slot_rx = i;1000 member->dsp->pcm_bank_tx = 2; /* loop */1001 member->dsp->pcm_bank_rx = 2;1002 member->dsp->hfc_conf = current_conf;1003 dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN,1004 i, 2, i, 2);1005 dsp_cmx_hw_message(member->dsp,1006 MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0);1007 }1008 conf->hardware = 1;1009 conf->software = tx_data;1010 return;1011 }1012 1013 /*1014 * no member is in a conference yet, so we find a free one1015 */1016 memset(freeunits, 1, sizeof(freeunits));1017 list_for_each_entry(dsp, &dsp_ilist, list) {1018 /* dsp must be on the same chip */1019 if (dsp->features.hfc_id == same_hfc &&1020 /* dsp must have joined a HW conference */1021 dsp->hfc_conf >= 0 &&1022 /* slot must be within range */1023 dsp->hfc_conf < 8)1024 freeunits[dsp->hfc_conf] = 0;1025 }1026 i = 0;1027 ii = 8;1028 while (i < ii) {1029 if (freeunits[i])1030 break;1031 i++;1032 }1033 if (i == ii) {1034 /* no more conferences available */1035 if (dsp_debug & DEBUG_DSP_CMX)1036 printk(KERN_DEBUG1037 "%s conference %d cannot be formed, because "1038 "no conference number free\n",1039 __func__, conf->id);1040 goto conf_software;1041 }1042 /* join all members */1043 current_conf = i;1044 goto join_members;1045}1046 1047 1048/*1049 * conf_id != 0: join or change conference1050 * conf_id == 0: split from conference if not already1051 */1052int1053dsp_cmx_conf(struct dsp *dsp, u32 conf_id)1054{1055 int err;1056 struct dsp_conf *conf;1057 struct dsp_conf_member *member;1058 1059 /* if conference doesn't change */1060 if (dsp->conf_id == conf_id)1061 return 0;1062 1063 /* first remove us from current conf */1064 if (dsp->conf_id) {1065 if (dsp_debug & DEBUG_DSP_CMX)1066 printk(KERN_DEBUG "removing us from conference %d\n",1067 dsp->conf->id);1068 /* remove us from conf */1069 conf = dsp->conf;1070 err = dsp_cmx_del_conf_member(dsp);1071 if (err)1072 return err;1073 dsp->conf_id = 0;1074 1075 /* update hardware */1076 dsp_cmx_hardware(NULL, dsp);1077 1078 /* conf now empty? */1079 if (list_empty(&conf->mlist)) {1080 if (dsp_debug & DEBUG_DSP_CMX)1081 printk(KERN_DEBUG1082 "conference is empty, so we remove it.\n");1083 err = dsp_cmx_del_conf(conf);1084 if (err)1085 return err;1086 } else {1087 /* update members left on conf */1088 dsp_cmx_hardware(conf, NULL);1089 }1090 }1091 1092 /* if split */1093 if (!conf_id)1094 return 0;1095 1096 /* now add us to conf */1097 if (dsp_debug & DEBUG_DSP_CMX)1098 printk(KERN_DEBUG "searching conference %d\n",1099 conf_id);1100 conf = dsp_cmx_search_conf(conf_id);1101 if (!conf) {1102 if (dsp_debug & DEBUG_DSP_CMX)1103 printk(KERN_DEBUG1104 "conference doesn't exist yet, creating.\n");1105 /* the conference doesn't exist, so we create */1106 conf = dsp_cmx_new_conf(conf_id);1107 if (!conf)1108 return -EINVAL;1109 } else if (!list_empty(&conf->mlist)) {1110 member = list_entry(conf->mlist.next, struct dsp_conf_member,1111 list);1112 if (dsp->hdlc && !member->dsp->hdlc) {1113 if (dsp_debug & DEBUG_DSP_CMX)1114 printk(KERN_DEBUG1115 "cannot join transparent conference.\n");1116 return -EINVAL;1117 }1118 if (!dsp->hdlc && member->dsp->hdlc) {1119 if (dsp_debug & DEBUG_DSP_CMX)1120 printk(KERN_DEBUG1121 "cannot join hdlc conference.\n");1122 return -EINVAL;1123 }1124 }1125 /* add conference member */1126 err = dsp_cmx_add_conf_member(dsp, conf);1127 if (err)1128 return err;1129 dsp->conf_id = conf_id;1130 1131 /* if we are alone, we do nothing! */1132 if (list_empty(&conf->mlist)) {1133 if (dsp_debug & DEBUG_DSP_CMX)1134 printk(KERN_DEBUG1135 "we are alone in this conference, so exit.\n");1136 /* update hardware */1137 dsp_cmx_hardware(NULL, dsp);1138 return 0;1139 }1140 1141 /* update members on conf */1142 dsp_cmx_hardware(conf, NULL);1143 1144 return 0;1145}1146 1147#ifdef CMX_DELAY_DEBUG1148int delaycount;1149static void1150showdelay(struct dsp *dsp, int samples, int delay)1151{1152 char bar[] = "--------------------------------------------------|";1153 int sdelay;1154 1155 delaycount += samples;1156 if (delaycount < 8000)1157 return;1158 delaycount = 0;1159 1160 sdelay = delay * 50 / (dsp_poll << 2);1161 1162 printk(KERN_DEBUG "DELAY (%s) %3d >%s\n", dsp->name, delay,1163 sdelay > 50 ? "..." : bar + 50 - sdelay);1164}1165#endif1166 1167/*1168 * audio data is received from card1169 */1170void1171dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb)1172{1173 u8 *d, *p;1174 int len = skb->len;1175 struct mISDNhead *hh = mISDN_HEAD_P(skb);1176 int w, i, ii;1177 1178 /* check if we have sompen */1179 if (len < 1)1180 return;1181 1182 /* half of the buffer should be larger than maximum packet size */1183 if (len >= CMX_BUFF_HALF) {1184 printk(KERN_ERR1185 "%s line %d: packet from card is too large (%d bytes). "1186 "please make card send smaller packets OR increase "1187 "CMX_BUFF_SIZE\n", __FILE__, __LINE__, len);1188 return;1189 }1190 1191 /*1192 * initialize pointers if not already -1193 * also add delay if requested by PH_SIGNAL1194 */1195 if (dsp->rx_init) {1196 dsp->rx_init = 0;1197 if (dsp->features.unordered) {1198 dsp->rx_R = (hh->id & CMX_BUFF_MASK);1199 if (dsp->cmx_delay)1200 dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)1201 & CMX_BUFF_MASK;1202 else1203 dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1))1204 & CMX_BUFF_MASK;1205 } else {1206 dsp->rx_R = 0;1207 if (dsp->cmx_delay)1208 dsp->rx_W = dsp->cmx_delay;1209 else1210 dsp->rx_W = dsp_poll >> 1;1211 }1212 }1213 /* if frame contains time code, write directly */1214 if (dsp->features.unordered) {1215 dsp->rx_W = (hh->id & CMX_BUFF_MASK);1216 /* printk(KERN_DEBUG "%s %08x\n", dsp->name, hh->id); */1217 }1218 /*1219 * if we underrun (or maybe overrun),1220 * we set our new read pointer, and write silence to buffer1221 */1222 if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) {1223 if (dsp_debug & DEBUG_DSP_CLOCK)1224 printk(KERN_DEBUG1225 "cmx_receive(dsp=%lx): UNDERRUN (or overrun the "1226 "maximum delay), adjusting read pointer! "1227 "(inst %s)\n", (u_long)dsp, dsp->name);1228 /* flush rx buffer and set delay to dsp_poll / 2 */1229 if (dsp->features.unordered) {1230 dsp->rx_R = (hh->id & CMX_BUFF_MASK);1231 if (dsp->cmx_delay)1232 dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)1233 & CMX_BUFF_MASK;1234 else1235 dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1))1236 & CMX_BUFF_MASK;1237 } else {1238 dsp->rx_R = 0;1239 if (dsp->cmx_delay)1240 dsp->rx_W = dsp->cmx_delay;1241 else1242 dsp->rx_W = dsp_poll >> 1;1243 }1244 memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));1245 }1246 /* if we have reached double delay, jump back to middle */1247 if (dsp->cmx_delay)1248 if (((dsp->rx_W - dsp->rx_R) & CMX_BUFF_MASK) >=1249 (dsp->cmx_delay << 1)) {1250 if (dsp_debug & DEBUG_DSP_CLOCK)1251 printk(KERN_DEBUG1252 "cmx_receive(dsp=%lx): OVERRUN (because "1253 "twice the delay is reached), adjusting "1254 "read pointer! (inst %s)\n",1255 (u_long)dsp, dsp->name);1256 /* flush buffer */1257 if (dsp->features.unordered) {1258 dsp->rx_R = (hh->id & CMX_BUFF_MASK);1259 dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)1260 & CMX_BUFF_MASK;1261 } else {1262 dsp->rx_R = 0;1263 dsp->rx_W = dsp->cmx_delay;1264 }1265 memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));1266 }1267 1268 /* show where to write */1269#ifdef CMX_DEBUG1270 printk(KERN_DEBUG1271 "cmx_receive(dsp=%lx): rx_R(dsp)=%05x rx_W(dsp)=%05x len=%d %s\n",1272 (u_long)dsp, dsp->rx_R, dsp->rx_W, len, dsp->name);1273#endif1274 1275 /* write data into rx_buffer */1276 p = skb->data;1277 d = dsp->rx_buff;1278 w = dsp->rx_W;1279 i = 0;1280 ii = len;1281 while (i < ii) {1282 d[w++ & CMX_BUFF_MASK] = *p++;1283 i++;1284 }1285 1286 /* increase write-pointer */1287 dsp->rx_W = ((dsp->rx_W + len) & CMX_BUFF_MASK);1288#ifdef CMX_DELAY_DEBUG1289 showdelay(dsp, len, (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK);1290#endif1291}1292 1293 1294/*1295 * send (mixed) audio data to card and control jitter1296 */1297static void1298dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)1299{1300 struct dsp_conf *conf = dsp->conf;1301 struct dsp *member, *other;1302 register s32 sample;1303 u8 *d, *p, *q, *o_q;1304 struct sk_buff *nskb, *txskb;1305 int r, rr, t, tt, o_r, o_rr;1306 int preload = 0;1307 struct mISDNhead *hh, *thh;1308 int tx_data_only = 0;1309 1310 /* don't process if: */1311 if (!dsp->b_active) { /* if not active */1312 dsp->last_tx = 0;1313 return;1314 }1315 if (((dsp->conf && dsp->conf->hardware) || /* hardware conf */1316 dsp->echo.hardware) && /* OR hardware echo */1317 dsp->tx_R == dsp->tx_W && /* AND no tx-data */1318 !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */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->echo.software && dsp->echo.hardware)1326 tx_data_only = 1;1327 }1328 1329#ifdef CMX_DEBUG1330 printk(KERN_DEBUG1331 "SEND members=%d dsp=%s, conf=%p, rx_R=%05x rx_W=%05x\n",1332 members, dsp->name, conf, dsp->rx_R, dsp->rx_W);1333#endif1334 1335 /* preload if we have delay set */1336 if (dsp->cmx_delay && !dsp->last_tx) {1337 preload = len;1338 if (preload < 128)1339 preload = 128;1340 }1341 1342 /* PREPARE RESULT */1343 nskb = mI_alloc_skb(len + preload, GFP_ATOMIC);1344 if (!nskb) {1345 printk(KERN_ERR1346 "FATAL ERROR in mISDN_dsp.o: cannot alloc %d bytes\n",1347 len + preload);1348 return;1349 }1350 hh = mISDN_HEAD_P(nskb);1351 hh->prim = PH_DATA_REQ;1352 hh->id = 0;1353 dsp->last_tx = 1;1354 1355 /* set pointers, indexes and stuff */1356 member = dsp;1357 p = dsp->tx_buff; /* transmit data */1358 q = dsp->rx_buff; /* received data */1359 d = skb_put(nskb, preload + len); /* result */1360 t = dsp->tx_R; /* tx-pointers */1361 tt = dsp->tx_W;1362 r = dsp->rx_R; /* rx-pointers */1363 rr = (r + len) & CMX_BUFF_MASK;1364 1365 /* preload with silence, if required */1366 if (preload) {1367 memset(d, dsp_silence, preload);1368 d += preload;1369 }1370 1371 /* PROCESS TONES/TX-DATA ONLY */1372 if (dsp->tone.tone && dsp->tone.software) {1373 /* -> copy tone */1374 dsp_tone_copy(dsp, d, len);1375 dsp->tx_R = 0; /* clear tx buffer */1376 dsp->tx_W = 0;1377 goto send_packet;1378 }1379 /* if we have tx-data but do not use mixing */1380 if (!dsp->tx_mix && t != tt) {1381 /* -> send tx-data and continue when not enough */1382#ifdef CMX_TX_DEBUG1383 sprintf(debugbuf, "TX sending (%04x-%04x)%p: ", t, tt, p);1384#endif1385 while (r != rr && t != tt) {1386#ifdef CMX_TX_DEBUG1387 if (strlen(debugbuf) < 48)1388 sprintf(debugbuf + strlen(debugbuf), " %02x",1389 p[t]);1390#endif1391 *d++ = p[t]; /* write tx_buff */1392 t = (t + 1) & CMX_BUFF_MASK;1393 r = (r + 1) & CMX_BUFF_MASK;1394 }1395 if (r == rr) {1396 dsp->tx_R = t;1397#ifdef CMX_TX_DEBUG1398 printk(KERN_DEBUG "%s\n", debugbuf);1399#endif1400 goto send_packet;1401 }1402 }1403#ifdef CMX_TX_DEBUG1404 printk(KERN_DEBUG "%s\n", debugbuf);1405#endif1406 1407 /* PROCESS DATA (one member / no conf) */1408 if (!conf || members <= 1) {1409 /* -> if echo is NOT enabled */1410 if (!dsp->echo.software) {1411 /* -> send tx-data if available or use 0-volume */1412 while (r != rr && t != tt) {1413 *d++ = p[t]; /* write tx_buff */1414 t = (t + 1) & CMX_BUFF_MASK;1415 r = (r + 1) & CMX_BUFF_MASK;1416 }1417 if (r != rr) {1418 if (dsp_debug & DEBUG_DSP_CLOCK)1419 printk(KERN_DEBUG "%s: RX empty\n",1420 __func__);1421 memset(d, dsp_silence, (rr - r) & CMX_BUFF_MASK);1422 }1423 /* -> if echo is enabled */1424 } else {1425 /*1426 * -> mix tx-data with echo if available,1427 * or use echo only1428 */1429 while (r != rr && t != tt) {1430 *d++ = dsp_audio_mix_law[(p[t] << 8) | q[r]];1431 t = (t + 1) & CMX_BUFF_MASK;1432 r = (r + 1) & CMX_BUFF_MASK;1433 }1434 while (r != rr) {1435 *d++ = q[r]; /* echo */1436 r = (r + 1) & CMX_BUFF_MASK;1437 }1438 }1439 dsp->tx_R = t;1440 goto send_packet;1441 }1442 /* PROCESS DATA (two members) */1443#ifdef CMX_CONF_DEBUG1444 if (0) {1445#else1446 if (members == 2) {1447#endif1448 /* "other" becomes other party */1449 other = (list_entry(conf->mlist.next,1450 struct dsp_conf_member, list))->dsp;1451 if (other == member)1452 other = (list_entry(conf->mlist.prev,1453 struct dsp_conf_member, list))->dsp;1454 o_q = other->rx_buff; /* received data */1455 o_rr = (other->rx_R + len) & CMX_BUFF_MASK;1456 /* end of rx-pointer */1457 o_r = (o_rr - rr + r) & CMX_BUFF_MASK;1458 /* start rx-pointer at current read position*/1459 /* -> if echo is NOT enabled */1460 if (!dsp->echo.software) {1461 /*1462 * -> copy other member's rx-data,1463 * if tx-data is available, mix1464 */1465 while (o_r != o_rr && t != tt) {1466 *d++ = dsp_audio_mix_law[(p[t] << 8) | o_q[o_r]];1467 t = (t + 1) & CMX_BUFF_MASK;1468 o_r = (o_r + 1) & CMX_BUFF_MASK;1469 }1470 while (o_r != o_rr) {1471 *d++ = o_q[o_r];1472 o_r = (o_r + 1) & CMX_BUFF_MASK;1473 }1474 /* -> if echo is enabled */1475 } else {1476 /*1477 * -> mix other member's rx-data with echo,1478 * if tx-data is available, mix1479 */1480 while (r != rr && t != tt) {1481 sample = dsp_audio_law_to_s32[p[t]] +1482 dsp_audio_law_to_s32[q[r]] +1483 dsp_audio_law_to_s32[o_q[o_r]];1484 if (sample < -32768)1485 sample = -32768;1486 else if (sample > 32767)1487 sample = 32767;1488 *d++ = dsp_audio_s16_to_law[sample & 0xffff];1489 /* tx-data + rx_data + echo */1490 t = (t + 1) & CMX_BUFF_MASK;1491 r = (r + 1) & CMX_BUFF_MASK;1492 o_r = (o_r + 1) & CMX_BUFF_MASK;1493 }1494 while (r != rr) {1495 *d++ = dsp_audio_mix_law[(q[r] << 8) | o_q[o_r]];1496 r = (r + 1) & CMX_BUFF_MASK;1497 o_r = (o_r + 1) & CMX_BUFF_MASK;1498 }1499 }1500 dsp->tx_R = t;1501 goto send_packet;1502 }1503 /* PROCESS DATA (three or more members) */1504 /* -> if echo is NOT enabled */1505 if (!dsp->echo.software) {1506 /*1507 * -> subtract rx-data from conf-data,1508 * if tx-data is available, mix1509 */1510 while (r != rr && t != tt) {1511 sample = dsp_audio_law_to_s32[p[t]] + *c++ -1512 dsp_audio_law_to_s32[q[r]];1513 if (sample < -32768)1514 sample = -32768;1515 else if (sample > 32767)1516 sample = 32767;1517 *d++ = dsp_audio_s16_to_law[sample & 0xffff];1518 /* conf-rx+tx */1519 r = (r + 1) & CMX_BUFF_MASK;1520 t = (t + 1) & CMX_BUFF_MASK;1521 }1522 while (r != rr) {1523 sample = *c++ - dsp_audio_law_to_s32[q[r]];1524 if (sample < -32768)1525 sample = -32768;1526 else if (sample > 32767)1527 sample = 32767;1528 *d++ = dsp_audio_s16_to_law[sample & 0xffff];1529 /* conf-rx */1530 r = (r + 1) & CMX_BUFF_MASK;1531 }1532 /* -> if echo is enabled */1533 } else {1534 /*1535 * -> encode conf-data, if tx-data1536 * is available, mix1537 */1538 while (r != rr && t != tt) {1539 sample = dsp_audio_law_to_s32[p[t]] + *c++;1540 if (sample < -32768)1541 sample = -32768;1542 else if (sample > 32767)1543 sample = 32767;1544 *d++ = dsp_audio_s16_to_law[sample & 0xffff];1545 /* conf(echo)+tx */1546 t = (t + 1) & CMX_BUFF_MASK;1547 r = (r + 1) & CMX_BUFF_MASK;1548 }1549 while (r != rr) {1550 sample = *c++;1551 if (sample < -32768)1552 sample = -32768;1553 else if (sample > 32767)1554 sample = 32767;1555 *d++ = dsp_audio_s16_to_law[sample & 0xffff];1556 /* conf(echo) */1557 r = (r + 1) & CMX_BUFF_MASK;1558 }1559 }1560 dsp->tx_R = t;1561 goto send_packet;1562 1563send_packet:1564 /*1565 * send tx-data if enabled - don't filter,1566 * because we want what we send, not what we filtered1567 */1568 if (dsp->tx_data) {1569 if (tx_data_only) {1570 hh->prim = DL_DATA_REQ;1571 hh->id = 0;1572 /* queue and trigger */1573 skb_queue_tail(&dsp->sendq, nskb);1574 schedule_work(&dsp->workq);1575 /* exit because only tx_data is used */1576 return;1577 } else {1578 txskb = mI_alloc_skb(len, GFP_ATOMIC);1579 if (!txskb) {1580 printk(KERN_ERR1581 "FATAL ERROR in mISDN_dsp.o: "1582 "cannot alloc %d bytes\n", len);1583 } else {1584 thh = mISDN_HEAD_P(txskb);1585 thh->prim = DL_DATA_REQ;1586 thh->id = 0;1587 skb_put_data(txskb, nskb->data + preload, len);1588 /* queue (trigger later) */1589 skb_queue_tail(&dsp->sendq, txskb);1590 }1591 }1592 }1593 1594 /* send data only to card, if we don't just calculated tx_data */1595 /* adjust volume */1596 if (dsp->tx_volume)1597 dsp_change_volume(nskb, dsp->tx_volume);1598 /* pipeline */1599 if (dsp->pipeline.inuse)1600 dsp_pipeline_process_tx(&dsp->pipeline, nskb->data,1601 nskb->len);1602 /* crypt */1603 if (dsp->bf_enable)1604 dsp_bf_encrypt(dsp, nskb->data, nskb->len);1605 /* queue and trigger */1606 skb_queue_tail(&dsp->sendq, nskb);1607 schedule_work(&dsp->workq);1608}1609 1610static u32 jittercount; /* counter for jitter check */1611struct timer_list dsp_spl_tl;1612unsigned long dsp_spl_jiffies; /* calculate the next time to fire */1613static u16 dsp_count; /* last sample count */1614static int dsp_count_valid; /* if we have last sample count */1615 1616void1617dsp_cmx_send(struct timer_list *arg)1618{1619 struct dsp_conf *conf;1620 struct dsp_conf_member *member;1621 struct dsp *dsp;1622 int mustmix, members;1623 static s32 mixbuffer[MAX_POLL + 100];1624 s32 *c;1625 u8 *p, *q;1626 int r, rr;1627 int jittercheck = 0, delay, i;1628 u_long flags;1629 u16 length, count;1630 1631 /* lock */1632 spin_lock_irqsave(&dsp_lock, flags);1633 1634 if (!dsp_count_valid) {1635 dsp_count = mISDN_clock_get();1636 length = dsp_poll;1637 dsp_count_valid = 1;1638 } else {1639 count = mISDN_clock_get();1640 length = count - dsp_count;1641 dsp_count = count;1642 }1643 if (length > MAX_POLL + 100)1644 length = MAX_POLL + 100;1645 /* printk(KERN_DEBUG "len=%d dsp_count=0x%x\n", length, dsp_count); */1646 1647 /*1648 * check if jitter needs to be checked (this is every second)1649 */1650 jittercount += length;1651 if (jittercount >= 8000) {1652 jittercount -= 8000;1653 jittercheck = 1;1654 }1655 1656 /* loop all members that do not require conference mixing */1657 list_for_each_entry(dsp, &dsp_ilist, list) {1658 if (dsp->hdlc)1659 continue;1660 conf = dsp->conf;1661 mustmix = 0;1662 members = 0;1663 if (conf) {1664 members = list_count_nodes(&conf->mlist);1665#ifdef CMX_CONF_DEBUG1666 if (conf->software && members > 1)1667#else1668 if (conf->software && members > 2)1669#endif1670 mustmix = 1;1671 }1672 1673 /* transmission required */1674 if (!mustmix) {1675 dsp_cmx_send_member(dsp, length, mixbuffer, members);1676 1677 /*1678 * unused mixbuffer is given to prevent a1679 * potential null-pointer-bug1680 */1681 }1682 }1683 1684 /* loop all members that require conference mixing */1685 list_for_each_entry(conf, &conf_ilist, list) {1686 /* count members and check hardware */1687 members = list_count_nodes(&conf->mlist);1688#ifdef CMX_CONF_DEBUG1689 if (conf->software && members > 1) {1690#else1691 if (conf->software && members > 2) {1692#endif1693 /* check for hdlc conf */1694 member = list_entry(conf->mlist.next,1695 struct dsp_conf_member, list);1696 if (member->dsp->hdlc)1697 continue;1698 /* mix all data */1699 memset(mixbuffer, 0, length * sizeof(s32));1700 list_for_each_entry(member, &conf->mlist, list) {1701 dsp = member->dsp;1702 /* get range of data to mix */1703 c = mixbuffer;1704 q = dsp->rx_buff;1705 r = dsp->rx_R;1706 rr = (r + length) & CMX_BUFF_MASK;1707 /* add member's data */1708 while (r != rr) {1709 *c++ += dsp_audio_law_to_s32[q[r]];1710 r = (r + 1) & CMX_BUFF_MASK;1711 }1712 }1713 1714 /* process each member */1715 list_for_each_entry(member, &conf->mlist, list) {1716 /* transmission */1717 dsp_cmx_send_member(member->dsp, length,1718 mixbuffer, members);1719 }1720 }1721 }1722 1723 /* delete rx-data, increment buffers, change pointers */1724 list_for_each_entry(dsp, &dsp_ilist, list) {1725 if (dsp->hdlc)1726 continue;1727 p = dsp->rx_buff;1728 q = dsp->tx_buff;1729 r = dsp->rx_R;1730 /* move receive pointer when receiving */1731 if (!dsp->rx_is_off) {1732 rr = (r + length) & CMX_BUFF_MASK;1733 /* delete rx-data */1734 while (r != rr) {1735 p[r] = dsp_silence;1736 r = (r + 1) & CMX_BUFF_MASK;1737 }1738 /* increment rx-buffer pointer */1739 dsp->rx_R = r; /* write incremented read pointer */1740 }1741 1742 /* check current rx_delay */1743 delay = (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK;1744 if (delay >= CMX_BUFF_HALF)1745 delay = 0; /* will be the delay before next write */1746 /* check for lower delay */1747 if (delay < dsp->rx_delay[0])1748 dsp->rx_delay[0] = delay;1749 /* check current tx_delay */1750 delay = (dsp->tx_W-dsp->tx_R) & CMX_BUFF_MASK;1751 if (delay >= CMX_BUFF_HALF)1752 delay = 0; /* will be the delay before next write */1753 /* check for lower delay */1754 if (delay < dsp->tx_delay[0])1755 dsp->tx_delay[0] = delay;1756 if (jittercheck) {1757 /* find the lowest of all rx_delays */1758 delay = dsp->rx_delay[0];1759 i = 1;1760 while (i < MAX_SECONDS_JITTER_CHECK) {1761 if (delay > dsp->rx_delay[i])1762 delay = dsp->rx_delay[i];1763 i++;1764 }1765 /*1766 * remove rx_delay only if we have delay AND we1767 * have not preset cmx_delay AND1768 * the delay is greater dsp_poll1769 */1770 if (delay > dsp_poll && !dsp->cmx_delay) {1771 if (dsp_debug & DEBUG_DSP_CLOCK)1772 printk(KERN_DEBUG1773 "%s lowest rx_delay of %d bytes for"1774 " dsp %s are now removed.\n",1775 __func__, delay,1776 dsp->name);1777 r = dsp->rx_R;1778 rr = (r + delay - (dsp_poll >> 1))1779 & CMX_BUFF_MASK;1780 /* delete rx-data */1781 while (r != rr) {1782 p[r] = dsp_silence;1783 r = (r + 1) & CMX_BUFF_MASK;1784 }1785 /* increment rx-buffer pointer */1786 dsp->rx_R = r;1787 /* write incremented read pointer */1788 }1789 /* find the lowest of all tx_delays */1790 delay = dsp->tx_delay[0];1791 i = 1;1792 while (i < MAX_SECONDS_JITTER_CHECK) {1793 if (delay > dsp->tx_delay[i])1794 delay = dsp->tx_delay[i];1795 i++;1796 }1797 /*1798 * remove delay only if we have delay AND we1799 * have enabled tx_dejitter1800 */1801 if (delay > dsp_poll && dsp->tx_dejitter) {1802 if (dsp_debug & DEBUG_DSP_CLOCK)1803 printk(KERN_DEBUG1804 "%s lowest tx_delay of %d bytes for"1805 " dsp %s are now removed.\n",1806 __func__, delay,1807 dsp->name);1808 r = dsp->tx_R;1809 rr = (r + delay - (dsp_poll >> 1))1810 & CMX_BUFF_MASK;1811 /* delete tx-data */1812 while (r != rr) {1813 q[r] = dsp_silence;1814 r = (r + 1) & CMX_BUFF_MASK;1815 }1816 /* increment rx-buffer pointer */1817 dsp->tx_R = r;1818 /* write incremented read pointer */1819 }1820 /* scroll up delays */1821 i = MAX_SECONDS_JITTER_CHECK - 1;1822 while (i) {1823 dsp->rx_delay[i] = dsp->rx_delay[i - 1];1824 dsp->tx_delay[i] = dsp->tx_delay[i - 1];1825 i--;1826 }1827 dsp->tx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */1828 dsp->rx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */1829 }1830 }1831 1832 /* if next event would be in the past ... */1833 if ((s32)(dsp_spl_jiffies + dsp_tics-jiffies) <= 0)1834 dsp_spl_jiffies = jiffies + 1;1835 else1836 dsp_spl_jiffies += dsp_tics;1837 1838 dsp_spl_tl.expires = dsp_spl_jiffies;1839 add_timer(&dsp_spl_tl);1840 1841 /* unlock */1842 spin_unlock_irqrestore(&dsp_lock, flags);1843}1844 1845/*1846 * audio data is transmitted from upper layer to the dsp1847 */1848void1849dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb)1850{1851 u_int w, ww;1852 u8 *d, *p;1853 int space; /* todo: , l = skb->len; */1854#ifdef CMX_TX_DEBUG1855 char debugbuf[256] = "";1856#endif1857 1858 /* check if there is enough space, and then copy */1859 w = dsp->tx_W;1860 ww = dsp->tx_R;1861 p = dsp->tx_buff;1862 d = skb->data;1863 space = (ww - w - 1) & CMX_BUFF_MASK;1864 /* write-pointer should not overrun nor reach read pointer */1865 if (space < skb->len) {1866 /* write to the space we have left */1867 ww = (ww - 1) & CMX_BUFF_MASK; /* end one byte prior tx_R */1868 if (dsp_debug & DEBUG_DSP_CLOCK)1869 printk(KERN_DEBUG "%s: TX overflow space=%d skb->len="1870 "%d, w=0x%04x, ww=0x%04x\n", __func__, space,1871 skb->len, w, ww);1872 } else1873 /* write until all byte are copied */1874 ww = (w + skb->len) & CMX_BUFF_MASK;1875 dsp->tx_W = ww;1876 /* show current buffer */1877#ifdef CMX_DEBUG1878 printk(KERN_DEBUG1879 "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n",1880 (u_long)dsp, (ww - w) & CMX_BUFF_MASK, w, ww, dsp->name);1881#endif1882 1883 /* copy transmit data to tx-buffer */1884#ifdef CMX_TX_DEBUG1885 sprintf(debugbuf, "TX getting (%04x-%04x)%p: ", w, ww, p);1886#endif1887 while (w != ww) {1888#ifdef CMX_TX_DEBUG1889 if (strlen(debugbuf) < 48)1890 sprintf(debugbuf + strlen(debugbuf), " %02x", *d);1891#endif1892 p[w] = *d++;1893 w = (w + 1) & CMX_BUFF_MASK;1894 }1895#ifdef CMX_TX_DEBUG1896 printk(KERN_DEBUG "%s\n", debugbuf);1897#endif1898 1899}1900 1901/*1902 * hdlc data is received from card and sent to all members.1903 */1904void1905dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb)1906{1907 struct sk_buff *nskb = NULL;1908 struct dsp_conf_member *member;1909 struct mISDNhead *hh;1910 1911 /* not if not active */1912 if (!dsp->b_active)1913 return;1914 1915 /* check if we have sompen */1916 if (skb->len < 1)1917 return;1918 1919 /* no conf */1920 if (!dsp->conf) {1921 /* in case of software echo */1922 if (dsp->echo.software) {1923 nskb = skb_clone(skb, GFP_ATOMIC);1924 if (nskb) {1925 hh = mISDN_HEAD_P(nskb);1926 hh->prim = PH_DATA_REQ;1927 hh->id = 0;1928 skb_queue_tail(&dsp->sendq, nskb);1929 schedule_work(&dsp->workq);1930 }1931 }1932 return;1933 }1934 /* in case of hardware conference */1935 if (dsp->conf->hardware)1936 return;1937 list_for_each_entry(member, &dsp->conf->mlist, list) {1938 if (dsp->echo.software || member->dsp != dsp) {1939 nskb = skb_clone(skb, GFP_ATOMIC);1940 if (nskb) {1941 hh = mISDN_HEAD_P(nskb);1942 hh->prim = PH_DATA_REQ;1943 hh->id = 0;1944 skb_queue_tail(&member->dsp->sendq, nskb);1945 schedule_work(&member->dsp->workq);1946 }1947 }1948 }1949}1950