1960366cfSKarsten Keil /*
2960366cfSKarsten Keil * Author Andreas Eversberg (jolly@eversberg.eu)
3960366cfSKarsten Keil * Based on source code structure by
4960366cfSKarsten Keil * Karsten Keil (keil@isdn4linux.de)
5960366cfSKarsten Keil *
6960366cfSKarsten Keil * This file is (c) under GNU PUBLIC LICENSE
7960366cfSKarsten Keil *
8960366cfSKarsten Keil * Thanks to Karsten Keil (great drivers)
9960366cfSKarsten Keil * Cologne Chip (great chips)
10960366cfSKarsten Keil *
11960366cfSKarsten Keil * This module does:
12960366cfSKarsten Keil * Real-time tone generation
13960366cfSKarsten Keil * DTMF detection
14960366cfSKarsten Keil * Real-time cross-connection and conferrence
15960366cfSKarsten Keil * Compensate jitter due to system load and hardware fault.
16960366cfSKarsten Keil * All features are done in kernel space and will be realized
17960366cfSKarsten Keil * using hardware, if available and supported by chip set.
18960366cfSKarsten Keil * Blowfish encryption/decryption
19960366cfSKarsten Keil */
20960366cfSKarsten Keil
21960366cfSKarsten Keil /* STRUCTURE:
22960366cfSKarsten Keil *
23960366cfSKarsten Keil * The dsp module provides layer 2 for b-channels (64kbit). It provides
24960366cfSKarsten Keil * transparent audio forwarding with special digital signal processing:
25960366cfSKarsten Keil *
26960366cfSKarsten Keil * - (1) generation of tones
27960366cfSKarsten Keil * - (2) detection of dtmf tones
28960366cfSKarsten Keil * - (3) crossconnecting and conferences (clocking)
29960366cfSKarsten Keil * - (4) echo generation for delay test
30960366cfSKarsten Keil * - (5) volume control
31960366cfSKarsten Keil * - (6) disable receive data
32960366cfSKarsten Keil * - (7) pipeline
33960366cfSKarsten Keil * - (8) encryption/decryption
34960366cfSKarsten Keil *
35960366cfSKarsten Keil * Look:
36960366cfSKarsten Keil * TX RX
37960366cfSKarsten Keil * ------upper layer------
38960366cfSKarsten Keil * | ^
39960366cfSKarsten Keil * | |(6)
40960366cfSKarsten Keil * v |
41960366cfSKarsten Keil * +-----+-------------+-----+
42960366cfSKarsten Keil * |(3)(4) |
43960366cfSKarsten Keil * | CMX |
44960366cfSKarsten Keil * | |
45960366cfSKarsten Keil * | +-------------+
46960366cfSKarsten Keil * | | ^
47960366cfSKarsten Keil * | | |
48960366cfSKarsten Keil * |+---------+| +----+----+
49960366cfSKarsten Keil * ||(1) || |(2) |
50960366cfSKarsten Keil * || || | |
51960366cfSKarsten Keil * || Tones || | DTMF |
52960366cfSKarsten Keil * || || | |
53960366cfSKarsten Keil * || || | |
54960366cfSKarsten Keil * |+----+----+| +----+----+
55960366cfSKarsten Keil * +-----+-----+ ^
56960366cfSKarsten Keil * | |
57960366cfSKarsten Keil * v |
58960366cfSKarsten Keil * +----+----+ +----+----+
59960366cfSKarsten Keil * |(5) | |(5) |
60960366cfSKarsten Keil * | | | |
61960366cfSKarsten Keil * |TX Volume| |RX Volume|
62960366cfSKarsten Keil * | | | |
63960366cfSKarsten Keil * | | | |
64960366cfSKarsten Keil * +----+----+ +----+----+
65960366cfSKarsten Keil * | ^
66960366cfSKarsten Keil * | |
67960366cfSKarsten Keil * v |
68960366cfSKarsten Keil * +----+-------------+----+
69960366cfSKarsten Keil * |(7) |
70960366cfSKarsten Keil * | |
71960366cfSKarsten Keil * | Pipeline Processing |
72960366cfSKarsten Keil * | |
73960366cfSKarsten Keil * | |
74960366cfSKarsten Keil * +----+-------------+----+
75960366cfSKarsten Keil * | ^
76960366cfSKarsten Keil * | |
77960366cfSKarsten Keil * v |
78960366cfSKarsten Keil * +----+----+ +----+----+
79960366cfSKarsten Keil * |(8) | |(8) |
80960366cfSKarsten Keil * | | | |
81960366cfSKarsten Keil * | Encrypt | | Decrypt |
82960366cfSKarsten Keil * | | | |
83960366cfSKarsten Keil * | | | |
84960366cfSKarsten Keil * +----+----+ +----+----+
85960366cfSKarsten Keil * | ^
86960366cfSKarsten Keil * | |
87960366cfSKarsten Keil * v |
88960366cfSKarsten Keil * ------card layer------
89960366cfSKarsten Keil * TX RX
90960366cfSKarsten Keil *
91960366cfSKarsten Keil * Above you can see the logical data flow. If software is used to do the
92960366cfSKarsten Keil * process, it is actually the real data flow. If hardware is used, data
93960366cfSKarsten Keil * may not flow, but hardware commands to the card, to provide the data flow
94960366cfSKarsten Keil * as shown.
95960366cfSKarsten Keil *
96960366cfSKarsten Keil * NOTE: The channel must be activated in order to make dsp work, even if
97960366cfSKarsten Keil * no data flow to the upper layer is intended. Activation can be done
98960366cfSKarsten Keil * after and before controlling the setting using PH_CONTROL requests.
99960366cfSKarsten Keil *
100960366cfSKarsten Keil * DTMF: Will be detected by hardware if possible. It is done before CMX
101960366cfSKarsten Keil * processing.
102960366cfSKarsten Keil *
103960366cfSKarsten Keil * Tones: Will be generated via software if endless looped audio fifos are
104960366cfSKarsten Keil * not supported by hardware. Tones will override all data from CMX.
105960366cfSKarsten Keil * It is not required to join a conference to use tones at any time.
106960366cfSKarsten Keil *
107960366cfSKarsten Keil * CMX: Is transparent when not used. When it is used, it will do
108960366cfSKarsten Keil * crossconnections and conferences via software if not possible through
109960366cfSKarsten Keil * hardware. If hardware capability is available, hardware is used.
110960366cfSKarsten Keil *
111af901ca1SAndré Goddard Rosa * Echo: Is generated by CMX and is used to check performance of hard and
112960366cfSKarsten Keil * software CMX.
113960366cfSKarsten Keil *
114960366cfSKarsten Keil * The CMX has special functions for conferences with one, two and more
115960366cfSKarsten Keil * members. It will allow different types of data flow. Receive and transmit
11608a7e621SMasahiro Yamada * data to/form upper layer may be switched on/off individually without losing
117960366cfSKarsten Keil * features of CMX, Tones and DTMF.
118960366cfSKarsten Keil *
119960366cfSKarsten Keil * Echo Cancellation: Sometimes we like to cancel echo from the interface.
120960366cfSKarsten Keil * Note that a VoIP call may not have echo caused by the IP phone. The echo
121960366cfSKarsten Keil * is generated by the telephone line connected to it. Because the delay
122960366cfSKarsten Keil * is high, it becomes an echo. RESULT: Echo Cachelation is required if
123960366cfSKarsten Keil * both echo AND delay is applied to an interface.
124960366cfSKarsten Keil * Remember that software CMX always generates a more or less delay.
125960366cfSKarsten Keil *
126960366cfSKarsten Keil * If all used features can be realized in hardware, and if transmit and/or
127960366cfSKarsten Keil * receive data ist disabled, the card may not send/receive any data at all.
12825985edcSLucas De Marchi * Not receiving is useful if only announcements are played. Not sending is
12925985edcSLucas De Marchi * useful if an answering machine records audio. Not sending and receiving is
13025985edcSLucas De Marchi * useful during most states of the call. If supported by hardware, tones
131960366cfSKarsten Keil * will be played without cpu load. Small PBXs and NT-Mode applications will
132960366cfSKarsten Keil * not need expensive hardware when processing calls.
133960366cfSKarsten Keil *
134960366cfSKarsten Keil *
135960366cfSKarsten Keil * LOCKING:
136960366cfSKarsten Keil *
137960366cfSKarsten Keil * When data is received from upper or lower layer (card), the complete dsp
138960366cfSKarsten Keil * module is locked by a global lock. This lock MUST lock irq, because it
139960366cfSKarsten Keil * must lock timer events by DSP poll timer.
140960366cfSKarsten Keil * When data is ready to be transmitted down, the data is queued and sent
141960366cfSKarsten Keil * outside lock and timer event.
142960366cfSKarsten Keil * PH_CONTROL must not change any settings, join or split conference members
143960366cfSKarsten Keil * during process of data.
144960366cfSKarsten Keil *
145960366cfSKarsten Keil * HDLC:
146960366cfSKarsten Keil *
147960366cfSKarsten Keil * It works quite the same as transparent, except that HDLC data is forwarded
148960366cfSKarsten Keil * to all other conference members if no hardware bridging is possible.
149960366cfSKarsten Keil * Send data will be writte to sendq. Sendq will be sent if confirm is received.
150960366cfSKarsten Keil * Conference cannot join, if one member is not hdlc.
151960366cfSKarsten Keil *
152960366cfSKarsten Keil */
153960366cfSKarsten Keil
154960366cfSKarsten Keil #include <linux/delay.h>
1555a0e3ad6STejun Heo #include <linux/gfp.h>
156960366cfSKarsten Keil #include <linux/mISDNif.h>
157960366cfSKarsten Keil #include <linux/mISDNdsp.h>
158960366cfSKarsten Keil #include <linux/module.h>
159960366cfSKarsten Keil #include <linux/vmalloc.h>
160960366cfSKarsten Keil #include "core.h"
161960366cfSKarsten Keil #include "dsp.h"
162960366cfSKarsten Keil
1635b834354SHannes Eder static const char *mISDN_dsp_revision = "2.0";
164960366cfSKarsten Keil
165960366cfSKarsten Keil static int debug;
166960366cfSKarsten Keil static int options;
167960366cfSKarsten Keil static int poll;
168960366cfSKarsten Keil static int dtmfthreshold = 100;
169960366cfSKarsten Keil
170960366cfSKarsten Keil MODULE_AUTHOR("Andreas Eversberg");
171960366cfSKarsten Keil module_param(debug, uint, S_IRUGO | S_IWUSR);
172960366cfSKarsten Keil module_param(options, uint, S_IRUGO | S_IWUSR);
173960366cfSKarsten Keil module_param(poll, uint, S_IRUGO | S_IWUSR);
174960366cfSKarsten Keil module_param(dtmfthreshold, uint, S_IRUGO | S_IWUSR);
175*2ebb87f4SJeff Johnson MODULE_DESCRIPTION("mISDN driver for Digital Audio Processing of transparent data");
176960366cfSKarsten Keil MODULE_LICENSE("GPL");
177960366cfSKarsten Keil
178960366cfSKarsten Keil /*int spinnest = 0;*/
179960366cfSKarsten Keil
18077053fb7SShixin Liu DEFINE_SPINLOCK(dsp_lock); /* global dsp lock */
1815979415dSShixin Liu LIST_HEAD(dsp_ilist);
1825979415dSShixin Liu LIST_HEAD(conf_ilist);
183960366cfSKarsten Keil int dsp_debug;
184960366cfSKarsten Keil int dsp_options;
185960366cfSKarsten Keil int dsp_poll, dsp_tics;
186960366cfSKarsten Keil
187960366cfSKarsten Keil /* check if rx may be turned off or must be turned on */
188960366cfSKarsten Keil static void
dsp_rx_off_member(struct dsp * dsp)189960366cfSKarsten Keil dsp_rx_off_member(struct dsp *dsp)
190960366cfSKarsten Keil {
191960366cfSKarsten Keil struct mISDN_ctrl_req cq;
192960366cfSKarsten Keil int rx_off = 1;
193960366cfSKarsten Keil
1948dd2f36fSAndreas Eversberg memset(&cq, 0, sizeof(cq));
1958dd2f36fSAndreas Eversberg
196960366cfSKarsten Keil if (!dsp->features_rx_off)
197960366cfSKarsten Keil return;
198960366cfSKarsten Keil
199960366cfSKarsten Keil /* not disabled */
200960366cfSKarsten Keil if (!dsp->rx_disabled)
201960366cfSKarsten Keil rx_off = 0;
202960366cfSKarsten Keil /* software dtmf */
203960366cfSKarsten Keil else if (dsp->dtmf.software)
204960366cfSKarsten Keil rx_off = 0;
205960366cfSKarsten Keil /* echo in software */
206bc138ec4SAndreas Eversberg else if (dsp->echo.software)
207960366cfSKarsten Keil rx_off = 0;
208960366cfSKarsten Keil /* bridge in software */
209bc138ec4SAndreas Eversberg else if (dsp->conf && dsp->conf->software)
210960366cfSKarsten Keil rx_off = 0;
211bc138ec4SAndreas Eversberg /* data is not required by user space and not required
212bc138ec4SAndreas Eversberg * for echo dtmf detection, soft-echo, soft-bridging */
213960366cfSKarsten Keil
214960366cfSKarsten Keil if (rx_off == dsp->rx_is_off)
215960366cfSKarsten Keil return;
216960366cfSKarsten Keil
217960366cfSKarsten Keil if (!dsp->ch.peer) {
218960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
219960366cfSKarsten Keil printk(KERN_DEBUG "%s: no peer, no rx_off\n",
220960366cfSKarsten Keil __func__);
221960366cfSKarsten Keil return;
222960366cfSKarsten Keil }
223960366cfSKarsten Keil cq.op = MISDN_CTRL_RX_OFF;
224960366cfSKarsten Keil cq.p1 = rx_off;
225960366cfSKarsten Keil if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) {
226960366cfSKarsten Keil printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n",
227960366cfSKarsten Keil __func__);
228960366cfSKarsten Keil return;
229960366cfSKarsten Keil }
230960366cfSKarsten Keil dsp->rx_is_off = rx_off;
231960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
232960366cfSKarsten Keil printk(KERN_DEBUG "%s: %s set rx_off = %d\n",
233960366cfSKarsten Keil __func__, dsp->name, rx_off);
234960366cfSKarsten Keil }
235960366cfSKarsten Keil static void
dsp_rx_off(struct dsp * dsp)236960366cfSKarsten Keil dsp_rx_off(struct dsp *dsp)
237960366cfSKarsten Keil {
238960366cfSKarsten Keil struct dsp_conf_member *member;
239960366cfSKarsten Keil
240960366cfSKarsten Keil if (dsp_options & DSP_OPT_NOHARDWARE)
241960366cfSKarsten Keil return;
242960366cfSKarsten Keil
243960366cfSKarsten Keil /* no conf */
244960366cfSKarsten Keil if (!dsp->conf) {
245960366cfSKarsten Keil dsp_rx_off_member(dsp);
246960366cfSKarsten Keil return;
247960366cfSKarsten Keil }
248960366cfSKarsten Keil /* check all members in conf */
249960366cfSKarsten Keil list_for_each_entry(member, &dsp->conf->mlist, list) {
250960366cfSKarsten Keil dsp_rx_off_member(member->dsp);
251960366cfSKarsten Keil }
252960366cfSKarsten Keil }
253960366cfSKarsten Keil
2548dd2f36fSAndreas Eversberg /* enable "fill empty" feature */
2558dd2f36fSAndreas Eversberg static void
dsp_fill_empty(struct dsp * dsp)2568dd2f36fSAndreas Eversberg dsp_fill_empty(struct dsp *dsp)
2578dd2f36fSAndreas Eversberg {
2588dd2f36fSAndreas Eversberg struct mISDN_ctrl_req cq;
2598dd2f36fSAndreas Eversberg
2608dd2f36fSAndreas Eversberg memset(&cq, 0, sizeof(cq));
2618dd2f36fSAndreas Eversberg
2628dd2f36fSAndreas Eversberg if (!dsp->ch.peer) {
2638dd2f36fSAndreas Eversberg if (dsp_debug & DEBUG_DSP_CORE)
2648dd2f36fSAndreas Eversberg printk(KERN_DEBUG "%s: no peer, no fill_empty\n",
2658dd2f36fSAndreas Eversberg __func__);
2668dd2f36fSAndreas Eversberg return;
2678dd2f36fSAndreas Eversberg }
2688dd2f36fSAndreas Eversberg cq.op = MISDN_CTRL_FILL_EMPTY;
2698dd2f36fSAndreas Eversberg cq.p1 = 1;
2706d1ee48fSKarsten Keil cq.p2 = dsp_silence;
2718dd2f36fSAndreas Eversberg if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) {
2728dd2f36fSAndreas Eversberg printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n",
2738dd2f36fSAndreas Eversberg __func__);
2748dd2f36fSAndreas Eversberg return;
2758dd2f36fSAndreas Eversberg }
2768dd2f36fSAndreas Eversberg if (dsp_debug & DEBUG_DSP_CORE)
2778dd2f36fSAndreas Eversberg printk(KERN_DEBUG "%s: %s set fill_empty = 1\n",
2788dd2f36fSAndreas Eversberg __func__, dsp->name);
2798dd2f36fSAndreas Eversberg }
2808dd2f36fSAndreas Eversberg
281960366cfSKarsten Keil static int
dsp_control_req(struct dsp * dsp,struct mISDNhead * hh,struct sk_buff * skb)282960366cfSKarsten Keil dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb)
283960366cfSKarsten Keil {
284960366cfSKarsten Keil struct sk_buff *nskb;
285960366cfSKarsten Keil int ret = 0;
286960366cfSKarsten Keil int cont;
287960366cfSKarsten Keil u8 *data;
288960366cfSKarsten Keil int len;
289960366cfSKarsten Keil
2900d63c27dSDan Carpenter if (skb->len < sizeof(int)) {
291960366cfSKarsten Keil printk(KERN_ERR "%s: PH_CONTROL message too short\n", __func__);
2920d63c27dSDan Carpenter return -EINVAL;
2930d63c27dSDan Carpenter }
294960366cfSKarsten Keil cont = *((int *)skb->data);
295960366cfSKarsten Keil len = skb->len - sizeof(int);
296960366cfSKarsten Keil data = skb->data + sizeof(int);
297960366cfSKarsten Keil
298960366cfSKarsten Keil switch (cont) {
299960366cfSKarsten Keil case DTMF_TONE_START: /* turn on DTMF */
300960366cfSKarsten Keil if (dsp->hdlc) {
301960366cfSKarsten Keil ret = -EINVAL;
302960366cfSKarsten Keil break;
303960366cfSKarsten Keil }
304960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
305960366cfSKarsten Keil printk(KERN_DEBUG "%s: start dtmf\n", __func__);
306960366cfSKarsten Keil if (len == sizeof(int)) {
307c6a2e587SAndreas Eversberg if (dsp_debug & DEBUG_DSP_CORE)
308960366cfSKarsten Keil printk(KERN_NOTICE "changing DTMF Threshold "
309960366cfSKarsten Keil "to %d\n", *((int *)data));
310960366cfSKarsten Keil dsp->dtmf.treshold = (*(int *)data) * 10000;
311960366cfSKarsten Keil }
312b0579d74SAndreas Eversberg dsp->dtmf.enable = 1;
313960366cfSKarsten Keil /* init goertzel */
314960366cfSKarsten Keil dsp_dtmf_goertzel_init(dsp);
315960366cfSKarsten Keil
316960366cfSKarsten Keil /* check dtmf hardware */
317960366cfSKarsten Keil dsp_dtmf_hardware(dsp);
318b5df5a5cSAndreas Eversberg dsp_rx_off(dsp);
319960366cfSKarsten Keil break;
320960366cfSKarsten Keil case DTMF_TONE_STOP: /* turn off DTMF */
321960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
322960366cfSKarsten Keil printk(KERN_DEBUG "%s: stop dtmf\n", __func__);
323b0579d74SAndreas Eversberg dsp->dtmf.enable = 0;
324960366cfSKarsten Keil dsp->dtmf.hardware = 0;
325960366cfSKarsten Keil dsp->dtmf.software = 0;
326960366cfSKarsten Keil break;
327960366cfSKarsten Keil case DSP_CONF_JOIN: /* join / update conference */
328960366cfSKarsten Keil if (len < sizeof(int)) {
329960366cfSKarsten Keil ret = -EINVAL;
330960366cfSKarsten Keil break;
331960366cfSKarsten Keil }
332960366cfSKarsten Keil if (*((u32 *)data) == 0)
333960366cfSKarsten Keil goto conf_split;
334960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
335960366cfSKarsten Keil printk(KERN_DEBUG "%s: join conference %d\n",
336960366cfSKarsten Keil __func__, *((u32 *)data));
337960366cfSKarsten Keil ret = dsp_cmx_conf(dsp, *((u32 *)data));
338960366cfSKarsten Keil /* dsp_cmx_hardware will also be called here */
339960366cfSKarsten Keil dsp_rx_off(dsp);
340960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CMX)
341960366cfSKarsten Keil dsp_cmx_debug(dsp);
342960366cfSKarsten Keil break;
343960366cfSKarsten Keil case DSP_CONF_SPLIT: /* remove from conference */
344960366cfSKarsten Keil conf_split:
345960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
346960366cfSKarsten Keil printk(KERN_DEBUG "%s: release conference\n", __func__);
347960366cfSKarsten Keil ret = dsp_cmx_conf(dsp, 0);
348960366cfSKarsten Keil /* dsp_cmx_hardware will also be called here */
349960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CMX)
350960366cfSKarsten Keil dsp_cmx_debug(dsp);
351960366cfSKarsten Keil dsp_rx_off(dsp);
352960366cfSKarsten Keil break;
353960366cfSKarsten Keil case DSP_TONE_PATT_ON: /* play tone */
354960366cfSKarsten Keil if (dsp->hdlc) {
355960366cfSKarsten Keil ret = -EINVAL;
356960366cfSKarsten Keil break;
357960366cfSKarsten Keil }
358960366cfSKarsten Keil if (len < sizeof(int)) {
359960366cfSKarsten Keil ret = -EINVAL;
360960366cfSKarsten Keil break;
361960366cfSKarsten Keil }
362960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
363960366cfSKarsten Keil printk(KERN_DEBUG "%s: turn tone 0x%x on\n",
364960366cfSKarsten Keil __func__, *((int *)skb->data));
365960366cfSKarsten Keil ret = dsp_tone(dsp, *((int *)data));
366960366cfSKarsten Keil if (!ret) {
367960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
368960366cfSKarsten Keil dsp_rx_off(dsp);
369960366cfSKarsten Keil }
370960366cfSKarsten Keil if (!dsp->tone.tone)
371960366cfSKarsten Keil goto tone_off;
372960366cfSKarsten Keil break;
373960366cfSKarsten Keil case DSP_TONE_PATT_OFF: /* stop tone */
374960366cfSKarsten Keil if (dsp->hdlc) {
375960366cfSKarsten Keil ret = -EINVAL;
376960366cfSKarsten Keil break;
377960366cfSKarsten Keil }
378960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
379960366cfSKarsten Keil printk(KERN_DEBUG "%s: turn tone off\n", __func__);
380960366cfSKarsten Keil dsp_tone(dsp, 0);
381960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
382960366cfSKarsten Keil dsp_rx_off(dsp);
383960366cfSKarsten Keil /* reset tx buffers (user space data) */
384960366cfSKarsten Keil tone_off:
385960366cfSKarsten Keil dsp->rx_W = 0;
386960366cfSKarsten Keil dsp->rx_R = 0;
387960366cfSKarsten Keil break;
388960366cfSKarsten Keil case DSP_VOL_CHANGE_TX: /* change volume */
389960366cfSKarsten Keil if (dsp->hdlc) {
390960366cfSKarsten Keil ret = -EINVAL;
391960366cfSKarsten Keil break;
392960366cfSKarsten Keil }
393960366cfSKarsten Keil if (len < sizeof(int)) {
394960366cfSKarsten Keil ret = -EINVAL;
395960366cfSKarsten Keil break;
396960366cfSKarsten Keil }
397960366cfSKarsten Keil dsp->tx_volume = *((int *)data);
398960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
399960366cfSKarsten Keil printk(KERN_DEBUG "%s: change tx vol to %d\n",
400960366cfSKarsten Keil __func__, dsp->tx_volume);
401960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
402960366cfSKarsten Keil dsp_dtmf_hardware(dsp);
403960366cfSKarsten Keil dsp_rx_off(dsp);
404960366cfSKarsten Keil break;
405960366cfSKarsten Keil case DSP_VOL_CHANGE_RX: /* change volume */
406960366cfSKarsten Keil if (dsp->hdlc) {
407960366cfSKarsten Keil ret = -EINVAL;
408960366cfSKarsten Keil break;
409960366cfSKarsten Keil }
410960366cfSKarsten Keil if (len < sizeof(int)) {
411960366cfSKarsten Keil ret = -EINVAL;
412960366cfSKarsten Keil break;
413960366cfSKarsten Keil }
414960366cfSKarsten Keil dsp->rx_volume = *((int *)data);
415960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
416960366cfSKarsten Keil printk(KERN_DEBUG "%s: change rx vol to %d\n",
417960366cfSKarsten Keil __func__, dsp->tx_volume);
418960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
419960366cfSKarsten Keil dsp_dtmf_hardware(dsp);
420960366cfSKarsten Keil dsp_rx_off(dsp);
421960366cfSKarsten Keil break;
422960366cfSKarsten Keil case DSP_ECHO_ON: /* enable echo */
423bc138ec4SAndreas Eversberg dsp->echo.software = 1; /* soft echo */
424960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
425960366cfSKarsten Keil printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__);
426960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
427960366cfSKarsten Keil dsp_rx_off(dsp);
428960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CMX)
429960366cfSKarsten Keil dsp_cmx_debug(dsp);
430960366cfSKarsten Keil break;
431960366cfSKarsten Keil case DSP_ECHO_OFF: /* disable echo */
432bc138ec4SAndreas Eversberg dsp->echo.software = 0;
433bc138ec4SAndreas Eversberg dsp->echo.hardware = 0;
434960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
435960366cfSKarsten Keil printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__);
436960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
437960366cfSKarsten Keil dsp_rx_off(dsp);
438960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CMX)
439960366cfSKarsten Keil dsp_cmx_debug(dsp);
440960366cfSKarsten Keil break;
441960366cfSKarsten Keil case DSP_RECEIVE_ON: /* enable receive to user space */
442960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
443960366cfSKarsten Keil printk(KERN_DEBUG "%s: enable receive to user "
444960366cfSKarsten Keil "space\n", __func__);
445960366cfSKarsten Keil dsp->rx_disabled = 0;
446960366cfSKarsten Keil dsp_rx_off(dsp);
447960366cfSKarsten Keil break;
448960366cfSKarsten Keil case DSP_RECEIVE_OFF: /* disable receive to user space */
449960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
450960366cfSKarsten Keil printk(KERN_DEBUG "%s: disable receive to "
451960366cfSKarsten Keil "user space\n", __func__);
452960366cfSKarsten Keil dsp->rx_disabled = 1;
453960366cfSKarsten Keil dsp_rx_off(dsp);
454960366cfSKarsten Keil break;
455960366cfSKarsten Keil case DSP_MIX_ON: /* enable mixing of tx data */
456960366cfSKarsten Keil if (dsp->hdlc) {
457960366cfSKarsten Keil ret = -EINVAL;
458960366cfSKarsten Keil break;
459960366cfSKarsten Keil }
460960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
461960366cfSKarsten Keil printk(KERN_DEBUG "%s: enable mixing of "
462d939be3aSMasanari Iida "tx-data with conf members\n", __func__);
463960366cfSKarsten Keil dsp->tx_mix = 1;
464960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
465960366cfSKarsten Keil dsp_rx_off(dsp);
466960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CMX)
467960366cfSKarsten Keil dsp_cmx_debug(dsp);
468960366cfSKarsten Keil break;
469960366cfSKarsten Keil case DSP_MIX_OFF: /* disable mixing of tx data */
470960366cfSKarsten Keil if (dsp->hdlc) {
471960366cfSKarsten Keil ret = -EINVAL;
472960366cfSKarsten Keil break;
473960366cfSKarsten Keil }
474960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
475960366cfSKarsten Keil printk(KERN_DEBUG "%s: disable mixing of "
476d939be3aSMasanari Iida "tx-data with conf members\n", __func__);
477960366cfSKarsten Keil dsp->tx_mix = 0;
478960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
479960366cfSKarsten Keil dsp_rx_off(dsp);
480960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CMX)
481960366cfSKarsten Keil dsp_cmx_debug(dsp);
482960366cfSKarsten Keil break;
483960366cfSKarsten Keil case DSP_TXDATA_ON: /* enable txdata */
484960366cfSKarsten Keil dsp->tx_data = 1;
485960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
486960366cfSKarsten Keil printk(KERN_DEBUG "%s: enable tx-data\n", __func__);
487960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
488960366cfSKarsten Keil dsp_rx_off(dsp);
489960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CMX)
490960366cfSKarsten Keil dsp_cmx_debug(dsp);
491960366cfSKarsten Keil break;
492960366cfSKarsten Keil case DSP_TXDATA_OFF: /* disable txdata */
493960366cfSKarsten Keil dsp->tx_data = 0;
494960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
495960366cfSKarsten Keil printk(KERN_DEBUG "%s: disable tx-data\n", __func__);
496960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
497960366cfSKarsten Keil dsp_rx_off(dsp);
498960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CMX)
499960366cfSKarsten Keil dsp_cmx_debug(dsp);
500960366cfSKarsten Keil break;
501960366cfSKarsten Keil case DSP_DELAY: /* use delay algorithm instead of dynamic
502960366cfSKarsten Keil jitter algorithm */
503960366cfSKarsten Keil if (dsp->hdlc) {
504960366cfSKarsten Keil ret = -EINVAL;
505960366cfSKarsten Keil break;
506960366cfSKarsten Keil }
507960366cfSKarsten Keil if (len < sizeof(int)) {
508960366cfSKarsten Keil ret = -EINVAL;
509960366cfSKarsten Keil break;
510960366cfSKarsten Keil }
511960366cfSKarsten Keil dsp->cmx_delay = (*((int *)data)) << 3;
51219af5cdbSMartin Olsson /* milliseconds to samples */
513960366cfSKarsten Keil if (dsp->cmx_delay >= (CMX_BUFF_HALF >> 1))
514960366cfSKarsten Keil /* clip to half of maximum usable buffer
515960366cfSKarsten Keil (half of half buffer) */
516960366cfSKarsten Keil dsp->cmx_delay = (CMX_BUFF_HALF >> 1) - 1;
517960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
518960366cfSKarsten Keil printk(KERN_DEBUG "%s: use delay algorithm to "
519960366cfSKarsten Keil "compensate jitter (%d samples)\n",
520960366cfSKarsten Keil __func__, dsp->cmx_delay);
521960366cfSKarsten Keil break;
522960366cfSKarsten Keil case DSP_JITTER: /* use dynamic jitter algorithm instead of
523960366cfSKarsten Keil delay algorithm */
524960366cfSKarsten Keil if (dsp->hdlc) {
525960366cfSKarsten Keil ret = -EINVAL;
526960366cfSKarsten Keil break;
527960366cfSKarsten Keil }
528960366cfSKarsten Keil dsp->cmx_delay = 0;
529960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
530960366cfSKarsten Keil printk(KERN_DEBUG "%s: use jitter algorithm to "
531960366cfSKarsten Keil "compensate jitter\n", __func__);
532960366cfSKarsten Keil break;
533960366cfSKarsten Keil case DSP_TX_DEJITTER: /* use dynamic jitter algorithm for tx-buffer */
534960366cfSKarsten Keil if (dsp->hdlc) {
535960366cfSKarsten Keil ret = -EINVAL;
536960366cfSKarsten Keil break;
537960366cfSKarsten Keil }
538960366cfSKarsten Keil dsp->tx_dejitter = 1;
539960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
540960366cfSKarsten Keil printk(KERN_DEBUG "%s: use dejitter on TX "
541960366cfSKarsten Keil "buffer\n", __func__);
542960366cfSKarsten Keil break;
543960366cfSKarsten Keil case DSP_TX_DEJ_OFF: /* use tx-buffer without dejittering*/
544960366cfSKarsten Keil if (dsp->hdlc) {
545960366cfSKarsten Keil ret = -EINVAL;
546960366cfSKarsten Keil break;
547960366cfSKarsten Keil }
548960366cfSKarsten Keil dsp->tx_dejitter = 0;
549960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
550960366cfSKarsten Keil printk(KERN_DEBUG "%s: use TX buffer without "
551960366cfSKarsten Keil "dejittering\n", __func__);
552960366cfSKarsten Keil break;
553960366cfSKarsten Keil case DSP_PIPELINE_CFG:
554960366cfSKarsten Keil if (dsp->hdlc) {
555960366cfSKarsten Keil ret = -EINVAL;
556960366cfSKarsten Keil break;
557960366cfSKarsten Keil }
558960366cfSKarsten Keil if (len > 0 && ((char *)data)[len - 1]) {
559960366cfSKarsten Keil printk(KERN_DEBUG "%s: pipeline config string "
560960366cfSKarsten Keil "is not NULL terminated!\n", __func__);
561960366cfSKarsten Keil ret = -EINVAL;
562960366cfSKarsten Keil } else {
563960366cfSKarsten Keil dsp->pipeline.inuse = 1;
564960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
565960366cfSKarsten Keil ret = dsp_pipeline_build(&dsp->pipeline,
566eac74af9SKarsten Keil len > 0 ? data : NULL);
567960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
568960366cfSKarsten Keil dsp_rx_off(dsp);
569960366cfSKarsten Keil }
570960366cfSKarsten Keil break;
571960366cfSKarsten Keil case DSP_BF_ENABLE_KEY: /* turn blowfish on */
572960366cfSKarsten Keil if (dsp->hdlc) {
573960366cfSKarsten Keil ret = -EINVAL;
574960366cfSKarsten Keil break;
575960366cfSKarsten Keil }
576960366cfSKarsten Keil if (len < 4 || len > 56) {
577960366cfSKarsten Keil ret = -EINVAL;
578960366cfSKarsten Keil break;
579960366cfSKarsten Keil }
580960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
581960366cfSKarsten Keil printk(KERN_DEBUG "%s: turn blowfish on (key "
582960366cfSKarsten Keil "not shown)\n", __func__);
583960366cfSKarsten Keil ret = dsp_bf_init(dsp, (u8 *)data, len);
584960366cfSKarsten Keil /* set new cont */
585960366cfSKarsten Keil if (!ret)
586960366cfSKarsten Keil cont = DSP_BF_ACCEPT;
587960366cfSKarsten Keil else
588960366cfSKarsten Keil cont = DSP_BF_REJECT;
589960366cfSKarsten Keil /* send indication if it worked to set it */
590960366cfSKarsten Keil nskb = _alloc_mISDN_skb(PH_CONTROL_IND, MISDN_ID_ANY,
591960366cfSKarsten Keil sizeof(int), &cont, GFP_ATOMIC);
592960366cfSKarsten Keil if (nskb) {
593960366cfSKarsten Keil if (dsp->up) {
594960366cfSKarsten Keil if (dsp->up->send(dsp->up, nskb))
595960366cfSKarsten Keil dev_kfree_skb(nskb);
596960366cfSKarsten Keil } else
597960366cfSKarsten Keil dev_kfree_skb(nskb);
598960366cfSKarsten Keil }
599960366cfSKarsten Keil if (!ret) {
600960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
601960366cfSKarsten Keil dsp_dtmf_hardware(dsp);
602960366cfSKarsten Keil dsp_rx_off(dsp);
603960366cfSKarsten Keil }
604960366cfSKarsten Keil break;
605960366cfSKarsten Keil case DSP_BF_DISABLE: /* turn blowfish off */
606960366cfSKarsten Keil if (dsp->hdlc) {
607960366cfSKarsten Keil ret = -EINVAL;
608960366cfSKarsten Keil break;
609960366cfSKarsten Keil }
610960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
611960366cfSKarsten Keil printk(KERN_DEBUG "%s: turn blowfish off\n", __func__);
612960366cfSKarsten Keil dsp_bf_cleanup(dsp);
613960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
614960366cfSKarsten Keil dsp_dtmf_hardware(dsp);
615960366cfSKarsten Keil dsp_rx_off(dsp);
616960366cfSKarsten Keil break;
617960366cfSKarsten Keil default:
618960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
619960366cfSKarsten Keil printk(KERN_DEBUG "%s: ctrl req %x unhandled\n",
620960366cfSKarsten Keil __func__, cont);
621960366cfSKarsten Keil ret = -EINVAL;
622960366cfSKarsten Keil }
623960366cfSKarsten Keil return ret;
624960366cfSKarsten Keil }
625960366cfSKarsten Keil
626960366cfSKarsten Keil static void
get_features(struct mISDNchannel * ch)627960366cfSKarsten Keil get_features(struct mISDNchannel *ch)
628960366cfSKarsten Keil {
629960366cfSKarsten Keil struct dsp *dsp = container_of(ch, struct dsp, ch);
630960366cfSKarsten Keil struct mISDN_ctrl_req cq;
631960366cfSKarsten Keil
632960366cfSKarsten Keil if (!ch->peer) {
633960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
634960366cfSKarsten Keil printk(KERN_DEBUG "%s: no peer, no features\n",
635960366cfSKarsten Keil __func__);
636960366cfSKarsten Keil return;
637960366cfSKarsten Keil }
638960366cfSKarsten Keil memset(&cq, 0, sizeof(cq));
639960366cfSKarsten Keil cq.op = MISDN_CTRL_GETOP;
640960366cfSKarsten Keil if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq) < 0) {
641960366cfSKarsten Keil printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n",
642960366cfSKarsten Keil __func__);
643960366cfSKarsten Keil return;
644960366cfSKarsten Keil }
645960366cfSKarsten Keil if (cq.op & MISDN_CTRL_RX_OFF)
646960366cfSKarsten Keil dsp->features_rx_off = 1;
6478dd2f36fSAndreas Eversberg if (cq.op & MISDN_CTRL_FILL_EMPTY)
6488dd2f36fSAndreas Eversberg dsp->features_fill_empty = 1;
6498dd2f36fSAndreas Eversberg if (dsp_options & DSP_OPT_NOHARDWARE)
6508dd2f36fSAndreas Eversberg return;
651960366cfSKarsten Keil if ((cq.op & MISDN_CTRL_HW_FEATURES_OP)) {
652960366cfSKarsten Keil cq.op = MISDN_CTRL_HW_FEATURES;
653960366cfSKarsten Keil *((u_long *)&cq.p1) = (u_long)&dsp->features;
654960366cfSKarsten Keil if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq)) {
655960366cfSKarsten Keil printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n",
656960366cfSKarsten Keil __func__);
657960366cfSKarsten Keil }
658960366cfSKarsten Keil } else
659960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
660960366cfSKarsten Keil printk(KERN_DEBUG "%s: features not supported for %s\n",
661960366cfSKarsten Keil __func__, dsp->name);
662960366cfSKarsten Keil }
663960366cfSKarsten Keil
664960366cfSKarsten Keil static int
dsp_function(struct mISDNchannel * ch,struct sk_buff * skb)665960366cfSKarsten Keil dsp_function(struct mISDNchannel *ch, struct sk_buff *skb)
666960366cfSKarsten Keil {
667960366cfSKarsten Keil struct dsp *dsp = container_of(ch, struct dsp, ch);
668960366cfSKarsten Keil struct mISDNhead *hh;
669960366cfSKarsten Keil int ret = 0;
670b5df5a5cSAndreas Eversberg u8 *digits = NULL;
671960366cfSKarsten Keil u_long flags;
672960366cfSKarsten Keil
673960366cfSKarsten Keil hh = mISDN_HEAD_P(skb);
674960366cfSKarsten Keil switch (hh->prim) {
675960366cfSKarsten Keil /* FROM DOWN */
676960366cfSKarsten Keil case (PH_DATA_CNF):
677960366cfSKarsten Keil dsp->data_pending = 0;
678960366cfSKarsten Keil /* trigger next hdlc frame, if any */
679960366cfSKarsten Keil if (dsp->hdlc) {
680960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
681960366cfSKarsten Keil if (dsp->b_active)
682960366cfSKarsten Keil schedule_work(&dsp->workq);
683960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
684960366cfSKarsten Keil }
685960366cfSKarsten Keil break;
686960366cfSKarsten Keil case (PH_DATA_IND):
687960366cfSKarsten Keil case (DL_DATA_IND):
688960366cfSKarsten Keil if (skb->len < 1) {
689960366cfSKarsten Keil ret = -EINVAL;
690960366cfSKarsten Keil break;
691960366cfSKarsten Keil }
692960366cfSKarsten Keil if (dsp->rx_is_off) {
693960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
694960366cfSKarsten Keil printk(KERN_DEBUG "%s: rx-data during rx_off"
695960366cfSKarsten Keil " for %s\n",
696960366cfSKarsten Keil __func__, dsp->name);
697960366cfSKarsten Keil }
698960366cfSKarsten Keil if (dsp->hdlc) {
699960366cfSKarsten Keil /* hdlc */
700960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
701960366cfSKarsten Keil dsp_cmx_hdlc(dsp, skb);
702960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
703960366cfSKarsten Keil if (dsp->rx_disabled) {
704960366cfSKarsten Keil /* if receive is not allowed */
705960366cfSKarsten Keil break;
706960366cfSKarsten Keil }
707960366cfSKarsten Keil hh->prim = DL_DATA_IND;
708960366cfSKarsten Keil if (dsp->up)
709960366cfSKarsten Keil return dsp->up->send(dsp->up, skb);
710960366cfSKarsten Keil break;
711960366cfSKarsten Keil }
712960366cfSKarsten Keil
713ba3af34eSAndreas Eversberg spin_lock_irqsave(&dsp_lock, flags);
714ba3af34eSAndreas Eversberg
715960366cfSKarsten Keil /* decrypt if enabled */
716960366cfSKarsten Keil if (dsp->bf_enable)
717960366cfSKarsten Keil dsp_bf_decrypt(dsp, skb->data, skb->len);
718960366cfSKarsten Keil /* pipeline */
719960366cfSKarsten Keil if (dsp->pipeline.inuse)
720960366cfSKarsten Keil dsp_pipeline_process_rx(&dsp->pipeline, skb->data,
7217cfa153dSAndreas Eversberg skb->len, hh->id);
722960366cfSKarsten Keil /* change volume if requested */
723960366cfSKarsten Keil if (dsp->rx_volume)
724960366cfSKarsten Keil dsp_change_volume(skb, dsp->rx_volume);
725960366cfSKarsten Keil /* check if dtmf soft decoding is turned on */
726960366cfSKarsten Keil if (dsp->dtmf.software) {
727960366cfSKarsten Keil digits = dsp_dtmf_goertzel_decode(dsp, skb->data,
728960366cfSKarsten Keil skb->len, (dsp_options & DSP_OPT_ULAW) ? 1 : 0);
729b5df5a5cSAndreas Eversberg }
730b5df5a5cSAndreas Eversberg /* we need to process receive data if software */
731bc138ec4SAndreas Eversberg if (dsp->conf && dsp->conf->software) {
732b5df5a5cSAndreas Eversberg /* process data from card at cmx */
733b5df5a5cSAndreas Eversberg dsp_cmx_receive(dsp, skb);
734b5df5a5cSAndreas Eversberg }
735b5df5a5cSAndreas Eversberg
736b5df5a5cSAndreas Eversberg spin_unlock_irqrestore(&dsp_lock, flags);
737b5df5a5cSAndreas Eversberg
738b5df5a5cSAndreas Eversberg /* send dtmf result, if any */
739b5df5a5cSAndreas Eversberg if (digits) {
740960366cfSKarsten Keil while (*digits) {
741b5df5a5cSAndreas Eversberg int k;
742bb68b1d9SHannes Eder struct sk_buff *nskb;
743960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_DTMF)
744960366cfSKarsten Keil printk(KERN_DEBUG "%s: digit"
745960366cfSKarsten Keil "(%c) to layer %s\n",
746960366cfSKarsten Keil __func__, *digits, dsp->name);
747b5df5a5cSAndreas Eversberg k = *digits | DTMF_TONE_VAL;
748960366cfSKarsten Keil nskb = _alloc_mISDN_skb(PH_CONTROL_IND,
749b5df5a5cSAndreas Eversberg MISDN_ID_ANY, sizeof(int), &k,
750960366cfSKarsten Keil GFP_ATOMIC);
751960366cfSKarsten Keil if (nskb) {
752960366cfSKarsten Keil if (dsp->up) {
753960366cfSKarsten Keil if (dsp->up->send(
754960366cfSKarsten Keil dsp->up, nskb))
755960366cfSKarsten Keil dev_kfree_skb(nskb);
756960366cfSKarsten Keil } else
757960366cfSKarsten Keil dev_kfree_skb(nskb);
758960366cfSKarsten Keil }
759960366cfSKarsten Keil digits++;
760960366cfSKarsten Keil }
761960366cfSKarsten Keil }
762960366cfSKarsten Keil if (dsp->rx_disabled) {
763960366cfSKarsten Keil /* if receive is not allowed */
764960366cfSKarsten Keil break;
765960366cfSKarsten Keil }
766960366cfSKarsten Keil hh->prim = DL_DATA_IND;
767960366cfSKarsten Keil if (dsp->up)
768960366cfSKarsten Keil return dsp->up->send(dsp->up, skb);
769960366cfSKarsten Keil break;
770960366cfSKarsten Keil case (PH_CONTROL_IND):
771960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
772960366cfSKarsten Keil printk(KERN_DEBUG "%s: PH_CONTROL INDICATION "
773960366cfSKarsten Keil "received: %x (len %d) %s\n", __func__,
774960366cfSKarsten Keil hh->id, skb->len, dsp->name);
775960366cfSKarsten Keil switch (hh->id) {
776960366cfSKarsten Keil case (DTMF_HFC_COEF): /* getting coefficients */
777960366cfSKarsten Keil if (!dsp->dtmf.hardware) {
778960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
779960366cfSKarsten Keil printk(KERN_DEBUG "%s: ignoring DTMF "
780960366cfSKarsten Keil "coefficients from HFC\n",
781960366cfSKarsten Keil __func__);
782960366cfSKarsten Keil break;
783960366cfSKarsten Keil }
784960366cfSKarsten Keil digits = dsp_dtmf_goertzel_decode(dsp, skb->data,
785960366cfSKarsten Keil skb->len, 2);
786960366cfSKarsten Keil while (*digits) {
787960366cfSKarsten Keil int k;
788960366cfSKarsten Keil struct sk_buff *nskb;
789960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_DTMF)
790960366cfSKarsten Keil printk(KERN_DEBUG "%s: digit"
791960366cfSKarsten Keil "(%c) to layer %s\n",
792960366cfSKarsten Keil __func__, *digits, dsp->name);
793960366cfSKarsten Keil k = *digits | DTMF_TONE_VAL;
794960366cfSKarsten Keil nskb = _alloc_mISDN_skb(PH_CONTROL_IND,
795960366cfSKarsten Keil MISDN_ID_ANY, sizeof(int), &k,
796960366cfSKarsten Keil GFP_ATOMIC);
797960366cfSKarsten Keil if (nskb) {
798960366cfSKarsten Keil if (dsp->up) {
799960366cfSKarsten Keil if (dsp->up->send(
800960366cfSKarsten Keil dsp->up, nskb))
801960366cfSKarsten Keil dev_kfree_skb(nskb);
802960366cfSKarsten Keil } else
803960366cfSKarsten Keil dev_kfree_skb(nskb);
804960366cfSKarsten Keil }
805960366cfSKarsten Keil digits++;
806960366cfSKarsten Keil }
807960366cfSKarsten Keil break;
808960366cfSKarsten Keil case (HFC_VOL_CHANGE_TX): /* change volume */
809960366cfSKarsten Keil if (skb->len != sizeof(int)) {
810960366cfSKarsten Keil ret = -EINVAL;
811960366cfSKarsten Keil break;
812960366cfSKarsten Keil }
813960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
814960366cfSKarsten Keil dsp->tx_volume = *((int *)skb->data);
815960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
816960366cfSKarsten Keil printk(KERN_DEBUG "%s: change tx volume to "
817960366cfSKarsten Keil "%d\n", __func__, dsp->tx_volume);
818960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
819960366cfSKarsten Keil dsp_dtmf_hardware(dsp);
820960366cfSKarsten Keil dsp_rx_off(dsp);
821960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
822960366cfSKarsten Keil break;
823960366cfSKarsten Keil default:
824960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
825960366cfSKarsten Keil printk(KERN_DEBUG "%s: ctrl ind %x unhandled "
826960366cfSKarsten Keil "%s\n", __func__, hh->id, dsp->name);
827960366cfSKarsten Keil ret = -EINVAL;
828960366cfSKarsten Keil }
829960366cfSKarsten Keil break;
830960366cfSKarsten Keil case (PH_ACTIVATE_IND):
831960366cfSKarsten Keil case (PH_ACTIVATE_CNF):
832960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
833960366cfSKarsten Keil printk(KERN_DEBUG "%s: b_channel is now active %s\n",
834960366cfSKarsten Keil __func__, dsp->name);
835960366cfSKarsten Keil /* bchannel now active */
836960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
837960366cfSKarsten Keil dsp->b_active = 1;
838960366cfSKarsten Keil dsp->data_pending = 0;
839960366cfSKarsten Keil dsp->rx_init = 1;
840960366cfSKarsten Keil /* rx_W and rx_R will be adjusted on first frame */
841960366cfSKarsten Keil dsp->rx_W = 0;
842960366cfSKarsten Keil dsp->rx_R = 0;
843960366cfSKarsten Keil memset(dsp->rx_buff, 0, sizeof(dsp->rx_buff));
844960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
845960366cfSKarsten Keil dsp_dtmf_hardware(dsp);
846960366cfSKarsten Keil dsp_rx_off(dsp);
847960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
848960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
849960366cfSKarsten Keil printk(KERN_DEBUG "%s: done with activation, sending "
850960366cfSKarsten Keil "confirm to user space. %s\n", __func__,
851960366cfSKarsten Keil dsp->name);
852960366cfSKarsten Keil /* send activation to upper layer */
853960366cfSKarsten Keil hh->prim = DL_ESTABLISH_CNF;
854960366cfSKarsten Keil if (dsp->up)
855960366cfSKarsten Keil return dsp->up->send(dsp->up, skb);
856960366cfSKarsten Keil break;
857960366cfSKarsten Keil case (PH_DEACTIVATE_IND):
858960366cfSKarsten Keil case (PH_DEACTIVATE_CNF):
859960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
860960366cfSKarsten Keil printk(KERN_DEBUG "%s: b_channel is now inactive %s\n",
861960366cfSKarsten Keil __func__, dsp->name);
862960366cfSKarsten Keil /* bchannel now inactive */
863960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
864960366cfSKarsten Keil dsp->b_active = 0;
865960366cfSKarsten Keil dsp->data_pending = 0;
866960366cfSKarsten Keil dsp_cmx_hardware(dsp->conf, dsp);
867960366cfSKarsten Keil dsp_rx_off(dsp);
868960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
869960366cfSKarsten Keil hh->prim = DL_RELEASE_CNF;
870960366cfSKarsten Keil if (dsp->up)
871960366cfSKarsten Keil return dsp->up->send(dsp->up, skb);
872960366cfSKarsten Keil break;
873960366cfSKarsten Keil /* FROM UP */
874960366cfSKarsten Keil case (DL_DATA_REQ):
875960366cfSKarsten Keil case (PH_DATA_REQ):
876960366cfSKarsten Keil if (skb->len < 1) {
877960366cfSKarsten Keil ret = -EINVAL;
878960366cfSKarsten Keil break;
879960366cfSKarsten Keil }
880960366cfSKarsten Keil if (dsp->hdlc) {
881960366cfSKarsten Keil /* hdlc */
882e4cce225SPeter Schlaile if (!dsp->b_active) {
883e4cce225SPeter Schlaile ret = -EIO;
884e4cce225SPeter Schlaile break;
885e4cce225SPeter Schlaile }
886e4cce225SPeter Schlaile hh->prim = PH_DATA_REQ;
887960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
888960366cfSKarsten Keil skb_queue_tail(&dsp->sendq, skb);
889960366cfSKarsten Keil schedule_work(&dsp->workq);
890960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
891960366cfSKarsten Keil return 0;
892960366cfSKarsten Keil }
893960366cfSKarsten Keil /* send data to tx-buffer (if no tone is played) */
894960366cfSKarsten Keil if (!dsp->tone.tone) {
895960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
896960366cfSKarsten Keil dsp_cmx_transmit(dsp, skb);
897960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
898960366cfSKarsten Keil }
899960366cfSKarsten Keil break;
900960366cfSKarsten Keil case (PH_CONTROL_REQ):
901960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
902960366cfSKarsten Keil ret = dsp_control_req(dsp, hh, skb);
903960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
904960366cfSKarsten Keil break;
905960366cfSKarsten Keil case (DL_ESTABLISH_REQ):
906960366cfSKarsten Keil case (PH_ACTIVATE_REQ):
907960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
908960366cfSKarsten Keil printk(KERN_DEBUG "%s: activating b_channel %s\n",
909960366cfSKarsten Keil __func__, dsp->name);
910960366cfSKarsten Keil if (dsp->dtmf.hardware || dsp->dtmf.software)
911960366cfSKarsten Keil dsp_dtmf_goertzel_init(dsp);
912960366cfSKarsten Keil get_features(ch);
9138dd2f36fSAndreas Eversberg /* enable fill_empty feature */
9148dd2f36fSAndreas Eversberg if (dsp->features_fill_empty)
9158dd2f36fSAndreas Eversberg dsp_fill_empty(dsp);
916960366cfSKarsten Keil /* send ph_activate */
917960366cfSKarsten Keil hh->prim = PH_ACTIVATE_REQ;
918960366cfSKarsten Keil if (ch->peer)
919960366cfSKarsten Keil return ch->recv(ch->peer, skb);
920960366cfSKarsten Keil break;
921960366cfSKarsten Keil case (DL_RELEASE_REQ):
922960366cfSKarsten Keil case (PH_DEACTIVATE_REQ):
923960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
924960366cfSKarsten Keil printk(KERN_DEBUG "%s: releasing b_channel %s\n",
925960366cfSKarsten Keil __func__, dsp->name);
926960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
927960366cfSKarsten Keil dsp->tone.tone = 0;
928960366cfSKarsten Keil dsp->tone.hardware = 0;
929960366cfSKarsten Keil dsp->tone.software = 0;
930960366cfSKarsten Keil if (timer_pending(&dsp->tone.tl))
931960366cfSKarsten Keil del_timer(&dsp->tone.tl);
932960366cfSKarsten Keil if (dsp->conf)
933960366cfSKarsten Keil dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be
934960366cfSKarsten Keil called here */
935960366cfSKarsten Keil skb_queue_purge(&dsp->sendq);
936960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
937960366cfSKarsten Keil hh->prim = PH_DEACTIVATE_REQ;
938960366cfSKarsten Keil if (ch->peer)
939960366cfSKarsten Keil return ch->recv(ch->peer, skb);
940960366cfSKarsten Keil break;
941960366cfSKarsten Keil default:
942960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
943960366cfSKarsten Keil printk(KERN_DEBUG "%s: msg %x unhandled %s\n",
944960366cfSKarsten Keil __func__, hh->prim, dsp->name);
945960366cfSKarsten Keil ret = -EINVAL;
946960366cfSKarsten Keil }
947960366cfSKarsten Keil if (!ret)
948960366cfSKarsten Keil dev_kfree_skb(skb);
949960366cfSKarsten Keil return ret;
950960366cfSKarsten Keil }
951960366cfSKarsten Keil
952960366cfSKarsten Keil static int
dsp_ctrl(struct mISDNchannel * ch,u_int cmd,void * arg)953960366cfSKarsten Keil dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
954960366cfSKarsten Keil {
955960366cfSKarsten Keil struct dsp *dsp = container_of(ch, struct dsp, ch);
956960366cfSKarsten Keil u_long flags;
957960366cfSKarsten Keil
958960366cfSKarsten Keil if (debug & DEBUG_DSP_CTRL)
959960366cfSKarsten Keil printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd);
960960366cfSKarsten Keil
961960366cfSKarsten Keil switch (cmd) {
962960366cfSKarsten Keil case OPEN_CHANNEL:
963960366cfSKarsten Keil break;
964960366cfSKarsten Keil case CLOSE_CHANNEL:
965960366cfSKarsten Keil if (dsp->ch.peer)
966960366cfSKarsten Keil dsp->ch.peer->ctrl(dsp->ch.peer, CLOSE_CHANNEL, NULL);
967960366cfSKarsten Keil
968960366cfSKarsten Keil /* wait until workqueue has finished,
969960366cfSKarsten Keil * must lock here, or we may hit send-process currently
970960366cfSKarsten Keil * queueing. */
971960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
972960366cfSKarsten Keil dsp->b_active = 0;
973960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
974960366cfSKarsten Keil /* MUST not be locked, because it waits until queue is done. */
975960366cfSKarsten Keil cancel_work_sync(&dsp->workq);
976960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
977960366cfSKarsten Keil if (timer_pending(&dsp->tone.tl))
978960366cfSKarsten Keil del_timer(&dsp->tone.tl);
979960366cfSKarsten Keil skb_queue_purge(&dsp->sendq);
980960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CTRL)
981960366cfSKarsten Keil printk(KERN_DEBUG "%s: releasing member %s\n",
982960366cfSKarsten Keil __func__, dsp->name);
983960366cfSKarsten Keil dsp->b_active = 0;
984960366cfSKarsten Keil dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be called
985960366cfSKarsten Keil here */
986960366cfSKarsten Keil dsp_pipeline_destroy(&dsp->pipeline);
987960366cfSKarsten Keil
988960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CTRL)
989960366cfSKarsten Keil printk(KERN_DEBUG "%s: remove & destroy object %s\n",
990960366cfSKarsten Keil __func__, dsp->name);
991960366cfSKarsten Keil list_del(&dsp->list);
992960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
993960366cfSKarsten Keil
994960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CTRL)
995960366cfSKarsten Keil printk(KERN_DEBUG "%s: dsp instance released\n",
996960366cfSKarsten Keil __func__);
997960366cfSKarsten Keil vfree(dsp);
998960366cfSKarsten Keil module_put(THIS_MODULE);
999960366cfSKarsten Keil break;
1000960366cfSKarsten Keil }
1001762c1adbSYang Li return 0;
1002960366cfSKarsten Keil }
1003960366cfSKarsten Keil
1004960366cfSKarsten Keil static void
dsp_send_bh(struct work_struct * work)1005960366cfSKarsten Keil dsp_send_bh(struct work_struct *work)
1006960366cfSKarsten Keil {
1007960366cfSKarsten Keil struct dsp *dsp = container_of(work, struct dsp, workq);
1008960366cfSKarsten Keil struct sk_buff *skb;
1009960366cfSKarsten Keil struct mISDNhead *hh;
1010960366cfSKarsten Keil
1011960366cfSKarsten Keil if (dsp->hdlc && dsp->data_pending)
1012960366cfSKarsten Keil return; /* wait until data has been acknowledged */
1013960366cfSKarsten Keil
1014960366cfSKarsten Keil /* send queued data */
1015960366cfSKarsten Keil while ((skb = skb_dequeue(&dsp->sendq))) {
1016960366cfSKarsten Keil /* in locked date, we must have still data in queue */
1017960366cfSKarsten Keil if (dsp->data_pending) {
1018960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CORE)
1019960366cfSKarsten Keil printk(KERN_DEBUG "%s: fifo full %s, this is "
1020960366cfSKarsten Keil "no bug!\n", __func__, dsp->name);
1021960366cfSKarsten Keil /* flush transparent data, if not acked */
1022960366cfSKarsten Keil dev_kfree_skb(skb);
1023960366cfSKarsten Keil continue;
1024960366cfSKarsten Keil }
1025960366cfSKarsten Keil hh = mISDN_HEAD_P(skb);
1026960366cfSKarsten Keil if (hh->prim == DL_DATA_REQ) {
1027960366cfSKarsten Keil /* send packet up */
1028960366cfSKarsten Keil if (dsp->up) {
1029960366cfSKarsten Keil if (dsp->up->send(dsp->up, skb))
1030960366cfSKarsten Keil dev_kfree_skb(skb);
1031960366cfSKarsten Keil } else
1032960366cfSKarsten Keil dev_kfree_skb(skb);
1033960366cfSKarsten Keil } else {
1034960366cfSKarsten Keil /* send packet down */
1035960366cfSKarsten Keil if (dsp->ch.peer) {
1036960366cfSKarsten Keil dsp->data_pending = 1;
1037960366cfSKarsten Keil if (dsp->ch.recv(dsp->ch.peer, skb)) {
1038960366cfSKarsten Keil dev_kfree_skb(skb);
1039960366cfSKarsten Keil dsp->data_pending = 0;
1040960366cfSKarsten Keil }
1041960366cfSKarsten Keil } else
1042960366cfSKarsten Keil dev_kfree_skb(skb);
1043960366cfSKarsten Keil }
1044960366cfSKarsten Keil }
1045960366cfSKarsten Keil }
1046960366cfSKarsten Keil
1047960366cfSKarsten Keil static int
dspcreate(struct channel_req * crq)1048960366cfSKarsten Keil dspcreate(struct channel_req *crq)
1049960366cfSKarsten Keil {
1050960366cfSKarsten Keil struct dsp *ndsp;
1051960366cfSKarsten Keil u_long flags;
1052960366cfSKarsten Keil
1053960366cfSKarsten Keil if (crq->protocol != ISDN_P_B_L2DSP
1054960366cfSKarsten Keil && crq->protocol != ISDN_P_B_L2DSPHDLC)
1055960366cfSKarsten Keil return -EPROTONOSUPPORT;
10561ac4594dSJoe Perches ndsp = vzalloc(sizeof(struct dsp));
1057960366cfSKarsten Keil if (!ndsp) {
1058960366cfSKarsten Keil printk(KERN_ERR "%s: vmalloc struct dsp failed\n", __func__);
1059960366cfSKarsten Keil return -ENOMEM;
1060960366cfSKarsten Keil }
1061960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_CTRL)
1062960366cfSKarsten Keil printk(KERN_DEBUG "%s: creating new dsp instance\n", __func__);
1063960366cfSKarsten Keil
1064960366cfSKarsten Keil /* default enabled */
1065960366cfSKarsten Keil INIT_WORK(&ndsp->workq, (void *)dsp_send_bh);
1066960366cfSKarsten Keil skb_queue_head_init(&ndsp->sendq);
1067960366cfSKarsten Keil ndsp->ch.send = dsp_function;
1068960366cfSKarsten Keil ndsp->ch.ctrl = dsp_ctrl;
1069960366cfSKarsten Keil ndsp->up = crq->ch;
1070960366cfSKarsten Keil crq->ch = &ndsp->ch;
1071960366cfSKarsten Keil if (crq->protocol == ISDN_P_B_L2DSP) {
1072960366cfSKarsten Keil crq->protocol = ISDN_P_B_RAW;
1073960366cfSKarsten Keil ndsp->hdlc = 0;
1074960366cfSKarsten Keil } else {
1075960366cfSKarsten Keil crq->protocol = ISDN_P_B_HDLC;
1076960366cfSKarsten Keil ndsp->hdlc = 1;
1077960366cfSKarsten Keil }
1078960366cfSKarsten Keil if (!try_module_get(THIS_MODULE))
1079960366cfSKarsten Keil printk(KERN_WARNING "%s:cannot get module\n",
1080960366cfSKarsten Keil __func__);
1081960366cfSKarsten Keil
1082960366cfSKarsten Keil sprintf(ndsp->name, "DSP_C%x(0x%p)",
1083960366cfSKarsten Keil ndsp->up->st->dev->id + 1, ndsp);
1084960366cfSKarsten Keil /* set frame size to start */
1085960366cfSKarsten Keil ndsp->features.hfc_id = -1; /* current PCM id */
1086960366cfSKarsten Keil ndsp->features.pcm_id = -1; /* current PCM id */
1087960366cfSKarsten Keil ndsp->pcm_slot_rx = -1; /* current CPM slot */
1088960366cfSKarsten Keil ndsp->pcm_slot_tx = -1;
1089960366cfSKarsten Keil ndsp->pcm_bank_rx = -1;
1090960366cfSKarsten Keil ndsp->pcm_bank_tx = -1;
1091960366cfSKarsten Keil ndsp->hfc_conf = -1; /* current conference number */
1092960366cfSKarsten Keil /* set tone timer */
1093e313ac12SKees Cook timer_setup(&ndsp->tone.tl, dsp_tone_timeout, 0);
1094960366cfSKarsten Keil
1095960366cfSKarsten Keil if (dtmfthreshold < 20 || dtmfthreshold > 500)
1096960366cfSKarsten Keil dtmfthreshold = 200;
1097960366cfSKarsten Keil ndsp->dtmf.treshold = dtmfthreshold * 10000;
1098960366cfSKarsten Keil
1099960366cfSKarsten Keil /* init pipeline append to list */
1100960366cfSKarsten Keil spin_lock_irqsave(&dsp_lock, flags);
1101960366cfSKarsten Keil dsp_pipeline_init(&ndsp->pipeline);
1102960366cfSKarsten Keil list_add_tail(&ndsp->list, &dsp_ilist);
1103960366cfSKarsten Keil spin_unlock_irqrestore(&dsp_lock, flags);
1104960366cfSKarsten Keil
1105960366cfSKarsten Keil return 0;
1106960366cfSKarsten Keil }
1107960366cfSKarsten Keil
1108960366cfSKarsten Keil
1109960366cfSKarsten Keil static struct Bprotocol DSP = {
1110960366cfSKarsten Keil .Bprotocols = (1 << (ISDN_P_B_L2DSP & ISDN_P_B_MASK))
1111960366cfSKarsten Keil | (1 << (ISDN_P_B_L2DSPHDLC & ISDN_P_B_MASK)),
1112960366cfSKarsten Keil .name = "dsp",
1113960366cfSKarsten Keil .create = dspcreate
1114960366cfSKarsten Keil };
1115960366cfSKarsten Keil
dsp_init(void)11163d956d1dSPeter Huewe static int __init dsp_init(void)
1117960366cfSKarsten Keil {
1118960366cfSKarsten Keil int err;
1119960366cfSKarsten Keil int tics;
1120960366cfSKarsten Keil
11214807f643SMasanari Iida printk(KERN_INFO "DSP module %s\n", mISDN_dsp_revision);
1122960366cfSKarsten Keil
1123960366cfSKarsten Keil dsp_options = options;
1124960366cfSKarsten Keil dsp_debug = debug;
1125960366cfSKarsten Keil
1126960366cfSKarsten Keil /* set packet size */
1127960366cfSKarsten Keil dsp_poll = poll;
1128960366cfSKarsten Keil if (dsp_poll) {
1129960366cfSKarsten Keil if (dsp_poll > MAX_POLL) {
1130960366cfSKarsten Keil printk(KERN_ERR "%s: Wrong poll value (%d), use %d "
1131960366cfSKarsten Keil "maximum.\n", __func__, poll, MAX_POLL);
1132960366cfSKarsten Keil err = -EINVAL;
1133960366cfSKarsten Keil return err;
1134960366cfSKarsten Keil }
1135960366cfSKarsten Keil if (dsp_poll < 8) {
1136960366cfSKarsten Keil printk(KERN_ERR "%s: Wrong poll value (%d), use 8 "
1137960366cfSKarsten Keil "minimum.\n", __func__, dsp_poll);
1138960366cfSKarsten Keil err = -EINVAL;
1139960366cfSKarsten Keil return err;
1140960366cfSKarsten Keil }
1141960366cfSKarsten Keil dsp_tics = poll * HZ / 8000;
1142960366cfSKarsten Keil if (dsp_tics * 8000 != poll * HZ) {
1143960366cfSKarsten Keil printk(KERN_INFO "mISDN_dsp: Cannot clock every %d "
1144960366cfSKarsten Keil "samples (0,125 ms). It is not a multiple of "
1145960366cfSKarsten Keil "%d HZ.\n", poll, HZ);
1146960366cfSKarsten Keil err = -EINVAL;
1147960366cfSKarsten Keil return err;
1148960366cfSKarsten Keil }
1149960366cfSKarsten Keil } else {
1150960366cfSKarsten Keil poll = 8;
1151960366cfSKarsten Keil while (poll <= MAX_POLL) {
1152400fd978SAndreas Eversberg tics = (poll * HZ) / 8000;
1153960366cfSKarsten Keil if (tics * 8000 == poll * HZ) {
1154960366cfSKarsten Keil dsp_tics = tics;
1155960366cfSKarsten Keil dsp_poll = poll;
1156960366cfSKarsten Keil if (poll >= 64)
1157960366cfSKarsten Keil break;
1158960366cfSKarsten Keil }
1159960366cfSKarsten Keil poll++;
1160960366cfSKarsten Keil }
1161960366cfSKarsten Keil }
1162960366cfSKarsten Keil if (dsp_poll == 0) {
1163960366cfSKarsten Keil printk(KERN_INFO "mISDN_dsp: There is no multiple of kernel "
1164960366cfSKarsten Keil "clock that equals exactly the duration of 8-256 "
1165960366cfSKarsten Keil "samples. (Choose kernel clock speed like 100, 250, "
1166960366cfSKarsten Keil "300, 1000)\n");
1167960366cfSKarsten Keil err = -EINVAL;
1168960366cfSKarsten Keil return err;
1169960366cfSKarsten Keil }
1170960366cfSKarsten Keil printk(KERN_INFO "mISDN_dsp: DSP clocks every %d samples. This equals "
1171960366cfSKarsten Keil "%d jiffies.\n", dsp_poll, dsp_tics);
1172960366cfSKarsten Keil
1173960366cfSKarsten Keil /* init conversion tables */
1174960366cfSKarsten Keil dsp_audio_generate_law_tables();
1175960366cfSKarsten Keil dsp_silence = (dsp_options & DSP_OPT_ULAW) ? 0xff : 0x2a;
1176eac74af9SKarsten Keil dsp_audio_law_to_s32 = (dsp_options & DSP_OPT_ULAW) ?
1177eac74af9SKarsten Keil dsp_audio_ulaw_to_s32 : dsp_audio_alaw_to_s32;
1178960366cfSKarsten Keil dsp_audio_generate_s2law_table();
1179960366cfSKarsten Keil dsp_audio_generate_seven();
1180960366cfSKarsten Keil dsp_audio_generate_mix_table();
1181960366cfSKarsten Keil if (dsp_options & DSP_OPT_ULAW)
1182960366cfSKarsten Keil dsp_audio_generate_ulaw_samples();
1183960366cfSKarsten Keil dsp_audio_generate_volume_changes();
1184960366cfSKarsten Keil
1185960366cfSKarsten Keil err = dsp_pipeline_module_init();
1186960366cfSKarsten Keil if (err) {
1187960366cfSKarsten Keil printk(KERN_ERR "mISDN_dsp: Can't initialize pipeline, "
1188960366cfSKarsten Keil "error(%d)\n", err);
1189960366cfSKarsten Keil return err;
1190960366cfSKarsten Keil }
1191960366cfSKarsten Keil
1192960366cfSKarsten Keil err = mISDN_register_Bprotocol(&DSP);
1193960366cfSKarsten Keil if (err) {
1194960366cfSKarsten Keil printk(KERN_ERR "Can't register %s error(%d)\n", DSP.name, err);
1195960366cfSKarsten Keil return err;
1196960366cfSKarsten Keil }
1197960366cfSKarsten Keil
1198960366cfSKarsten Keil /* set sample timer */
11991696ec86SNathan Chancellor timer_setup(&dsp_spl_tl, dsp_cmx_send, 0);
1200960366cfSKarsten Keil dsp_spl_tl.expires = jiffies + dsp_tics;
1201960366cfSKarsten Keil dsp_spl_jiffies = dsp_spl_tl.expires;
1202960366cfSKarsten Keil add_timer(&dsp_spl_tl);
1203960366cfSKarsten Keil
1204960366cfSKarsten Keil return 0;
1205960366cfSKarsten Keil }
1206960366cfSKarsten Keil
1207960366cfSKarsten Keil
dsp_cleanup(void)12083d956d1dSPeter Huewe static void __exit dsp_cleanup(void)
1209960366cfSKarsten Keil {
1210960366cfSKarsten Keil mISDN_unregister_Bprotocol(&DSP);
1211960366cfSKarsten Keil
12124a0ae7b0SKonstantin Khlebnikov del_timer_sync(&dsp_spl_tl);
1213960366cfSKarsten Keil
1214960366cfSKarsten Keil if (!list_empty(&dsp_ilist)) {
1215960366cfSKarsten Keil printk(KERN_ERR "mISDN_dsp: Audio DSP object inst list not "
1216960366cfSKarsten Keil "empty.\n");
1217960366cfSKarsten Keil }
1218960366cfSKarsten Keil if (!list_empty(&conf_ilist)) {
1219960366cfSKarsten Keil printk(KERN_ERR "mISDN_dsp: Conference list not empty. Not "
1220960366cfSKarsten Keil "all memory freed.\n");
1221960366cfSKarsten Keil }
1222960366cfSKarsten Keil
1223960366cfSKarsten Keil dsp_pipeline_module_exit();
1224960366cfSKarsten Keil }
1225960366cfSKarsten Keil
1226960366cfSKarsten Keil module_init(dsp_init);
1227960366cfSKarsten Keil module_exit(dsp_cleanup);
1228