xref: /linux/drivers/isdn/mISDN/dsp_core.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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