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