162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Audio crossconnecting/conferrencing (hardware level). 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright 2002 by Andreas Eversberg (jolly@eversberg.eu) 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software may be used and distributed according to the terms 762306a36Sopenharmony_ci * of the GNU General Public License, incorporated herein by reference. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * The process of adding and removing parties to/from a conference: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * There is a chain of struct dsp_conf which has one or more members in a chain 1562306a36Sopenharmony_ci * of struct dsp_conf_member. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * After a party is added, the conference is checked for hardware capability. 1862306a36Sopenharmony_ci * Also if a party is removed, the conference is checked again. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * There are 3 different solutions: -1 = software, 0 = hardware-crossconnect 2162306a36Sopenharmony_ci * 1-n = hardware-conference. The n will give the conference number. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Depending on the change after removal or insertion of a party, hardware 2462306a36Sopenharmony_ci * commands are given. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * The current solution is stored within the struct dsp_conf entry. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * HOW THE CMX WORKS: 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * There are 3 types of interaction: One member is alone, in this case only 3362306a36Sopenharmony_ci * data flow from upper to lower layer is done. 3462306a36Sopenharmony_ci * Two members will also exchange their data so they are crossconnected. 3562306a36Sopenharmony_ci * Three or more members will be added in a conference and will hear each 3662306a36Sopenharmony_ci * other but will not receive their own speech (echo) if not enabled. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * Features of CMX are: 3962306a36Sopenharmony_ci * - Crossconnecting or even conference, if more than two members are together. 4062306a36Sopenharmony_ci * - Force mixing of transmit data with other crossconnect/conference members. 4162306a36Sopenharmony_ci * - Echo generation to benchmark the delay of audio processing. 4262306a36Sopenharmony_ci * - Use hardware to minimize cpu load, disable FIFO load and minimize delay. 4362306a36Sopenharmony_ci * - Dejittering and clock generation. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * There are 2 buffers: 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * RX-Buffer 4962306a36Sopenharmony_ci * R W 5062306a36Sopenharmony_ci * | | 5162306a36Sopenharmony_ci * ----------------+-------------+------------------- 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * The rx-buffer is a ring buffer used to store the received data for each 5462306a36Sopenharmony_ci * individual member. This is only the case if data needs to be dejittered 5562306a36Sopenharmony_ci * or in case of a conference where different clocks require reclocking. 5662306a36Sopenharmony_ci * The transmit-clock (R) will read the buffer. 5762306a36Sopenharmony_ci * If the clock overruns the write-pointer, we will have a buffer underrun. 5862306a36Sopenharmony_ci * If the write pointer always has a certain distance from the transmit- 5962306a36Sopenharmony_ci * clock, we will have a delay. The delay will dynamically be increased and 6062306a36Sopenharmony_ci * reduced. 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * TX-Buffer 6462306a36Sopenharmony_ci * R W 6562306a36Sopenharmony_ci * | | 6662306a36Sopenharmony_ci * -----------------+--------+----------------------- 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * The tx-buffer is a ring buffer to queue the transmit data from user space 6962306a36Sopenharmony_ci * until it will be mixed or sent. There are two pointers, R and W. If the write 7062306a36Sopenharmony_ci * pointer W would reach or overrun R, the buffer would overrun. In this case 7162306a36Sopenharmony_ci * (some) data is dropped so that it will not overrun. 7262306a36Sopenharmony_ci * Additionally a dynamic dejittering can be enabled. this allows data from 7362306a36Sopenharmony_ci * user space that have jitter and different clock source. 7462306a36Sopenharmony_ci * 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * Clock: 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * A Clock is not required, if the data source has exactly one clock. In this 7962306a36Sopenharmony_ci * case the data source is forwarded to the destination. 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * A Clock is required, because the data source 8262306a36Sopenharmony_ci * - has multiple clocks. 8362306a36Sopenharmony_ci * - has no usable clock due to jitter or packet loss (VoIP). 8462306a36Sopenharmony_ci * In this case the system's clock is used. The clock resolution depends on 8562306a36Sopenharmony_ci * the jiffie resolution. 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * If a member joins a conference: 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * - If a member joins, its rx_buff is set to silence and change read pointer 9062306a36Sopenharmony_ci * to transmit clock. 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * The procedure of received data from card is explained in cmx_receive. 9362306a36Sopenharmony_ci * The procedure of received data from user space is explained in cmx_transmit. 9462306a36Sopenharmony_ci * The procedure of transmit data to card is cmx_send. 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * Interaction with other features: 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * DTMF: 10062306a36Sopenharmony_ci * DTMF decoding is done before the data is crossconnected. 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci * Volume change: 10362306a36Sopenharmony_ci * Changing rx-volume is done before the data is crossconnected. The tx-volume 10462306a36Sopenharmony_ci * must be changed whenever data is transmitted to the card by the cmx. 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * Tones: 10762306a36Sopenharmony_ci * If a tone is enabled, it will be processed whenever data is transmitted to 10862306a36Sopenharmony_ci * the card. It will replace the tx-data from the user space. 10962306a36Sopenharmony_ci * If tones are generated by hardware, this conference member is removed for 11062306a36Sopenharmony_ci * this time. 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * Disable rx-data: 11362306a36Sopenharmony_ci * If cmx is realized in hardware, rx data will be disabled if requested by 11462306a36Sopenharmony_ci * the upper layer. If dtmf decoding is done by software and enabled, rx data 11562306a36Sopenharmony_ci * will not be disabled but blocked to the upper layer. 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * HFC conference engine: 11862306a36Sopenharmony_ci * If it is possible to realize all features using hardware, hardware will be 11962306a36Sopenharmony_ci * used if not forbidden by control command. Disabling rx-data provides 12062306a36Sopenharmony_ci * absolutely traffic free audio processing. (except for the quick 1-frame 12162306a36Sopenharmony_ci * upload of a tone loop, only once for a new tone) 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* delay.h is required for hw_lock.h */ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#include <linux/slab.h> 12862306a36Sopenharmony_ci#include <linux/delay.h> 12962306a36Sopenharmony_ci#include <linux/mISDNif.h> 13062306a36Sopenharmony_ci#include <linux/mISDNdsp.h> 13162306a36Sopenharmony_ci#include "core.h" 13262306a36Sopenharmony_ci#include "dsp.h" 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * debugging of multi party conference, 13562306a36Sopenharmony_ci * by using conference even with two members 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* #define CMX_CONF_DEBUG */ 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/*#define CMX_DEBUG * massive read/write pointer output */ 14162306a36Sopenharmony_ci/*#define CMX_DELAY_DEBUG * gives rx-buffer delay overview */ 14262306a36Sopenharmony_ci/*#define CMX_TX_DEBUG * massive read/write on tx-buffer with content */ 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* 14562306a36Sopenharmony_ci * debug cmx memory structure 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_civoid 14862306a36Sopenharmony_cidsp_cmx_debug(struct dsp *dsp) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct dsp_conf *conf; 15162306a36Sopenharmony_ci struct dsp_conf_member *member; 15262306a36Sopenharmony_ci struct dsp *odsp; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci printk(KERN_DEBUG "-----Current DSP\n"); 15562306a36Sopenharmony_ci list_for_each_entry(odsp, &dsp_ilist, list) { 15662306a36Sopenharmony_ci printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d", 15762306a36Sopenharmony_ci odsp->name, odsp->echo.hardware, odsp->echo.software, 15862306a36Sopenharmony_ci odsp->tx_mix); 15962306a36Sopenharmony_ci if (odsp->conf) 16062306a36Sopenharmony_ci printk(" (Conf %d)", odsp->conf->id); 16162306a36Sopenharmony_ci if (dsp == odsp) 16262306a36Sopenharmony_ci printk(" *this*"); 16362306a36Sopenharmony_ci printk("\n"); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci printk(KERN_DEBUG "-----Current Conf:\n"); 16662306a36Sopenharmony_ci list_for_each_entry(conf, &conf_ilist, list) { 16762306a36Sopenharmony_ci printk(KERN_DEBUG "* Conf %d (%p)\n", conf->id, conf); 16862306a36Sopenharmony_ci list_for_each_entry(member, &conf->mlist, list) { 16962306a36Sopenharmony_ci printk(KERN_DEBUG 17062306a36Sopenharmony_ci " - member = %s (slot_tx %d, bank_tx %d, " 17162306a36Sopenharmony_ci "slot_rx %d, bank_rx %d hfc_conf %d " 17262306a36Sopenharmony_ci "tx_data %d rx_is_off %d)%s\n", 17362306a36Sopenharmony_ci member->dsp->name, member->dsp->pcm_slot_tx, 17462306a36Sopenharmony_ci member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, 17562306a36Sopenharmony_ci member->dsp->pcm_bank_rx, member->dsp->hfc_conf, 17662306a36Sopenharmony_ci member->dsp->tx_data, member->dsp->rx_is_off, 17762306a36Sopenharmony_ci (member->dsp == dsp) ? " *this*" : ""); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci printk(KERN_DEBUG "-----end\n"); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* 18462306a36Sopenharmony_ci * search conference 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_cistatic struct dsp_conf * 18762306a36Sopenharmony_cidsp_cmx_search_conf(u32 id) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct dsp_conf *conf; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (!id) { 19262306a36Sopenharmony_ci printk(KERN_WARNING "%s: conference ID is 0.\n", __func__); 19362306a36Sopenharmony_ci return NULL; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* search conference */ 19762306a36Sopenharmony_ci list_for_each_entry(conf, &conf_ilist, list) 19862306a36Sopenharmony_ci if (conf->id == id) 19962306a36Sopenharmony_ci return conf; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return NULL; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* 20662306a36Sopenharmony_ci * add member to conference 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_cistatic int 20962306a36Sopenharmony_cidsp_cmx_add_conf_member(struct dsp *dsp, struct dsp_conf *conf) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct dsp_conf_member *member; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (!conf || !dsp) { 21462306a36Sopenharmony_ci printk(KERN_WARNING "%s: conf or dsp is 0.\n", __func__); 21562306a36Sopenharmony_ci return -EINVAL; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci if (dsp->member) { 21862306a36Sopenharmony_ci printk(KERN_WARNING "%s: dsp is already member in a conf.\n", 21962306a36Sopenharmony_ci __func__); 22062306a36Sopenharmony_ci return -EINVAL; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (dsp->conf) { 22462306a36Sopenharmony_ci printk(KERN_WARNING "%s: dsp is already in a conf.\n", 22562306a36Sopenharmony_ci __func__); 22662306a36Sopenharmony_ci return -EINVAL; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci member = kzalloc(sizeof(struct dsp_conf_member), GFP_ATOMIC); 23062306a36Sopenharmony_ci if (!member) { 23162306a36Sopenharmony_ci printk(KERN_ERR "kzalloc struct dsp_conf_member failed\n"); 23262306a36Sopenharmony_ci return -ENOMEM; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci member->dsp = dsp; 23562306a36Sopenharmony_ci /* clear rx buffer */ 23662306a36Sopenharmony_ci memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); 23762306a36Sopenharmony_ci dsp->rx_init = 1; /* rx_W and rx_R will be adjusted on first frame */ 23862306a36Sopenharmony_ci dsp->rx_W = 0; 23962306a36Sopenharmony_ci dsp->rx_R = 0; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci list_add_tail(&member->list, &conf->mlist); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci dsp->conf = conf; 24462306a36Sopenharmony_ci dsp->member = member; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* 25162306a36Sopenharmony_ci * del member from conference 25262306a36Sopenharmony_ci */ 25362306a36Sopenharmony_ciint 25462306a36Sopenharmony_cidsp_cmx_del_conf_member(struct dsp *dsp) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct dsp_conf_member *member; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!dsp) { 25962306a36Sopenharmony_ci printk(KERN_WARNING "%s: dsp is 0.\n", 26062306a36Sopenharmony_ci __func__); 26162306a36Sopenharmony_ci return -EINVAL; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (!dsp->conf) { 26562306a36Sopenharmony_ci printk(KERN_WARNING "%s: dsp is not in a conf.\n", 26662306a36Sopenharmony_ci __func__); 26762306a36Sopenharmony_ci return -EINVAL; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (list_empty(&dsp->conf->mlist)) { 27162306a36Sopenharmony_ci printk(KERN_WARNING "%s: dsp has linked an empty conf.\n", 27262306a36Sopenharmony_ci __func__); 27362306a36Sopenharmony_ci return -EINVAL; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* find us in conf */ 27762306a36Sopenharmony_ci list_for_each_entry(member, &dsp->conf->mlist, list) { 27862306a36Sopenharmony_ci if (member->dsp == dsp) { 27962306a36Sopenharmony_ci list_del(&member->list); 28062306a36Sopenharmony_ci dsp->conf = NULL; 28162306a36Sopenharmony_ci dsp->member = NULL; 28262306a36Sopenharmony_ci kfree(member); 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci printk(KERN_WARNING 28762306a36Sopenharmony_ci "%s: dsp is not present in its own conf_member list.\n", 28862306a36Sopenharmony_ci __func__); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return -EINVAL; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/* 29562306a36Sopenharmony_ci * new conference 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_cistatic struct dsp_conf 29862306a36Sopenharmony_ci*dsp_cmx_new_conf(u32 id) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct dsp_conf *conf; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (!id) { 30362306a36Sopenharmony_ci printk(KERN_WARNING "%s: id is 0.\n", 30462306a36Sopenharmony_ci __func__); 30562306a36Sopenharmony_ci return NULL; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci conf = kzalloc(sizeof(struct dsp_conf), GFP_ATOMIC); 30962306a36Sopenharmony_ci if (!conf) { 31062306a36Sopenharmony_ci printk(KERN_ERR "kzalloc struct dsp_conf failed\n"); 31162306a36Sopenharmony_ci return NULL; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci INIT_LIST_HEAD(&conf->mlist); 31462306a36Sopenharmony_ci conf->id = id; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci list_add_tail(&conf->list, &conf_ilist); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return conf; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci/* 32362306a36Sopenharmony_ci * del conference 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_ciint 32662306a36Sopenharmony_cidsp_cmx_del_conf(struct dsp_conf *conf) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci if (!conf) { 32962306a36Sopenharmony_ci printk(KERN_WARNING "%s: conf is null.\n", 33062306a36Sopenharmony_ci __func__); 33162306a36Sopenharmony_ci return -EINVAL; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (!list_empty(&conf->mlist)) { 33562306a36Sopenharmony_ci printk(KERN_WARNING "%s: conf not empty.\n", 33662306a36Sopenharmony_ci __func__); 33762306a36Sopenharmony_ci return -EINVAL; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci list_del(&conf->list); 34062306a36Sopenharmony_ci kfree(conf); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return 0; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/* 34762306a36Sopenharmony_ci * send HW message to hfc card 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_cistatic void 35062306a36Sopenharmony_cidsp_cmx_hw_message(struct dsp *dsp, u32 message, u32 param1, u32 param2, 35162306a36Sopenharmony_ci u32 param3, u32 param4) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct mISDN_ctrl_req cq; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci memset(&cq, 0, sizeof(cq)); 35662306a36Sopenharmony_ci cq.op = message; 35762306a36Sopenharmony_ci cq.p1 = param1 | (param2 << 8); 35862306a36Sopenharmony_ci cq.p2 = param3 | (param4 << 8); 35962306a36Sopenharmony_ci if (dsp->ch.peer) 36062306a36Sopenharmony_ci dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci/* 36562306a36Sopenharmony_ci * do hardware update and set the software/hardware flag 36662306a36Sopenharmony_ci * 36762306a36Sopenharmony_ci * either a conference or a dsp instance can be given 36862306a36Sopenharmony_ci * if only dsp instance is given, the instance is not associated with a conf 36962306a36Sopenharmony_ci * and therefore removed. if a conference is given, the dsp is expected to 37062306a36Sopenharmony_ci * be member of that conference. 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_civoid 37362306a36Sopenharmony_cidsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct dsp_conf_member *member, *nextm; 37662306a36Sopenharmony_ci struct dsp *finddsp; 37762306a36Sopenharmony_ci int memb = 0, i, ii, i1, i2; 37862306a36Sopenharmony_ci int freeunits[8]; 37962306a36Sopenharmony_ci u_char freeslots[256]; 38062306a36Sopenharmony_ci int same_hfc = -1, same_pcm = -1, current_conf = -1, 38162306a36Sopenharmony_ci all_conf = 1, tx_data = 0; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* dsp gets updated (no conf) */ 38462306a36Sopenharmony_ci if (!conf) { 38562306a36Sopenharmony_ci if (!dsp) 38662306a36Sopenharmony_ci return; 38762306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 38862306a36Sopenharmony_ci printk(KERN_DEBUG "%s checking dsp %s\n", 38962306a36Sopenharmony_ci __func__, dsp->name); 39062306a36Sopenharmony_ci one_member: 39162306a36Sopenharmony_ci /* remove HFC conference if enabled */ 39262306a36Sopenharmony_ci if (dsp->hfc_conf >= 0) { 39362306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 39462306a36Sopenharmony_ci printk(KERN_DEBUG 39562306a36Sopenharmony_ci "%s removing %s from HFC conf %d " 39662306a36Sopenharmony_ci "because dsp is split\n", __func__, 39762306a36Sopenharmony_ci dsp->name, dsp->hfc_conf); 39862306a36Sopenharmony_ci dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_CONF_SPLIT, 39962306a36Sopenharmony_ci 0, 0, 0, 0); 40062306a36Sopenharmony_ci dsp->hfc_conf = -1; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci /* process hw echo */ 40362306a36Sopenharmony_ci if (dsp->features.pcm_banks < 1) 40462306a36Sopenharmony_ci return; 40562306a36Sopenharmony_ci if (!dsp->echo.software && !dsp->echo.hardware) { 40662306a36Sopenharmony_ci /* NO ECHO: remove PCM slot if assigned */ 40762306a36Sopenharmony_ci if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { 40862306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 40962306a36Sopenharmony_ci printk(KERN_DEBUG "%s removing %s from" 41062306a36Sopenharmony_ci " PCM slot %d (TX) %d (RX) because" 41162306a36Sopenharmony_ci " dsp is split (no echo)\n", 41262306a36Sopenharmony_ci __func__, dsp->name, 41362306a36Sopenharmony_ci dsp->pcm_slot_tx, dsp->pcm_slot_rx); 41462306a36Sopenharmony_ci dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_DISC, 41562306a36Sopenharmony_ci 0, 0, 0, 0); 41662306a36Sopenharmony_ci dsp->pcm_slot_tx = -1; 41762306a36Sopenharmony_ci dsp->pcm_bank_tx = -1; 41862306a36Sopenharmony_ci dsp->pcm_slot_rx = -1; 41962306a36Sopenharmony_ci dsp->pcm_bank_rx = -1; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci return; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci /* echo is enabled, find out if we use soft or hardware */ 42462306a36Sopenharmony_ci dsp->echo.software = dsp->tx_data; 42562306a36Sopenharmony_ci dsp->echo.hardware = 0; 42662306a36Sopenharmony_ci /* ECHO: already echo */ 42762306a36Sopenharmony_ci if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 && 42862306a36Sopenharmony_ci dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) { 42962306a36Sopenharmony_ci dsp->echo.hardware = 1; 43062306a36Sopenharmony_ci return; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci /* ECHO: if slot already assigned */ 43362306a36Sopenharmony_ci if (dsp->pcm_slot_tx >= 0) { 43462306a36Sopenharmony_ci dsp->pcm_slot_rx = dsp->pcm_slot_tx; 43562306a36Sopenharmony_ci dsp->pcm_bank_tx = 2; /* 2 means loop */ 43662306a36Sopenharmony_ci dsp->pcm_bank_rx = 2; 43762306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 43862306a36Sopenharmony_ci printk(KERN_DEBUG 43962306a36Sopenharmony_ci "%s refresh %s for echo using slot %d\n", 44062306a36Sopenharmony_ci __func__, dsp->name, 44162306a36Sopenharmony_ci dsp->pcm_slot_tx); 44262306a36Sopenharmony_ci dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, 44362306a36Sopenharmony_ci dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); 44462306a36Sopenharmony_ci dsp->echo.hardware = 1; 44562306a36Sopenharmony_ci return; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci /* ECHO: find slot */ 44862306a36Sopenharmony_ci dsp->pcm_slot_tx = -1; 44962306a36Sopenharmony_ci dsp->pcm_slot_rx = -1; 45062306a36Sopenharmony_ci memset(freeslots, 1, sizeof(freeslots)); 45162306a36Sopenharmony_ci list_for_each_entry(finddsp, &dsp_ilist, list) { 45262306a36Sopenharmony_ci if (finddsp->features.pcm_id == dsp->features.pcm_id) { 45362306a36Sopenharmony_ci if (finddsp->pcm_slot_rx >= 0 && 45462306a36Sopenharmony_ci finddsp->pcm_slot_rx < sizeof(freeslots)) 45562306a36Sopenharmony_ci freeslots[finddsp->pcm_slot_rx] = 0; 45662306a36Sopenharmony_ci if (finddsp->pcm_slot_tx >= 0 && 45762306a36Sopenharmony_ci finddsp->pcm_slot_tx < sizeof(freeslots)) 45862306a36Sopenharmony_ci freeslots[finddsp->pcm_slot_tx] = 0; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci i = 0; 46262306a36Sopenharmony_ci ii = dsp->features.pcm_slots; 46362306a36Sopenharmony_ci while (i < ii) { 46462306a36Sopenharmony_ci if (freeslots[i]) 46562306a36Sopenharmony_ci break; 46662306a36Sopenharmony_ci i++; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci if (i == ii) { 46962306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 47062306a36Sopenharmony_ci printk(KERN_DEBUG 47162306a36Sopenharmony_ci "%s no slot available for echo\n", 47262306a36Sopenharmony_ci __func__); 47362306a36Sopenharmony_ci /* no more slots available */ 47462306a36Sopenharmony_ci dsp->echo.software = 1; 47562306a36Sopenharmony_ci return; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci /* assign free slot */ 47862306a36Sopenharmony_ci dsp->pcm_slot_tx = i; 47962306a36Sopenharmony_ci dsp->pcm_slot_rx = i; 48062306a36Sopenharmony_ci dsp->pcm_bank_tx = 2; /* loop */ 48162306a36Sopenharmony_ci dsp->pcm_bank_rx = 2; 48262306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 48362306a36Sopenharmony_ci printk(KERN_DEBUG 48462306a36Sopenharmony_ci "%s assign echo for %s using slot %d\n", 48562306a36Sopenharmony_ci __func__, dsp->name, dsp->pcm_slot_tx); 48662306a36Sopenharmony_ci dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, 48762306a36Sopenharmony_ci dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); 48862306a36Sopenharmony_ci dsp->echo.hardware = 1; 48962306a36Sopenharmony_ci return; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* conf gets updated (all members) */ 49362306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 49462306a36Sopenharmony_ci printk(KERN_DEBUG "%s checking conference %d\n", 49562306a36Sopenharmony_ci __func__, conf->id); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (list_empty(&conf->mlist)) { 49862306a36Sopenharmony_ci printk(KERN_ERR "%s: conference without members\n", 49962306a36Sopenharmony_ci __func__); 50062306a36Sopenharmony_ci return; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci member = list_entry(conf->mlist.next, struct dsp_conf_member, list); 50362306a36Sopenharmony_ci same_hfc = member->dsp->features.hfc_id; 50462306a36Sopenharmony_ci same_pcm = member->dsp->features.pcm_id; 50562306a36Sopenharmony_ci /* check all members in our conference */ 50662306a36Sopenharmony_ci list_for_each_entry(member, &conf->mlist, list) { 50762306a36Sopenharmony_ci /* check if member uses mixing */ 50862306a36Sopenharmony_ci if (member->dsp->tx_mix) { 50962306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 51062306a36Sopenharmony_ci printk(KERN_DEBUG 51162306a36Sopenharmony_ci "%s dsp %s cannot form a conf, because " 51262306a36Sopenharmony_ci "tx_mix is turned on\n", __func__, 51362306a36Sopenharmony_ci member->dsp->name); 51462306a36Sopenharmony_ci conf_software: 51562306a36Sopenharmony_ci list_for_each_entry(member, &conf->mlist, list) { 51662306a36Sopenharmony_ci dsp = member->dsp; 51762306a36Sopenharmony_ci /* remove HFC conference if enabled */ 51862306a36Sopenharmony_ci if (dsp->hfc_conf >= 0) { 51962306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 52062306a36Sopenharmony_ci printk(KERN_DEBUG 52162306a36Sopenharmony_ci "%s removing %s from HFC " 52262306a36Sopenharmony_ci "conf %d because not " 52362306a36Sopenharmony_ci "possible with hardware\n", 52462306a36Sopenharmony_ci __func__, 52562306a36Sopenharmony_ci dsp->name, 52662306a36Sopenharmony_ci dsp->hfc_conf); 52762306a36Sopenharmony_ci dsp_cmx_hw_message(dsp, 52862306a36Sopenharmony_ci MISDN_CTRL_HFC_CONF_SPLIT, 52962306a36Sopenharmony_ci 0, 0, 0, 0); 53062306a36Sopenharmony_ci dsp->hfc_conf = -1; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci /* remove PCM slot if assigned */ 53362306a36Sopenharmony_ci if (dsp->pcm_slot_tx >= 0 || 53462306a36Sopenharmony_ci dsp->pcm_slot_rx >= 0) { 53562306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 53662306a36Sopenharmony_ci printk(KERN_DEBUG "%s removing " 53762306a36Sopenharmony_ci "%s from PCM slot %d (TX)" 53862306a36Sopenharmony_ci " slot %d (RX) because not" 53962306a36Sopenharmony_ci " possible with hardware\n", 54062306a36Sopenharmony_ci __func__, 54162306a36Sopenharmony_ci dsp->name, 54262306a36Sopenharmony_ci dsp->pcm_slot_tx, 54362306a36Sopenharmony_ci dsp->pcm_slot_rx); 54462306a36Sopenharmony_ci dsp_cmx_hw_message(dsp, 54562306a36Sopenharmony_ci MISDN_CTRL_HFC_PCM_DISC, 54662306a36Sopenharmony_ci 0, 0, 0, 0); 54762306a36Sopenharmony_ci dsp->pcm_slot_tx = -1; 54862306a36Sopenharmony_ci dsp->pcm_bank_tx = -1; 54962306a36Sopenharmony_ci dsp->pcm_slot_rx = -1; 55062306a36Sopenharmony_ci dsp->pcm_bank_rx = -1; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci conf->hardware = 0; 55462306a36Sopenharmony_ci conf->software = 1; 55562306a36Sopenharmony_ci return; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci /* check if member has echo turned on */ 55862306a36Sopenharmony_ci if (member->dsp->echo.hardware || member->dsp->echo.software) { 55962306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 56062306a36Sopenharmony_ci printk(KERN_DEBUG 56162306a36Sopenharmony_ci "%s dsp %s cannot form a conf, because " 56262306a36Sopenharmony_ci "echo is turned on\n", __func__, 56362306a36Sopenharmony_ci member->dsp->name); 56462306a36Sopenharmony_ci goto conf_software; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci /* check if member has tx_mix turned on */ 56762306a36Sopenharmony_ci if (member->dsp->tx_mix) { 56862306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 56962306a36Sopenharmony_ci printk(KERN_DEBUG 57062306a36Sopenharmony_ci "%s dsp %s cannot form a conf, because " 57162306a36Sopenharmony_ci "tx_mix is turned on\n", 57262306a36Sopenharmony_ci __func__, member->dsp->name); 57362306a36Sopenharmony_ci goto conf_software; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci /* check if member changes volume at an not suppoted level */ 57662306a36Sopenharmony_ci if (member->dsp->tx_volume) { 57762306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 57862306a36Sopenharmony_ci printk(KERN_DEBUG 57962306a36Sopenharmony_ci "%s dsp %s cannot form a conf, because " 58062306a36Sopenharmony_ci "tx_volume is changed\n", 58162306a36Sopenharmony_ci __func__, member->dsp->name); 58262306a36Sopenharmony_ci goto conf_software; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci if (member->dsp->rx_volume) { 58562306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 58662306a36Sopenharmony_ci printk(KERN_DEBUG 58762306a36Sopenharmony_ci "%s dsp %s cannot form a conf, because " 58862306a36Sopenharmony_ci "rx_volume is changed\n", 58962306a36Sopenharmony_ci __func__, member->dsp->name); 59062306a36Sopenharmony_ci goto conf_software; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci /* check if tx-data turned on */ 59362306a36Sopenharmony_ci if (member->dsp->tx_data) { 59462306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 59562306a36Sopenharmony_ci printk(KERN_DEBUG 59662306a36Sopenharmony_ci "%s dsp %s tx_data is turned on\n", 59762306a36Sopenharmony_ci __func__, member->dsp->name); 59862306a36Sopenharmony_ci tx_data = 1; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci /* check if pipeline exists */ 60162306a36Sopenharmony_ci if (member->dsp->pipeline.inuse) { 60262306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 60362306a36Sopenharmony_ci printk(KERN_DEBUG 60462306a36Sopenharmony_ci "%s dsp %s cannot form a conf, because " 60562306a36Sopenharmony_ci "pipeline exists\n", __func__, 60662306a36Sopenharmony_ci member->dsp->name); 60762306a36Sopenharmony_ci goto conf_software; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci /* check if encryption is enabled */ 61062306a36Sopenharmony_ci if (member->dsp->bf_enable) { 61162306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 61262306a36Sopenharmony_ci printk(KERN_DEBUG "%s dsp %s cannot form a " 61362306a36Sopenharmony_ci "conf, because encryption is enabled\n", 61462306a36Sopenharmony_ci __func__, member->dsp->name); 61562306a36Sopenharmony_ci goto conf_software; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci /* check if member is on a card with PCM support */ 61862306a36Sopenharmony_ci if (member->dsp->features.pcm_id < 0) { 61962306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 62062306a36Sopenharmony_ci printk(KERN_DEBUG 62162306a36Sopenharmony_ci "%s dsp %s cannot form a conf, because " 62262306a36Sopenharmony_ci "dsp has no PCM bus\n", 62362306a36Sopenharmony_ci __func__, member->dsp->name); 62462306a36Sopenharmony_ci goto conf_software; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci /* check if relations are on the same PCM bus */ 62762306a36Sopenharmony_ci if (member->dsp->features.pcm_id != same_pcm) { 62862306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 62962306a36Sopenharmony_ci printk(KERN_DEBUG 63062306a36Sopenharmony_ci "%s dsp %s cannot form a conf, because " 63162306a36Sopenharmony_ci "dsp is on a different PCM bus than the " 63262306a36Sopenharmony_ci "first dsp\n", 63362306a36Sopenharmony_ci __func__, member->dsp->name); 63462306a36Sopenharmony_ci goto conf_software; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci /* determine if members are on the same hfc chip */ 63762306a36Sopenharmony_ci if (same_hfc != member->dsp->features.hfc_id) 63862306a36Sopenharmony_ci same_hfc = -1; 63962306a36Sopenharmony_ci /* if there are members already in a conference */ 64062306a36Sopenharmony_ci if (current_conf < 0 && member->dsp->hfc_conf >= 0) 64162306a36Sopenharmony_ci current_conf = member->dsp->hfc_conf; 64262306a36Sopenharmony_ci /* if any member is not in a conference */ 64362306a36Sopenharmony_ci if (member->dsp->hfc_conf < 0) 64462306a36Sopenharmony_ci all_conf = 0; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci memb++; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* if no member, this is an error */ 65062306a36Sopenharmony_ci if (memb < 1) 65162306a36Sopenharmony_ci return; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* one member */ 65462306a36Sopenharmony_ci if (memb == 1) { 65562306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 65662306a36Sopenharmony_ci printk(KERN_DEBUG 65762306a36Sopenharmony_ci "%s conf %d cannot form a HW conference, " 65862306a36Sopenharmony_ci "because dsp is alone\n", __func__, conf->id); 65962306a36Sopenharmony_ci conf->hardware = 0; 66062306a36Sopenharmony_ci conf->software = 0; 66162306a36Sopenharmony_ci member = list_entry(conf->mlist.next, struct dsp_conf_member, 66262306a36Sopenharmony_ci list); 66362306a36Sopenharmony_ci dsp = member->dsp; 66462306a36Sopenharmony_ci goto one_member; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * ok, now we are sure that all members are on the same pcm. 66962306a36Sopenharmony_ci * now we will see if we have only two members, so we can do 67062306a36Sopenharmony_ci * crossconnections, which don't have any limitations. 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci /* if we have only two members */ 67462306a36Sopenharmony_ci if (memb == 2) { 67562306a36Sopenharmony_ci member = list_entry(conf->mlist.next, struct dsp_conf_member, 67662306a36Sopenharmony_ci list); 67762306a36Sopenharmony_ci nextm = list_entry(member->list.next, struct dsp_conf_member, 67862306a36Sopenharmony_ci list); 67962306a36Sopenharmony_ci /* remove HFC conference if enabled */ 68062306a36Sopenharmony_ci if (member->dsp->hfc_conf >= 0) { 68162306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 68262306a36Sopenharmony_ci printk(KERN_DEBUG 68362306a36Sopenharmony_ci "%s removing %s from HFC conf %d because " 68462306a36Sopenharmony_ci "two parties require only a PCM slot\n", 68562306a36Sopenharmony_ci __func__, member->dsp->name, 68662306a36Sopenharmony_ci member->dsp->hfc_conf); 68762306a36Sopenharmony_ci dsp_cmx_hw_message(member->dsp, 68862306a36Sopenharmony_ci MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); 68962306a36Sopenharmony_ci member->dsp->hfc_conf = -1; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci if (nextm->dsp->hfc_conf >= 0) { 69262306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 69362306a36Sopenharmony_ci printk(KERN_DEBUG 69462306a36Sopenharmony_ci "%s removing %s from HFC conf %d because " 69562306a36Sopenharmony_ci "two parties require only a PCM slot\n", 69662306a36Sopenharmony_ci __func__, nextm->dsp->name, 69762306a36Sopenharmony_ci nextm->dsp->hfc_conf); 69862306a36Sopenharmony_ci dsp_cmx_hw_message(nextm->dsp, 69962306a36Sopenharmony_ci MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); 70062306a36Sopenharmony_ci nextm->dsp->hfc_conf = -1; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci /* if members have two banks (and not on the same chip) */ 70362306a36Sopenharmony_ci if (member->dsp->features.pcm_banks > 1 && 70462306a36Sopenharmony_ci nextm->dsp->features.pcm_banks > 1 && 70562306a36Sopenharmony_ci member->dsp->features.hfc_id != 70662306a36Sopenharmony_ci nextm->dsp->features.hfc_id) { 70762306a36Sopenharmony_ci /* if both members have same slots with crossed banks */ 70862306a36Sopenharmony_ci if (member->dsp->pcm_slot_tx >= 0 && 70962306a36Sopenharmony_ci member->dsp->pcm_slot_rx >= 0 && 71062306a36Sopenharmony_ci nextm->dsp->pcm_slot_tx >= 0 && 71162306a36Sopenharmony_ci nextm->dsp->pcm_slot_rx >= 0 && 71262306a36Sopenharmony_ci nextm->dsp->pcm_slot_tx == 71362306a36Sopenharmony_ci member->dsp->pcm_slot_rx && 71462306a36Sopenharmony_ci nextm->dsp->pcm_slot_rx == 71562306a36Sopenharmony_ci member->dsp->pcm_slot_tx && 71662306a36Sopenharmony_ci nextm->dsp->pcm_slot_tx == 71762306a36Sopenharmony_ci member->dsp->pcm_slot_tx && 71862306a36Sopenharmony_ci member->dsp->pcm_bank_tx != 71962306a36Sopenharmony_ci member->dsp->pcm_bank_rx && 72062306a36Sopenharmony_ci nextm->dsp->pcm_bank_tx != 72162306a36Sopenharmony_ci nextm->dsp->pcm_bank_rx) { 72262306a36Sopenharmony_ci /* all members have same slot */ 72362306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 72462306a36Sopenharmony_ci printk(KERN_DEBUG 72562306a36Sopenharmony_ci "%s dsp %s & %s stay joined on " 72662306a36Sopenharmony_ci "PCM slot %d bank %d (TX) bank %d " 72762306a36Sopenharmony_ci "(RX) (on different chips)\n", 72862306a36Sopenharmony_ci __func__, 72962306a36Sopenharmony_ci member->dsp->name, 73062306a36Sopenharmony_ci nextm->dsp->name, 73162306a36Sopenharmony_ci member->dsp->pcm_slot_tx, 73262306a36Sopenharmony_ci member->dsp->pcm_bank_tx, 73362306a36Sopenharmony_ci member->dsp->pcm_bank_rx); 73462306a36Sopenharmony_ci conf->hardware = 1; 73562306a36Sopenharmony_ci conf->software = tx_data; 73662306a36Sopenharmony_ci return; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci /* find a new slot */ 73962306a36Sopenharmony_ci memset(freeslots, 1, sizeof(freeslots)); 74062306a36Sopenharmony_ci list_for_each_entry(dsp, &dsp_ilist, list) { 74162306a36Sopenharmony_ci if (dsp != member->dsp && 74262306a36Sopenharmony_ci dsp != nextm->dsp && 74362306a36Sopenharmony_ci member->dsp->features.pcm_id == 74462306a36Sopenharmony_ci dsp->features.pcm_id) { 74562306a36Sopenharmony_ci if (dsp->pcm_slot_rx >= 0 && 74662306a36Sopenharmony_ci dsp->pcm_slot_rx < 74762306a36Sopenharmony_ci sizeof(freeslots)) 74862306a36Sopenharmony_ci freeslots[dsp->pcm_slot_rx] = 0; 74962306a36Sopenharmony_ci if (dsp->pcm_slot_tx >= 0 && 75062306a36Sopenharmony_ci dsp->pcm_slot_tx < 75162306a36Sopenharmony_ci sizeof(freeslots)) 75262306a36Sopenharmony_ci freeslots[dsp->pcm_slot_tx] = 0; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci i = 0; 75662306a36Sopenharmony_ci ii = member->dsp->features.pcm_slots; 75762306a36Sopenharmony_ci while (i < ii) { 75862306a36Sopenharmony_ci if (freeslots[i]) 75962306a36Sopenharmony_ci break; 76062306a36Sopenharmony_ci i++; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci if (i == ii) { 76362306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 76462306a36Sopenharmony_ci printk(KERN_DEBUG 76562306a36Sopenharmony_ci "%s no slot available for " 76662306a36Sopenharmony_ci "%s & %s\n", __func__, 76762306a36Sopenharmony_ci member->dsp->name, 76862306a36Sopenharmony_ci nextm->dsp->name); 76962306a36Sopenharmony_ci /* no more slots available */ 77062306a36Sopenharmony_ci goto conf_software; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci /* assign free slot */ 77362306a36Sopenharmony_ci member->dsp->pcm_slot_tx = i; 77462306a36Sopenharmony_ci member->dsp->pcm_slot_rx = i; 77562306a36Sopenharmony_ci nextm->dsp->pcm_slot_tx = i; 77662306a36Sopenharmony_ci nextm->dsp->pcm_slot_rx = i; 77762306a36Sopenharmony_ci member->dsp->pcm_bank_rx = 0; 77862306a36Sopenharmony_ci member->dsp->pcm_bank_tx = 1; 77962306a36Sopenharmony_ci nextm->dsp->pcm_bank_rx = 1; 78062306a36Sopenharmony_ci nextm->dsp->pcm_bank_tx = 0; 78162306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 78262306a36Sopenharmony_ci printk(KERN_DEBUG 78362306a36Sopenharmony_ci "%s adding %s & %s to new PCM slot %d " 78462306a36Sopenharmony_ci "(TX and RX on different chips) because " 78562306a36Sopenharmony_ci "both members have not same slots\n", 78662306a36Sopenharmony_ci __func__, 78762306a36Sopenharmony_ci member->dsp->name, 78862306a36Sopenharmony_ci nextm->dsp->name, 78962306a36Sopenharmony_ci member->dsp->pcm_slot_tx); 79062306a36Sopenharmony_ci dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, 79162306a36Sopenharmony_ci member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, 79262306a36Sopenharmony_ci member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); 79362306a36Sopenharmony_ci dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, 79462306a36Sopenharmony_ci nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, 79562306a36Sopenharmony_ci nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); 79662306a36Sopenharmony_ci conf->hardware = 1; 79762306a36Sopenharmony_ci conf->software = tx_data; 79862306a36Sopenharmony_ci return; 79962306a36Sopenharmony_ci /* if members have one bank (or on the same chip) */ 80062306a36Sopenharmony_ci } else { 80162306a36Sopenharmony_ci /* if both members have different crossed slots */ 80262306a36Sopenharmony_ci if (member->dsp->pcm_slot_tx >= 0 && 80362306a36Sopenharmony_ci member->dsp->pcm_slot_rx >= 0 && 80462306a36Sopenharmony_ci nextm->dsp->pcm_slot_tx >= 0 && 80562306a36Sopenharmony_ci nextm->dsp->pcm_slot_rx >= 0 && 80662306a36Sopenharmony_ci nextm->dsp->pcm_slot_tx == 80762306a36Sopenharmony_ci member->dsp->pcm_slot_rx && 80862306a36Sopenharmony_ci nextm->dsp->pcm_slot_rx == 80962306a36Sopenharmony_ci member->dsp->pcm_slot_tx && 81062306a36Sopenharmony_ci member->dsp->pcm_slot_tx != 81162306a36Sopenharmony_ci member->dsp->pcm_slot_rx && 81262306a36Sopenharmony_ci member->dsp->pcm_bank_tx == 0 && 81362306a36Sopenharmony_ci member->dsp->pcm_bank_rx == 0 && 81462306a36Sopenharmony_ci nextm->dsp->pcm_bank_tx == 0 && 81562306a36Sopenharmony_ci nextm->dsp->pcm_bank_rx == 0) { 81662306a36Sopenharmony_ci /* all members have same slot */ 81762306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 81862306a36Sopenharmony_ci printk(KERN_DEBUG 81962306a36Sopenharmony_ci "%s dsp %s & %s stay joined on PCM " 82062306a36Sopenharmony_ci "slot %d (TX) %d (RX) on same chip " 82162306a36Sopenharmony_ci "or one bank PCM)\n", __func__, 82262306a36Sopenharmony_ci member->dsp->name, 82362306a36Sopenharmony_ci nextm->dsp->name, 82462306a36Sopenharmony_ci member->dsp->pcm_slot_tx, 82562306a36Sopenharmony_ci member->dsp->pcm_slot_rx); 82662306a36Sopenharmony_ci conf->hardware = 1; 82762306a36Sopenharmony_ci conf->software = tx_data; 82862306a36Sopenharmony_ci return; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci /* find two new slot */ 83162306a36Sopenharmony_ci memset(freeslots, 1, sizeof(freeslots)); 83262306a36Sopenharmony_ci list_for_each_entry(dsp, &dsp_ilist, list) { 83362306a36Sopenharmony_ci if (dsp != member->dsp && 83462306a36Sopenharmony_ci dsp != nextm->dsp && 83562306a36Sopenharmony_ci member->dsp->features.pcm_id == 83662306a36Sopenharmony_ci dsp->features.pcm_id) { 83762306a36Sopenharmony_ci if (dsp->pcm_slot_rx >= 0 && 83862306a36Sopenharmony_ci dsp->pcm_slot_rx < 83962306a36Sopenharmony_ci sizeof(freeslots)) 84062306a36Sopenharmony_ci freeslots[dsp->pcm_slot_rx] = 0; 84162306a36Sopenharmony_ci if (dsp->pcm_slot_tx >= 0 && 84262306a36Sopenharmony_ci dsp->pcm_slot_tx < 84362306a36Sopenharmony_ci sizeof(freeslots)) 84462306a36Sopenharmony_ci freeslots[dsp->pcm_slot_tx] = 0; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci i1 = 0; 84862306a36Sopenharmony_ci ii = member->dsp->features.pcm_slots; 84962306a36Sopenharmony_ci while (i1 < ii) { 85062306a36Sopenharmony_ci if (freeslots[i1]) 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci i1++; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci if (i1 == ii) { 85562306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 85662306a36Sopenharmony_ci printk(KERN_DEBUG 85762306a36Sopenharmony_ci "%s no slot available " 85862306a36Sopenharmony_ci "for %s & %s\n", __func__, 85962306a36Sopenharmony_ci member->dsp->name, 86062306a36Sopenharmony_ci nextm->dsp->name); 86162306a36Sopenharmony_ci /* no more slots available */ 86262306a36Sopenharmony_ci goto conf_software; 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci i2 = i1 + 1; 86562306a36Sopenharmony_ci while (i2 < ii) { 86662306a36Sopenharmony_ci if (freeslots[i2]) 86762306a36Sopenharmony_ci break; 86862306a36Sopenharmony_ci i2++; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci if (i2 == ii) { 87162306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 87262306a36Sopenharmony_ci printk(KERN_DEBUG 87362306a36Sopenharmony_ci "%s no slot available " 87462306a36Sopenharmony_ci "for %s & %s\n", 87562306a36Sopenharmony_ci __func__, 87662306a36Sopenharmony_ci member->dsp->name, 87762306a36Sopenharmony_ci nextm->dsp->name); 87862306a36Sopenharmony_ci /* no more slots available */ 87962306a36Sopenharmony_ci goto conf_software; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci /* assign free slots */ 88262306a36Sopenharmony_ci member->dsp->pcm_slot_tx = i1; 88362306a36Sopenharmony_ci member->dsp->pcm_slot_rx = i2; 88462306a36Sopenharmony_ci nextm->dsp->pcm_slot_tx = i2; 88562306a36Sopenharmony_ci nextm->dsp->pcm_slot_rx = i1; 88662306a36Sopenharmony_ci member->dsp->pcm_bank_rx = 0; 88762306a36Sopenharmony_ci member->dsp->pcm_bank_tx = 0; 88862306a36Sopenharmony_ci nextm->dsp->pcm_bank_rx = 0; 88962306a36Sopenharmony_ci nextm->dsp->pcm_bank_tx = 0; 89062306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 89162306a36Sopenharmony_ci printk(KERN_DEBUG 89262306a36Sopenharmony_ci "%s adding %s & %s to new PCM slot %d " 89362306a36Sopenharmony_ci "(TX) %d (RX) on same chip or one bank " 89462306a36Sopenharmony_ci "PCM, because both members have not " 89562306a36Sopenharmony_ci "crossed slots\n", __func__, 89662306a36Sopenharmony_ci member->dsp->name, 89762306a36Sopenharmony_ci nextm->dsp->name, 89862306a36Sopenharmony_ci member->dsp->pcm_slot_tx, 89962306a36Sopenharmony_ci member->dsp->pcm_slot_rx); 90062306a36Sopenharmony_ci dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, 90162306a36Sopenharmony_ci member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, 90262306a36Sopenharmony_ci member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); 90362306a36Sopenharmony_ci dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, 90462306a36Sopenharmony_ci nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, 90562306a36Sopenharmony_ci nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); 90662306a36Sopenharmony_ci conf->hardware = 1; 90762306a36Sopenharmony_ci conf->software = tx_data; 90862306a36Sopenharmony_ci return; 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci /* 91362306a36Sopenharmony_ci * if we have more than two, we may check if we have a conference 91462306a36Sopenharmony_ci * unit available on the chip. also all members must be on the same 91562306a36Sopenharmony_ci */ 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci /* if not the same HFC chip */ 91862306a36Sopenharmony_ci if (same_hfc < 0) { 91962306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 92062306a36Sopenharmony_ci printk(KERN_DEBUG 92162306a36Sopenharmony_ci "%s conference %d cannot be formed, because " 92262306a36Sopenharmony_ci "members are on different chips or not " 92362306a36Sopenharmony_ci "on HFC chip\n", 92462306a36Sopenharmony_ci __func__, conf->id); 92562306a36Sopenharmony_ci goto conf_software; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* for more than two members.. */ 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci /* if all members already have the same conference */ 93162306a36Sopenharmony_ci if (all_conf) { 93262306a36Sopenharmony_ci conf->hardware = 1; 93362306a36Sopenharmony_ci conf->software = tx_data; 93462306a36Sopenharmony_ci return; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* 93862306a36Sopenharmony_ci * if there is an existing conference, but not all members have joined 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_ci if (current_conf >= 0) { 94162306a36Sopenharmony_ci join_members: 94262306a36Sopenharmony_ci list_for_each_entry(member, &conf->mlist, list) { 94362306a36Sopenharmony_ci /* if no conference engine on our chip, change to 94462306a36Sopenharmony_ci * software */ 94562306a36Sopenharmony_ci if (!member->dsp->features.hfc_conf) 94662306a36Sopenharmony_ci goto conf_software; 94762306a36Sopenharmony_ci /* in case of hdlc, change to software */ 94862306a36Sopenharmony_ci if (member->dsp->hdlc) 94962306a36Sopenharmony_ci goto conf_software; 95062306a36Sopenharmony_ci /* join to current conference */ 95162306a36Sopenharmony_ci if (member->dsp->hfc_conf == current_conf) 95262306a36Sopenharmony_ci continue; 95362306a36Sopenharmony_ci /* get a free timeslot first */ 95462306a36Sopenharmony_ci memset(freeslots, 1, sizeof(freeslots)); 95562306a36Sopenharmony_ci list_for_each_entry(dsp, &dsp_ilist, list) { 95662306a36Sopenharmony_ci /* 95762306a36Sopenharmony_ci * not checking current member, because 95862306a36Sopenharmony_ci * slot will be overwritten. 95962306a36Sopenharmony_ci */ 96062306a36Sopenharmony_ci if ( 96162306a36Sopenharmony_ci dsp != member->dsp && 96262306a36Sopenharmony_ci /* dsp must be on the same PCM */ 96362306a36Sopenharmony_ci member->dsp->features.pcm_id == 96462306a36Sopenharmony_ci dsp->features.pcm_id) { 96562306a36Sopenharmony_ci /* dsp must be on a slot */ 96662306a36Sopenharmony_ci if (dsp->pcm_slot_tx >= 0 && 96762306a36Sopenharmony_ci dsp->pcm_slot_tx < 96862306a36Sopenharmony_ci sizeof(freeslots)) 96962306a36Sopenharmony_ci freeslots[dsp->pcm_slot_tx] = 0; 97062306a36Sopenharmony_ci if (dsp->pcm_slot_rx >= 0 && 97162306a36Sopenharmony_ci dsp->pcm_slot_rx < 97262306a36Sopenharmony_ci sizeof(freeslots)) 97362306a36Sopenharmony_ci freeslots[dsp->pcm_slot_rx] = 0; 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci i = 0; 97762306a36Sopenharmony_ci ii = member->dsp->features.pcm_slots; 97862306a36Sopenharmony_ci while (i < ii) { 97962306a36Sopenharmony_ci if (freeslots[i]) 98062306a36Sopenharmony_ci break; 98162306a36Sopenharmony_ci i++; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci if (i == ii) { 98462306a36Sopenharmony_ci /* no more slots available */ 98562306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 98662306a36Sopenharmony_ci printk(KERN_DEBUG 98762306a36Sopenharmony_ci "%s conference %d cannot be formed," 98862306a36Sopenharmony_ci " because no slot free\n", 98962306a36Sopenharmony_ci __func__, conf->id); 99062306a36Sopenharmony_ci goto conf_software; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 99362306a36Sopenharmony_ci printk(KERN_DEBUG 99462306a36Sopenharmony_ci "%s changing dsp %s to HW conference " 99562306a36Sopenharmony_ci "%d slot %d\n", __func__, 99662306a36Sopenharmony_ci member->dsp->name, current_conf, i); 99762306a36Sopenharmony_ci /* assign free slot & set PCM & join conf */ 99862306a36Sopenharmony_ci member->dsp->pcm_slot_tx = i; 99962306a36Sopenharmony_ci member->dsp->pcm_slot_rx = i; 100062306a36Sopenharmony_ci member->dsp->pcm_bank_tx = 2; /* loop */ 100162306a36Sopenharmony_ci member->dsp->pcm_bank_rx = 2; 100262306a36Sopenharmony_ci member->dsp->hfc_conf = current_conf; 100362306a36Sopenharmony_ci dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, 100462306a36Sopenharmony_ci i, 2, i, 2); 100562306a36Sopenharmony_ci dsp_cmx_hw_message(member->dsp, 100662306a36Sopenharmony_ci MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0); 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci conf->hardware = 1; 100962306a36Sopenharmony_ci conf->software = tx_data; 101062306a36Sopenharmony_ci return; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci /* 101462306a36Sopenharmony_ci * no member is in a conference yet, so we find a free one 101562306a36Sopenharmony_ci */ 101662306a36Sopenharmony_ci memset(freeunits, 1, sizeof(freeunits)); 101762306a36Sopenharmony_ci list_for_each_entry(dsp, &dsp_ilist, list) { 101862306a36Sopenharmony_ci /* dsp must be on the same chip */ 101962306a36Sopenharmony_ci if (dsp->features.hfc_id == same_hfc && 102062306a36Sopenharmony_ci /* dsp must have joined a HW conference */ 102162306a36Sopenharmony_ci dsp->hfc_conf >= 0 && 102262306a36Sopenharmony_ci /* slot must be within range */ 102362306a36Sopenharmony_ci dsp->hfc_conf < 8) 102462306a36Sopenharmony_ci freeunits[dsp->hfc_conf] = 0; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci i = 0; 102762306a36Sopenharmony_ci ii = 8; 102862306a36Sopenharmony_ci while (i < ii) { 102962306a36Sopenharmony_ci if (freeunits[i]) 103062306a36Sopenharmony_ci break; 103162306a36Sopenharmony_ci i++; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci if (i == ii) { 103462306a36Sopenharmony_ci /* no more conferences available */ 103562306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 103662306a36Sopenharmony_ci printk(KERN_DEBUG 103762306a36Sopenharmony_ci "%s conference %d cannot be formed, because " 103862306a36Sopenharmony_ci "no conference number free\n", 103962306a36Sopenharmony_ci __func__, conf->id); 104062306a36Sopenharmony_ci goto conf_software; 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci /* join all members */ 104362306a36Sopenharmony_ci current_conf = i; 104462306a36Sopenharmony_ci goto join_members; 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci/* 104962306a36Sopenharmony_ci * conf_id != 0: join or change conference 105062306a36Sopenharmony_ci * conf_id == 0: split from conference if not already 105162306a36Sopenharmony_ci */ 105262306a36Sopenharmony_ciint 105362306a36Sopenharmony_cidsp_cmx_conf(struct dsp *dsp, u32 conf_id) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci int err; 105662306a36Sopenharmony_ci struct dsp_conf *conf; 105762306a36Sopenharmony_ci struct dsp_conf_member *member; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci /* if conference doesn't change */ 106062306a36Sopenharmony_ci if (dsp->conf_id == conf_id) 106162306a36Sopenharmony_ci return 0; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* first remove us from current conf */ 106462306a36Sopenharmony_ci if (dsp->conf_id) { 106562306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 106662306a36Sopenharmony_ci printk(KERN_DEBUG "removing us from conference %d\n", 106762306a36Sopenharmony_ci dsp->conf->id); 106862306a36Sopenharmony_ci /* remove us from conf */ 106962306a36Sopenharmony_ci conf = dsp->conf; 107062306a36Sopenharmony_ci err = dsp_cmx_del_conf_member(dsp); 107162306a36Sopenharmony_ci if (err) 107262306a36Sopenharmony_ci return err; 107362306a36Sopenharmony_ci dsp->conf_id = 0; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* update hardware */ 107662306a36Sopenharmony_ci dsp_cmx_hardware(NULL, dsp); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* conf now empty? */ 107962306a36Sopenharmony_ci if (list_empty(&conf->mlist)) { 108062306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 108162306a36Sopenharmony_ci printk(KERN_DEBUG 108262306a36Sopenharmony_ci "conference is empty, so we remove it.\n"); 108362306a36Sopenharmony_ci err = dsp_cmx_del_conf(conf); 108462306a36Sopenharmony_ci if (err) 108562306a36Sopenharmony_ci return err; 108662306a36Sopenharmony_ci } else { 108762306a36Sopenharmony_ci /* update members left on conf */ 108862306a36Sopenharmony_ci dsp_cmx_hardware(conf, NULL); 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci /* if split */ 109362306a36Sopenharmony_ci if (!conf_id) 109462306a36Sopenharmony_ci return 0; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* now add us to conf */ 109762306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 109862306a36Sopenharmony_ci printk(KERN_DEBUG "searching conference %d\n", 109962306a36Sopenharmony_ci conf_id); 110062306a36Sopenharmony_ci conf = dsp_cmx_search_conf(conf_id); 110162306a36Sopenharmony_ci if (!conf) { 110262306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 110362306a36Sopenharmony_ci printk(KERN_DEBUG 110462306a36Sopenharmony_ci "conference doesn't exist yet, creating.\n"); 110562306a36Sopenharmony_ci /* the conference doesn't exist, so we create */ 110662306a36Sopenharmony_ci conf = dsp_cmx_new_conf(conf_id); 110762306a36Sopenharmony_ci if (!conf) 110862306a36Sopenharmony_ci return -EINVAL; 110962306a36Sopenharmony_ci } else if (!list_empty(&conf->mlist)) { 111062306a36Sopenharmony_ci member = list_entry(conf->mlist.next, struct dsp_conf_member, 111162306a36Sopenharmony_ci list); 111262306a36Sopenharmony_ci if (dsp->hdlc && !member->dsp->hdlc) { 111362306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 111462306a36Sopenharmony_ci printk(KERN_DEBUG 111562306a36Sopenharmony_ci "cannot join transparent conference.\n"); 111662306a36Sopenharmony_ci return -EINVAL; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci if (!dsp->hdlc && member->dsp->hdlc) { 111962306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 112062306a36Sopenharmony_ci printk(KERN_DEBUG 112162306a36Sopenharmony_ci "cannot join hdlc conference.\n"); 112262306a36Sopenharmony_ci return -EINVAL; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci /* add conference member */ 112662306a36Sopenharmony_ci err = dsp_cmx_add_conf_member(dsp, conf); 112762306a36Sopenharmony_ci if (err) 112862306a36Sopenharmony_ci return err; 112962306a36Sopenharmony_ci dsp->conf_id = conf_id; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci /* if we are alone, we do nothing! */ 113262306a36Sopenharmony_ci if (list_empty(&conf->mlist)) { 113362306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CMX) 113462306a36Sopenharmony_ci printk(KERN_DEBUG 113562306a36Sopenharmony_ci "we are alone in this conference, so exit.\n"); 113662306a36Sopenharmony_ci /* update hardware */ 113762306a36Sopenharmony_ci dsp_cmx_hardware(NULL, dsp); 113862306a36Sopenharmony_ci return 0; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* update members on conf */ 114262306a36Sopenharmony_ci dsp_cmx_hardware(conf, NULL); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci return 0; 114562306a36Sopenharmony_ci} 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci#ifdef CMX_DELAY_DEBUG 114862306a36Sopenharmony_ciint delaycount; 114962306a36Sopenharmony_cistatic void 115062306a36Sopenharmony_cishowdelay(struct dsp *dsp, int samples, int delay) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci char bar[] = "--------------------------------------------------|"; 115362306a36Sopenharmony_ci int sdelay; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci delaycount += samples; 115662306a36Sopenharmony_ci if (delaycount < 8000) 115762306a36Sopenharmony_ci return; 115862306a36Sopenharmony_ci delaycount = 0; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci sdelay = delay * 50 / (dsp_poll << 2); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci printk(KERN_DEBUG "DELAY (%s) %3d >%s\n", dsp->name, delay, 116362306a36Sopenharmony_ci sdelay > 50 ? "..." : bar + 50 - sdelay); 116462306a36Sopenharmony_ci} 116562306a36Sopenharmony_ci#endif 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci/* 116862306a36Sopenharmony_ci * audio data is received from card 116962306a36Sopenharmony_ci */ 117062306a36Sopenharmony_civoid 117162306a36Sopenharmony_cidsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci u8 *d, *p; 117462306a36Sopenharmony_ci int len = skb->len; 117562306a36Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 117662306a36Sopenharmony_ci int w, i, ii; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci /* check if we have sompen */ 117962306a36Sopenharmony_ci if (len < 1) 118062306a36Sopenharmony_ci return; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* half of the buffer should be larger than maximum packet size */ 118362306a36Sopenharmony_ci if (len >= CMX_BUFF_HALF) { 118462306a36Sopenharmony_ci printk(KERN_ERR 118562306a36Sopenharmony_ci "%s line %d: packet from card is too large (%d bytes). " 118662306a36Sopenharmony_ci "please make card send smaller packets OR increase " 118762306a36Sopenharmony_ci "CMX_BUFF_SIZE\n", __FILE__, __LINE__, len); 118862306a36Sopenharmony_ci return; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci /* 119262306a36Sopenharmony_ci * initialize pointers if not already - 119362306a36Sopenharmony_ci * also add delay if requested by PH_SIGNAL 119462306a36Sopenharmony_ci */ 119562306a36Sopenharmony_ci if (dsp->rx_init) { 119662306a36Sopenharmony_ci dsp->rx_init = 0; 119762306a36Sopenharmony_ci if (dsp->features.unordered) { 119862306a36Sopenharmony_ci dsp->rx_R = (hh->id & CMX_BUFF_MASK); 119962306a36Sopenharmony_ci if (dsp->cmx_delay) 120062306a36Sopenharmony_ci dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) 120162306a36Sopenharmony_ci & CMX_BUFF_MASK; 120262306a36Sopenharmony_ci else 120362306a36Sopenharmony_ci dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1)) 120462306a36Sopenharmony_ci & CMX_BUFF_MASK; 120562306a36Sopenharmony_ci } else { 120662306a36Sopenharmony_ci dsp->rx_R = 0; 120762306a36Sopenharmony_ci if (dsp->cmx_delay) 120862306a36Sopenharmony_ci dsp->rx_W = dsp->cmx_delay; 120962306a36Sopenharmony_ci else 121062306a36Sopenharmony_ci dsp->rx_W = dsp_poll >> 1; 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci /* if frame contains time code, write directly */ 121462306a36Sopenharmony_ci if (dsp->features.unordered) { 121562306a36Sopenharmony_ci dsp->rx_W = (hh->id & CMX_BUFF_MASK); 121662306a36Sopenharmony_ci /* printk(KERN_DEBUG "%s %08x\n", dsp->name, hh->id); */ 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci /* 121962306a36Sopenharmony_ci * if we underrun (or maybe overrun), 122062306a36Sopenharmony_ci * we set our new read pointer, and write silence to buffer 122162306a36Sopenharmony_ci */ 122262306a36Sopenharmony_ci if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) { 122362306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CLOCK) 122462306a36Sopenharmony_ci printk(KERN_DEBUG 122562306a36Sopenharmony_ci "cmx_receive(dsp=%lx): UNDERRUN (or overrun the " 122662306a36Sopenharmony_ci "maximum delay), adjusting read pointer! " 122762306a36Sopenharmony_ci "(inst %s)\n", (u_long)dsp, dsp->name); 122862306a36Sopenharmony_ci /* flush rx buffer and set delay to dsp_poll / 2 */ 122962306a36Sopenharmony_ci if (dsp->features.unordered) { 123062306a36Sopenharmony_ci dsp->rx_R = (hh->id & CMX_BUFF_MASK); 123162306a36Sopenharmony_ci if (dsp->cmx_delay) 123262306a36Sopenharmony_ci dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) 123362306a36Sopenharmony_ci & CMX_BUFF_MASK; 123462306a36Sopenharmony_ci else 123562306a36Sopenharmony_ci dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1)) 123662306a36Sopenharmony_ci & CMX_BUFF_MASK; 123762306a36Sopenharmony_ci } else { 123862306a36Sopenharmony_ci dsp->rx_R = 0; 123962306a36Sopenharmony_ci if (dsp->cmx_delay) 124062306a36Sopenharmony_ci dsp->rx_W = dsp->cmx_delay; 124162306a36Sopenharmony_ci else 124262306a36Sopenharmony_ci dsp->rx_W = dsp_poll >> 1; 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci /* if we have reached double delay, jump back to middle */ 124762306a36Sopenharmony_ci if (dsp->cmx_delay) 124862306a36Sopenharmony_ci if (((dsp->rx_W - dsp->rx_R) & CMX_BUFF_MASK) >= 124962306a36Sopenharmony_ci (dsp->cmx_delay << 1)) { 125062306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CLOCK) 125162306a36Sopenharmony_ci printk(KERN_DEBUG 125262306a36Sopenharmony_ci "cmx_receive(dsp=%lx): OVERRUN (because " 125362306a36Sopenharmony_ci "twice the delay is reached), adjusting " 125462306a36Sopenharmony_ci "read pointer! (inst %s)\n", 125562306a36Sopenharmony_ci (u_long)dsp, dsp->name); 125662306a36Sopenharmony_ci /* flush buffer */ 125762306a36Sopenharmony_ci if (dsp->features.unordered) { 125862306a36Sopenharmony_ci dsp->rx_R = (hh->id & CMX_BUFF_MASK); 125962306a36Sopenharmony_ci dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) 126062306a36Sopenharmony_ci & CMX_BUFF_MASK; 126162306a36Sopenharmony_ci } else { 126262306a36Sopenharmony_ci dsp->rx_R = 0; 126362306a36Sopenharmony_ci dsp->rx_W = dsp->cmx_delay; 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci /* show where to write */ 126962306a36Sopenharmony_ci#ifdef CMX_DEBUG 127062306a36Sopenharmony_ci printk(KERN_DEBUG 127162306a36Sopenharmony_ci "cmx_receive(dsp=%lx): rx_R(dsp)=%05x rx_W(dsp)=%05x len=%d %s\n", 127262306a36Sopenharmony_ci (u_long)dsp, dsp->rx_R, dsp->rx_W, len, dsp->name); 127362306a36Sopenharmony_ci#endif 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci /* write data into rx_buffer */ 127662306a36Sopenharmony_ci p = skb->data; 127762306a36Sopenharmony_ci d = dsp->rx_buff; 127862306a36Sopenharmony_ci w = dsp->rx_W; 127962306a36Sopenharmony_ci i = 0; 128062306a36Sopenharmony_ci ii = len; 128162306a36Sopenharmony_ci while (i < ii) { 128262306a36Sopenharmony_ci d[w++ & CMX_BUFF_MASK] = *p++; 128362306a36Sopenharmony_ci i++; 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci /* increase write-pointer */ 128762306a36Sopenharmony_ci dsp->rx_W = ((dsp->rx_W + len) & CMX_BUFF_MASK); 128862306a36Sopenharmony_ci#ifdef CMX_DELAY_DEBUG 128962306a36Sopenharmony_ci showdelay(dsp, len, (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK); 129062306a36Sopenharmony_ci#endif 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci/* 129562306a36Sopenharmony_ci * send (mixed) audio data to card and control jitter 129662306a36Sopenharmony_ci */ 129762306a36Sopenharmony_cistatic void 129862306a36Sopenharmony_cidsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci struct dsp_conf *conf = dsp->conf; 130162306a36Sopenharmony_ci struct dsp *member, *other; 130262306a36Sopenharmony_ci register s32 sample; 130362306a36Sopenharmony_ci u8 *d, *p, *q, *o_q; 130462306a36Sopenharmony_ci struct sk_buff *nskb, *txskb; 130562306a36Sopenharmony_ci int r, rr, t, tt, o_r, o_rr; 130662306a36Sopenharmony_ci int preload = 0; 130762306a36Sopenharmony_ci struct mISDNhead *hh, *thh; 130862306a36Sopenharmony_ci int tx_data_only = 0; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci /* don't process if: */ 131162306a36Sopenharmony_ci if (!dsp->b_active) { /* if not active */ 131262306a36Sopenharmony_ci dsp->last_tx = 0; 131362306a36Sopenharmony_ci return; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci if (((dsp->conf && dsp->conf->hardware) || /* hardware conf */ 131662306a36Sopenharmony_ci dsp->echo.hardware) && /* OR hardware echo */ 131762306a36Sopenharmony_ci dsp->tx_R == dsp->tx_W && /* AND no tx-data */ 131862306a36Sopenharmony_ci !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ 131962306a36Sopenharmony_ci if (!dsp->tx_data) { /* no tx_data for user space required */ 132062306a36Sopenharmony_ci dsp->last_tx = 0; 132162306a36Sopenharmony_ci return; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci if (dsp->conf && dsp->conf->software && dsp->conf->hardware) 132462306a36Sopenharmony_ci tx_data_only = 1; 132562306a36Sopenharmony_ci if (dsp->echo.software && dsp->echo.hardware) 132662306a36Sopenharmony_ci tx_data_only = 1; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci#ifdef CMX_DEBUG 133062306a36Sopenharmony_ci printk(KERN_DEBUG 133162306a36Sopenharmony_ci "SEND members=%d dsp=%s, conf=%p, rx_R=%05x rx_W=%05x\n", 133262306a36Sopenharmony_ci members, dsp->name, conf, dsp->rx_R, dsp->rx_W); 133362306a36Sopenharmony_ci#endif 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci /* preload if we have delay set */ 133662306a36Sopenharmony_ci if (dsp->cmx_delay && !dsp->last_tx) { 133762306a36Sopenharmony_ci preload = len; 133862306a36Sopenharmony_ci if (preload < 128) 133962306a36Sopenharmony_ci preload = 128; 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci /* PREPARE RESULT */ 134362306a36Sopenharmony_ci nskb = mI_alloc_skb(len + preload, GFP_ATOMIC); 134462306a36Sopenharmony_ci if (!nskb) { 134562306a36Sopenharmony_ci printk(KERN_ERR 134662306a36Sopenharmony_ci "FATAL ERROR in mISDN_dsp.o: cannot alloc %d bytes\n", 134762306a36Sopenharmony_ci len + preload); 134862306a36Sopenharmony_ci return; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci hh = mISDN_HEAD_P(nskb); 135162306a36Sopenharmony_ci hh->prim = PH_DATA_REQ; 135262306a36Sopenharmony_ci hh->id = 0; 135362306a36Sopenharmony_ci dsp->last_tx = 1; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci /* set pointers, indexes and stuff */ 135662306a36Sopenharmony_ci member = dsp; 135762306a36Sopenharmony_ci p = dsp->tx_buff; /* transmit data */ 135862306a36Sopenharmony_ci q = dsp->rx_buff; /* received data */ 135962306a36Sopenharmony_ci d = skb_put(nskb, preload + len); /* result */ 136062306a36Sopenharmony_ci t = dsp->tx_R; /* tx-pointers */ 136162306a36Sopenharmony_ci tt = dsp->tx_W; 136262306a36Sopenharmony_ci r = dsp->rx_R; /* rx-pointers */ 136362306a36Sopenharmony_ci rr = (r + len) & CMX_BUFF_MASK; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci /* preload with silence, if required */ 136662306a36Sopenharmony_ci if (preload) { 136762306a36Sopenharmony_ci memset(d, dsp_silence, preload); 136862306a36Sopenharmony_ci d += preload; 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci /* PROCESS TONES/TX-DATA ONLY */ 137262306a36Sopenharmony_ci if (dsp->tone.tone && dsp->tone.software) { 137362306a36Sopenharmony_ci /* -> copy tone */ 137462306a36Sopenharmony_ci dsp_tone_copy(dsp, d, len); 137562306a36Sopenharmony_ci dsp->tx_R = 0; /* clear tx buffer */ 137662306a36Sopenharmony_ci dsp->tx_W = 0; 137762306a36Sopenharmony_ci goto send_packet; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci /* if we have tx-data but do not use mixing */ 138062306a36Sopenharmony_ci if (!dsp->tx_mix && t != tt) { 138162306a36Sopenharmony_ci /* -> send tx-data and continue when not enough */ 138262306a36Sopenharmony_ci#ifdef CMX_TX_DEBUG 138362306a36Sopenharmony_ci sprintf(debugbuf, "TX sending (%04x-%04x)%p: ", t, tt, p); 138462306a36Sopenharmony_ci#endif 138562306a36Sopenharmony_ci while (r != rr && t != tt) { 138662306a36Sopenharmony_ci#ifdef CMX_TX_DEBUG 138762306a36Sopenharmony_ci if (strlen(debugbuf) < 48) 138862306a36Sopenharmony_ci sprintf(debugbuf + strlen(debugbuf), " %02x", 138962306a36Sopenharmony_ci p[t]); 139062306a36Sopenharmony_ci#endif 139162306a36Sopenharmony_ci *d++ = p[t]; /* write tx_buff */ 139262306a36Sopenharmony_ci t = (t + 1) & CMX_BUFF_MASK; 139362306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci if (r == rr) { 139662306a36Sopenharmony_ci dsp->tx_R = t; 139762306a36Sopenharmony_ci#ifdef CMX_TX_DEBUG 139862306a36Sopenharmony_ci printk(KERN_DEBUG "%s\n", debugbuf); 139962306a36Sopenharmony_ci#endif 140062306a36Sopenharmony_ci goto send_packet; 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci#ifdef CMX_TX_DEBUG 140462306a36Sopenharmony_ci printk(KERN_DEBUG "%s\n", debugbuf); 140562306a36Sopenharmony_ci#endif 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci /* PROCESS DATA (one member / no conf) */ 140862306a36Sopenharmony_ci if (!conf || members <= 1) { 140962306a36Sopenharmony_ci /* -> if echo is NOT enabled */ 141062306a36Sopenharmony_ci if (!dsp->echo.software) { 141162306a36Sopenharmony_ci /* -> send tx-data if available or use 0-volume */ 141262306a36Sopenharmony_ci while (r != rr && t != tt) { 141362306a36Sopenharmony_ci *d++ = p[t]; /* write tx_buff */ 141462306a36Sopenharmony_ci t = (t + 1) & CMX_BUFF_MASK; 141562306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci if (r != rr) { 141862306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CLOCK) 141962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: RX empty\n", 142062306a36Sopenharmony_ci __func__); 142162306a36Sopenharmony_ci memset(d, dsp_silence, (rr - r) & CMX_BUFF_MASK); 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci /* -> if echo is enabled */ 142462306a36Sopenharmony_ci } else { 142562306a36Sopenharmony_ci /* 142662306a36Sopenharmony_ci * -> mix tx-data with echo if available, 142762306a36Sopenharmony_ci * or use echo only 142862306a36Sopenharmony_ci */ 142962306a36Sopenharmony_ci while (r != rr && t != tt) { 143062306a36Sopenharmony_ci *d++ = dsp_audio_mix_law[(p[t] << 8) | q[r]]; 143162306a36Sopenharmony_ci t = (t + 1) & CMX_BUFF_MASK; 143262306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci while (r != rr) { 143562306a36Sopenharmony_ci *d++ = q[r]; /* echo */ 143662306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci dsp->tx_R = t; 144062306a36Sopenharmony_ci goto send_packet; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci /* PROCESS DATA (two members) */ 144362306a36Sopenharmony_ci#ifdef CMX_CONF_DEBUG 144462306a36Sopenharmony_ci if (0) { 144562306a36Sopenharmony_ci#else 144662306a36Sopenharmony_ci if (members == 2) { 144762306a36Sopenharmony_ci#endif 144862306a36Sopenharmony_ci /* "other" becomes other party */ 144962306a36Sopenharmony_ci other = (list_entry(conf->mlist.next, 145062306a36Sopenharmony_ci struct dsp_conf_member, list))->dsp; 145162306a36Sopenharmony_ci if (other == member) 145262306a36Sopenharmony_ci other = (list_entry(conf->mlist.prev, 145362306a36Sopenharmony_ci struct dsp_conf_member, list))->dsp; 145462306a36Sopenharmony_ci o_q = other->rx_buff; /* received data */ 145562306a36Sopenharmony_ci o_rr = (other->rx_R + len) & CMX_BUFF_MASK; 145662306a36Sopenharmony_ci /* end of rx-pointer */ 145762306a36Sopenharmony_ci o_r = (o_rr - rr + r) & CMX_BUFF_MASK; 145862306a36Sopenharmony_ci /* start rx-pointer at current read position*/ 145962306a36Sopenharmony_ci /* -> if echo is NOT enabled */ 146062306a36Sopenharmony_ci if (!dsp->echo.software) { 146162306a36Sopenharmony_ci /* 146262306a36Sopenharmony_ci * -> copy other member's rx-data, 146362306a36Sopenharmony_ci * if tx-data is available, mix 146462306a36Sopenharmony_ci */ 146562306a36Sopenharmony_ci while (o_r != o_rr && t != tt) { 146662306a36Sopenharmony_ci *d++ = dsp_audio_mix_law[(p[t] << 8) | o_q[o_r]]; 146762306a36Sopenharmony_ci t = (t + 1) & CMX_BUFF_MASK; 146862306a36Sopenharmony_ci o_r = (o_r + 1) & CMX_BUFF_MASK; 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci while (o_r != o_rr) { 147162306a36Sopenharmony_ci *d++ = o_q[o_r]; 147262306a36Sopenharmony_ci o_r = (o_r + 1) & CMX_BUFF_MASK; 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci /* -> if echo is enabled */ 147562306a36Sopenharmony_ci } else { 147662306a36Sopenharmony_ci /* 147762306a36Sopenharmony_ci * -> mix other member's rx-data with echo, 147862306a36Sopenharmony_ci * if tx-data is available, mix 147962306a36Sopenharmony_ci */ 148062306a36Sopenharmony_ci while (r != rr && t != tt) { 148162306a36Sopenharmony_ci sample = dsp_audio_law_to_s32[p[t]] + 148262306a36Sopenharmony_ci dsp_audio_law_to_s32[q[r]] + 148362306a36Sopenharmony_ci dsp_audio_law_to_s32[o_q[o_r]]; 148462306a36Sopenharmony_ci if (sample < -32768) 148562306a36Sopenharmony_ci sample = -32768; 148662306a36Sopenharmony_ci else if (sample > 32767) 148762306a36Sopenharmony_ci sample = 32767; 148862306a36Sopenharmony_ci *d++ = dsp_audio_s16_to_law[sample & 0xffff]; 148962306a36Sopenharmony_ci /* tx-data + rx_data + echo */ 149062306a36Sopenharmony_ci t = (t + 1) & CMX_BUFF_MASK; 149162306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 149262306a36Sopenharmony_ci o_r = (o_r + 1) & CMX_BUFF_MASK; 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci while (r != rr) { 149562306a36Sopenharmony_ci *d++ = dsp_audio_mix_law[(q[r] << 8) | o_q[o_r]]; 149662306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 149762306a36Sopenharmony_ci o_r = (o_r + 1) & CMX_BUFF_MASK; 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci dsp->tx_R = t; 150162306a36Sopenharmony_ci goto send_packet; 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci /* PROCESS DATA (three or more members) */ 150462306a36Sopenharmony_ci /* -> if echo is NOT enabled */ 150562306a36Sopenharmony_ci if (!dsp->echo.software) { 150662306a36Sopenharmony_ci /* 150762306a36Sopenharmony_ci * -> subtract rx-data from conf-data, 150862306a36Sopenharmony_ci * if tx-data is available, mix 150962306a36Sopenharmony_ci */ 151062306a36Sopenharmony_ci while (r != rr && t != tt) { 151162306a36Sopenharmony_ci sample = dsp_audio_law_to_s32[p[t]] + *c++ - 151262306a36Sopenharmony_ci dsp_audio_law_to_s32[q[r]]; 151362306a36Sopenharmony_ci if (sample < -32768) 151462306a36Sopenharmony_ci sample = -32768; 151562306a36Sopenharmony_ci else if (sample > 32767) 151662306a36Sopenharmony_ci sample = 32767; 151762306a36Sopenharmony_ci *d++ = dsp_audio_s16_to_law[sample & 0xffff]; 151862306a36Sopenharmony_ci /* conf-rx+tx */ 151962306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 152062306a36Sopenharmony_ci t = (t + 1) & CMX_BUFF_MASK; 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci while (r != rr) { 152362306a36Sopenharmony_ci sample = *c++ - dsp_audio_law_to_s32[q[r]]; 152462306a36Sopenharmony_ci if (sample < -32768) 152562306a36Sopenharmony_ci sample = -32768; 152662306a36Sopenharmony_ci else if (sample > 32767) 152762306a36Sopenharmony_ci sample = 32767; 152862306a36Sopenharmony_ci *d++ = dsp_audio_s16_to_law[sample & 0xffff]; 152962306a36Sopenharmony_ci /* conf-rx */ 153062306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci /* -> if echo is enabled */ 153362306a36Sopenharmony_ci } else { 153462306a36Sopenharmony_ci /* 153562306a36Sopenharmony_ci * -> encode conf-data, if tx-data 153662306a36Sopenharmony_ci * is available, mix 153762306a36Sopenharmony_ci */ 153862306a36Sopenharmony_ci while (r != rr && t != tt) { 153962306a36Sopenharmony_ci sample = dsp_audio_law_to_s32[p[t]] + *c++; 154062306a36Sopenharmony_ci if (sample < -32768) 154162306a36Sopenharmony_ci sample = -32768; 154262306a36Sopenharmony_ci else if (sample > 32767) 154362306a36Sopenharmony_ci sample = 32767; 154462306a36Sopenharmony_ci *d++ = dsp_audio_s16_to_law[sample & 0xffff]; 154562306a36Sopenharmony_ci /* conf(echo)+tx */ 154662306a36Sopenharmony_ci t = (t + 1) & CMX_BUFF_MASK; 154762306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci while (r != rr) { 155062306a36Sopenharmony_ci sample = *c++; 155162306a36Sopenharmony_ci if (sample < -32768) 155262306a36Sopenharmony_ci sample = -32768; 155362306a36Sopenharmony_ci else if (sample > 32767) 155462306a36Sopenharmony_ci sample = 32767; 155562306a36Sopenharmony_ci *d++ = dsp_audio_s16_to_law[sample & 0xffff]; 155662306a36Sopenharmony_ci /* conf(echo) */ 155762306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci dsp->tx_R = t; 156162306a36Sopenharmony_ci goto send_packet; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cisend_packet: 156462306a36Sopenharmony_ci /* 156562306a36Sopenharmony_ci * send tx-data if enabled - don't filter, 156662306a36Sopenharmony_ci * because we want what we send, not what we filtered 156762306a36Sopenharmony_ci */ 156862306a36Sopenharmony_ci if (dsp->tx_data) { 156962306a36Sopenharmony_ci if (tx_data_only) { 157062306a36Sopenharmony_ci hh->prim = DL_DATA_REQ; 157162306a36Sopenharmony_ci hh->id = 0; 157262306a36Sopenharmony_ci /* queue and trigger */ 157362306a36Sopenharmony_ci skb_queue_tail(&dsp->sendq, nskb); 157462306a36Sopenharmony_ci schedule_work(&dsp->workq); 157562306a36Sopenharmony_ci /* exit because only tx_data is used */ 157662306a36Sopenharmony_ci return; 157762306a36Sopenharmony_ci } else { 157862306a36Sopenharmony_ci txskb = mI_alloc_skb(len, GFP_ATOMIC); 157962306a36Sopenharmony_ci if (!txskb) { 158062306a36Sopenharmony_ci printk(KERN_ERR 158162306a36Sopenharmony_ci "FATAL ERROR in mISDN_dsp.o: " 158262306a36Sopenharmony_ci "cannot alloc %d bytes\n", len); 158362306a36Sopenharmony_ci } else { 158462306a36Sopenharmony_ci thh = mISDN_HEAD_P(txskb); 158562306a36Sopenharmony_ci thh->prim = DL_DATA_REQ; 158662306a36Sopenharmony_ci thh->id = 0; 158762306a36Sopenharmony_ci skb_put_data(txskb, nskb->data + preload, len); 158862306a36Sopenharmony_ci /* queue (trigger later) */ 158962306a36Sopenharmony_ci skb_queue_tail(&dsp->sendq, txskb); 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci /* send data only to card, if we don't just calculated tx_data */ 159562306a36Sopenharmony_ci /* adjust volume */ 159662306a36Sopenharmony_ci if (dsp->tx_volume) 159762306a36Sopenharmony_ci dsp_change_volume(nskb, dsp->tx_volume); 159862306a36Sopenharmony_ci /* pipeline */ 159962306a36Sopenharmony_ci if (dsp->pipeline.inuse) 160062306a36Sopenharmony_ci dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, 160162306a36Sopenharmony_ci nskb->len); 160262306a36Sopenharmony_ci /* crypt */ 160362306a36Sopenharmony_ci if (dsp->bf_enable) 160462306a36Sopenharmony_ci dsp_bf_encrypt(dsp, nskb->data, nskb->len); 160562306a36Sopenharmony_ci /* queue and trigger */ 160662306a36Sopenharmony_ci skb_queue_tail(&dsp->sendq, nskb); 160762306a36Sopenharmony_ci schedule_work(&dsp->workq); 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_cistatic u32 jittercount; /* counter for jitter check */ 161162306a36Sopenharmony_cistruct timer_list dsp_spl_tl; 161262306a36Sopenharmony_ciunsigned long dsp_spl_jiffies; /* calculate the next time to fire */ 161362306a36Sopenharmony_cistatic u16 dsp_count; /* last sample count */ 161462306a36Sopenharmony_cistatic int dsp_count_valid; /* if we have last sample count */ 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_civoid 161762306a36Sopenharmony_cidsp_cmx_send(struct timer_list *arg) 161862306a36Sopenharmony_ci{ 161962306a36Sopenharmony_ci struct dsp_conf *conf; 162062306a36Sopenharmony_ci struct dsp_conf_member *member; 162162306a36Sopenharmony_ci struct dsp *dsp; 162262306a36Sopenharmony_ci int mustmix, members; 162362306a36Sopenharmony_ci static s32 mixbuffer[MAX_POLL + 100]; 162462306a36Sopenharmony_ci s32 *c; 162562306a36Sopenharmony_ci u8 *p, *q; 162662306a36Sopenharmony_ci int r, rr; 162762306a36Sopenharmony_ci int jittercheck = 0, delay, i; 162862306a36Sopenharmony_ci u_long flags; 162962306a36Sopenharmony_ci u16 length, count; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci /* lock */ 163262306a36Sopenharmony_ci spin_lock_irqsave(&dsp_lock, flags); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci if (!dsp_count_valid) { 163562306a36Sopenharmony_ci dsp_count = mISDN_clock_get(); 163662306a36Sopenharmony_ci length = dsp_poll; 163762306a36Sopenharmony_ci dsp_count_valid = 1; 163862306a36Sopenharmony_ci } else { 163962306a36Sopenharmony_ci count = mISDN_clock_get(); 164062306a36Sopenharmony_ci length = count - dsp_count; 164162306a36Sopenharmony_ci dsp_count = count; 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci if (length > MAX_POLL + 100) 164462306a36Sopenharmony_ci length = MAX_POLL + 100; 164562306a36Sopenharmony_ci /* printk(KERN_DEBUG "len=%d dsp_count=0x%x\n", length, dsp_count); */ 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci /* 164862306a36Sopenharmony_ci * check if jitter needs to be checked (this is every second) 164962306a36Sopenharmony_ci */ 165062306a36Sopenharmony_ci jittercount += length; 165162306a36Sopenharmony_ci if (jittercount >= 8000) { 165262306a36Sopenharmony_ci jittercount -= 8000; 165362306a36Sopenharmony_ci jittercheck = 1; 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci /* loop all members that do not require conference mixing */ 165762306a36Sopenharmony_ci list_for_each_entry(dsp, &dsp_ilist, list) { 165862306a36Sopenharmony_ci if (dsp->hdlc) 165962306a36Sopenharmony_ci continue; 166062306a36Sopenharmony_ci conf = dsp->conf; 166162306a36Sopenharmony_ci mustmix = 0; 166262306a36Sopenharmony_ci members = 0; 166362306a36Sopenharmony_ci if (conf) { 166462306a36Sopenharmony_ci members = list_count_nodes(&conf->mlist); 166562306a36Sopenharmony_ci#ifdef CMX_CONF_DEBUG 166662306a36Sopenharmony_ci if (conf->software && members > 1) 166762306a36Sopenharmony_ci#else 166862306a36Sopenharmony_ci if (conf->software && members > 2) 166962306a36Sopenharmony_ci#endif 167062306a36Sopenharmony_ci mustmix = 1; 167162306a36Sopenharmony_ci } 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci /* transmission required */ 167462306a36Sopenharmony_ci if (!mustmix) { 167562306a36Sopenharmony_ci dsp_cmx_send_member(dsp, length, mixbuffer, members); 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci /* 167862306a36Sopenharmony_ci * unused mixbuffer is given to prevent a 167962306a36Sopenharmony_ci * potential null-pointer-bug 168062306a36Sopenharmony_ci */ 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci /* loop all members that require conference mixing */ 168562306a36Sopenharmony_ci list_for_each_entry(conf, &conf_ilist, list) { 168662306a36Sopenharmony_ci /* count members and check hardware */ 168762306a36Sopenharmony_ci members = list_count_nodes(&conf->mlist); 168862306a36Sopenharmony_ci#ifdef CMX_CONF_DEBUG 168962306a36Sopenharmony_ci if (conf->software && members > 1) { 169062306a36Sopenharmony_ci#else 169162306a36Sopenharmony_ci if (conf->software && members > 2) { 169262306a36Sopenharmony_ci#endif 169362306a36Sopenharmony_ci /* check for hdlc conf */ 169462306a36Sopenharmony_ci member = list_entry(conf->mlist.next, 169562306a36Sopenharmony_ci struct dsp_conf_member, list); 169662306a36Sopenharmony_ci if (member->dsp->hdlc) 169762306a36Sopenharmony_ci continue; 169862306a36Sopenharmony_ci /* mix all data */ 169962306a36Sopenharmony_ci memset(mixbuffer, 0, length * sizeof(s32)); 170062306a36Sopenharmony_ci list_for_each_entry(member, &conf->mlist, list) { 170162306a36Sopenharmony_ci dsp = member->dsp; 170262306a36Sopenharmony_ci /* get range of data to mix */ 170362306a36Sopenharmony_ci c = mixbuffer; 170462306a36Sopenharmony_ci q = dsp->rx_buff; 170562306a36Sopenharmony_ci r = dsp->rx_R; 170662306a36Sopenharmony_ci rr = (r + length) & CMX_BUFF_MASK; 170762306a36Sopenharmony_ci /* add member's data */ 170862306a36Sopenharmony_ci while (r != rr) { 170962306a36Sopenharmony_ci *c++ += dsp_audio_law_to_s32[q[r]]; 171062306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci } 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci /* process each member */ 171562306a36Sopenharmony_ci list_for_each_entry(member, &conf->mlist, list) { 171662306a36Sopenharmony_ci /* transmission */ 171762306a36Sopenharmony_ci dsp_cmx_send_member(member->dsp, length, 171862306a36Sopenharmony_ci mixbuffer, members); 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci } 172162306a36Sopenharmony_ci } 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci /* delete rx-data, increment buffers, change pointers */ 172462306a36Sopenharmony_ci list_for_each_entry(dsp, &dsp_ilist, list) { 172562306a36Sopenharmony_ci if (dsp->hdlc) 172662306a36Sopenharmony_ci continue; 172762306a36Sopenharmony_ci p = dsp->rx_buff; 172862306a36Sopenharmony_ci q = dsp->tx_buff; 172962306a36Sopenharmony_ci r = dsp->rx_R; 173062306a36Sopenharmony_ci /* move receive pointer when receiving */ 173162306a36Sopenharmony_ci if (!dsp->rx_is_off) { 173262306a36Sopenharmony_ci rr = (r + length) & CMX_BUFF_MASK; 173362306a36Sopenharmony_ci /* delete rx-data */ 173462306a36Sopenharmony_ci while (r != rr) { 173562306a36Sopenharmony_ci p[r] = dsp_silence; 173662306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 173762306a36Sopenharmony_ci } 173862306a36Sopenharmony_ci /* increment rx-buffer pointer */ 173962306a36Sopenharmony_ci dsp->rx_R = r; /* write incremented read pointer */ 174062306a36Sopenharmony_ci } 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci /* check current rx_delay */ 174362306a36Sopenharmony_ci delay = (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK; 174462306a36Sopenharmony_ci if (delay >= CMX_BUFF_HALF) 174562306a36Sopenharmony_ci delay = 0; /* will be the delay before next write */ 174662306a36Sopenharmony_ci /* check for lower delay */ 174762306a36Sopenharmony_ci if (delay < dsp->rx_delay[0]) 174862306a36Sopenharmony_ci dsp->rx_delay[0] = delay; 174962306a36Sopenharmony_ci /* check current tx_delay */ 175062306a36Sopenharmony_ci delay = (dsp->tx_W-dsp->tx_R) & CMX_BUFF_MASK; 175162306a36Sopenharmony_ci if (delay >= CMX_BUFF_HALF) 175262306a36Sopenharmony_ci delay = 0; /* will be the delay before next write */ 175362306a36Sopenharmony_ci /* check for lower delay */ 175462306a36Sopenharmony_ci if (delay < dsp->tx_delay[0]) 175562306a36Sopenharmony_ci dsp->tx_delay[0] = delay; 175662306a36Sopenharmony_ci if (jittercheck) { 175762306a36Sopenharmony_ci /* find the lowest of all rx_delays */ 175862306a36Sopenharmony_ci delay = dsp->rx_delay[0]; 175962306a36Sopenharmony_ci i = 1; 176062306a36Sopenharmony_ci while (i < MAX_SECONDS_JITTER_CHECK) { 176162306a36Sopenharmony_ci if (delay > dsp->rx_delay[i]) 176262306a36Sopenharmony_ci delay = dsp->rx_delay[i]; 176362306a36Sopenharmony_ci i++; 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci /* 176662306a36Sopenharmony_ci * remove rx_delay only if we have delay AND we 176762306a36Sopenharmony_ci * have not preset cmx_delay AND 176862306a36Sopenharmony_ci * the delay is greater dsp_poll 176962306a36Sopenharmony_ci */ 177062306a36Sopenharmony_ci if (delay > dsp_poll && !dsp->cmx_delay) { 177162306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CLOCK) 177262306a36Sopenharmony_ci printk(KERN_DEBUG 177362306a36Sopenharmony_ci "%s lowest rx_delay of %d bytes for" 177462306a36Sopenharmony_ci " dsp %s are now removed.\n", 177562306a36Sopenharmony_ci __func__, delay, 177662306a36Sopenharmony_ci dsp->name); 177762306a36Sopenharmony_ci r = dsp->rx_R; 177862306a36Sopenharmony_ci rr = (r + delay - (dsp_poll >> 1)) 177962306a36Sopenharmony_ci & CMX_BUFF_MASK; 178062306a36Sopenharmony_ci /* delete rx-data */ 178162306a36Sopenharmony_ci while (r != rr) { 178262306a36Sopenharmony_ci p[r] = dsp_silence; 178362306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 178462306a36Sopenharmony_ci } 178562306a36Sopenharmony_ci /* increment rx-buffer pointer */ 178662306a36Sopenharmony_ci dsp->rx_R = r; 178762306a36Sopenharmony_ci /* write incremented read pointer */ 178862306a36Sopenharmony_ci } 178962306a36Sopenharmony_ci /* find the lowest of all tx_delays */ 179062306a36Sopenharmony_ci delay = dsp->tx_delay[0]; 179162306a36Sopenharmony_ci i = 1; 179262306a36Sopenharmony_ci while (i < MAX_SECONDS_JITTER_CHECK) { 179362306a36Sopenharmony_ci if (delay > dsp->tx_delay[i]) 179462306a36Sopenharmony_ci delay = dsp->tx_delay[i]; 179562306a36Sopenharmony_ci i++; 179662306a36Sopenharmony_ci } 179762306a36Sopenharmony_ci /* 179862306a36Sopenharmony_ci * remove delay only if we have delay AND we 179962306a36Sopenharmony_ci * have enabled tx_dejitter 180062306a36Sopenharmony_ci */ 180162306a36Sopenharmony_ci if (delay > dsp_poll && dsp->tx_dejitter) { 180262306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CLOCK) 180362306a36Sopenharmony_ci printk(KERN_DEBUG 180462306a36Sopenharmony_ci "%s lowest tx_delay of %d bytes for" 180562306a36Sopenharmony_ci " dsp %s are now removed.\n", 180662306a36Sopenharmony_ci __func__, delay, 180762306a36Sopenharmony_ci dsp->name); 180862306a36Sopenharmony_ci r = dsp->tx_R; 180962306a36Sopenharmony_ci rr = (r + delay - (dsp_poll >> 1)) 181062306a36Sopenharmony_ci & CMX_BUFF_MASK; 181162306a36Sopenharmony_ci /* delete tx-data */ 181262306a36Sopenharmony_ci while (r != rr) { 181362306a36Sopenharmony_ci q[r] = dsp_silence; 181462306a36Sopenharmony_ci r = (r + 1) & CMX_BUFF_MASK; 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci /* increment rx-buffer pointer */ 181762306a36Sopenharmony_ci dsp->tx_R = r; 181862306a36Sopenharmony_ci /* write incremented read pointer */ 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci /* scroll up delays */ 182162306a36Sopenharmony_ci i = MAX_SECONDS_JITTER_CHECK - 1; 182262306a36Sopenharmony_ci while (i) { 182362306a36Sopenharmony_ci dsp->rx_delay[i] = dsp->rx_delay[i - 1]; 182462306a36Sopenharmony_ci dsp->tx_delay[i] = dsp->tx_delay[i - 1]; 182562306a36Sopenharmony_ci i--; 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci dsp->tx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ 182862306a36Sopenharmony_ci dsp->rx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ 182962306a36Sopenharmony_ci } 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci /* if next event would be in the past ... */ 183362306a36Sopenharmony_ci if ((s32)(dsp_spl_jiffies + dsp_tics-jiffies) <= 0) 183462306a36Sopenharmony_ci dsp_spl_jiffies = jiffies + 1; 183562306a36Sopenharmony_ci else 183662306a36Sopenharmony_ci dsp_spl_jiffies += dsp_tics; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci dsp_spl_tl.expires = dsp_spl_jiffies; 183962306a36Sopenharmony_ci add_timer(&dsp_spl_tl); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci /* unlock */ 184262306a36Sopenharmony_ci spin_unlock_irqrestore(&dsp_lock, flags); 184362306a36Sopenharmony_ci} 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci/* 184662306a36Sopenharmony_ci * audio data is transmitted from upper layer to the dsp 184762306a36Sopenharmony_ci */ 184862306a36Sopenharmony_civoid 184962306a36Sopenharmony_cidsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) 185062306a36Sopenharmony_ci{ 185162306a36Sopenharmony_ci u_int w, ww; 185262306a36Sopenharmony_ci u8 *d, *p; 185362306a36Sopenharmony_ci int space; /* todo: , l = skb->len; */ 185462306a36Sopenharmony_ci#ifdef CMX_TX_DEBUG 185562306a36Sopenharmony_ci char debugbuf[256] = ""; 185662306a36Sopenharmony_ci#endif 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci /* check if there is enough space, and then copy */ 185962306a36Sopenharmony_ci w = dsp->tx_W; 186062306a36Sopenharmony_ci ww = dsp->tx_R; 186162306a36Sopenharmony_ci p = dsp->tx_buff; 186262306a36Sopenharmony_ci d = skb->data; 186362306a36Sopenharmony_ci space = (ww - w - 1) & CMX_BUFF_MASK; 186462306a36Sopenharmony_ci /* write-pointer should not overrun nor reach read pointer */ 186562306a36Sopenharmony_ci if (space < skb->len) { 186662306a36Sopenharmony_ci /* write to the space we have left */ 186762306a36Sopenharmony_ci ww = (ww - 1) & CMX_BUFF_MASK; /* end one byte prior tx_R */ 186862306a36Sopenharmony_ci if (dsp_debug & DEBUG_DSP_CLOCK) 186962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: TX overflow space=%d skb->len=" 187062306a36Sopenharmony_ci "%d, w=0x%04x, ww=0x%04x\n", __func__, space, 187162306a36Sopenharmony_ci skb->len, w, ww); 187262306a36Sopenharmony_ci } else 187362306a36Sopenharmony_ci /* write until all byte are copied */ 187462306a36Sopenharmony_ci ww = (w + skb->len) & CMX_BUFF_MASK; 187562306a36Sopenharmony_ci dsp->tx_W = ww; 187662306a36Sopenharmony_ci /* show current buffer */ 187762306a36Sopenharmony_ci#ifdef CMX_DEBUG 187862306a36Sopenharmony_ci printk(KERN_DEBUG 187962306a36Sopenharmony_ci "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n", 188062306a36Sopenharmony_ci (u_long)dsp, (ww - w) & CMX_BUFF_MASK, w, ww, dsp->name); 188162306a36Sopenharmony_ci#endif 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci /* copy transmit data to tx-buffer */ 188462306a36Sopenharmony_ci#ifdef CMX_TX_DEBUG 188562306a36Sopenharmony_ci sprintf(debugbuf, "TX getting (%04x-%04x)%p: ", w, ww, p); 188662306a36Sopenharmony_ci#endif 188762306a36Sopenharmony_ci while (w != ww) { 188862306a36Sopenharmony_ci#ifdef CMX_TX_DEBUG 188962306a36Sopenharmony_ci if (strlen(debugbuf) < 48) 189062306a36Sopenharmony_ci sprintf(debugbuf + strlen(debugbuf), " %02x", *d); 189162306a36Sopenharmony_ci#endif 189262306a36Sopenharmony_ci p[w] = *d++; 189362306a36Sopenharmony_ci w = (w + 1) & CMX_BUFF_MASK; 189462306a36Sopenharmony_ci } 189562306a36Sopenharmony_ci#ifdef CMX_TX_DEBUG 189662306a36Sopenharmony_ci printk(KERN_DEBUG "%s\n", debugbuf); 189762306a36Sopenharmony_ci#endif 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci} 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci/* 190262306a36Sopenharmony_ci * hdlc data is received from card and sent to all members. 190362306a36Sopenharmony_ci */ 190462306a36Sopenharmony_civoid 190562306a36Sopenharmony_cidsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) 190662306a36Sopenharmony_ci{ 190762306a36Sopenharmony_ci struct sk_buff *nskb = NULL; 190862306a36Sopenharmony_ci struct dsp_conf_member *member; 190962306a36Sopenharmony_ci struct mISDNhead *hh; 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci /* not if not active */ 191262306a36Sopenharmony_ci if (!dsp->b_active) 191362306a36Sopenharmony_ci return; 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci /* check if we have sompen */ 191662306a36Sopenharmony_ci if (skb->len < 1) 191762306a36Sopenharmony_ci return; 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci /* no conf */ 192062306a36Sopenharmony_ci if (!dsp->conf) { 192162306a36Sopenharmony_ci /* in case of software echo */ 192262306a36Sopenharmony_ci if (dsp->echo.software) { 192362306a36Sopenharmony_ci nskb = skb_clone(skb, GFP_ATOMIC); 192462306a36Sopenharmony_ci if (nskb) { 192562306a36Sopenharmony_ci hh = mISDN_HEAD_P(nskb); 192662306a36Sopenharmony_ci hh->prim = PH_DATA_REQ; 192762306a36Sopenharmony_ci hh->id = 0; 192862306a36Sopenharmony_ci skb_queue_tail(&dsp->sendq, nskb); 192962306a36Sopenharmony_ci schedule_work(&dsp->workq); 193062306a36Sopenharmony_ci } 193162306a36Sopenharmony_ci } 193262306a36Sopenharmony_ci return; 193362306a36Sopenharmony_ci } 193462306a36Sopenharmony_ci /* in case of hardware conference */ 193562306a36Sopenharmony_ci if (dsp->conf->hardware) 193662306a36Sopenharmony_ci return; 193762306a36Sopenharmony_ci list_for_each_entry(member, &dsp->conf->mlist, list) { 193862306a36Sopenharmony_ci if (dsp->echo.software || member->dsp != dsp) { 193962306a36Sopenharmony_ci nskb = skb_clone(skb, GFP_ATOMIC); 194062306a36Sopenharmony_ci if (nskb) { 194162306a36Sopenharmony_ci hh = mISDN_HEAD_P(nskb); 194262306a36Sopenharmony_ci hh->prim = PH_DATA_REQ; 194362306a36Sopenharmony_ci hh->id = 0; 194462306a36Sopenharmony_ci skb_queue_tail(&member->dsp->sendq, nskb); 194562306a36Sopenharmony_ci schedule_work(&member->dsp->workq); 194662306a36Sopenharmony_ci } 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci } 194962306a36Sopenharmony_ci} 1950