1 | /* |
2 | * Author Andreas Eversberg (jolly@eversberg.eu) |
3 | * Based on source code structure by |
4 | * Karsten Keil (keil@isdn4linux.de) |
5 | * |
6 | * This file is (c) under GNU PUBLIC LICENSE |
7 | * |
8 | * Thanks to Karsten Keil (great drivers) |
9 | * Cologne Chip (great chips) |
10 | * |
11 | * This module does: |
12 | * Real-time tone generation |
13 | * DTMF detection |
14 | * Real-time cross-connection and conferrence |
15 | * Compensate jitter due to system load and hardware fault. |
16 | * All features are done in kernel space and will be realized |
17 | * using hardware, if available and supported by chip set. |
18 | * Blowfish encryption/decryption |
19 | */ |
20 | |
21 | /* STRUCTURE: |
22 | * |
23 | * The dsp module provides layer 2 for b-channels (64kbit). It provides |
24 | * transparent audio forwarding with special digital signal processing: |
25 | * |
26 | * - (1) generation of tones |
27 | * - (2) detection of dtmf tones |
28 | * - (3) crossconnecting and conferences (clocking) |
29 | * - (4) echo generation for delay test |
30 | * - (5) volume control |
31 | * - (6) disable receive data |
32 | * - (7) pipeline |
33 | * - (8) encryption/decryption |
34 | * |
35 | * Look: |
36 | * TX RX |
37 | * ------upper layer------ |
38 | * | ^ |
39 | * | |(6) |
40 | * v | |
41 | * +-----+-------------+-----+ |
42 | * |(3)(4) | |
43 | * | CMX | |
44 | * | | |
45 | * | +-------------+ |
46 | * | | ^ |
47 | * | | | |
48 | * |+---------+| +----+----+ |
49 | * ||(1) || |(2) | |
50 | * || || | | |
51 | * || Tones || | DTMF | |
52 | * || || | | |
53 | * || || | | |
54 | * |+----+----+| +----+----+ |
55 | * +-----+-----+ ^ |
56 | * | | |
57 | * v | |
58 | * +----+----+ +----+----+ |
59 | * |(5) | |(5) | |
60 | * | | | | |
61 | * |TX Volume| |RX Volume| |
62 | * | | | | |
63 | * | | | | |
64 | * +----+----+ +----+----+ |
65 | * | ^ |
66 | * | | |
67 | * v | |
68 | * +----+-------------+----+ |
69 | * |(7) | |
70 | * | | |
71 | * | Pipeline Processing | |
72 | * | | |
73 | * | | |
74 | * +----+-------------+----+ |
75 | * | ^ |
76 | * | | |
77 | * v | |
78 | * +----+----+ +----+----+ |
79 | * |(8) | |(8) | |
80 | * | | | | |
81 | * | Encrypt | | Decrypt | |
82 | * | | | | |
83 | * | | | | |
84 | * +----+----+ +----+----+ |
85 | * | ^ |
86 | * | | |
87 | * v | |
88 | * ------card layer------ |
89 | * TX RX |
90 | * |
91 | * Above you can see the logical data flow. If software is used to do the |
92 | * process, it is actually the real data flow. If hardware is used, data |
93 | * may not flow, but hardware commands to the card, to provide the data flow |
94 | * as shown. |
95 | * |
96 | * NOTE: The channel must be activated in order to make dsp work, even if |
97 | * no data flow to the upper layer is intended. Activation can be done |
98 | * after and before controlling the setting using PH_CONTROL requests. |
99 | * |
100 | * DTMF: Will be detected by hardware if possible. It is done before CMX |
101 | * processing. |
102 | * |
103 | * Tones: Will be generated via software if endless looped audio fifos are |
104 | * not supported by hardware. Tones will override all data from CMX. |
105 | * It is not required to join a conference to use tones at any time. |
106 | * |
107 | * CMX: Is transparent when not used. When it is used, it will do |
108 | * crossconnections and conferences via software if not possible through |
109 | * hardware. If hardware capability is available, hardware is used. |
110 | * |
111 | * Echo: Is generated by CMX and is used to check performance of hard and |
112 | * software CMX. |
113 | * |
114 | * The CMX has special functions for conferences with one, two and more |
115 | * members. It will allow different types of data flow. Receive and transmit |
116 | * data to/form upper layer may be switched on/off individually without losing |
117 | * features of CMX, Tones and DTMF. |
118 | * |
119 | * Echo Cancellation: Sometimes we like to cancel echo from the interface. |
120 | * Note that a VoIP call may not have echo caused by the IP phone. The echo |
121 | * is generated by the telephone line connected to it. Because the delay |
122 | * is high, it becomes an echo. RESULT: Echo Cachelation is required if |
123 | * both echo AND delay is applied to an interface. |
124 | * Remember that software CMX always generates a more or less delay. |
125 | * |
126 | * If all used features can be realized in hardware, and if transmit and/or |
127 | * receive data ist disabled, the card may not send/receive any data at all. |
128 | * Not receiving is useful if only announcements are played. Not sending is |
129 | * useful if an answering machine records audio. Not sending and receiving is |
130 | * useful during most states of the call. If supported by hardware, tones |
131 | * will be played without cpu load. Small PBXs and NT-Mode applications will |
132 | * not need expensive hardware when processing calls. |
133 | * |
134 | * |
135 | * LOCKING: |
136 | * |
137 | * When data is received from upper or lower layer (card), the complete dsp |
138 | * module is locked by a global lock. This lock MUST lock irq, because it |
139 | * must lock timer events by DSP poll timer. |
140 | * When data is ready to be transmitted down, the data is queued and sent |
141 | * outside lock and timer event. |
142 | * PH_CONTROL must not change any settings, join or split conference members |
143 | * during process of data. |
144 | * |
145 | * HDLC: |
146 | * |
147 | * It works quite the same as transparent, except that HDLC data is forwarded |
148 | * to all other conference members if no hardware bridging is possible. |
149 | * Send data will be writte to sendq. Sendq will be sent if confirm is received. |
150 | * Conference cannot join, if one member is not hdlc. |
151 | * |
152 | */ |
153 | |
154 | #include <linux/delay.h> |
155 | #include <linux/gfp.h> |
156 | #include <linux/mISDNif.h> |
157 | #include <linux/mISDNdsp.h> |
158 | #include <linux/module.h> |
159 | #include <linux/vmalloc.h> |
160 | #include "core.h" |
161 | #include "dsp.h" |
162 | |
163 | static const char *mISDN_dsp_revision = "2.0" ; |
164 | |
165 | static int debug; |
166 | static int options; |
167 | static int poll; |
168 | static int dtmfthreshold = 100; |
169 | |
170 | MODULE_AUTHOR("Andreas Eversberg" ); |
171 | module_param(debug, uint, S_IRUGO | S_IWUSR); |
172 | module_param(options, uint, S_IRUGO | S_IWUSR); |
173 | module_param(poll, uint, S_IRUGO | S_IWUSR); |
174 | module_param(dtmfthreshold, uint, S_IRUGO | S_IWUSR); |
175 | MODULE_LICENSE("GPL" ); |
176 | |
177 | /*int spinnest = 0;*/ |
178 | |
179 | DEFINE_SPINLOCK(dsp_lock); /* global dsp lock */ |
180 | LIST_HEAD(dsp_ilist); |
181 | LIST_HEAD(conf_ilist); |
182 | int dsp_debug; |
183 | int dsp_options; |
184 | int dsp_poll, dsp_tics; |
185 | |
186 | /* check if rx may be turned off or must be turned on */ |
187 | static void |
188 | dsp_rx_off_member(struct dsp *dsp) |
189 | { |
190 | struct mISDN_ctrl_req cq; |
191 | int rx_off = 1; |
192 | |
193 | memset(&cq, 0, sizeof(cq)); |
194 | |
195 | if (!dsp->features_rx_off) |
196 | return; |
197 | |
198 | /* not disabled */ |
199 | if (!dsp->rx_disabled) |
200 | rx_off = 0; |
201 | /* software dtmf */ |
202 | else if (dsp->dtmf.software) |
203 | rx_off = 0; |
204 | /* echo in software */ |
205 | else if (dsp->echo.software) |
206 | rx_off = 0; |
207 | /* bridge in software */ |
208 | else if (dsp->conf && dsp->conf->software) |
209 | rx_off = 0; |
210 | /* data is not required by user space and not required |
211 | * for echo dtmf detection, soft-echo, soft-bridging */ |
212 | |
213 | if (rx_off == dsp->rx_is_off) |
214 | return; |
215 | |
216 | if (!dsp->ch.peer) { |
217 | if (dsp_debug & DEBUG_DSP_CORE) |
218 | printk(KERN_DEBUG "%s: no peer, no rx_off\n" , |
219 | __func__); |
220 | return; |
221 | } |
222 | cq.op = MISDN_CTRL_RX_OFF; |
223 | cq.p1 = rx_off; |
224 | if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { |
225 | printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n" , |
226 | __func__); |
227 | return; |
228 | } |
229 | dsp->rx_is_off = rx_off; |
230 | if (dsp_debug & DEBUG_DSP_CORE) |
231 | printk(KERN_DEBUG "%s: %s set rx_off = %d\n" , |
232 | __func__, dsp->name, rx_off); |
233 | } |
234 | static void |
235 | dsp_rx_off(struct dsp *dsp) |
236 | { |
237 | struct dsp_conf_member *member; |
238 | |
239 | if (dsp_options & DSP_OPT_NOHARDWARE) |
240 | return; |
241 | |
242 | /* no conf */ |
243 | if (!dsp->conf) { |
244 | dsp_rx_off_member(dsp); |
245 | return; |
246 | } |
247 | /* check all members in conf */ |
248 | list_for_each_entry(member, &dsp->conf->mlist, list) { |
249 | dsp_rx_off_member(dsp: member->dsp); |
250 | } |
251 | } |
252 | |
253 | /* enable "fill empty" feature */ |
254 | static void |
255 | dsp_fill_empty(struct dsp *dsp) |
256 | { |
257 | struct mISDN_ctrl_req cq; |
258 | |
259 | memset(&cq, 0, sizeof(cq)); |
260 | |
261 | if (!dsp->ch.peer) { |
262 | if (dsp_debug & DEBUG_DSP_CORE) |
263 | printk(KERN_DEBUG "%s: no peer, no fill_empty\n" , |
264 | __func__); |
265 | return; |
266 | } |
267 | cq.op = MISDN_CTRL_FILL_EMPTY; |
268 | cq.p1 = 1; |
269 | cq.p2 = dsp_silence; |
270 | if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { |
271 | printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n" , |
272 | __func__); |
273 | return; |
274 | } |
275 | if (dsp_debug & DEBUG_DSP_CORE) |
276 | printk(KERN_DEBUG "%s: %s set fill_empty = 1\n" , |
277 | __func__, dsp->name); |
278 | } |
279 | |
280 | static int |
281 | dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) |
282 | { |
283 | struct sk_buff *nskb; |
284 | int ret = 0; |
285 | int cont; |
286 | u8 *data; |
287 | int len; |
288 | |
289 | if (skb->len < sizeof(int)) { |
290 | printk(KERN_ERR "%s: PH_CONTROL message too short\n" , __func__); |
291 | return -EINVAL; |
292 | } |
293 | cont = *((int *)skb->data); |
294 | len = skb->len - sizeof(int); |
295 | data = skb->data + sizeof(int); |
296 | |
297 | switch (cont) { |
298 | case DTMF_TONE_START: /* turn on DTMF */ |
299 | if (dsp->hdlc) { |
300 | ret = -EINVAL; |
301 | break; |
302 | } |
303 | if (dsp_debug & DEBUG_DSP_CORE) |
304 | printk(KERN_DEBUG "%s: start dtmf\n" , __func__); |
305 | if (len == sizeof(int)) { |
306 | if (dsp_debug & DEBUG_DSP_CORE) |
307 | printk(KERN_NOTICE "changing DTMF Threshold " |
308 | "to %d\n" , *((int *)data)); |
309 | dsp->dtmf.treshold = (*(int *)data) * 10000; |
310 | } |
311 | dsp->dtmf.enable = 1; |
312 | /* init goertzel */ |
313 | dsp_dtmf_goertzel_init(dsp); |
314 | |
315 | /* check dtmf hardware */ |
316 | dsp_dtmf_hardware(dsp); |
317 | dsp_rx_off(dsp); |
318 | break; |
319 | case DTMF_TONE_STOP: /* turn off DTMF */ |
320 | if (dsp_debug & DEBUG_DSP_CORE) |
321 | printk(KERN_DEBUG "%s: stop dtmf\n" , __func__); |
322 | dsp->dtmf.enable = 0; |
323 | dsp->dtmf.hardware = 0; |
324 | dsp->dtmf.software = 0; |
325 | break; |
326 | case DSP_CONF_JOIN: /* join / update conference */ |
327 | if (len < sizeof(int)) { |
328 | ret = -EINVAL; |
329 | break; |
330 | } |
331 | if (*((u32 *)data) == 0) |
332 | goto conf_split; |
333 | if (dsp_debug & DEBUG_DSP_CORE) |
334 | printk(KERN_DEBUG "%s: join conference %d\n" , |
335 | __func__, *((u32 *)data)); |
336 | ret = dsp_cmx_conf(dsp, conf_id: *((u32 *)data)); |
337 | /* dsp_cmx_hardware will also be called here */ |
338 | dsp_rx_off(dsp); |
339 | if (dsp_debug & DEBUG_DSP_CMX) |
340 | dsp_cmx_debug(dsp); |
341 | break; |
342 | case DSP_CONF_SPLIT: /* remove from conference */ |
343 | conf_split: |
344 | if (dsp_debug & DEBUG_DSP_CORE) |
345 | printk(KERN_DEBUG "%s: release conference\n" , __func__); |
346 | ret = dsp_cmx_conf(dsp, conf_id: 0); |
347 | /* dsp_cmx_hardware will also be called here */ |
348 | if (dsp_debug & DEBUG_DSP_CMX) |
349 | dsp_cmx_debug(dsp); |
350 | dsp_rx_off(dsp); |
351 | break; |
352 | case DSP_TONE_PATT_ON: /* play tone */ |
353 | if (dsp->hdlc) { |
354 | ret = -EINVAL; |
355 | break; |
356 | } |
357 | if (len < sizeof(int)) { |
358 | ret = -EINVAL; |
359 | break; |
360 | } |
361 | if (dsp_debug & DEBUG_DSP_CORE) |
362 | printk(KERN_DEBUG "%s: turn tone 0x%x on\n" , |
363 | __func__, *((int *)skb->data)); |
364 | ret = dsp_tone(dsp, tone: *((int *)data)); |
365 | if (!ret) { |
366 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
367 | dsp_rx_off(dsp); |
368 | } |
369 | if (!dsp->tone.tone) |
370 | goto tone_off; |
371 | break; |
372 | case DSP_TONE_PATT_OFF: /* stop tone */ |
373 | if (dsp->hdlc) { |
374 | ret = -EINVAL; |
375 | break; |
376 | } |
377 | if (dsp_debug & DEBUG_DSP_CORE) |
378 | printk(KERN_DEBUG "%s: turn tone off\n" , __func__); |
379 | dsp_tone(dsp, tone: 0); |
380 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
381 | dsp_rx_off(dsp); |
382 | /* reset tx buffers (user space data) */ |
383 | tone_off: |
384 | dsp->rx_W = 0; |
385 | dsp->rx_R = 0; |
386 | break; |
387 | case DSP_VOL_CHANGE_TX: /* change volume */ |
388 | if (dsp->hdlc) { |
389 | ret = -EINVAL; |
390 | break; |
391 | } |
392 | if (len < sizeof(int)) { |
393 | ret = -EINVAL; |
394 | break; |
395 | } |
396 | dsp->tx_volume = *((int *)data); |
397 | if (dsp_debug & DEBUG_DSP_CORE) |
398 | printk(KERN_DEBUG "%s: change tx vol to %d\n" , |
399 | __func__, dsp->tx_volume); |
400 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
401 | dsp_dtmf_hardware(dsp); |
402 | dsp_rx_off(dsp); |
403 | break; |
404 | case DSP_VOL_CHANGE_RX: /* change volume */ |
405 | if (dsp->hdlc) { |
406 | ret = -EINVAL; |
407 | break; |
408 | } |
409 | if (len < sizeof(int)) { |
410 | ret = -EINVAL; |
411 | break; |
412 | } |
413 | dsp->rx_volume = *((int *)data); |
414 | if (dsp_debug & DEBUG_DSP_CORE) |
415 | printk(KERN_DEBUG "%s: change rx vol to %d\n" , |
416 | __func__, dsp->tx_volume); |
417 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
418 | dsp_dtmf_hardware(dsp); |
419 | dsp_rx_off(dsp); |
420 | break; |
421 | case DSP_ECHO_ON: /* enable echo */ |
422 | dsp->echo.software = 1; /* soft echo */ |
423 | if (dsp_debug & DEBUG_DSP_CORE) |
424 | printk(KERN_DEBUG "%s: enable cmx-echo\n" , __func__); |
425 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
426 | dsp_rx_off(dsp); |
427 | if (dsp_debug & DEBUG_DSP_CMX) |
428 | dsp_cmx_debug(dsp); |
429 | break; |
430 | case DSP_ECHO_OFF: /* disable echo */ |
431 | dsp->echo.software = 0; |
432 | dsp->echo.hardware = 0; |
433 | if (dsp_debug & DEBUG_DSP_CORE) |
434 | printk(KERN_DEBUG "%s: disable cmx-echo\n" , __func__); |
435 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
436 | dsp_rx_off(dsp); |
437 | if (dsp_debug & DEBUG_DSP_CMX) |
438 | dsp_cmx_debug(dsp); |
439 | break; |
440 | case DSP_RECEIVE_ON: /* enable receive to user space */ |
441 | if (dsp_debug & DEBUG_DSP_CORE) |
442 | printk(KERN_DEBUG "%s: enable receive to user " |
443 | "space\n" , __func__); |
444 | dsp->rx_disabled = 0; |
445 | dsp_rx_off(dsp); |
446 | break; |
447 | case DSP_RECEIVE_OFF: /* disable receive to user space */ |
448 | if (dsp_debug & DEBUG_DSP_CORE) |
449 | printk(KERN_DEBUG "%s: disable receive to " |
450 | "user space\n" , __func__); |
451 | dsp->rx_disabled = 1; |
452 | dsp_rx_off(dsp); |
453 | break; |
454 | case DSP_MIX_ON: /* enable mixing of tx data */ |
455 | if (dsp->hdlc) { |
456 | ret = -EINVAL; |
457 | break; |
458 | } |
459 | if (dsp_debug & DEBUG_DSP_CORE) |
460 | printk(KERN_DEBUG "%s: enable mixing of " |
461 | "tx-data with conf members\n" , __func__); |
462 | dsp->tx_mix = 1; |
463 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
464 | dsp_rx_off(dsp); |
465 | if (dsp_debug & DEBUG_DSP_CMX) |
466 | dsp_cmx_debug(dsp); |
467 | break; |
468 | case DSP_MIX_OFF: /* disable mixing of tx data */ |
469 | if (dsp->hdlc) { |
470 | ret = -EINVAL; |
471 | break; |
472 | } |
473 | if (dsp_debug & DEBUG_DSP_CORE) |
474 | printk(KERN_DEBUG "%s: disable mixing of " |
475 | "tx-data with conf members\n" , __func__); |
476 | dsp->tx_mix = 0; |
477 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
478 | dsp_rx_off(dsp); |
479 | if (dsp_debug & DEBUG_DSP_CMX) |
480 | dsp_cmx_debug(dsp); |
481 | break; |
482 | case DSP_TXDATA_ON: /* enable txdata */ |
483 | dsp->tx_data = 1; |
484 | if (dsp_debug & DEBUG_DSP_CORE) |
485 | printk(KERN_DEBUG "%s: enable tx-data\n" , __func__); |
486 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
487 | dsp_rx_off(dsp); |
488 | if (dsp_debug & DEBUG_DSP_CMX) |
489 | dsp_cmx_debug(dsp); |
490 | break; |
491 | case DSP_TXDATA_OFF: /* disable txdata */ |
492 | dsp->tx_data = 0; |
493 | if (dsp_debug & DEBUG_DSP_CORE) |
494 | printk(KERN_DEBUG "%s: disable tx-data\n" , __func__); |
495 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
496 | dsp_rx_off(dsp); |
497 | if (dsp_debug & DEBUG_DSP_CMX) |
498 | dsp_cmx_debug(dsp); |
499 | break; |
500 | case DSP_DELAY: /* use delay algorithm instead of dynamic |
501 | jitter algorithm */ |
502 | if (dsp->hdlc) { |
503 | ret = -EINVAL; |
504 | break; |
505 | } |
506 | if (len < sizeof(int)) { |
507 | ret = -EINVAL; |
508 | break; |
509 | } |
510 | dsp->cmx_delay = (*((int *)data)) << 3; |
511 | /* milliseconds to samples */ |
512 | if (dsp->cmx_delay >= (CMX_BUFF_HALF >> 1)) |
513 | /* clip to half of maximum usable buffer |
514 | (half of half buffer) */ |
515 | dsp->cmx_delay = (CMX_BUFF_HALF >> 1) - 1; |
516 | if (dsp_debug & DEBUG_DSP_CORE) |
517 | printk(KERN_DEBUG "%s: use delay algorithm to " |
518 | "compensate jitter (%d samples)\n" , |
519 | __func__, dsp->cmx_delay); |
520 | break; |
521 | case DSP_JITTER: /* use dynamic jitter algorithm instead of |
522 | delay algorithm */ |
523 | if (dsp->hdlc) { |
524 | ret = -EINVAL; |
525 | break; |
526 | } |
527 | dsp->cmx_delay = 0; |
528 | if (dsp_debug & DEBUG_DSP_CORE) |
529 | printk(KERN_DEBUG "%s: use jitter algorithm to " |
530 | "compensate jitter\n" , __func__); |
531 | break; |
532 | case DSP_TX_DEJITTER: /* use dynamic jitter algorithm for tx-buffer */ |
533 | if (dsp->hdlc) { |
534 | ret = -EINVAL; |
535 | break; |
536 | } |
537 | dsp->tx_dejitter = 1; |
538 | if (dsp_debug & DEBUG_DSP_CORE) |
539 | printk(KERN_DEBUG "%s: use dejitter on TX " |
540 | "buffer\n" , __func__); |
541 | break; |
542 | case DSP_TX_DEJ_OFF: /* use tx-buffer without dejittering*/ |
543 | if (dsp->hdlc) { |
544 | ret = -EINVAL; |
545 | break; |
546 | } |
547 | dsp->tx_dejitter = 0; |
548 | if (dsp_debug & DEBUG_DSP_CORE) |
549 | printk(KERN_DEBUG "%s: use TX buffer without " |
550 | "dejittering\n" , __func__); |
551 | break; |
552 | case DSP_PIPELINE_CFG: |
553 | if (dsp->hdlc) { |
554 | ret = -EINVAL; |
555 | break; |
556 | } |
557 | if (len > 0 && ((char *)data)[len - 1]) { |
558 | printk(KERN_DEBUG "%s: pipeline config string " |
559 | "is not NULL terminated!\n" , __func__); |
560 | ret = -EINVAL; |
561 | } else { |
562 | dsp->pipeline.inuse = 1; |
563 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
564 | ret = dsp_pipeline_build(pipeline: &dsp->pipeline, |
565 | cfg: len > 0 ? data : NULL); |
566 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
567 | dsp_rx_off(dsp); |
568 | } |
569 | break; |
570 | case DSP_BF_ENABLE_KEY: /* turn blowfish on */ |
571 | if (dsp->hdlc) { |
572 | ret = -EINVAL; |
573 | break; |
574 | } |
575 | if (len < 4 || len > 56) { |
576 | ret = -EINVAL; |
577 | break; |
578 | } |
579 | if (dsp_debug & DEBUG_DSP_CORE) |
580 | printk(KERN_DEBUG "%s: turn blowfish on (key " |
581 | "not shown)\n" , __func__); |
582 | ret = dsp_bf_init(dsp, key: (u8 *)data, keylen: len); |
583 | /* set new cont */ |
584 | if (!ret) |
585 | cont = DSP_BF_ACCEPT; |
586 | else |
587 | cont = DSP_BF_REJECT; |
588 | /* send indication if it worked to set it */ |
589 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, MISDN_ID_ANY, |
590 | len: sizeof(int), dp: &cont, GFP_ATOMIC); |
591 | if (nskb) { |
592 | if (dsp->up) { |
593 | if (dsp->up->send(dsp->up, nskb)) |
594 | dev_kfree_skb(nskb); |
595 | } else |
596 | dev_kfree_skb(nskb); |
597 | } |
598 | if (!ret) { |
599 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
600 | dsp_dtmf_hardware(dsp); |
601 | dsp_rx_off(dsp); |
602 | } |
603 | break; |
604 | case DSP_BF_DISABLE: /* turn blowfish off */ |
605 | if (dsp->hdlc) { |
606 | ret = -EINVAL; |
607 | break; |
608 | } |
609 | if (dsp_debug & DEBUG_DSP_CORE) |
610 | printk(KERN_DEBUG "%s: turn blowfish off\n" , __func__); |
611 | dsp_bf_cleanup(dsp); |
612 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
613 | dsp_dtmf_hardware(dsp); |
614 | dsp_rx_off(dsp); |
615 | break; |
616 | default: |
617 | if (dsp_debug & DEBUG_DSP_CORE) |
618 | printk(KERN_DEBUG "%s: ctrl req %x unhandled\n" , |
619 | __func__, cont); |
620 | ret = -EINVAL; |
621 | } |
622 | return ret; |
623 | } |
624 | |
625 | static void |
626 | get_features(struct mISDNchannel *ch) |
627 | { |
628 | struct dsp *dsp = container_of(ch, struct dsp, ch); |
629 | struct mISDN_ctrl_req cq; |
630 | |
631 | if (!ch->peer) { |
632 | if (dsp_debug & DEBUG_DSP_CORE) |
633 | printk(KERN_DEBUG "%s: no peer, no features\n" , |
634 | __func__); |
635 | return; |
636 | } |
637 | memset(&cq, 0, sizeof(cq)); |
638 | cq.op = MISDN_CTRL_GETOP; |
639 | if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq) < 0) { |
640 | printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n" , |
641 | __func__); |
642 | return; |
643 | } |
644 | if (cq.op & MISDN_CTRL_RX_OFF) |
645 | dsp->features_rx_off = 1; |
646 | if (cq.op & MISDN_CTRL_FILL_EMPTY) |
647 | dsp->features_fill_empty = 1; |
648 | if (dsp_options & DSP_OPT_NOHARDWARE) |
649 | return; |
650 | if ((cq.op & MISDN_CTRL_HW_FEATURES_OP)) { |
651 | cq.op = MISDN_CTRL_HW_FEATURES; |
652 | *((u_long *)&cq.p1) = (u_long)&dsp->features; |
653 | if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq)) { |
654 | printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n" , |
655 | __func__); |
656 | } |
657 | } else |
658 | if (dsp_debug & DEBUG_DSP_CORE) |
659 | printk(KERN_DEBUG "%s: features not supported for %s\n" , |
660 | __func__, dsp->name); |
661 | } |
662 | |
663 | static int |
664 | dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) |
665 | { |
666 | struct dsp *dsp = container_of(ch, struct dsp, ch); |
667 | struct mISDNhead *hh; |
668 | int ret = 0; |
669 | u8 *digits = NULL; |
670 | u_long flags; |
671 | |
672 | hh = mISDN_HEAD_P(skb); |
673 | switch (hh->prim) { |
674 | /* FROM DOWN */ |
675 | case (PH_DATA_CNF): |
676 | dsp->data_pending = 0; |
677 | /* trigger next hdlc frame, if any */ |
678 | if (dsp->hdlc) { |
679 | spin_lock_irqsave(&dsp_lock, flags); |
680 | if (dsp->b_active) |
681 | schedule_work(work: &dsp->workq); |
682 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
683 | } |
684 | break; |
685 | case (PH_DATA_IND): |
686 | case (DL_DATA_IND): |
687 | if (skb->len < 1) { |
688 | ret = -EINVAL; |
689 | break; |
690 | } |
691 | if (dsp->rx_is_off) { |
692 | if (dsp_debug & DEBUG_DSP_CORE) |
693 | printk(KERN_DEBUG "%s: rx-data during rx_off" |
694 | " for %s\n" , |
695 | __func__, dsp->name); |
696 | } |
697 | if (dsp->hdlc) { |
698 | /* hdlc */ |
699 | spin_lock_irqsave(&dsp_lock, flags); |
700 | dsp_cmx_hdlc(dsp, skb); |
701 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
702 | if (dsp->rx_disabled) { |
703 | /* if receive is not allowed */ |
704 | break; |
705 | } |
706 | hh->prim = DL_DATA_IND; |
707 | if (dsp->up) |
708 | return dsp->up->send(dsp->up, skb); |
709 | break; |
710 | } |
711 | |
712 | spin_lock_irqsave(&dsp_lock, flags); |
713 | |
714 | /* decrypt if enabled */ |
715 | if (dsp->bf_enable) |
716 | dsp_bf_decrypt(dsp, data: skb->data, len: skb->len); |
717 | /* pipeline */ |
718 | if (dsp->pipeline.inuse) |
719 | dsp_pipeline_process_rx(pipeline: &dsp->pipeline, data: skb->data, |
720 | len: skb->len, txlen: hh->id); |
721 | /* change volume if requested */ |
722 | if (dsp->rx_volume) |
723 | dsp_change_volume(skb, volume: dsp->rx_volume); |
724 | /* check if dtmf soft decoding is turned on */ |
725 | if (dsp->dtmf.software) { |
726 | digits = dsp_dtmf_goertzel_decode(dsp, data: skb->data, |
727 | len: skb->len, fmt: (dsp_options & DSP_OPT_ULAW) ? 1 : 0); |
728 | } |
729 | /* we need to process receive data if software */ |
730 | if (dsp->conf && dsp->conf->software) { |
731 | /* process data from card at cmx */ |
732 | dsp_cmx_receive(dsp, skb); |
733 | } |
734 | |
735 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
736 | |
737 | /* send dtmf result, if any */ |
738 | if (digits) { |
739 | while (*digits) { |
740 | int k; |
741 | struct sk_buff *nskb; |
742 | if (dsp_debug & DEBUG_DSP_DTMF) |
743 | printk(KERN_DEBUG "%s: digit" |
744 | "(%c) to layer %s\n" , |
745 | __func__, *digits, dsp->name); |
746 | k = *digits | DTMF_TONE_VAL; |
747 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, |
748 | MISDN_ID_ANY, len: sizeof(int), dp: &k, |
749 | GFP_ATOMIC); |
750 | if (nskb) { |
751 | if (dsp->up) { |
752 | if (dsp->up->send( |
753 | dsp->up, nskb)) |
754 | dev_kfree_skb(nskb); |
755 | } else |
756 | dev_kfree_skb(nskb); |
757 | } |
758 | digits++; |
759 | } |
760 | } |
761 | if (dsp->rx_disabled) { |
762 | /* if receive is not allowed */ |
763 | break; |
764 | } |
765 | hh->prim = DL_DATA_IND; |
766 | if (dsp->up) |
767 | return dsp->up->send(dsp->up, skb); |
768 | break; |
769 | case (PH_CONTROL_IND): |
770 | if (dsp_debug & DEBUG_DSP_DTMFCOEFF) |
771 | printk(KERN_DEBUG "%s: PH_CONTROL INDICATION " |
772 | "received: %x (len %d) %s\n" , __func__, |
773 | hh->id, skb->len, dsp->name); |
774 | switch (hh->id) { |
775 | case (DTMF_HFC_COEF): /* getting coefficients */ |
776 | if (!dsp->dtmf.hardware) { |
777 | if (dsp_debug & DEBUG_DSP_DTMFCOEFF) |
778 | printk(KERN_DEBUG "%s: ignoring DTMF " |
779 | "coefficients from HFC\n" , |
780 | __func__); |
781 | break; |
782 | } |
783 | digits = dsp_dtmf_goertzel_decode(dsp, data: skb->data, |
784 | len: skb->len, fmt: 2); |
785 | while (*digits) { |
786 | int k; |
787 | struct sk_buff *nskb; |
788 | if (dsp_debug & DEBUG_DSP_DTMF) |
789 | printk(KERN_DEBUG "%s: digit" |
790 | "(%c) to layer %s\n" , |
791 | __func__, *digits, dsp->name); |
792 | k = *digits | DTMF_TONE_VAL; |
793 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, |
794 | MISDN_ID_ANY, len: sizeof(int), dp: &k, |
795 | GFP_ATOMIC); |
796 | if (nskb) { |
797 | if (dsp->up) { |
798 | if (dsp->up->send( |
799 | dsp->up, nskb)) |
800 | dev_kfree_skb(nskb); |
801 | } else |
802 | dev_kfree_skb(nskb); |
803 | } |
804 | digits++; |
805 | } |
806 | break; |
807 | case (HFC_VOL_CHANGE_TX): /* change volume */ |
808 | if (skb->len != sizeof(int)) { |
809 | ret = -EINVAL; |
810 | break; |
811 | } |
812 | spin_lock_irqsave(&dsp_lock, flags); |
813 | dsp->tx_volume = *((int *)skb->data); |
814 | if (dsp_debug & DEBUG_DSP_CORE) |
815 | printk(KERN_DEBUG "%s: change tx volume to " |
816 | "%d\n" , __func__, dsp->tx_volume); |
817 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
818 | dsp_dtmf_hardware(dsp); |
819 | dsp_rx_off(dsp); |
820 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
821 | break; |
822 | default: |
823 | if (dsp_debug & DEBUG_DSP_CORE) |
824 | printk(KERN_DEBUG "%s: ctrl ind %x unhandled " |
825 | "%s\n" , __func__, hh->id, dsp->name); |
826 | ret = -EINVAL; |
827 | } |
828 | break; |
829 | case (PH_ACTIVATE_IND): |
830 | case (PH_ACTIVATE_CNF): |
831 | if (dsp_debug & DEBUG_DSP_CORE) |
832 | printk(KERN_DEBUG "%s: b_channel is now active %s\n" , |
833 | __func__, dsp->name); |
834 | /* bchannel now active */ |
835 | spin_lock_irqsave(&dsp_lock, flags); |
836 | dsp->b_active = 1; |
837 | dsp->data_pending = 0; |
838 | dsp->rx_init = 1; |
839 | /* rx_W and rx_R will be adjusted on first frame */ |
840 | dsp->rx_W = 0; |
841 | dsp->rx_R = 0; |
842 | memset(dsp->rx_buff, 0, sizeof(dsp->rx_buff)); |
843 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
844 | dsp_dtmf_hardware(dsp); |
845 | dsp_rx_off(dsp); |
846 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
847 | if (dsp_debug & DEBUG_DSP_CORE) |
848 | printk(KERN_DEBUG "%s: done with activation, sending " |
849 | "confirm to user space. %s\n" , __func__, |
850 | dsp->name); |
851 | /* send activation to upper layer */ |
852 | hh->prim = DL_ESTABLISH_CNF; |
853 | if (dsp->up) |
854 | return dsp->up->send(dsp->up, skb); |
855 | break; |
856 | case (PH_DEACTIVATE_IND): |
857 | case (PH_DEACTIVATE_CNF): |
858 | if (dsp_debug & DEBUG_DSP_CORE) |
859 | printk(KERN_DEBUG "%s: b_channel is now inactive %s\n" , |
860 | __func__, dsp->name); |
861 | /* bchannel now inactive */ |
862 | spin_lock_irqsave(&dsp_lock, flags); |
863 | dsp->b_active = 0; |
864 | dsp->data_pending = 0; |
865 | dsp_cmx_hardware(conf: dsp->conf, dsp); |
866 | dsp_rx_off(dsp); |
867 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
868 | hh->prim = DL_RELEASE_CNF; |
869 | if (dsp->up) |
870 | return dsp->up->send(dsp->up, skb); |
871 | break; |
872 | /* FROM UP */ |
873 | case (DL_DATA_REQ): |
874 | case (PH_DATA_REQ): |
875 | if (skb->len < 1) { |
876 | ret = -EINVAL; |
877 | break; |
878 | } |
879 | if (dsp->hdlc) { |
880 | /* hdlc */ |
881 | if (!dsp->b_active) { |
882 | ret = -EIO; |
883 | break; |
884 | } |
885 | hh->prim = PH_DATA_REQ; |
886 | spin_lock_irqsave(&dsp_lock, flags); |
887 | skb_queue_tail(list: &dsp->sendq, newsk: skb); |
888 | schedule_work(work: &dsp->workq); |
889 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
890 | return 0; |
891 | } |
892 | /* send data to tx-buffer (if no tone is played) */ |
893 | if (!dsp->tone.tone) { |
894 | spin_lock_irqsave(&dsp_lock, flags); |
895 | dsp_cmx_transmit(dsp, skb); |
896 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
897 | } |
898 | break; |
899 | case (PH_CONTROL_REQ): |
900 | spin_lock_irqsave(&dsp_lock, flags); |
901 | ret = dsp_control_req(dsp, hh, skb); |
902 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
903 | break; |
904 | case (DL_ESTABLISH_REQ): |
905 | case (PH_ACTIVATE_REQ): |
906 | if (dsp_debug & DEBUG_DSP_CORE) |
907 | printk(KERN_DEBUG "%s: activating b_channel %s\n" , |
908 | __func__, dsp->name); |
909 | if (dsp->dtmf.hardware || dsp->dtmf.software) |
910 | dsp_dtmf_goertzel_init(dsp); |
911 | get_features(ch); |
912 | /* enable fill_empty feature */ |
913 | if (dsp->features_fill_empty) |
914 | dsp_fill_empty(dsp); |
915 | /* send ph_activate */ |
916 | hh->prim = PH_ACTIVATE_REQ; |
917 | if (ch->peer) |
918 | return ch->recv(ch->peer, skb); |
919 | break; |
920 | case (DL_RELEASE_REQ): |
921 | case (PH_DEACTIVATE_REQ): |
922 | if (dsp_debug & DEBUG_DSP_CORE) |
923 | printk(KERN_DEBUG "%s: releasing b_channel %s\n" , |
924 | __func__, dsp->name); |
925 | spin_lock_irqsave(&dsp_lock, flags); |
926 | dsp->tone.tone = 0; |
927 | dsp->tone.hardware = 0; |
928 | dsp->tone.software = 0; |
929 | if (timer_pending(timer: &dsp->tone.tl)) |
930 | del_timer(timer: &dsp->tone.tl); |
931 | if (dsp->conf) |
932 | dsp_cmx_conf(dsp, conf_id: 0); /* dsp_cmx_hardware will also be |
933 | called here */ |
934 | skb_queue_purge(list: &dsp->sendq); |
935 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
936 | hh->prim = PH_DEACTIVATE_REQ; |
937 | if (ch->peer) |
938 | return ch->recv(ch->peer, skb); |
939 | break; |
940 | default: |
941 | if (dsp_debug & DEBUG_DSP_CORE) |
942 | printk(KERN_DEBUG "%s: msg %x unhandled %s\n" , |
943 | __func__, hh->prim, dsp->name); |
944 | ret = -EINVAL; |
945 | } |
946 | if (!ret) |
947 | dev_kfree_skb(skb); |
948 | return ret; |
949 | } |
950 | |
951 | static int |
952 | dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) |
953 | { |
954 | struct dsp *dsp = container_of(ch, struct dsp, ch); |
955 | u_long flags; |
956 | |
957 | if (debug & DEBUG_DSP_CTRL) |
958 | printk(KERN_DEBUG "%s:(%x)\n" , __func__, cmd); |
959 | |
960 | switch (cmd) { |
961 | case OPEN_CHANNEL: |
962 | break; |
963 | case CLOSE_CHANNEL: |
964 | if (dsp->ch.peer) |
965 | dsp->ch.peer->ctrl(dsp->ch.peer, CLOSE_CHANNEL, NULL); |
966 | |
967 | /* wait until workqueue has finished, |
968 | * must lock here, or we may hit send-process currently |
969 | * queueing. */ |
970 | spin_lock_irqsave(&dsp_lock, flags); |
971 | dsp->b_active = 0; |
972 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
973 | /* MUST not be locked, because it waits until queue is done. */ |
974 | cancel_work_sync(work: &dsp->workq); |
975 | spin_lock_irqsave(&dsp_lock, flags); |
976 | if (timer_pending(timer: &dsp->tone.tl)) |
977 | del_timer(timer: &dsp->tone.tl); |
978 | skb_queue_purge(list: &dsp->sendq); |
979 | if (dsp_debug & DEBUG_DSP_CTRL) |
980 | printk(KERN_DEBUG "%s: releasing member %s\n" , |
981 | __func__, dsp->name); |
982 | dsp->b_active = 0; |
983 | dsp_cmx_conf(dsp, conf_id: 0); /* dsp_cmx_hardware will also be called |
984 | here */ |
985 | dsp_pipeline_destroy(pipeline: &dsp->pipeline); |
986 | |
987 | if (dsp_debug & DEBUG_DSP_CTRL) |
988 | printk(KERN_DEBUG "%s: remove & destroy object %s\n" , |
989 | __func__, dsp->name); |
990 | list_del(entry: &dsp->list); |
991 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
992 | |
993 | if (dsp_debug & DEBUG_DSP_CTRL) |
994 | printk(KERN_DEBUG "%s: dsp instance released\n" , |
995 | __func__); |
996 | vfree(addr: dsp); |
997 | module_put(THIS_MODULE); |
998 | break; |
999 | } |
1000 | return 0; |
1001 | } |
1002 | |
1003 | static void |
1004 | dsp_send_bh(struct work_struct *work) |
1005 | { |
1006 | struct dsp *dsp = container_of(work, struct dsp, workq); |
1007 | struct sk_buff *skb; |
1008 | struct mISDNhead *hh; |
1009 | |
1010 | if (dsp->hdlc && dsp->data_pending) |
1011 | return; /* wait until data has been acknowledged */ |
1012 | |
1013 | /* send queued data */ |
1014 | while ((skb = skb_dequeue(list: &dsp->sendq))) { |
1015 | /* in locked date, we must have still data in queue */ |
1016 | if (dsp->data_pending) { |
1017 | if (dsp_debug & DEBUG_DSP_CORE) |
1018 | printk(KERN_DEBUG "%s: fifo full %s, this is " |
1019 | "no bug!\n" , __func__, dsp->name); |
1020 | /* flush transparent data, if not acked */ |
1021 | dev_kfree_skb(skb); |
1022 | continue; |
1023 | } |
1024 | hh = mISDN_HEAD_P(skb); |
1025 | if (hh->prim == DL_DATA_REQ) { |
1026 | /* send packet up */ |
1027 | if (dsp->up) { |
1028 | if (dsp->up->send(dsp->up, skb)) |
1029 | dev_kfree_skb(skb); |
1030 | } else |
1031 | dev_kfree_skb(skb); |
1032 | } else { |
1033 | /* send packet down */ |
1034 | if (dsp->ch.peer) { |
1035 | dsp->data_pending = 1; |
1036 | if (dsp->ch.recv(dsp->ch.peer, skb)) { |
1037 | dev_kfree_skb(skb); |
1038 | dsp->data_pending = 0; |
1039 | } |
1040 | } else |
1041 | dev_kfree_skb(skb); |
1042 | } |
1043 | } |
1044 | } |
1045 | |
1046 | static int |
1047 | dspcreate(struct channel_req *crq) |
1048 | { |
1049 | struct dsp *ndsp; |
1050 | u_long flags; |
1051 | |
1052 | if (crq->protocol != ISDN_P_B_L2DSP |
1053 | && crq->protocol != ISDN_P_B_L2DSPHDLC) |
1054 | return -EPROTONOSUPPORT; |
1055 | ndsp = vzalloc(size: sizeof(struct dsp)); |
1056 | if (!ndsp) { |
1057 | printk(KERN_ERR "%s: vmalloc struct dsp failed\n" , __func__); |
1058 | return -ENOMEM; |
1059 | } |
1060 | if (dsp_debug & DEBUG_DSP_CTRL) |
1061 | printk(KERN_DEBUG "%s: creating new dsp instance\n" , __func__); |
1062 | |
1063 | /* default enabled */ |
1064 | INIT_WORK(&ndsp->workq, (void *)dsp_send_bh); |
1065 | skb_queue_head_init(list: &ndsp->sendq); |
1066 | ndsp->ch.send = dsp_function; |
1067 | ndsp->ch.ctrl = dsp_ctrl; |
1068 | ndsp->up = crq->ch; |
1069 | crq->ch = &ndsp->ch; |
1070 | if (crq->protocol == ISDN_P_B_L2DSP) { |
1071 | crq->protocol = ISDN_P_B_RAW; |
1072 | ndsp->hdlc = 0; |
1073 | } else { |
1074 | crq->protocol = ISDN_P_B_HDLC; |
1075 | ndsp->hdlc = 1; |
1076 | } |
1077 | if (!try_module_get(THIS_MODULE)) |
1078 | printk(KERN_WARNING "%s:cannot get module\n" , |
1079 | __func__); |
1080 | |
1081 | sprintf(buf: ndsp->name, fmt: "DSP_C%x(0x%p)" , |
1082 | ndsp->up->st->dev->id + 1, ndsp); |
1083 | /* set frame size to start */ |
1084 | ndsp->features.hfc_id = -1; /* current PCM id */ |
1085 | ndsp->features.pcm_id = -1; /* current PCM id */ |
1086 | ndsp->pcm_slot_rx = -1; /* current CPM slot */ |
1087 | ndsp->pcm_slot_tx = -1; |
1088 | ndsp->pcm_bank_rx = -1; |
1089 | ndsp->pcm_bank_tx = -1; |
1090 | ndsp->hfc_conf = -1; /* current conference number */ |
1091 | /* set tone timer */ |
1092 | timer_setup(&ndsp->tone.tl, dsp_tone_timeout, 0); |
1093 | |
1094 | if (dtmfthreshold < 20 || dtmfthreshold > 500) |
1095 | dtmfthreshold = 200; |
1096 | ndsp->dtmf.treshold = dtmfthreshold * 10000; |
1097 | |
1098 | /* init pipeline append to list */ |
1099 | spin_lock_irqsave(&dsp_lock, flags); |
1100 | dsp_pipeline_init(pipeline: &ndsp->pipeline); |
1101 | list_add_tail(new: &ndsp->list, head: &dsp_ilist); |
1102 | spin_unlock_irqrestore(lock: &dsp_lock, flags); |
1103 | |
1104 | return 0; |
1105 | } |
1106 | |
1107 | |
1108 | static struct Bprotocol DSP = { |
1109 | .Bprotocols = (1 << (ISDN_P_B_L2DSP & ISDN_P_B_MASK)) |
1110 | | (1 << (ISDN_P_B_L2DSPHDLC & ISDN_P_B_MASK)), |
1111 | .name = "dsp" , |
1112 | .create = dspcreate |
1113 | }; |
1114 | |
1115 | static int __init dsp_init(void) |
1116 | { |
1117 | int err; |
1118 | int tics; |
1119 | |
1120 | printk(KERN_INFO "DSP module %s\n" , mISDN_dsp_revision); |
1121 | |
1122 | dsp_options = options; |
1123 | dsp_debug = debug; |
1124 | |
1125 | /* set packet size */ |
1126 | dsp_poll = poll; |
1127 | if (dsp_poll) { |
1128 | if (dsp_poll > MAX_POLL) { |
1129 | printk(KERN_ERR "%s: Wrong poll value (%d), use %d " |
1130 | "maximum.\n" , __func__, poll, MAX_POLL); |
1131 | err = -EINVAL; |
1132 | return err; |
1133 | } |
1134 | if (dsp_poll < 8) { |
1135 | printk(KERN_ERR "%s: Wrong poll value (%d), use 8 " |
1136 | "minimum.\n" , __func__, dsp_poll); |
1137 | err = -EINVAL; |
1138 | return err; |
1139 | } |
1140 | dsp_tics = poll * HZ / 8000; |
1141 | if (dsp_tics * 8000 != poll * HZ) { |
1142 | printk(KERN_INFO "mISDN_dsp: Cannot clock every %d " |
1143 | "samples (0,125 ms). It is not a multiple of " |
1144 | "%d HZ.\n" , poll, HZ); |
1145 | err = -EINVAL; |
1146 | return err; |
1147 | } |
1148 | } else { |
1149 | poll = 8; |
1150 | while (poll <= MAX_POLL) { |
1151 | tics = (poll * HZ) / 8000; |
1152 | if (tics * 8000 == poll * HZ) { |
1153 | dsp_tics = tics; |
1154 | dsp_poll = poll; |
1155 | if (poll >= 64) |
1156 | break; |
1157 | } |
1158 | poll++; |
1159 | } |
1160 | } |
1161 | if (dsp_poll == 0) { |
1162 | printk(KERN_INFO "mISDN_dsp: There is no multiple of kernel " |
1163 | "clock that equals exactly the duration of 8-256 " |
1164 | "samples. (Choose kernel clock speed like 100, 250, " |
1165 | "300, 1000)\n" ); |
1166 | err = -EINVAL; |
1167 | return err; |
1168 | } |
1169 | printk(KERN_INFO "mISDN_dsp: DSP clocks every %d samples. This equals " |
1170 | "%d jiffies.\n" , dsp_poll, dsp_tics); |
1171 | |
1172 | /* init conversion tables */ |
1173 | dsp_audio_generate_law_tables(); |
1174 | dsp_silence = (dsp_options & DSP_OPT_ULAW) ? 0xff : 0x2a; |
1175 | dsp_audio_law_to_s32 = (dsp_options & DSP_OPT_ULAW) ? |
1176 | dsp_audio_ulaw_to_s32 : dsp_audio_alaw_to_s32; |
1177 | dsp_audio_generate_s2law_table(); |
1178 | dsp_audio_generate_seven(); |
1179 | dsp_audio_generate_mix_table(); |
1180 | if (dsp_options & DSP_OPT_ULAW) |
1181 | dsp_audio_generate_ulaw_samples(); |
1182 | dsp_audio_generate_volume_changes(); |
1183 | |
1184 | err = dsp_pipeline_module_init(); |
1185 | if (err) { |
1186 | printk(KERN_ERR "mISDN_dsp: Can't initialize pipeline, " |
1187 | "error(%d)\n" , err); |
1188 | return err; |
1189 | } |
1190 | |
1191 | err = mISDN_register_Bprotocol(&DSP); |
1192 | if (err) { |
1193 | printk(KERN_ERR "Can't register %s error(%d)\n" , DSP.name, err); |
1194 | return err; |
1195 | } |
1196 | |
1197 | /* set sample timer */ |
1198 | timer_setup(&dsp_spl_tl, dsp_cmx_send, 0); |
1199 | dsp_spl_tl.expires = jiffies + dsp_tics; |
1200 | dsp_spl_jiffies = dsp_spl_tl.expires; |
1201 | add_timer(timer: &dsp_spl_tl); |
1202 | |
1203 | return 0; |
1204 | } |
1205 | |
1206 | |
1207 | static void __exit dsp_cleanup(void) |
1208 | { |
1209 | mISDN_unregister_Bprotocol(&DSP); |
1210 | |
1211 | del_timer_sync(timer: &dsp_spl_tl); |
1212 | |
1213 | if (!list_empty(head: &dsp_ilist)) { |
1214 | printk(KERN_ERR "mISDN_dsp: Audio DSP object inst list not " |
1215 | "empty.\n" ); |
1216 | } |
1217 | if (!list_empty(head: &conf_ilist)) { |
1218 | printk(KERN_ERR "mISDN_dsp: Conference list not empty. Not " |
1219 | "all memory freed.\n" ); |
1220 | } |
1221 | |
1222 | dsp_pipeline_module_exit(); |
1223 | } |
1224 | |
1225 | module_init(dsp_init); |
1226 | module_exit(dsp_cleanup); |
1227 | |