diff options
-rw-r--r-- | drivers/isdn/mISDN/Kconfig | 18 | ||||
-rw-r--r-- | drivers/isdn/mISDN/Makefile | 2 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp.h | 263 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_audio.c | 434 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_biquad.h | 65 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_blowfish.c | 672 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_cmx.c | 1886 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_core.c | 1191 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_dtmf.c | 303 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_ecdis.h | 110 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_hwec.c | 138 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_hwec.h | 10 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_pipeline.c | 348 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_tones.c | 551 | ||||
-rw-r--r-- | include/linux/mISDNdsp.h | 37 |
15 files changed, 6028 insertions, 0 deletions
diff --git a/drivers/isdn/mISDN/Kconfig b/drivers/isdn/mISDN/Kconfig index 231bd0d08316..6a97e86e7f21 100644 --- a/drivers/isdn/mISDN/Kconfig +++ b/drivers/isdn/mISDN/Kconfig | |||
@@ -7,3 +7,21 @@ menuconfig MISDN | |||
7 | help | 7 | help |
8 | Enable support for the modular ISDN driver. | 8 | Enable support for the modular ISDN driver. |
9 | 9 | ||
10 | if MISDN != n | ||
11 | |||
12 | config MISDN_DSP | ||
13 | tristate "Digital Audio Processing of transparent data" | ||
14 | depends on MISDN | ||
15 | help | ||
16 | Enable support for digital audio processing capability. | ||
17 | This module may be used for special applications that require | ||
18 | cross connecting of bchannels, conferencing, dtmf decoding | ||
19 | echo cancelation, tone generation, and Blowfish encryption and | ||
20 | decryption. | ||
21 | It may use hardware features if available. | ||
22 | E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu | ||
23 | and get more informations about this module and it's usage. | ||
24 | If unsure, say 'N'. | ||
25 | |||
26 | source "drivers/isdn/hardware/mISDN/Kconfig" | ||
27 | endif #MISDN | ||
diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile index 87c563d33612..7f1a21804208 100644 --- a/drivers/isdn/mISDN/Makefile +++ b/drivers/isdn/mISDN/Makefile | |||
@@ -3,7 +3,9 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_MISDN) += mISDN_core.o | 5 | obj-$(CONFIG_MISDN) += mISDN_core.o |
6 | obj-$(CONFIG_MISDN_DSP) += mISDN_dsp.o | ||
6 | 7 | ||
7 | # multi objects | 8 | # multi objects |
8 | 9 | ||
9 | mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o | 10 | mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o |
11 | mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_pipeline.o dsp_hwec.o | ||
diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h new file mode 100644 index 000000000000..6c3fed6b8d4f --- /dev/null +++ b/drivers/isdn/mISDN/dsp.h | |||
@@ -0,0 +1,263 @@ | |||
1 | /* | ||
2 | * Audio support data for ISDN4Linux. | ||
3 | * | ||
4 | * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * | ||
6 | * This software may be used and distributed according to the terms | ||
7 | * of the GNU General Public License, incorporated herein by reference. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #define DEBUG_DSP_CTRL 0x0001 | ||
12 | #define DEBUG_DSP_CORE 0x0002 | ||
13 | #define DEBUG_DSP_DTMF 0x0004 | ||
14 | #define DEBUG_DSP_CMX 0x0010 | ||
15 | #define DEBUG_DSP_TONE 0x0020 | ||
16 | #define DEBUG_DSP_BLOWFISH 0x0040 | ||
17 | #define DEBUG_DSP_DELAY 0x0100 | ||
18 | #define DEBUG_DSP_DTMFCOEFF 0x8000 /* heavy output */ | ||
19 | |||
20 | /* options may be: | ||
21 | * | ||
22 | * bit 0 = use ulaw instead of alaw | ||
23 | * bit 1 = enable hfc hardware accelleration for all channels | ||
24 | * | ||
25 | */ | ||
26 | #define DSP_OPT_ULAW (1<<0) | ||
27 | #define DSP_OPT_NOHARDWARE (1<<1) | ||
28 | |||
29 | #include <linux/timer.h> | ||
30 | #include <linux/workqueue.h> | ||
31 | |||
32 | #include "dsp_ecdis.h" | ||
33 | |||
34 | extern int dsp_options; | ||
35 | extern int dsp_debug; | ||
36 | extern int dsp_poll; | ||
37 | extern int dsp_tics; | ||
38 | extern spinlock_t dsp_lock; | ||
39 | extern struct work_struct dsp_workq; | ||
40 | extern u32 dsp_poll_diff; /* calculated fix-comma corrected poll value */ | ||
41 | |||
42 | /*************** | ||
43 | * audio stuff * | ||
44 | ***************/ | ||
45 | |||
46 | extern s32 dsp_audio_alaw_to_s32[256]; | ||
47 | extern s32 dsp_audio_ulaw_to_s32[256]; | ||
48 | extern s32 *dsp_audio_law_to_s32; | ||
49 | extern u8 dsp_audio_s16_to_law[65536]; | ||
50 | extern u8 dsp_audio_alaw_to_ulaw[256]; | ||
51 | extern u8 dsp_audio_mix_law[65536]; | ||
52 | extern u8 dsp_audio_seven2law[128]; | ||
53 | extern u8 dsp_audio_law2seven[256]; | ||
54 | extern void dsp_audio_generate_law_tables(void); | ||
55 | extern void dsp_audio_generate_s2law_table(void); | ||
56 | extern void dsp_audio_generate_seven(void); | ||
57 | extern void dsp_audio_generate_mix_table(void); | ||
58 | extern void dsp_audio_generate_ulaw_samples(void); | ||
59 | extern void dsp_audio_generate_volume_changes(void); | ||
60 | extern u8 dsp_silence; | ||
61 | |||
62 | |||
63 | /************* | ||
64 | * cmx stuff * | ||
65 | *************/ | ||
66 | |||
67 | #define MAX_POLL 256 /* maximum number of send-chunks */ | ||
68 | |||
69 | #define CMX_BUFF_SIZE 0x8000 /* must be 2**n (0x1000 about 1/2 second) */ | ||
70 | #define CMX_BUFF_HALF 0x4000 /* CMX_BUFF_SIZE / 2 */ | ||
71 | #define CMX_BUFF_MASK 0x7fff /* CMX_BUFF_SIZE - 1 */ | ||
72 | |||
73 | /* how many seconds will we check the lowest delay until the jitter buffer | ||
74 | is reduced by that delay */ | ||
75 | #define MAX_SECONDS_JITTER_CHECK 5 | ||
76 | |||
77 | extern struct timer_list dsp_spl_tl; | ||
78 | extern u32 dsp_spl_jiffies; | ||
79 | |||
80 | /* the structure of conferences: | ||
81 | * | ||
82 | * each conference has a unique number, given by user space. | ||
83 | * the conferences are linked in a chain. | ||
84 | * each conference has members linked in a chain. | ||
85 | * each dsplayer points to a member, each member points to a dsplayer. | ||
86 | */ | ||
87 | |||
88 | /* all members within a conference (this is linked 1:1 with the dsp) */ | ||
89 | struct dsp; | ||
90 | struct dsp_conf_member { | ||
91 | struct list_head list; | ||
92 | struct dsp *dsp; | ||
93 | }; | ||
94 | |||
95 | /* the list of all conferences */ | ||
96 | struct dsp_conf { | ||
97 | struct list_head list; | ||
98 | u32 id; | ||
99 | /* all cmx stacks with the same ID are | ||
100 | connected */ | ||
101 | struct list_head mlist; | ||
102 | int software; /* conf is processed by software */ | ||
103 | int hardware; /* conf is processed by hardware */ | ||
104 | /* note: if both unset, has only one member */ | ||
105 | }; | ||
106 | |||
107 | |||
108 | /************** | ||
109 | * DTMF stuff * | ||
110 | **************/ | ||
111 | |||
112 | #define DSP_DTMF_NPOINTS 102 | ||
113 | |||
114 | #define ECHOCAN_BUFLEN (4*128) | ||
115 | |||
116 | struct dsp_dtmf { | ||
117 | int treshold; /* above this is dtmf (square of) */ | ||
118 | int software; /* dtmf uses software decoding */ | ||
119 | int hardware; /* dtmf uses hardware decoding */ | ||
120 | int size; /* number of bytes in buffer */ | ||
121 | signed short buffer[DSP_DTMF_NPOINTS]; | ||
122 | /* buffers one full dtmf frame */ | ||
123 | u8 lastwhat, lastdigit; | ||
124 | int count; | ||
125 | u8 digits[16]; /* just the dtmf result */ | ||
126 | }; | ||
127 | |||
128 | |||
129 | /****************** | ||
130 | * pipeline stuff * | ||
131 | ******************/ | ||
132 | struct dsp_pipeline { | ||
133 | rwlock_t lock; | ||
134 | struct list_head list; | ||
135 | int inuse; | ||
136 | }; | ||
137 | |||
138 | /*************** | ||
139 | * tones stuff * | ||
140 | ***************/ | ||
141 | |||
142 | struct dsp_tone { | ||
143 | int software; /* tones are generated by software */ | ||
144 | int hardware; /* tones are generated by hardware */ | ||
145 | int tone; | ||
146 | void *pattern; | ||
147 | int count; | ||
148 | int index; | ||
149 | struct timer_list tl; | ||
150 | }; | ||
151 | |||
152 | /***************** | ||
153 | * general stuff * | ||
154 | *****************/ | ||
155 | |||
156 | struct dsp { | ||
157 | struct list_head list; | ||
158 | struct mISDNchannel ch; | ||
159 | struct mISDNchannel *up; | ||
160 | unsigned char name[64]; | ||
161 | int b_active; | ||
162 | int echo; /* echo is enabled */ | ||
163 | int rx_disabled; /* what the user wants */ | ||
164 | int rx_is_off; /* what the card is */ | ||
165 | int tx_mix; | ||
166 | struct dsp_tone tone; | ||
167 | struct dsp_dtmf dtmf; | ||
168 | int tx_volume, rx_volume; | ||
169 | |||
170 | /* queue for sending frames */ | ||
171 | struct work_struct workq; | ||
172 | struct sk_buff_head sendq; | ||
173 | int hdlc; /* if mode is hdlc */ | ||
174 | int data_pending; /* currently an unconfirmed frame */ | ||
175 | |||
176 | /* conference stuff */ | ||
177 | u32 conf_id; | ||
178 | struct dsp_conf *conf; | ||
179 | struct dsp_conf_member | ||
180 | *member; | ||
181 | |||
182 | /* buffer stuff */ | ||
183 | int rx_W; /* current write pos for data without timestamp */ | ||
184 | int rx_R; /* current read pos for transmit clock */ | ||
185 | int rx_init; /* if set, pointers will be adjusted first */ | ||
186 | int tx_W; /* current write pos for transmit data */ | ||
187 | int tx_R; /* current read pos for transmit clock */ | ||
188 | int rx_delay[MAX_SECONDS_JITTER_CHECK]; | ||
189 | int tx_delay[MAX_SECONDS_JITTER_CHECK]; | ||
190 | u8 tx_buff[CMX_BUFF_SIZE]; | ||
191 | u8 rx_buff[CMX_BUFF_SIZE]; | ||
192 | int last_tx; /* if set, we transmitted last poll interval */ | ||
193 | int cmx_delay; /* initial delay of buffers, | ||
194 | or 0 for dynamic jitter buffer */ | ||
195 | int tx_dejitter; /* if set, dejitter tx buffer */ | ||
196 | int tx_data; /* enables tx-data of CMX to upper layer */ | ||
197 | |||
198 | /* hardware stuff */ | ||
199 | struct dsp_features features; | ||
200 | int features_rx_off; /* set if rx_off is featured */ | ||
201 | int pcm_slot_rx; /* current PCM slot (or -1) */ | ||
202 | int pcm_bank_rx; | ||
203 | int pcm_slot_tx; | ||
204 | int pcm_bank_tx; | ||
205 | int hfc_conf; /* unique id of current conference (or -1) */ | ||
206 | |||
207 | /* encryption stuff */ | ||
208 | int bf_enable; | ||
209 | u32 bf_p[18]; | ||
210 | u32 bf_s[1024]; | ||
211 | int bf_crypt_pos; | ||
212 | u8 bf_data_in[9]; | ||
213 | u8 bf_crypt_out[9]; | ||
214 | int bf_decrypt_in_pos; | ||
215 | int bf_decrypt_out_pos; | ||
216 | u8 bf_crypt_inring[16]; | ||
217 | u8 bf_data_out[9]; | ||
218 | int bf_sync; | ||
219 | |||
220 | struct dsp_pipeline | ||
221 | pipeline; | ||
222 | }; | ||
223 | |||
224 | /* functions */ | ||
225 | |||
226 | extern void dsp_change_volume(struct sk_buff *skb, int volume); | ||
227 | |||
228 | extern struct list_head dsp_ilist; | ||
229 | extern struct list_head conf_ilist; | ||
230 | extern void dsp_cmx_debug(struct dsp *dsp); | ||
231 | extern void dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp); | ||
232 | extern int dsp_cmx_conf(struct dsp *dsp, u32 conf_id); | ||
233 | extern void dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb); | ||
234 | extern void dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb); | ||
235 | extern void dsp_cmx_send(void *arg); | ||
236 | extern void dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb); | ||
237 | extern int dsp_cmx_del_conf_member(struct dsp *dsp); | ||
238 | extern int dsp_cmx_del_conf(struct dsp_conf *conf); | ||
239 | |||
240 | extern void dsp_dtmf_goertzel_init(struct dsp *dsp); | ||
241 | extern void dsp_dtmf_hardware(struct dsp *dsp); | ||
242 | extern u8 *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, | ||
243 | int fmt); | ||
244 | |||
245 | extern int dsp_tone(struct dsp *dsp, int tone); | ||
246 | extern void dsp_tone_copy(struct dsp *dsp, u8 *data, int len); | ||
247 | extern void dsp_tone_timeout(void *arg); | ||
248 | |||
249 | extern void dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len); | ||
250 | extern void dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len); | ||
251 | extern int dsp_bf_init(struct dsp *dsp, const u8 *key, unsigned int keylen); | ||
252 | extern void dsp_bf_cleanup(struct dsp *dsp); | ||
253 | |||
254 | extern int dsp_pipeline_module_init(void); | ||
255 | extern void dsp_pipeline_module_exit(void); | ||
256 | extern int dsp_pipeline_init(struct dsp_pipeline *pipeline); | ||
257 | extern void dsp_pipeline_destroy(struct dsp_pipeline *pipeline); | ||
258 | extern int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg); | ||
259 | extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, | ||
260 | int len); | ||
261 | extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, | ||
262 | int len); | ||
263 | |||
diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c new file mode 100644 index 000000000000..1c2dd5694773 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_audio.c | |||
@@ -0,0 +1,434 @@ | |||
1 | /* | ||
2 | * Audio support data for mISDN_dsp. | ||
3 | * | ||
4 | * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * Rewritten by Peter | ||
6 | * | ||
7 | * This software may be used and distributed according to the terms | ||
8 | * of the GNU General Public License, incorporated herein by reference. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/delay.h> | ||
13 | #include <linux/mISDNif.h> | ||
14 | #include <linux/mISDNdsp.h> | ||
15 | #include "core.h" | ||
16 | #include "dsp.h" | ||
17 | |||
18 | /* ulaw[unsigned char] -> signed 16-bit */ | ||
19 | s32 dsp_audio_ulaw_to_s32[256]; | ||
20 | /* alaw[unsigned char] -> signed 16-bit */ | ||
21 | s32 dsp_audio_alaw_to_s32[256]; | ||
22 | |||
23 | s32 *dsp_audio_law_to_s32; | ||
24 | EXPORT_SYMBOL(dsp_audio_law_to_s32); | ||
25 | |||
26 | /* signed 16-bit -> law */ | ||
27 | u8 dsp_audio_s16_to_law[65536]; | ||
28 | EXPORT_SYMBOL(dsp_audio_s16_to_law); | ||
29 | |||
30 | /* alaw -> ulaw */ | ||
31 | u8 dsp_audio_alaw_to_ulaw[256]; | ||
32 | /* ulaw -> alaw */ | ||
33 | u8 dsp_audio_ulaw_to_alaw[256]; | ||
34 | u8 dsp_silence; | ||
35 | |||
36 | |||
37 | /***************************************************** | ||
38 | * generate table for conversion of s16 to alaw/ulaw * | ||
39 | *****************************************************/ | ||
40 | |||
41 | #define AMI_MASK 0x55 | ||
42 | |||
43 | static inline unsigned char linear2alaw(short int linear) | ||
44 | { | ||
45 | int mask; | ||
46 | int seg; | ||
47 | int pcm_val; | ||
48 | static int seg_end[8] = { | ||
49 | 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF | ||
50 | }; | ||
51 | |||
52 | pcm_val = linear; | ||
53 | if (pcm_val >= 0) { | ||
54 | /* Sign (7th) bit = 1 */ | ||
55 | mask = AMI_MASK | 0x80; | ||
56 | } else { | ||
57 | /* Sign bit = 0 */ | ||
58 | mask = AMI_MASK; | ||
59 | pcm_val = -pcm_val; | ||
60 | } | ||
61 | |||
62 | /* Convert the scaled magnitude to segment number. */ | ||
63 | for (seg = 0; seg < 8; seg++) { | ||
64 | if (pcm_val <= seg_end[seg]) | ||
65 | break; | ||
66 | } | ||
67 | /* Combine the sign, segment, and quantization bits. */ | ||
68 | return ((seg << 4) | | ||
69 | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask; | ||
70 | } | ||
71 | |||
72 | |||
73 | static inline short int alaw2linear(unsigned char alaw) | ||
74 | { | ||
75 | int i; | ||
76 | int seg; | ||
77 | |||
78 | alaw ^= AMI_MASK; | ||
79 | i = ((alaw & 0x0F) << 4) + 8 /* rounding error */; | ||
80 | seg = (((int) alaw & 0x70) >> 4); | ||
81 | if (seg) | ||
82 | i = (i + 0x100) << (seg - 1); | ||
83 | return (short int) ((alaw & 0x80) ? i : -i); | ||
84 | } | ||
85 | |||
86 | static inline short int ulaw2linear(unsigned char ulaw) | ||
87 | { | ||
88 | short mu, e, f, y; | ||
89 | static short etab[] = {0, 132, 396, 924, 1980, 4092, 8316, 16764}; | ||
90 | |||
91 | mu = 255 - ulaw; | ||
92 | e = (mu & 0x70) / 16; | ||
93 | f = mu & 0x0f; | ||
94 | y = f * (1 << (e + 3)); | ||
95 | y += etab[e]; | ||
96 | if (mu & 0x80) | ||
97 | y = -y; | ||
98 | return y; | ||
99 | } | ||
100 | |||
101 | #define BIAS 0x84 /*!< define the add-in bias for 16 bit samples */ | ||
102 | |||
103 | static unsigned char linear2ulaw(short sample) | ||
104 | { | ||
105 | static int exp_lut[256] = { | ||
106 | 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, | ||
107 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | ||
108 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | ||
109 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | ||
110 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
111 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
112 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
113 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
114 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
115 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
116 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
117 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
118 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
119 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
120 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
121 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; | ||
122 | int sign, exponent, mantissa; | ||
123 | unsigned char ulawbyte; | ||
124 | |||
125 | /* Get the sample into sign-magnitude. */ | ||
126 | sign = (sample >> 8) & 0x80; /* set aside the sign */ | ||
127 | if (sign != 0) | ||
128 | sample = -sample; /* get magnitude */ | ||
129 | |||
130 | /* Convert from 16 bit linear to ulaw. */ | ||
131 | sample = sample + BIAS; | ||
132 | exponent = exp_lut[(sample >> 7) & 0xFF]; | ||
133 | mantissa = (sample >> (exponent + 3)) & 0x0F; | ||
134 | ulawbyte = ~(sign | (exponent << 4) | mantissa); | ||
135 | |||
136 | return ulawbyte; | ||
137 | } | ||
138 | |||
139 | static int reverse_bits(int i) | ||
140 | { | ||
141 | int z, j; | ||
142 | z = 0; | ||
143 | |||
144 | for (j = 0; j < 8; j++) { | ||
145 | if ((i & (1 << j)) != 0) | ||
146 | z |= 1 << (7 - j); | ||
147 | } | ||
148 | return z; | ||
149 | } | ||
150 | |||
151 | |||
152 | void dsp_audio_generate_law_tables(void) | ||
153 | { | ||
154 | int i; | ||
155 | for (i = 0; i < 256; i++) | ||
156 | dsp_audio_alaw_to_s32[i] = alaw2linear(reverse_bits(i)); | ||
157 | |||
158 | for (i = 0; i < 256; i++) | ||
159 | dsp_audio_ulaw_to_s32[i] = ulaw2linear(reverse_bits(i)); | ||
160 | |||
161 | for (i = 0; i < 256; i++) { | ||
162 | dsp_audio_alaw_to_ulaw[i] = | ||
163 | linear2ulaw(dsp_audio_alaw_to_s32[i]); | ||
164 | dsp_audio_ulaw_to_alaw[i] = | ||
165 | linear2alaw(dsp_audio_ulaw_to_s32[i]); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | void | ||
170 | dsp_audio_generate_s2law_table(void) | ||
171 | { | ||
172 | int i; | ||
173 | |||
174 | if (dsp_options & DSP_OPT_ULAW) { | ||
175 | /* generating ulaw-table */ | ||
176 | for (i = -32768; i < 32768; i++) { | ||
177 | dsp_audio_s16_to_law[i & 0xffff] = | ||
178 | reverse_bits(linear2ulaw(i)); | ||
179 | } | ||
180 | } else { | ||
181 | /* generating alaw-table */ | ||
182 | for (i = -32768; i < 32768; i++) { | ||
183 | dsp_audio_s16_to_law[i & 0xffff] = | ||
184 | reverse_bits(linear2alaw(i)); | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | |||
189 | |||
190 | /* | ||
191 | * the seven bit sample is the number of every second alaw-sample ordered by | ||
192 | * aplitude. 0x00 is negative, 0x7f is positive amplitude. | ||
193 | */ | ||
194 | u8 dsp_audio_seven2law[128]; | ||
195 | u8 dsp_audio_law2seven[256]; | ||
196 | |||
197 | /******************************************************************** | ||
198 | * generate table for conversion law from/to 7-bit alaw-like sample * | ||
199 | ********************************************************************/ | ||
200 | |||
201 | void | ||
202 | dsp_audio_generate_seven(void) | ||
203 | { | ||
204 | int i, j, k; | ||
205 | u8 spl; | ||
206 | u8 sorted_alaw[256]; | ||
207 | |||
208 | /* generate alaw table, sorted by the linear value */ | ||
209 | for (i = 0; i < 256; i++) { | ||
210 | j = 0; | ||
211 | for (k = 0; k < 256; k++) { | ||
212 | if (dsp_audio_alaw_to_s32[k] | ||
213 | < dsp_audio_alaw_to_s32[i]) { | ||
214 | j++; | ||
215 | } | ||
216 | } | ||
217 | sorted_alaw[j] = i; | ||
218 | } | ||
219 | |||
220 | /* generate tabels */ | ||
221 | for (i = 0; i < 256; i++) { | ||
222 | /* spl is the source: the law-sample (converted to alaw) */ | ||
223 | spl = i; | ||
224 | if (dsp_options & DSP_OPT_ULAW) | ||
225 | spl = dsp_audio_ulaw_to_alaw[i]; | ||
226 | /* find the 7-bit-sample */ | ||
227 | for (j = 0; j < 256; j++) { | ||
228 | if (sorted_alaw[j] == spl) | ||
229 | break; | ||
230 | } | ||
231 | /* write 7-bit audio value */ | ||
232 | dsp_audio_law2seven[i] = j >> 1; | ||
233 | } | ||
234 | for (i = 0; i < 128; i++) { | ||
235 | spl = sorted_alaw[i << 1]; | ||
236 | if (dsp_options & DSP_OPT_ULAW) | ||
237 | spl = dsp_audio_alaw_to_ulaw[spl]; | ||
238 | dsp_audio_seven2law[i] = spl; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | |||
243 | /* mix 2*law -> law */ | ||
244 | u8 dsp_audio_mix_law[65536]; | ||
245 | |||
246 | /****************************************************** | ||
247 | * generate mix table to mix two law samples into one * | ||
248 | ******************************************************/ | ||
249 | |||
250 | void | ||
251 | dsp_audio_generate_mix_table(void) | ||
252 | { | ||
253 | int i, j; | ||
254 | s32 sample; | ||
255 | |||
256 | i = 0; | ||
257 | while (i < 256) { | ||
258 | j = 0; | ||
259 | while (j < 256) { | ||
260 | sample = dsp_audio_law_to_s32[i]; | ||
261 | sample += dsp_audio_law_to_s32[j]; | ||
262 | if (sample > 32767) | ||
263 | sample = 32767; | ||
264 | if (sample < -32768) | ||
265 | sample = -32768; | ||
266 | dsp_audio_mix_law[(i<<8)|j] = | ||
267 | dsp_audio_s16_to_law[sample & 0xffff]; | ||
268 | j++; | ||
269 | } | ||
270 | i++; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | |||
275 | /************************************* | ||
276 | * generate different volume changes * | ||
277 | *************************************/ | ||
278 | |||
279 | static u8 dsp_audio_reduce8[256]; | ||
280 | static u8 dsp_audio_reduce7[256]; | ||
281 | static u8 dsp_audio_reduce6[256]; | ||
282 | static u8 dsp_audio_reduce5[256]; | ||
283 | static u8 dsp_audio_reduce4[256]; | ||
284 | static u8 dsp_audio_reduce3[256]; | ||
285 | static u8 dsp_audio_reduce2[256]; | ||
286 | static u8 dsp_audio_reduce1[256]; | ||
287 | static u8 dsp_audio_increase1[256]; | ||
288 | static u8 dsp_audio_increase2[256]; | ||
289 | static u8 dsp_audio_increase3[256]; | ||
290 | static u8 dsp_audio_increase4[256]; | ||
291 | static u8 dsp_audio_increase5[256]; | ||
292 | static u8 dsp_audio_increase6[256]; | ||
293 | static u8 dsp_audio_increase7[256]; | ||
294 | static u8 dsp_audio_increase8[256]; | ||
295 | |||
296 | static u8 *dsp_audio_volume_change[16] = { | ||
297 | dsp_audio_reduce8, | ||
298 | dsp_audio_reduce7, | ||
299 | dsp_audio_reduce6, | ||
300 | dsp_audio_reduce5, | ||
301 | dsp_audio_reduce4, | ||
302 | dsp_audio_reduce3, | ||
303 | dsp_audio_reduce2, | ||
304 | dsp_audio_reduce1, | ||
305 | dsp_audio_increase1, | ||
306 | dsp_audio_increase2, | ||
307 | dsp_audio_increase3, | ||
308 | dsp_audio_increase4, | ||
309 | dsp_audio_increase5, | ||
310 | dsp_audio_increase6, | ||
311 | dsp_audio_increase7, | ||
312 | dsp_audio_increase8, | ||
313 | }; | ||
314 | |||
315 | void | ||
316 | dsp_audio_generate_volume_changes(void) | ||
317 | { | ||
318 | register s32 sample; | ||
319 | int i; | ||
320 | int num[] = { 110, 125, 150, 175, 200, 300, 400, 500 }; | ||
321 | int denum[] = { 100, 100, 100, 100, 100, 100, 100, 100 }; | ||
322 | |||
323 | i = 0; | ||
324 | while (i < 256) { | ||
325 | dsp_audio_reduce8[i] = dsp_audio_s16_to_law[ | ||
326 | (dsp_audio_law_to_s32[i] * denum[7] / num[7]) & 0xffff]; | ||
327 | dsp_audio_reduce7[i] = dsp_audio_s16_to_law[ | ||
328 | (dsp_audio_law_to_s32[i] * denum[6] / num[6]) & 0xffff]; | ||
329 | dsp_audio_reduce6[i] = dsp_audio_s16_to_law[ | ||
330 | (dsp_audio_law_to_s32[i] * denum[5] / num[5]) & 0xffff]; | ||
331 | dsp_audio_reduce5[i] = dsp_audio_s16_to_law[ | ||
332 | (dsp_audio_law_to_s32[i] * denum[4] / num[4]) & 0xffff]; | ||
333 | dsp_audio_reduce4[i] = dsp_audio_s16_to_law[ | ||
334 | (dsp_audio_law_to_s32[i] * denum[3] / num[3]) & 0xffff]; | ||
335 | dsp_audio_reduce3[i] = dsp_audio_s16_to_law[ | ||
336 | (dsp_audio_law_to_s32[i] * denum[2] / num[2]) & 0xffff]; | ||
337 | dsp_audio_reduce2[i] = dsp_audio_s16_to_law[ | ||
338 | (dsp_audio_law_to_s32[i] * denum[1] / num[1]) & 0xffff]; | ||
339 | dsp_audio_reduce1[i] = dsp_audio_s16_to_law[ | ||
340 | (dsp_audio_law_to_s32[i] * denum[0] / num[0]) & 0xffff]; | ||
341 | sample = dsp_audio_law_to_s32[i] * num[0] / denum[0]; | ||
342 | if (sample < -32768) | ||
343 | sample = -32768; | ||
344 | else if (sample > 32767) | ||
345 | sample = 32767; | ||
346 | dsp_audio_increase1[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
347 | sample = dsp_audio_law_to_s32[i] * num[1] / denum[1]; | ||
348 | if (sample < -32768) | ||
349 | sample = -32768; | ||
350 | else if (sample > 32767) | ||
351 | sample = 32767; | ||
352 | dsp_audio_increase2[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
353 | sample = dsp_audio_law_to_s32[i] * num[2] / denum[2]; | ||
354 | if (sample < -32768) | ||
355 | sample = -32768; | ||
356 | else if (sample > 32767) | ||
357 | sample = 32767; | ||
358 | dsp_audio_increase3[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
359 | sample = dsp_audio_law_to_s32[i] * num[3] / denum[3]; | ||
360 | if (sample < -32768) | ||
361 | sample = -32768; | ||
362 | else if (sample > 32767) | ||
363 | sample = 32767; | ||
364 | dsp_audio_increase4[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
365 | sample = dsp_audio_law_to_s32[i] * num[4] / denum[4]; | ||
366 | if (sample < -32768) | ||
367 | sample = -32768; | ||
368 | else if (sample > 32767) | ||
369 | sample = 32767; | ||
370 | dsp_audio_increase5[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
371 | sample = dsp_audio_law_to_s32[i] * num[5] / denum[5]; | ||
372 | if (sample < -32768) | ||
373 | sample = -32768; | ||
374 | else if (sample > 32767) | ||
375 | sample = 32767; | ||
376 | dsp_audio_increase6[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
377 | sample = dsp_audio_law_to_s32[i] * num[6] / denum[6]; | ||
378 | if (sample < -32768) | ||
379 | sample = -32768; | ||
380 | else if (sample > 32767) | ||
381 | sample = 32767; | ||
382 | dsp_audio_increase7[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
383 | sample = dsp_audio_law_to_s32[i] * num[7] / denum[7]; | ||
384 | if (sample < -32768) | ||
385 | sample = -32768; | ||
386 | else if (sample > 32767) | ||
387 | sample = 32767; | ||
388 | dsp_audio_increase8[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
389 | |||
390 | i++; | ||
391 | } | ||
392 | } | ||
393 | |||
394 | |||
395 | /************************************** | ||
396 | * change the volume of the given skb * | ||
397 | **************************************/ | ||
398 | |||
399 | /* this is a helper function for changing volume of skb. the range may be | ||
400 | * -8 to 8, which is a shift to the power of 2. 0 == no volume, 3 == volume*8 | ||
401 | */ | ||
402 | void | ||
403 | dsp_change_volume(struct sk_buff *skb, int volume) | ||
404 | { | ||
405 | u8 *volume_change; | ||
406 | int i, ii; | ||
407 | u8 *p; | ||
408 | int shift; | ||
409 | |||
410 | if (volume == 0) | ||
411 | return; | ||
412 | |||
413 | /* get correct conversion table */ | ||
414 | if (volume < 0) { | ||
415 | shift = volume + 8; | ||
416 | if (shift < 0) | ||
417 | shift = 0; | ||
418 | } else { | ||
419 | shift = volume + 7; | ||
420 | if (shift > 15) | ||
421 | shift = 15; | ||
422 | } | ||
423 | volume_change = dsp_audio_volume_change[shift]; | ||
424 | i = 0; | ||
425 | ii = skb->len; | ||
426 | p = skb->data; | ||
427 | /* change volume */ | ||
428 | while (i < ii) { | ||
429 | *p = volume_change[*p]; | ||
430 | p++; | ||
431 | i++; | ||
432 | } | ||
433 | } | ||
434 | |||
diff --git a/drivers/isdn/mISDN/dsp_biquad.h b/drivers/isdn/mISDN/dsp_biquad.h new file mode 100644 index 000000000000..038191bc45f5 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_biquad.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * SpanDSP - a series of DSP components for telephony | ||
3 | * | ||
4 | * biquad.h - General telephony bi-quad section routines (currently this just | ||
5 | * handles canonic/type 2 form) | ||
6 | * | ||
7 | * Written by Steve Underwood <steveu@coppice.org> | ||
8 | * | ||
9 | * Copyright (C) 2001 Steve Underwood | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | struct biquad2_state { | ||
30 | int32_t gain; | ||
31 | int32_t a1; | ||
32 | int32_t a2; | ||
33 | int32_t b1; | ||
34 | int32_t b2; | ||
35 | |||
36 | int32_t z1; | ||
37 | int32_t z2; | ||
38 | }; | ||
39 | |||
40 | static inline void biquad2_init(struct biquad2_state *bq, | ||
41 | int32_t gain, int32_t a1, int32_t a2, int32_t b1, int32_t b2) | ||
42 | { | ||
43 | bq->gain = gain; | ||
44 | bq->a1 = a1; | ||
45 | bq->a2 = a2; | ||
46 | bq->b1 = b1; | ||
47 | bq->b2 = b2; | ||
48 | |||
49 | bq->z1 = 0; | ||
50 | bq->z2 = 0; | ||
51 | } | ||
52 | |||
53 | static inline int16_t biquad2(struct biquad2_state *bq, int16_t sample) | ||
54 | { | ||
55 | int32_t y; | ||
56 | int32_t z0; | ||
57 | |||
58 | z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2; | ||
59 | y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2; | ||
60 | |||
61 | bq->z2 = bq->z1; | ||
62 | bq->z1 = z0 >> 15; | ||
63 | y >>= 15; | ||
64 | return y; | ||
65 | } | ||
diff --git a/drivers/isdn/mISDN/dsp_blowfish.c b/drivers/isdn/mISDN/dsp_blowfish.c new file mode 100644 index 000000000000..18e411e95bba --- /dev/null +++ b/drivers/isdn/mISDN/dsp_blowfish.c | |||
@@ -0,0 +1,672 @@ | |||
1 | /* | ||
2 | * Blowfish encryption/decryption for mISDN_dsp. | ||
3 | * | ||
4 | * Copyright Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * | ||
6 | * This software may be used and distributed according to the terms | ||
7 | * of the GNU General Public License, incorporated herein by reference. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/mISDNif.h> | ||
12 | #include <linux/mISDNdsp.h> | ||
13 | #include "core.h" | ||
14 | #include "dsp.h" | ||
15 | |||
16 | /* | ||
17 | * how to encode a sample stream to 64-bit blocks that will be encryped | ||
18 | * | ||
19 | * first of all, data is collected until a block of 9 samples are received. | ||
20 | * of course, a packet may have much more than 9 sample, but is may have | ||
21 | * not excacly the multiple of 9 samples. if there is a rest, the next | ||
22 | * received data will complete the block. | ||
23 | * | ||
24 | * the block is then converted to 9 uLAW samples without the least sigificant | ||
25 | * bit. the result is a 7-bit encoded sample. | ||
26 | * | ||
27 | * the samples will be reoganised to form 8 bytes of data: | ||
28 | * (5(6) means: encoded sample no. 5, bit 6) | ||
29 | * | ||
30 | * 0(6) 0(5) 0(4) 0(3) 0(2) 0(1) 0(0) 1(6) | ||
31 | * 1(5) 1(4) 1(3) 1(2) 1(1) 1(0) 2(6) 2(5) | ||
32 | * 2(4) 2(3) 2(2) 2(1) 2(0) 3(6) 3(5) 3(4) | ||
33 | * 3(3) 3(2) 3(1) 3(0) 4(6) 4(5) 4(4) 4(3) | ||
34 | * 4(2) 4(1) 4(0) 5(6) 5(5) 5(4) 5(3) 5(2) | ||
35 | * 5(1) 5(0) 6(6) 6(5) 6(4) 6(3) 6(2) 6(1) | ||
36 | * 6(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0) | ||
37 | * 8(6) 8(5) 8(4) 8(3) 8(2) 8(1) 8(0) | ||
38 | * | ||
39 | * the missing bit 0 of the last byte is filled with some | ||
40 | * random noise, to fill all 8 bytes. | ||
41 | * | ||
42 | * the 8 bytes will be encrypted using blowfish. | ||
43 | * | ||
44 | * the result will be converted into 9 bytes. the bit 7 is used for | ||
45 | * checksumme (CS) for sync (0, 1) and for the last bit: | ||
46 | * (5(6) means: crypted byte 5, bit 6) | ||
47 | * | ||
48 | * 1 0(7) 0(6) 0(5) 0(4) 0(3) 0(2) 0(1) | ||
49 | * 0 0(0) 1(7) 1(6) 1(5) 1(4) 1(3) 1(2) | ||
50 | * 0 1(1) 1(0) 2(7) 2(6) 2(5) 2(4) 2(3) | ||
51 | * 0 2(2) 2(1) 2(0) 3(7) 3(6) 3(5) 3(4) | ||
52 | * 0 3(3) 3(2) 3(1) 3(0) 4(7) 4(6) 4(5) | ||
53 | * CS 4(4) 4(3) 4(2) 4(1) 4(0) 5(7) 5(6) | ||
54 | * CS 5(5) 5(4) 5(3) 5(2) 5(1) 5(0) 6(7) | ||
55 | * CS 6(6) 6(5) 6(4) 6(3) 6(2) 6(1) 6(0) | ||
56 | * 7(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0) | ||
57 | * | ||
58 | * the checksum is used to detect transmission errors and frame drops. | ||
59 | * | ||
60 | * synchronisation of received block is done by shifting the upper bit of each | ||
61 | * byte (bit 7) to a shift register. if the rigister has the first five bits | ||
62 | * (10000), this is used to find the sync. only if sync has been found, the | ||
63 | * current block of 9 received bytes are decrypted. before that the check | ||
64 | * sum is calculated. if it is incorrect the block is dropped. | ||
65 | * this will avoid loud noise due to corrupt encrypted data. | ||
66 | * | ||
67 | * if the last block is corrupt, the current decoded block is repeated | ||
68 | * until a valid block has been received. | ||
69 | */ | ||
70 | |||
71 | /* | ||
72 | * some blowfish parts are taken from the | ||
73 | * crypto-api for faster implementation | ||
74 | */ | ||
75 | |||
76 | struct bf_ctx { | ||
77 | u32 p[18]; | ||
78 | u32 s[1024]; | ||
79 | }; | ||
80 | |||
81 | static const u32 bf_pbox[16 + 2] = { | ||
82 | 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, | ||
83 | 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, | ||
84 | 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, | ||
85 | 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, | ||
86 | 0x9216d5d9, 0x8979fb1b, | ||
87 | }; | ||
88 | |||
89 | static const u32 bf_sbox[256 * 4] = { | ||
90 | 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, | ||
91 | 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, | ||
92 | 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, | ||
93 | 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, | ||
94 | 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, | ||
95 | 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, | ||
96 | 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, | ||
97 | 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, | ||
98 | 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, | ||
99 | 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, | ||
100 | 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, | ||
101 | 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, | ||
102 | 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, | ||
103 | 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, | ||
104 | 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, | ||
105 | 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, | ||
106 | 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, | ||
107 | 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, | ||
108 | 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, | ||
109 | 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, | ||
110 | 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, | ||
111 | 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, | ||
112 | 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, | ||
113 | 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, | ||
114 | 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, | ||
115 | 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, | ||
116 | 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, | ||
117 | 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, | ||
118 | 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, | ||
119 | 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, | ||
120 | 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, | ||
121 | 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, | ||
122 | 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, | ||
123 | 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, | ||
124 | 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, | ||
125 | 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, | ||
126 | 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, | ||
127 | 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, | ||
128 | 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, | ||
129 | 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, | ||
130 | 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, | ||
131 | 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, | ||
132 | 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, | ||
133 | 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, | ||
134 | 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, | ||
135 | 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, | ||
136 | 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, | ||
137 | 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, | ||
138 | 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, | ||
139 | 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, | ||
140 | 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, | ||
141 | 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, | ||
142 | 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, | ||
143 | 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, | ||
144 | 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, | ||
145 | 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, | ||
146 | 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, | ||
147 | 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, | ||
148 | 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, | ||
149 | 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, | ||
150 | 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, | ||
151 | 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, | ||
152 | 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, | ||
153 | 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, | ||
154 | 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, | ||
155 | 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, | ||
156 | 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, | ||
157 | 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, | ||
158 | 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, | ||
159 | 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, | ||
160 | 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, | ||
161 | 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, | ||
162 | 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, | ||
163 | 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, | ||
164 | 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, | ||
165 | 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, | ||
166 | 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, | ||
167 | 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, | ||
168 | 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, | ||
169 | 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, | ||
170 | 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, | ||
171 | 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, | ||
172 | 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, | ||
173 | 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, | ||
174 | 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, | ||
175 | 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, | ||
176 | 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, | ||
177 | 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, | ||
178 | 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, | ||
179 | 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, | ||
180 | 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, | ||
181 | 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, | ||
182 | 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, | ||
183 | 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, | ||
184 | 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, | ||
185 | 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, | ||
186 | 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, | ||
187 | 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, | ||
188 | 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, | ||
189 | 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, | ||
190 | 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, | ||
191 | 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, | ||
192 | 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, | ||
193 | 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, | ||
194 | 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, | ||
195 | 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, | ||
196 | 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, | ||
197 | 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, | ||
198 | 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, | ||
199 | 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, | ||
200 | 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, | ||
201 | 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, | ||
202 | 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, | ||
203 | 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, | ||
204 | 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, | ||
205 | 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, | ||
206 | 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, | ||
207 | 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, | ||
208 | 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, | ||
209 | 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, | ||
210 | 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, | ||
211 | 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, | ||
212 | 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, | ||
213 | 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, | ||
214 | 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, | ||
215 | 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, | ||
216 | 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, | ||
217 | 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, | ||
218 | 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, | ||
219 | 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, | ||
220 | 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, | ||
221 | 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, | ||
222 | 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, | ||
223 | 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, | ||
224 | 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, | ||
225 | 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, | ||
226 | 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, | ||
227 | 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, | ||
228 | 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, | ||
229 | 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, | ||
230 | 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, | ||
231 | 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, | ||
232 | 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, | ||
233 | 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, | ||
234 | 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, | ||
235 | 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, | ||
236 | 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, | ||
237 | 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, | ||
238 | 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, | ||
239 | 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, | ||
240 | 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, | ||
241 | 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, | ||
242 | 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, | ||
243 | 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, | ||
244 | 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, | ||
245 | 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, | ||
246 | 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, | ||
247 | 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, | ||
248 | 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, | ||
249 | 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, | ||
250 | 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, | ||
251 | 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, | ||
252 | 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, | ||
253 | 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, | ||
254 | 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, | ||
255 | 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, | ||
256 | 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, | ||
257 | 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, | ||
258 | 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, | ||
259 | 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, | ||
260 | 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, | ||
261 | 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, | ||
262 | 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, | ||
263 | 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, | ||
264 | 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, | ||
265 | 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, | ||
266 | 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, | ||
267 | 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, | ||
268 | 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, | ||
269 | 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, | ||
270 | 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, | ||
271 | 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, | ||
272 | 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, | ||
273 | 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, | ||
274 | 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, | ||
275 | 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, | ||
276 | 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, | ||
277 | 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, | ||
278 | 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, | ||
279 | 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, | ||
280 | 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, | ||
281 | 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, | ||
282 | 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, | ||
283 | 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, | ||
284 | 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, | ||
285 | 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, | ||
286 | 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, | ||
287 | 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, | ||
288 | 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, | ||
289 | 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, | ||
290 | 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, | ||
291 | 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, | ||
292 | 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, | ||
293 | 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, | ||
294 | 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, | ||
295 | 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, | ||
296 | 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, | ||
297 | 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, | ||
298 | 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, | ||
299 | 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, | ||
300 | 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, | ||
301 | 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, | ||
302 | 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, | ||
303 | 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, | ||
304 | 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, | ||
305 | 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, | ||
306 | 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, | ||
307 | 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, | ||
308 | 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, | ||
309 | 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, | ||
310 | 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, | ||
311 | 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, | ||
312 | 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, | ||
313 | 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, | ||
314 | 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, | ||
315 | 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, | ||
316 | 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, | ||
317 | 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, | ||
318 | 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, | ||
319 | 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, | ||
320 | 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, | ||
321 | 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, | ||
322 | 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, | ||
323 | 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, | ||
324 | 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, | ||
325 | 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, | ||
326 | 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, | ||
327 | 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, | ||
328 | 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, | ||
329 | 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, | ||
330 | 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, | ||
331 | 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, | ||
332 | 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, | ||
333 | 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, | ||
334 | 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, | ||
335 | 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, | ||
336 | 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, | ||
337 | 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, | ||
338 | 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, | ||
339 | 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, | ||
340 | 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, | ||
341 | 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, | ||
342 | 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, | ||
343 | 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, | ||
344 | 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, | ||
345 | 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, | ||
346 | }; | ||
347 | |||
348 | /* | ||
349 | * Round loop unrolling macros, S is a pointer to a S-Box array | ||
350 | * organized in 4 unsigned longs at a row. | ||
351 | */ | ||
352 | #define GET32_3(x) (((x) & 0xff)) | ||
353 | #define GET32_2(x) (((x) >> (8)) & (0xff)) | ||
354 | #define GET32_1(x) (((x) >> (16)) & (0xff)) | ||
355 | #define GET32_0(x) (((x) >> (24)) & (0xff)) | ||
356 | |||
357 | #define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \ | ||
358 | S[512 + GET32_2(x)]) + S[768 + GET32_3(x)]) | ||
359 | |||
360 | #define EROUND(a, b, n) do { b ^= P[n]; a ^= bf_F(b); } while (0) | ||
361 | #define DROUND(a, b, n) do { a ^= bf_F(b); b ^= P[n]; } while (0) | ||
362 | |||
363 | |||
364 | /* | ||
365 | * encrypt isdn data frame | ||
366 | * every block with 9 samples is encrypted | ||
367 | */ | ||
368 | void | ||
369 | dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len) | ||
370 | { | ||
371 | int i = 0, j = dsp->bf_crypt_pos; | ||
372 | u8 *bf_data_in = dsp->bf_data_in; | ||
373 | u8 *bf_crypt_out = dsp->bf_crypt_out; | ||
374 | u32 *P = dsp->bf_p; | ||
375 | u32 *S = dsp->bf_s; | ||
376 | u32 yl, yr; | ||
377 | u32 cs; | ||
378 | u8 nibble; | ||
379 | |||
380 | while (i < len) { | ||
381 | /* collect a block of 9 samples */ | ||
382 | if (j < 9) { | ||
383 | bf_data_in[j] = *data; | ||
384 | *data++ = bf_crypt_out[j++]; | ||
385 | i++; | ||
386 | continue; | ||
387 | } | ||
388 | j = 0; | ||
389 | /* transcode 9 samples xlaw to 8 bytes */ | ||
390 | yl = dsp_audio_law2seven[bf_data_in[0]]; | ||
391 | yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[1]]; | ||
392 | yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[2]]; | ||
393 | yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[3]]; | ||
394 | nibble = dsp_audio_law2seven[bf_data_in[4]]; | ||
395 | yr = nibble; | ||
396 | yl = (yl<<4) | (nibble>>3); | ||
397 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[5]]; | ||
398 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[6]]; | ||
399 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[7]]; | ||
400 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[8]]; | ||
401 | yr = (yr<<1) | (bf_data_in[0] & 1); | ||
402 | |||
403 | /* fill unused bit with random noise of audio input */ | ||
404 | /* encrypt */ | ||
405 | |||
406 | EROUND(yr, yl, 0); | ||
407 | EROUND(yl, yr, 1); | ||
408 | EROUND(yr, yl, 2); | ||
409 | EROUND(yl, yr, 3); | ||
410 | EROUND(yr, yl, 4); | ||
411 | EROUND(yl, yr, 5); | ||
412 | EROUND(yr, yl, 6); | ||
413 | EROUND(yl, yr, 7); | ||
414 | EROUND(yr, yl, 8); | ||
415 | EROUND(yl, yr, 9); | ||
416 | EROUND(yr, yl, 10); | ||
417 | EROUND(yl, yr, 11); | ||
418 | EROUND(yr, yl, 12); | ||
419 | EROUND(yl, yr, 13); | ||
420 | EROUND(yr, yl, 14); | ||
421 | EROUND(yl, yr, 15); | ||
422 | yl ^= P[16]; | ||
423 | yr ^= P[17]; | ||
424 | |||
425 | /* calculate 3-bit checksumme */ | ||
426 | cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15) | ||
427 | ^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30) | ||
428 | ^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10) | ||
429 | ^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25) | ||
430 | ^ (yr>>28) ^ (yr>>31); | ||
431 | |||
432 | /* | ||
433 | * transcode 8 crypted bytes to 9 data bytes with sync | ||
434 | * and checksum information | ||
435 | */ | ||
436 | bf_crypt_out[0] = (yl>>25) | 0x80; | ||
437 | bf_crypt_out[1] = (yl>>18) & 0x7f; | ||
438 | bf_crypt_out[2] = (yl>>11) & 0x7f; | ||
439 | bf_crypt_out[3] = (yl>>4) & 0x7f; | ||
440 | bf_crypt_out[4] = ((yl<<3) & 0x78) | ((yr>>29) & 0x07); | ||
441 | bf_crypt_out[5] = ((yr>>22) & 0x7f) | ((cs<<5) & 0x80); | ||
442 | bf_crypt_out[6] = ((yr>>15) & 0x7f) | ((cs<<6) & 0x80); | ||
443 | bf_crypt_out[7] = ((yr>>8) & 0x7f) | (cs<<7); | ||
444 | bf_crypt_out[8] = yr; | ||
445 | } | ||
446 | |||
447 | /* write current count */ | ||
448 | dsp->bf_crypt_pos = j; | ||
449 | |||
450 | } | ||
451 | |||
452 | |||
453 | /* | ||
454 | * decrypt isdn data frame | ||
455 | * every block with 9 bytes is decrypted | ||
456 | */ | ||
457 | void | ||
458 | dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len) | ||
459 | { | ||
460 | int i = 0; | ||
461 | u8 j = dsp->bf_decrypt_in_pos; | ||
462 | u8 k = dsp->bf_decrypt_out_pos; | ||
463 | u8 *bf_crypt_inring = dsp->bf_crypt_inring; | ||
464 | u8 *bf_data_out = dsp->bf_data_out; | ||
465 | u16 sync = dsp->bf_sync; | ||
466 | u32 *P = dsp->bf_p; | ||
467 | u32 *S = dsp->bf_s; | ||
468 | u32 yl, yr; | ||
469 | u8 nibble; | ||
470 | u8 cs, cs0, cs1, cs2; | ||
471 | |||
472 | while (i < len) { | ||
473 | /* | ||
474 | * shift upper bit and rotate data to buffer ring | ||
475 | * send current decrypted data | ||
476 | */ | ||
477 | sync = (sync<<1) | ((*data)>>7); | ||
478 | bf_crypt_inring[j++ & 15] = *data; | ||
479 | *data++ = bf_data_out[k++]; | ||
480 | i++; | ||
481 | if (k == 9) | ||
482 | k = 0; /* repeat if no sync has been found */ | ||
483 | /* check if not in sync */ | ||
484 | if ((sync&0x1f0) != 0x100) | ||
485 | continue; | ||
486 | j -= 9; | ||
487 | /* transcode receive data to 64 bit block of encrypted data */ | ||
488 | yl = bf_crypt_inring[j++ & 15]; | ||
489 | yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
490 | yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
491 | yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
492 | nibble = bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
493 | yr = nibble; | ||
494 | yl = (yl<<4) | (nibble>>3); | ||
495 | cs2 = bf_crypt_inring[j++ & 15]; | ||
496 | yr = (yr<<7) | (cs2 & 0x7f); | ||
497 | cs1 = bf_crypt_inring[j++ & 15]; | ||
498 | yr = (yr<<7) | (cs1 & 0x7f); | ||
499 | cs0 = bf_crypt_inring[j++ & 15]; | ||
500 | yr = (yr<<7) | (cs0 & 0x7f); | ||
501 | yr = (yr<<8) | bf_crypt_inring[j++ & 15]; | ||
502 | |||
503 | /* calculate 3-bit checksumme */ | ||
504 | cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15) | ||
505 | ^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30) | ||
506 | ^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10) | ||
507 | ^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25) | ||
508 | ^ (yr>>28) ^ (yr>>31); | ||
509 | |||
510 | /* check if frame is valid */ | ||
511 | if ((cs&0x7) != (((cs2>>5)&4) | ((cs1>>6)&2) | (cs0 >> 7))) { | ||
512 | if (dsp_debug & DEBUG_DSP_BLOWFISH) | ||
513 | printk(KERN_DEBUG | ||
514 | "DSP BLOWFISH: received corrupt frame, " | ||
515 | "checksumme is not correct\n"); | ||
516 | continue; | ||
517 | } | ||
518 | |||
519 | /* decrypt */ | ||
520 | yr ^= P[17]; | ||
521 | yl ^= P[16]; | ||
522 | DROUND(yl, yr, 15); | ||
523 | DROUND(yr, yl, 14); | ||
524 | DROUND(yl, yr, 13); | ||
525 | DROUND(yr, yl, 12); | ||
526 | DROUND(yl, yr, 11); | ||
527 | DROUND(yr, yl, 10); | ||
528 | DROUND(yl, yr, 9); | ||
529 | DROUND(yr, yl, 8); | ||
530 | DROUND(yl, yr, 7); | ||
531 | DROUND(yr, yl, 6); | ||
532 | DROUND(yl, yr, 5); | ||
533 | DROUND(yr, yl, 4); | ||
534 | DROUND(yl, yr, 3); | ||
535 | DROUND(yr, yl, 2); | ||
536 | DROUND(yl, yr, 1); | ||
537 | DROUND(yr, yl, 0); | ||
538 | |||
539 | /* transcode 8 crypted bytes to 9 sample bytes */ | ||
540 | bf_data_out[0] = dsp_audio_seven2law[(yl>>25) & 0x7f]; | ||
541 | bf_data_out[1] = dsp_audio_seven2law[(yl>>18) & 0x7f]; | ||
542 | bf_data_out[2] = dsp_audio_seven2law[(yl>>11) & 0x7f]; | ||
543 | bf_data_out[3] = dsp_audio_seven2law[(yl>>4) & 0x7f]; | ||
544 | bf_data_out[4] = dsp_audio_seven2law[((yl<<3) & 0x78) | | ||
545 | ((yr>>29) & 0x07)]; | ||
546 | |||
547 | bf_data_out[5] = dsp_audio_seven2law[(yr>>22) & 0x7f]; | ||
548 | bf_data_out[6] = dsp_audio_seven2law[(yr>>15) & 0x7f]; | ||
549 | bf_data_out[7] = dsp_audio_seven2law[(yr>>8) & 0x7f]; | ||
550 | bf_data_out[8] = dsp_audio_seven2law[(yr>>1) & 0x7f]; | ||
551 | k = 0; /* start with new decoded frame */ | ||
552 | } | ||
553 | |||
554 | /* write current count and sync */ | ||
555 | dsp->bf_decrypt_in_pos = j; | ||
556 | dsp->bf_decrypt_out_pos = k; | ||
557 | dsp->bf_sync = sync; | ||
558 | } | ||
559 | |||
560 | |||
561 | /* used to encrypt S and P boxes */ | ||
562 | static inline void | ||
563 | encrypt_block(const u32 *P, const u32 *S, u32 *dst, u32 *src) | ||
564 | { | ||
565 | u32 yl = src[0]; | ||
566 | u32 yr = src[1]; | ||
567 | |||
568 | EROUND(yr, yl, 0); | ||
569 | EROUND(yl, yr, 1); | ||
570 | EROUND(yr, yl, 2); | ||
571 | EROUND(yl, yr, 3); | ||
572 | EROUND(yr, yl, 4); | ||
573 | EROUND(yl, yr, 5); | ||
574 | EROUND(yr, yl, 6); | ||
575 | EROUND(yl, yr, 7); | ||
576 | EROUND(yr, yl, 8); | ||
577 | EROUND(yl, yr, 9); | ||
578 | EROUND(yr, yl, 10); | ||
579 | EROUND(yl, yr, 11); | ||
580 | EROUND(yr, yl, 12); | ||
581 | EROUND(yl, yr, 13); | ||
582 | EROUND(yr, yl, 14); | ||
583 | EROUND(yl, yr, 15); | ||
584 | |||
585 | yl ^= P[16]; | ||
586 | yr ^= P[17]; | ||
587 | |||
588 | dst[0] = yr; | ||
589 | dst[1] = yl; | ||
590 | } | ||
591 | |||
592 | /* | ||
593 | * initialize the dsp for encryption and decryption using the same key | ||
594 | * Calculates the blowfish S and P boxes for encryption and decryption. | ||
595 | * The margin of keylen must be 4-56 bytes. | ||
596 | * returns 0 if ok. | ||
597 | */ | ||
598 | int | ||
599 | dsp_bf_init(struct dsp *dsp, const u8 *key, uint keylen) | ||
600 | { | ||
601 | short i, j, count; | ||
602 | u32 data[2], temp; | ||
603 | u32 *P = (u32 *)dsp->bf_p; | ||
604 | u32 *S = (u32 *)dsp->bf_s; | ||
605 | |||
606 | if (keylen < 4 || keylen > 56) | ||
607 | return 1; | ||
608 | |||
609 | /* Set dsp states */ | ||
610 | i = 0; | ||
611 | while (i < 9) { | ||
612 | dsp->bf_crypt_out[i] = 0xff; | ||
613 | dsp->bf_data_out[i] = dsp_silence; | ||
614 | i++; | ||
615 | } | ||
616 | dsp->bf_crypt_pos = 0; | ||
617 | dsp->bf_decrypt_in_pos = 0; | ||
618 | dsp->bf_decrypt_out_pos = 0; | ||
619 | dsp->bf_sync = 0x1ff; | ||
620 | dsp->bf_enable = 1; | ||
621 | |||
622 | /* Copy the initialization s-boxes */ | ||
623 | for (i = 0, count = 0; i < 256; i++) | ||
624 | for (j = 0; j < 4; j++, count++) | ||
625 | S[count] = bf_sbox[count]; | ||
626 | |||
627 | /* Set the p-boxes */ | ||
628 | for (i = 0; i < 16 + 2; i++) | ||
629 | P[i] = bf_pbox[i]; | ||
630 | |||
631 | /* Actual subkey generation */ | ||
632 | for (j = 0, i = 0; i < 16 + 2; i++) { | ||
633 | temp = (((u32)key[j] << 24) | | ||
634 | ((u32)key[(j + 1) % keylen] << 16) | | ||
635 | ((u32)key[(j + 2) % keylen] << 8) | | ||
636 | ((u32)key[(j + 3) % keylen])); | ||
637 | |||
638 | P[i] = P[i] ^ temp; | ||
639 | j = (j + 4) % keylen; | ||
640 | } | ||
641 | |||
642 | data[0] = 0x00000000; | ||
643 | data[1] = 0x00000000; | ||
644 | |||
645 | for (i = 0; i < 16 + 2; i += 2) { | ||
646 | encrypt_block(P, S, data, data); | ||
647 | |||
648 | P[i] = data[0]; | ||
649 | P[i + 1] = data[1]; | ||
650 | } | ||
651 | |||
652 | for (i = 0; i < 4; i++) { | ||
653 | for (j = 0, count = i * 256; j < 256; j += 2, count += 2) { | ||
654 | encrypt_block(P, S, data, data); | ||
655 | |||
656 | S[count] = data[0]; | ||
657 | S[count + 1] = data[1]; | ||
658 | } | ||
659 | } | ||
660 | |||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | |||
665 | /* | ||
666 | * turn encryption off | ||
667 | */ | ||
668 | void | ||
669 | dsp_bf_cleanup(struct dsp *dsp) | ||
670 | { | ||
671 | dsp->bf_enable = 0; | ||
672 | } | ||
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c new file mode 100644 index 000000000000..e92b1ba4b45e --- /dev/null +++ b/drivers/isdn/mISDN/dsp_cmx.c | |||
@@ -0,0 +1,1886 @@ | |||
1 | /* | ||
2 | * Audio crossconnecting/conferrencing (hardware level). | ||
3 | * | ||
4 | * Copyright 2002 by Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * | ||
6 | * This software may be used and distributed according to the terms | ||
7 | * of the GNU General Public License, incorporated herein by reference. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * The process of adding and removing parties to/from a conference: | ||
13 | * | ||
14 | * There is a chain of struct dsp_conf which has one or more members in a chain | ||
15 | * of struct dsp_conf_member. | ||
16 | * | ||
17 | * After a party is added, the conference is checked for hardware capability. | ||
18 | * Also if a party is removed, the conference is checked again. | ||
19 | * | ||
20 | * There are 3 different solutions: -1 = software, 0 = hardware-crossconnect | ||
21 | * 1-n = hardware-conference. The n will give the conference number. | ||
22 | * | ||
23 | * Depending on the change after removal or insertion of a party, hardware | ||
24 | * commands are given. | ||
25 | * | ||
26 | * The current solution is stored within the struct dsp_conf entry. | ||
27 | */ | ||
28 | |||
29 | /* | ||
30 | * HOW THE CMX WORKS: | ||
31 | * | ||
32 | * There are 3 types of interaction: One member is alone, in this case only | ||
33 | * data flow from upper to lower layer is done. | ||
34 | * Two members will also exchange their data so they are crossconnected. | ||
35 | * Three or more members will be added in a conference and will hear each | ||
36 | * other but will not receive their own speech (echo) if not enabled. | ||
37 | * | ||
38 | * Features of CMX are: | ||
39 | * - Crossconnecting or even conference, if more than two members are together. | ||
40 | * - Force mixing of transmit data with other crossconnect/conference members. | ||
41 | * - Echo generation to benchmark the delay of audio processing. | ||
42 | * - Use hardware to minimize cpu load, disable FIFO load and minimize delay. | ||
43 | * - Dejittering and clock generation. | ||
44 | * | ||
45 | * There are 2 buffers: | ||
46 | * | ||
47 | * | ||
48 | * RX-Buffer | ||
49 | * R W | ||
50 | * | | | ||
51 | * ----------------+-------------+------------------- | ||
52 | * | ||
53 | * The rx-buffer is a ring buffer used to store the received data for each | ||
54 | * individual member. This is only the case if data needs to be dejittered | ||
55 | * or in case of a conference where different clocks require reclocking. | ||
56 | * The transmit-clock (R) will read the buffer. | ||
57 | * If the clock overruns the write-pointer, we will have a buffer underrun. | ||
58 | * If the write pointer always has a certain distance from the transmit- | ||
59 | * clock, we will have a delay. The delay will dynamically be increased and | ||
60 | * reduced. | ||
61 | * | ||
62 | * | ||
63 | * TX-Buffer | ||
64 | * R W | ||
65 | * | | | ||
66 | * -----------------+--------+----------------------- | ||
67 | * | ||
68 | * The tx-buffer is a ring buffer to queue the transmit data from user space | ||
69 | * until it will be mixed or sent. There are two pointers, R and W. If the write | ||
70 | * pointer W would reach or overrun R, the buffer would overrun. In this case | ||
71 | * (some) data is dropped so that it will not overrun. | ||
72 | * Additionally a dynamic dejittering can be enabled. this allows data from | ||
73 | * user space that have jitter and different clock source. | ||
74 | * | ||
75 | * | ||
76 | * Clock: | ||
77 | * | ||
78 | * A Clock is not required, if the data source has exactly one clock. In this | ||
79 | * case the data source is forwarded to the destination. | ||
80 | * | ||
81 | * A Clock is required, because the data source | ||
82 | * - has multiple clocks. | ||
83 | * - has no usable clock due to jitter or packet loss (VoIP). | ||
84 | * In this case the system's clock is used. The clock resolution depends on | ||
85 | * the jiffie resolution. | ||
86 | * | ||
87 | * If a member joins a conference: | ||
88 | * | ||
89 | * - If a member joins, its rx_buff is set to silence and change read pointer | ||
90 | * to transmit clock. | ||
91 | * | ||
92 | * The procedure of received data from card is explained in cmx_receive. | ||
93 | * The procedure of received data from user space is explained in cmx_transmit. | ||
94 | * The procedure of transmit data to card is cmx_send. | ||
95 | * | ||
96 | * | ||
97 | * Interaction with other features: | ||
98 | * | ||
99 | * DTMF: | ||
100 | * DTMF decoding is done before the data is crossconnected. | ||
101 | * | ||
102 | * Volume change: | ||
103 | * Changing rx-volume is done before the data is crossconnected. The tx-volume | ||
104 | * must be changed whenever data is transmitted to the card by the cmx. | ||
105 | * | ||
106 | * Tones: | ||
107 | * If a tone is enabled, it will be processed whenever data is transmitted to | ||
108 | * the card. It will replace the tx-data from the user space. | ||
109 | * If tones are generated by hardware, this conference member is removed for | ||
110 | * this time. | ||
111 | * | ||
112 | * Disable rx-data: | ||
113 | * If cmx is realized in hardware, rx data will be disabled if requested by | ||
114 | * the upper layer. If dtmf decoding is done by software and enabled, rx data | ||
115 | * will not be diabled but blocked to the upper layer. | ||
116 | * | ||
117 | * HFC conference engine: | ||
118 | * If it is possible to realize all features using hardware, hardware will be | ||
119 | * used if not forbidden by control command. Disabling rx-data provides | ||
120 | * absolutely traffic free audio processing. (except for the quick 1-frame | ||
121 | * upload of a tone loop, only once for a new tone) | ||
122 | * | ||
123 | */ | ||
124 | |||
125 | /* delay.h is required for hw_lock.h */ | ||
126 | |||
127 | #include <linux/delay.h> | ||
128 | #include <linux/mISDNif.h> | ||
129 | #include <linux/mISDNdsp.h> | ||
130 | #include "core.h" | ||
131 | #include "dsp.h" | ||
132 | /* | ||
133 | * debugging of multi party conference, | ||
134 | * by using conference even with two members | ||
135 | */ | ||
136 | |||
137 | /* #define CMX_CONF_DEBUG */ | ||
138 | |||
139 | /*#define CMX_DEBUG * massive read/write pointer output */ | ||
140 | /*#define CMX_TX_DEBUG * massive read/write on tx-buffer with content */ | ||
141 | |||
142 | static inline int | ||
143 | count_list_member(struct list_head *head) | ||
144 | { | ||
145 | int cnt = 0; | ||
146 | struct list_head *m; | ||
147 | |||
148 | list_for_each(m, head) | ||
149 | cnt++; | ||
150 | return cnt; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * debug cmx memory structure | ||
155 | */ | ||
156 | void | ||
157 | dsp_cmx_debug(struct dsp *dsp) | ||
158 | { | ||
159 | struct dsp_conf *conf; | ||
160 | struct dsp_conf_member *member; | ||
161 | struct dsp *odsp; | ||
162 | |||
163 | printk(KERN_DEBUG "-----Current DSP\n"); | ||
164 | list_for_each_entry(odsp, &dsp_ilist, list) { | ||
165 | printk(KERN_DEBUG "* %s echo=%d txmix=%d", | ||
166 | odsp->name, odsp->echo, odsp->tx_mix); | ||
167 | if (odsp->conf) | ||
168 | printk(" (Conf %d)", odsp->conf->id); | ||
169 | if (dsp == odsp) | ||
170 | printk(" *this*"); | ||
171 | printk("\n"); | ||
172 | } | ||
173 | printk(KERN_DEBUG "-----Current Conf:\n"); | ||
174 | list_for_each_entry(conf, &conf_ilist, list) { | ||
175 | printk(KERN_DEBUG "* Conf %d (%p)\n", conf->id, conf); | ||
176 | list_for_each_entry(member, &conf->mlist, list) { | ||
177 | printk(KERN_DEBUG | ||
178 | " - member = %s (slot_tx %d, bank_tx %d, " | ||
179 | "slot_rx %d, bank_rx %d hfc_conf %d)%s\n", | ||
180 | member->dsp->name, member->dsp->pcm_slot_tx, | ||
181 | member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, | ||
182 | member->dsp->pcm_bank_rx, member->dsp->hfc_conf, | ||
183 | (member->dsp == dsp) ? " *this*" : ""); | ||
184 | } | ||
185 | } | ||
186 | printk(KERN_DEBUG "-----end\n"); | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * search conference | ||
191 | */ | ||
192 | static struct dsp_conf * | ||
193 | dsp_cmx_search_conf(u32 id) | ||
194 | { | ||
195 | struct dsp_conf *conf; | ||
196 | |||
197 | if (!id) { | ||
198 | printk(KERN_WARNING "%s: conference ID is 0.\n", __func__); | ||
199 | return NULL; | ||
200 | } | ||
201 | |||
202 | /* search conference */ | ||
203 | list_for_each_entry(conf, &conf_ilist, list) | ||
204 | if (conf->id == id) | ||
205 | return conf; | ||
206 | |||
207 | return NULL; | ||
208 | } | ||
209 | |||
210 | |||
211 | /* | ||
212 | * add member to conference | ||
213 | */ | ||
214 | static int | ||
215 | dsp_cmx_add_conf_member(struct dsp *dsp, struct dsp_conf *conf) | ||
216 | { | ||
217 | struct dsp_conf_member *member; | ||
218 | |||
219 | if (!conf || !dsp) { | ||
220 | printk(KERN_WARNING "%s: conf or dsp is 0.\n", __func__); | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | if (dsp->member) { | ||
224 | printk(KERN_WARNING "%s: dsp is already member in a conf.\n", | ||
225 | __func__); | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | |||
229 | if (dsp->conf) { | ||
230 | printk(KERN_WARNING "%s: dsp is already in a conf.\n", | ||
231 | __func__); | ||
232 | return -EINVAL; | ||
233 | } | ||
234 | |||
235 | member = kzalloc(sizeof(struct dsp_conf_member), GFP_ATOMIC); | ||
236 | if (!member) { | ||
237 | printk(KERN_ERR "kmalloc struct dsp_conf_member failed\n"); | ||
238 | return -ENOMEM; | ||
239 | } | ||
240 | member->dsp = dsp; | ||
241 | /* clear rx buffer */ | ||
242 | memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); | ||
243 | dsp->rx_init = 1; /* rx_W and rx_R will be adjusted on first frame */ | ||
244 | dsp->rx_W = 0; | ||
245 | dsp->rx_R = 0; | ||
246 | |||
247 | list_add_tail(&member->list, &conf->mlist); | ||
248 | |||
249 | dsp->conf = conf; | ||
250 | dsp->member = member; | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | |||
256 | /* | ||
257 | * del member from conference | ||
258 | */ | ||
259 | int | ||
260 | dsp_cmx_del_conf_member(struct dsp *dsp) | ||
261 | { | ||
262 | struct dsp_conf_member *member; | ||
263 | |||
264 | if (!dsp) { | ||
265 | printk(KERN_WARNING "%s: dsp is 0.\n", | ||
266 | __func__); | ||
267 | return -EINVAL; | ||
268 | } | ||
269 | |||
270 | if (!dsp->conf) { | ||
271 | printk(KERN_WARNING "%s: dsp is not in a conf.\n", | ||
272 | __func__); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | |||
276 | if (list_empty(&dsp->conf->mlist)) { | ||
277 | printk(KERN_WARNING "%s: dsp has linked an empty conf.\n", | ||
278 | __func__); | ||
279 | return -EINVAL; | ||
280 | } | ||
281 | |||
282 | /* find us in conf */ | ||
283 | list_for_each_entry(member, &dsp->conf->mlist, list) { | ||
284 | if (member->dsp == dsp) { | ||
285 | list_del(&member->list); | ||
286 | dsp->conf = NULL; | ||
287 | dsp->member = NULL; | ||
288 | kfree(member); | ||
289 | return 0; | ||
290 | } | ||
291 | } | ||
292 | printk(KERN_WARNING | ||
293 | "%s: dsp is not present in its own conf_meber list.\n", | ||
294 | __func__); | ||
295 | |||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | |||
300 | /* | ||
301 | * new conference | ||
302 | */ | ||
303 | static struct dsp_conf | ||
304 | *dsp_cmx_new_conf(u32 id) | ||
305 | { | ||
306 | struct dsp_conf *conf; | ||
307 | |||
308 | if (!id) { | ||
309 | printk(KERN_WARNING "%s: id is 0.\n", | ||
310 | __func__); | ||
311 | return NULL; | ||
312 | } | ||
313 | |||
314 | conf = kzalloc(sizeof(struct dsp_conf), GFP_ATOMIC); | ||
315 | if (!conf) { | ||
316 | printk(KERN_ERR "kmalloc struct dsp_conf failed\n"); | ||
317 | return NULL; | ||
318 | } | ||
319 | INIT_LIST_HEAD(&conf->mlist); | ||
320 | conf->id = id; | ||
321 | |||
322 | list_add_tail(&conf->list, &conf_ilist); | ||
323 | |||
324 | return conf; | ||
325 | } | ||
326 | |||
327 | |||
328 | /* | ||
329 | * del conference | ||
330 | */ | ||
331 | int | ||
332 | dsp_cmx_del_conf(struct dsp_conf *conf) | ||
333 | { | ||
334 | if (!conf) { | ||
335 | printk(KERN_WARNING "%s: conf is null.\n", | ||
336 | __func__); | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | |||
340 | if (!list_empty(&conf->mlist)) { | ||
341 | printk(KERN_WARNING "%s: conf not empty.\n", | ||
342 | __func__); | ||
343 | return -EINVAL; | ||
344 | } | ||
345 | list_del(&conf->list); | ||
346 | kfree(conf); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | |||
352 | /* | ||
353 | * send HW message to hfc card | ||
354 | */ | ||
355 | static void | ||
356 | dsp_cmx_hw_message(struct dsp *dsp, u32 message, u32 param1, u32 param2, | ||
357 | u32 param3, u32 param4) | ||
358 | { | ||
359 | struct mISDN_ctrl_req cq; | ||
360 | |||
361 | memset(&cq, 0, sizeof(cq)); | ||
362 | cq.op = message; | ||
363 | cq.p1 = param1 | (param2 << 8); | ||
364 | cq.p2 = param3 | (param4 << 8); | ||
365 | if (dsp->ch.peer) | ||
366 | dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq); | ||
367 | } | ||
368 | |||
369 | |||
370 | /* | ||
371 | * do hardware update and set the software/hardware flag | ||
372 | * | ||
373 | * either a conference or a dsp instance can be given | ||
374 | * if only dsp instance is given, the instance is not associated with a conf | ||
375 | * and therefore removed. if a conference is given, the dsp is expected to | ||
376 | * be member of that conference. | ||
377 | */ | ||
378 | void | ||
379 | dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) | ||
380 | { | ||
381 | struct dsp_conf_member *member, *nextm; | ||
382 | struct dsp *finddsp; | ||
383 | int memb = 0, i, ii, i1, i2; | ||
384 | int freeunits[8]; | ||
385 | u_char freeslots[256]; | ||
386 | int same_hfc = -1, same_pcm = -1, current_conf = -1, | ||
387 | all_conf = 1; | ||
388 | |||
389 | /* dsp gets updated (no conf) */ | ||
390 | if (!conf) { | ||
391 | if (!dsp) | ||
392 | return; | ||
393 | if (dsp_debug & DEBUG_DSP_CMX) | ||
394 | printk(KERN_DEBUG "%s checking dsp %s\n", | ||
395 | __func__, dsp->name); | ||
396 | one_member: | ||
397 | /* remove HFC conference if enabled */ | ||
398 | if (dsp->hfc_conf >= 0) { | ||
399 | if (dsp_debug & DEBUG_DSP_CMX) | ||
400 | printk(KERN_DEBUG | ||
401 | "%s removing %s from HFC conf %d " | ||
402 | "because dsp is split\n", __func__, | ||
403 | dsp->name, dsp->hfc_conf); | ||
404 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_CONF_SPLIT, | ||
405 | 0, 0, 0, 0); | ||
406 | dsp->hfc_conf = -1; | ||
407 | } | ||
408 | /* process hw echo */ | ||
409 | if (dsp->features.pcm_banks < 1) | ||
410 | return; | ||
411 | if (!dsp->echo) { | ||
412 | /* NO ECHO: remove PCM slot if assigned */ | ||
413 | if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { | ||
414 | if (dsp_debug & DEBUG_DSP_CMX) | ||
415 | printk(KERN_DEBUG "%s removing %s from" | ||
416 | " PCM slot %d (TX) %d (RX) because" | ||
417 | " dsp is split (no echo)\n", | ||
418 | __func__, dsp->name, | ||
419 | dsp->pcm_slot_tx, dsp->pcm_slot_rx); | ||
420 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_DISC, | ||
421 | 0, 0, 0, 0); | ||
422 | dsp->pcm_slot_tx = -1; | ||
423 | dsp->pcm_bank_tx = -1; | ||
424 | dsp->pcm_slot_rx = -1; | ||
425 | dsp->pcm_bank_rx = -1; | ||
426 | } | ||
427 | return; | ||
428 | } | ||
429 | /* ECHO: already echo */ | ||
430 | if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 && | ||
431 | dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) | ||
432 | return; | ||
433 | /* ECHO: if slot already assigned */ | ||
434 | if (dsp->pcm_slot_tx >= 0) { | ||
435 | dsp->pcm_slot_rx = dsp->pcm_slot_tx; | ||
436 | dsp->pcm_bank_tx = 2; /* 2 means loop */ | ||
437 | dsp->pcm_bank_rx = 2; | ||
438 | if (dsp_debug & DEBUG_DSP_CMX) | ||
439 | printk(KERN_DEBUG | ||
440 | "%s refresh %s for echo using slot %d\n", | ||
441 | __func__, dsp->name, | ||
442 | dsp->pcm_slot_tx); | ||
443 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
444 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); | ||
445 | return; | ||
446 | } | ||
447 | /* ECHO: find slot */ | ||
448 | dsp->pcm_slot_tx = -1; | ||
449 | dsp->pcm_slot_rx = -1; | ||
450 | memset(freeslots, 1, sizeof(freeslots)); | ||
451 | list_for_each_entry(finddsp, &dsp_ilist, list) { | ||
452 | if (finddsp->features.pcm_id == dsp->features.pcm_id) { | ||
453 | if (finddsp->pcm_slot_rx >= 0 && | ||
454 | finddsp->pcm_slot_rx < sizeof(freeslots)) | ||
455 | freeslots[finddsp->pcm_slot_tx] = 0; | ||
456 | if (finddsp->pcm_slot_tx >= 0 && | ||
457 | finddsp->pcm_slot_tx < sizeof(freeslots)) | ||
458 | freeslots[finddsp->pcm_slot_rx] = 0; | ||
459 | } | ||
460 | } | ||
461 | i = 0; | ||
462 | ii = dsp->features.pcm_slots; | ||
463 | while (i < ii) { | ||
464 | if (freeslots[i]) | ||
465 | break; | ||
466 | i++; | ||
467 | } | ||
468 | if (i == ii) { | ||
469 | if (dsp_debug & DEBUG_DSP_CMX) | ||
470 | printk(KERN_DEBUG | ||
471 | "%s no slot available for echo\n", | ||
472 | __func__); | ||
473 | /* no more slots available */ | ||
474 | return; | ||
475 | } | ||
476 | /* assign free slot */ | ||
477 | dsp->pcm_slot_tx = i; | ||
478 | dsp->pcm_slot_rx = i; | ||
479 | dsp->pcm_bank_tx = 2; /* loop */ | ||
480 | dsp->pcm_bank_rx = 2; | ||
481 | if (dsp_debug & DEBUG_DSP_CMX) | ||
482 | printk(KERN_DEBUG | ||
483 | "%s assign echo for %s using slot %d\n", | ||
484 | __func__, dsp->name, dsp->pcm_slot_tx); | ||
485 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
486 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); | ||
487 | return; | ||
488 | } | ||
489 | |||
490 | /* conf gets updated (all members) */ | ||
491 | if (dsp_debug & DEBUG_DSP_CMX) | ||
492 | printk(KERN_DEBUG "%s checking conference %d\n", | ||
493 | __func__, conf->id); | ||
494 | |||
495 | if (list_empty(&conf->mlist)) { | ||
496 | printk(KERN_ERR "%s: conference whithout members\n", | ||
497 | __func__); | ||
498 | return; | ||
499 | } | ||
500 | member = list_entry(conf->mlist.next, struct dsp_conf_member, list); | ||
501 | same_hfc = member->dsp->features.hfc_id; | ||
502 | same_pcm = member->dsp->features.pcm_id; | ||
503 | /* check all members in our conference */ | ||
504 | list_for_each_entry(member, &conf->mlist, list) { | ||
505 | /* check if member uses mixing */ | ||
506 | if (member->dsp->tx_mix) { | ||
507 | if (dsp_debug & DEBUG_DSP_CMX) | ||
508 | printk(KERN_DEBUG | ||
509 | "%s dsp %s cannot form a conf, because " | ||
510 | "tx_mix is turned on\n", __func__, | ||
511 | member->dsp->name); | ||
512 | conf_software: | ||
513 | list_for_each_entry(member, &conf->mlist, list) { | ||
514 | dsp = member->dsp; | ||
515 | /* remove HFC conference if enabled */ | ||
516 | if (dsp->hfc_conf >= 0) { | ||
517 | if (dsp_debug & DEBUG_DSP_CMX) | ||
518 | printk(KERN_DEBUG | ||
519 | "%s removing %s from HFC " | ||
520 | "conf %d because not " | ||
521 | "possible with hardware\n", | ||
522 | __func__, | ||
523 | dsp->name, | ||
524 | dsp->hfc_conf); | ||
525 | dsp_cmx_hw_message(dsp, | ||
526 | MISDN_CTRL_HFC_CONF_SPLIT, | ||
527 | 0, 0, 0, 0); | ||
528 | dsp->hfc_conf = -1; | ||
529 | } | ||
530 | /* remove PCM slot if assigned */ | ||
531 | if (dsp->pcm_slot_tx >= 0 || | ||
532 | dsp->pcm_slot_rx >= 0) { | ||
533 | if (dsp_debug & DEBUG_DSP_CMX) | ||
534 | printk(KERN_DEBUG "%s removing " | ||
535 | "%s from PCM slot %d (TX)" | ||
536 | " slot %d (RX) because not" | ||
537 | " possible with hardware\n", | ||
538 | __func__, | ||
539 | dsp->name, | ||
540 | dsp->pcm_slot_tx, | ||
541 | dsp->pcm_slot_rx); | ||
542 | dsp_cmx_hw_message(dsp, | ||
543 | MISDN_CTRL_HFC_PCM_DISC, | ||
544 | 0, 0, 0, 0); | ||
545 | dsp->pcm_slot_tx = -1; | ||
546 | dsp->pcm_bank_tx = -1; | ||
547 | dsp->pcm_slot_rx = -1; | ||
548 | dsp->pcm_bank_rx = -1; | ||
549 | } | ||
550 | } | ||
551 | conf->hardware = 0; | ||
552 | conf->software = 1; | ||
553 | return; | ||
554 | } | ||
555 | /* check if member has echo turned on */ | ||
556 | if (member->dsp->echo) { | ||
557 | if (dsp_debug & DEBUG_DSP_CMX) | ||
558 | printk(KERN_DEBUG | ||
559 | "%s dsp %s cannot form a conf, because " | ||
560 | "echo is turned on\n", __func__, | ||
561 | member->dsp->name); | ||
562 | goto conf_software; | ||
563 | } | ||
564 | /* check if member has tx_mix turned on */ | ||
565 | if (member->dsp->tx_mix) { | ||
566 | if (dsp_debug & DEBUG_DSP_CMX) | ||
567 | printk(KERN_DEBUG | ||
568 | "%s dsp %s cannot form a conf, because " | ||
569 | "tx_mix is turned on\n", | ||
570 | __func__, member->dsp->name); | ||
571 | goto conf_software; | ||
572 | } | ||
573 | /* check if member changes volume at an not suppoted level */ | ||
574 | if (member->dsp->tx_volume) { | ||
575 | if (dsp_debug & DEBUG_DSP_CMX) | ||
576 | printk(KERN_DEBUG | ||
577 | "%s dsp %s cannot form a conf, because " | ||
578 | "tx_volume is changed\n", | ||
579 | __func__, member->dsp->name); | ||
580 | goto conf_software; | ||
581 | } | ||
582 | if (member->dsp->rx_volume) { | ||
583 | if (dsp_debug & DEBUG_DSP_CMX) | ||
584 | printk(KERN_DEBUG | ||
585 | "%s dsp %s cannot form a conf, because " | ||
586 | "rx_volume is changed\n", | ||
587 | __func__, member->dsp->name); | ||
588 | goto conf_software; | ||
589 | } | ||
590 | /* check if tx-data turned on */ | ||
591 | if (member->dsp->tx_data) { | ||
592 | if (dsp_debug & DEBUG_DSP_CMX) | ||
593 | printk(KERN_DEBUG | ||
594 | "%s dsp %s cannot form a conf, because " | ||
595 | "tx_data is turned on\n", | ||
596 | __func__, member->dsp->name); | ||
597 | goto conf_software; | ||
598 | } | ||
599 | /* check if pipeline exists */ | ||
600 | if (member->dsp->pipeline.inuse) { | ||
601 | if (dsp_debug & DEBUG_DSP_CMX) | ||
602 | printk(KERN_DEBUG | ||
603 | "%s dsp %s cannot form a conf, because " | ||
604 | "pipeline exists\n", __func__, | ||
605 | member->dsp->name); | ||
606 | goto conf_software; | ||
607 | } | ||
608 | /* check if encryption is enabled */ | ||
609 | if (member->dsp->bf_enable) { | ||
610 | if (dsp_debug & DEBUG_DSP_CMX) | ||
611 | printk(KERN_DEBUG "%s dsp %s cannot form a " | ||
612 | "conf, because encryption is enabled\n", | ||
613 | __func__, member->dsp->name); | ||
614 | goto conf_software; | ||
615 | } | ||
616 | /* check if member is on a card with PCM support */ | ||
617 | if (member->dsp->features.pcm_id < 0) { | ||
618 | if (dsp_debug & DEBUG_DSP_CMX) | ||
619 | printk(KERN_DEBUG | ||
620 | "%s dsp %s cannot form a conf, because " | ||
621 | "dsp has no PCM bus\n", | ||
622 | __func__, member->dsp->name); | ||
623 | goto conf_software; | ||
624 | } | ||
625 | /* check if relations are on the same PCM bus */ | ||
626 | if (member->dsp->features.pcm_id != same_pcm) { | ||
627 | if (dsp_debug & DEBUG_DSP_CMX) | ||
628 | printk(KERN_DEBUG | ||
629 | "%s dsp %s cannot form a conf, because " | ||
630 | "dsp is on a different PCM bus than the " | ||
631 | "first dsp\n", | ||
632 | __func__, member->dsp->name); | ||
633 | goto conf_software; | ||
634 | } | ||
635 | /* determine if members are on the same hfc chip */ | ||
636 | if (same_hfc != member->dsp->features.hfc_id) | ||
637 | same_hfc = -1; | ||
638 | /* if there are members already in a conference */ | ||
639 | if (current_conf < 0 && member->dsp->hfc_conf >= 0) | ||
640 | current_conf = member->dsp->hfc_conf; | ||
641 | /* if any member is not in a conference */ | ||
642 | if (member->dsp->hfc_conf < 0) | ||
643 | all_conf = 0; | ||
644 | |||
645 | memb++; | ||
646 | } | ||
647 | |||
648 | /* if no member, this is an error */ | ||
649 | if (memb < 1) | ||
650 | return; | ||
651 | |||
652 | /* one member */ | ||
653 | if (memb == 1) { | ||
654 | if (dsp_debug & DEBUG_DSP_CMX) | ||
655 | printk(KERN_DEBUG | ||
656 | "%s conf %d cannot form a HW conference, " | ||
657 | "because dsp is alone\n", __func__, conf->id); | ||
658 | conf->hardware = 0; | ||
659 | conf->software = 0; | ||
660 | member = list_entry(conf->mlist.next, struct dsp_conf_member, | ||
661 | list); | ||
662 | dsp = member->dsp; | ||
663 | goto one_member; | ||
664 | } | ||
665 | |||
666 | /* | ||
667 | * ok, now we are sure that all members are on the same pcm. | ||
668 | * now we will see if we have only two members, so we can do | ||
669 | * crossconnections, which don't have any limitations. | ||
670 | */ | ||
671 | |||
672 | /* if we have only two members */ | ||
673 | if (memb == 2) { | ||
674 | member = list_entry(conf->mlist.next, struct dsp_conf_member, | ||
675 | list); | ||
676 | nextm = list_entry(member->list.next, struct dsp_conf_member, | ||
677 | list); | ||
678 | /* remove HFC conference if enabled */ | ||
679 | if (member->dsp->hfc_conf >= 0) { | ||
680 | if (dsp_debug & DEBUG_DSP_CMX) | ||
681 | printk(KERN_DEBUG | ||
682 | "%s removing %s from HFC conf %d because " | ||
683 | "two parties require only a PCM slot\n", | ||
684 | __func__, member->dsp->name, | ||
685 | member->dsp->hfc_conf); | ||
686 | dsp_cmx_hw_message(member->dsp, | ||
687 | MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); | ||
688 | member->dsp->hfc_conf = -1; | ||
689 | } | ||
690 | if (nextm->dsp->hfc_conf >= 0) { | ||
691 | if (dsp_debug & DEBUG_DSP_CMX) | ||
692 | printk(KERN_DEBUG | ||
693 | "%s removing %s from HFC conf %d because " | ||
694 | "two parties require only a PCM slot\n", | ||
695 | __func__, nextm->dsp->name, | ||
696 | nextm->dsp->hfc_conf); | ||
697 | dsp_cmx_hw_message(nextm->dsp, | ||
698 | MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); | ||
699 | nextm->dsp->hfc_conf = -1; | ||
700 | } | ||
701 | /* if members have two banks (and not on the same chip) */ | ||
702 | if (member->dsp->features.pcm_banks > 1 && | ||
703 | nextm->dsp->features.pcm_banks > 1 && | ||
704 | member->dsp->features.hfc_id != | ||
705 | nextm->dsp->features.hfc_id) { | ||
706 | /* if both members have same slots with crossed banks */ | ||
707 | if (member->dsp->pcm_slot_tx >= 0 && | ||
708 | member->dsp->pcm_slot_rx >= 0 && | ||
709 | nextm->dsp->pcm_slot_tx >= 0 && | ||
710 | nextm->dsp->pcm_slot_rx >= 0 && | ||
711 | nextm->dsp->pcm_slot_tx == | ||
712 | member->dsp->pcm_slot_rx && | ||
713 | nextm->dsp->pcm_slot_rx == | ||
714 | member->dsp->pcm_slot_tx && | ||
715 | nextm->dsp->pcm_slot_tx == | ||
716 | member->dsp->pcm_slot_tx && | ||
717 | member->dsp->pcm_bank_tx != | ||
718 | member->dsp->pcm_bank_rx && | ||
719 | nextm->dsp->pcm_bank_tx != | ||
720 | nextm->dsp->pcm_bank_rx) { | ||
721 | /* all members have same slot */ | ||
722 | if (dsp_debug & DEBUG_DSP_CMX) | ||
723 | printk(KERN_DEBUG | ||
724 | "%s dsp %s & %s stay joined on " | ||
725 | "PCM slot %d bank %d (TX) bank %d " | ||
726 | "(RX) (on different chips)\n", | ||
727 | __func__, | ||
728 | member->dsp->name, | ||
729 | nextm->dsp->name, | ||
730 | member->dsp->pcm_slot_tx, | ||
731 | member->dsp->pcm_bank_tx, | ||
732 | member->dsp->pcm_bank_rx); | ||
733 | conf->hardware = 0; | ||
734 | conf->software = 1; | ||
735 | return; | ||
736 | } | ||
737 | /* find a new slot */ | ||
738 | memset(freeslots, 1, sizeof(freeslots)); | ||
739 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
740 | if (dsp != member->dsp && | ||
741 | dsp != nextm->dsp && | ||
742 | member->dsp->features.pcm_id == | ||
743 | dsp->features.pcm_id) { | ||
744 | if (dsp->pcm_slot_rx >= 0 && | ||
745 | dsp->pcm_slot_rx < | ||
746 | sizeof(freeslots)) | ||
747 | freeslots[dsp->pcm_slot_tx] = 0; | ||
748 | if (dsp->pcm_slot_tx >= 0 && | ||
749 | dsp->pcm_slot_tx < | ||
750 | sizeof(freeslots)) | ||
751 | freeslots[dsp->pcm_slot_rx] = 0; | ||
752 | } | ||
753 | } | ||
754 | i = 0; | ||
755 | ii = member->dsp->features.pcm_slots; | ||
756 | while (i < ii) { | ||
757 | if (freeslots[i]) | ||
758 | break; | ||
759 | i++; | ||
760 | } | ||
761 | if (i == ii) { | ||
762 | if (dsp_debug & DEBUG_DSP_CMX) | ||
763 | printk(KERN_DEBUG | ||
764 | "%s no slot available for " | ||
765 | "%s & %s\n", __func__, | ||
766 | member->dsp->name, | ||
767 | nextm->dsp->name); | ||
768 | /* no more slots available */ | ||
769 | goto conf_software; | ||
770 | } | ||
771 | /* assign free slot */ | ||
772 | member->dsp->pcm_slot_tx = i; | ||
773 | member->dsp->pcm_slot_rx = i; | ||
774 | nextm->dsp->pcm_slot_tx = i; | ||
775 | nextm->dsp->pcm_slot_rx = i; | ||
776 | member->dsp->pcm_bank_rx = 0; | ||
777 | member->dsp->pcm_bank_tx = 1; | ||
778 | nextm->dsp->pcm_bank_rx = 1; | ||
779 | nextm->dsp->pcm_bank_tx = 0; | ||
780 | if (dsp_debug & DEBUG_DSP_CMX) | ||
781 | printk(KERN_DEBUG | ||
782 | "%s adding %s & %s to new PCM slot %d " | ||
783 | "(TX and RX on different chips) because " | ||
784 | "both members have not same slots\n", | ||
785 | __func__, | ||
786 | member->dsp->name, | ||
787 | nextm->dsp->name, | ||
788 | member->dsp->pcm_slot_tx); | ||
789 | dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
790 | member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, | ||
791 | member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); | ||
792 | dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
793 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, | ||
794 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); | ||
795 | conf->hardware = 1; | ||
796 | conf->software = 0; | ||
797 | return; | ||
798 | /* if members have one bank (or on the same chip) */ | ||
799 | } else { | ||
800 | /* if both members have different crossed slots */ | ||
801 | if (member->dsp->pcm_slot_tx >= 0 && | ||
802 | member->dsp->pcm_slot_rx >= 0 && | ||
803 | nextm->dsp->pcm_slot_tx >= 0 && | ||
804 | nextm->dsp->pcm_slot_rx >= 0 && | ||
805 | nextm->dsp->pcm_slot_tx == | ||
806 | member->dsp->pcm_slot_rx && | ||
807 | nextm->dsp->pcm_slot_rx == | ||
808 | member->dsp->pcm_slot_tx && | ||
809 | member->dsp->pcm_slot_tx != | ||
810 | member->dsp->pcm_slot_rx && | ||
811 | member->dsp->pcm_bank_tx == 0 && | ||
812 | member->dsp->pcm_bank_rx == 0 && | ||
813 | nextm->dsp->pcm_bank_tx == 0 && | ||
814 | nextm->dsp->pcm_bank_rx == 0) { | ||
815 | /* all members have same slot */ | ||
816 | if (dsp_debug & DEBUG_DSP_CMX) | ||
817 | printk(KERN_DEBUG | ||
818 | "%s dsp %s & %s stay joined on PCM " | ||
819 | "slot %d (TX) %d (RX) on same chip " | ||
820 | "or one bank PCM)\n", __func__, | ||
821 | member->dsp->name, | ||
822 | nextm->dsp->name, | ||
823 | member->dsp->pcm_slot_tx, | ||
824 | member->dsp->pcm_slot_rx); | ||
825 | conf->hardware = 0; | ||
826 | conf->software = 1; | ||
827 | return; | ||
828 | } | ||
829 | /* find two new slot */ | ||
830 | memset(freeslots, 1, sizeof(freeslots)); | ||
831 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
832 | if (dsp != member->dsp && | ||
833 | dsp != nextm->dsp && | ||
834 | member->dsp->features.pcm_id == | ||
835 | dsp->features.pcm_id) { | ||
836 | if (dsp->pcm_slot_rx >= 0 && | ||
837 | dsp->pcm_slot_rx < | ||
838 | sizeof(freeslots)) | ||
839 | freeslots[dsp->pcm_slot_tx] = 0; | ||
840 | if (dsp->pcm_slot_tx >= 0 && | ||
841 | dsp->pcm_slot_tx < | ||
842 | sizeof(freeslots)) | ||
843 | freeslots[dsp->pcm_slot_rx] = 0; | ||
844 | } | ||
845 | } | ||
846 | i1 = 0; | ||
847 | ii = member->dsp->features.pcm_slots; | ||
848 | while (i1 < ii) { | ||
849 | if (freeslots[i1]) | ||
850 | break; | ||
851 | i1++; | ||
852 | } | ||
853 | if (i1 == ii) { | ||
854 | if (dsp_debug & DEBUG_DSP_CMX) | ||
855 | printk(KERN_DEBUG | ||
856 | "%s no slot available " | ||
857 | "for %s & %s\n", __func__, | ||
858 | member->dsp->name, | ||
859 | nextm->dsp->name); | ||
860 | /* no more slots available */ | ||
861 | goto conf_software; | ||
862 | } | ||
863 | i2 = i1+1; | ||
864 | while (i2 < ii) { | ||
865 | if (freeslots[i2]) | ||
866 | break; | ||
867 | i2++; | ||
868 | } | ||
869 | if (i2 == ii) { | ||
870 | if (dsp_debug & DEBUG_DSP_CMX) | ||
871 | printk(KERN_DEBUG | ||
872 | "%s no slot available " | ||
873 | "for %s & %s\n", | ||
874 | __func__, | ||
875 | member->dsp->name, | ||
876 | nextm->dsp->name); | ||
877 | /* no more slots available */ | ||
878 | goto conf_software; | ||
879 | } | ||
880 | /* assign free slots */ | ||
881 | member->dsp->pcm_slot_tx = i1; | ||
882 | member->dsp->pcm_slot_rx = i2; | ||
883 | nextm->dsp->pcm_slot_tx = i2; | ||
884 | nextm->dsp->pcm_slot_rx = i1; | ||
885 | member->dsp->pcm_bank_rx = 0; | ||
886 | member->dsp->pcm_bank_tx = 0; | ||
887 | nextm->dsp->pcm_bank_rx = 0; | ||
888 | nextm->dsp->pcm_bank_tx = 0; | ||
889 | if (dsp_debug & DEBUG_DSP_CMX) | ||
890 | printk(KERN_DEBUG | ||
891 | "%s adding %s & %s to new PCM slot %d " | ||
892 | "(TX) %d (RX) on same chip or one bank " | ||
893 | "PCM, because both members have not " | ||
894 | "crossed slots\n", __func__, | ||
895 | member->dsp->name, | ||
896 | nextm->dsp->name, | ||
897 | member->dsp->pcm_slot_tx, | ||
898 | member->dsp->pcm_slot_rx); | ||
899 | dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
900 | member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, | ||
901 | member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); | ||
902 | dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
903 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, | ||
904 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); | ||
905 | conf->hardware = 1; | ||
906 | conf->software = 0; | ||
907 | return; | ||
908 | } | ||
909 | } | ||
910 | |||
911 | /* | ||
912 | * if we have more than two, we may check if we have a conference | ||
913 | * unit available on the chip. also all members must be on the same | ||
914 | */ | ||
915 | |||
916 | /* if not the same HFC chip */ | ||
917 | if (same_hfc < 0) { | ||
918 | if (dsp_debug & DEBUG_DSP_CMX) | ||
919 | printk(KERN_DEBUG | ||
920 | "%s conference %d cannot be formed, because " | ||
921 | "members are on different chips or not " | ||
922 | "on HFC chip\n", | ||
923 | __func__, conf->id); | ||
924 | goto conf_software; | ||
925 | } | ||
926 | |||
927 | /* for more than two members.. */ | ||
928 | |||
929 | /* in case of hdlc, we change to software */ | ||
930 | if (dsp->hdlc) | ||
931 | goto conf_software; | ||
932 | |||
933 | /* if all members already have the same conference */ | ||
934 | if (all_conf) | ||
935 | return; | ||
936 | |||
937 | /* | ||
938 | * if there is an existing conference, but not all members have joined | ||
939 | */ | ||
940 | if (current_conf >= 0) { | ||
941 | join_members: | ||
942 | list_for_each_entry(member, &conf->mlist, list) { | ||
943 | /* join to current conference */ | ||
944 | if (member->dsp->hfc_conf == current_conf) | ||
945 | continue; | ||
946 | /* get a free timeslot first */ | ||
947 | memset(freeslots, 1, sizeof(freeslots)); | ||
948 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
949 | /* | ||
950 | * not checking current member, because | ||
951 | * slot will be overwritten. | ||
952 | */ | ||
953 | if ( | ||
954 | dsp != member->dsp && | ||
955 | /* dsp must be on the same PCM */ | ||
956 | member->dsp->features.pcm_id == | ||
957 | dsp->features.pcm_id) { | ||
958 | /* dsp must be on a slot */ | ||
959 | if (dsp->pcm_slot_tx >= 0 && | ||
960 | dsp->pcm_slot_tx < | ||
961 | sizeof(freeslots)) | ||
962 | freeslots[dsp->pcm_slot_tx] = 0; | ||
963 | if (dsp->pcm_slot_rx >= 0 && | ||
964 | dsp->pcm_slot_rx < | ||
965 | sizeof(freeslots)) | ||
966 | freeslots[dsp->pcm_slot_rx] = 0; | ||
967 | } | ||
968 | } | ||
969 | i = 0; | ||
970 | ii = member->dsp->features.pcm_slots; | ||
971 | while (i < ii) { | ||
972 | if (freeslots[i]) | ||
973 | break; | ||
974 | i++; | ||
975 | } | ||
976 | if (i == ii) { | ||
977 | /* no more slots available */ | ||
978 | if (dsp_debug & DEBUG_DSP_CMX) | ||
979 | printk(KERN_DEBUG | ||
980 | "%s conference %d cannot be formed," | ||
981 | " because no slot free\n", | ||
982 | __func__, conf->id); | ||
983 | goto conf_software; | ||
984 | } | ||
985 | if (dsp_debug & DEBUG_DSP_CMX) | ||
986 | printk(KERN_DEBUG | ||
987 | "%s changing dsp %s to HW conference " | ||
988 | "%d slot %d\n", __func__, | ||
989 | member->dsp->name, current_conf, i); | ||
990 | /* assign free slot & set PCM & join conf */ | ||
991 | member->dsp->pcm_slot_tx = i; | ||
992 | member->dsp->pcm_slot_rx = i; | ||
993 | member->dsp->pcm_bank_tx = 2; /* loop */ | ||
994 | member->dsp->pcm_bank_rx = 2; | ||
995 | member->dsp->hfc_conf = current_conf; | ||
996 | dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
997 | i, 2, i, 2); | ||
998 | dsp_cmx_hw_message(member->dsp, | ||
999 | MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0); | ||
1000 | } | ||
1001 | return; | ||
1002 | } | ||
1003 | |||
1004 | /* | ||
1005 | * no member is in a conference yet, so we find a free one | ||
1006 | */ | ||
1007 | memset(freeunits, 1, sizeof(freeunits)); | ||
1008 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
1009 | /* dsp must be on the same chip */ | ||
1010 | if (dsp->features.hfc_id == same_hfc && | ||
1011 | /* dsp must have joined a HW conference */ | ||
1012 | dsp->hfc_conf >= 0 && | ||
1013 | /* slot must be within range */ | ||
1014 | dsp->hfc_conf < 8) | ||
1015 | freeunits[dsp->hfc_conf] = 0; | ||
1016 | } | ||
1017 | i = 0; | ||
1018 | ii = 8; | ||
1019 | while (i < ii) { | ||
1020 | if (freeunits[i]) | ||
1021 | break; | ||
1022 | i++; | ||
1023 | } | ||
1024 | if (i == ii) { | ||
1025 | /* no more conferences available */ | ||
1026 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1027 | printk(KERN_DEBUG | ||
1028 | "%s conference %d cannot be formed, because " | ||
1029 | "no conference number free\n", | ||
1030 | __func__, conf->id); | ||
1031 | goto conf_software; | ||
1032 | } | ||
1033 | /* join all members */ | ||
1034 | current_conf = i; | ||
1035 | goto join_members; | ||
1036 | } | ||
1037 | |||
1038 | |||
1039 | /* | ||
1040 | * conf_id != 0: join or change conference | ||
1041 | * conf_id == 0: split from conference if not already | ||
1042 | */ | ||
1043 | int | ||
1044 | dsp_cmx_conf(struct dsp *dsp, u32 conf_id) | ||
1045 | { | ||
1046 | int err; | ||
1047 | struct dsp_conf *conf; | ||
1048 | struct dsp_conf_member *member; | ||
1049 | |||
1050 | /* if conference doesn't change */ | ||
1051 | if (dsp->conf_id == conf_id) | ||
1052 | return 0; | ||
1053 | |||
1054 | /* first remove us from current conf */ | ||
1055 | if (dsp->conf_id) { | ||
1056 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1057 | printk(KERN_DEBUG "removing us from conference %d\n", | ||
1058 | dsp->conf->id); | ||
1059 | /* remove us from conf */ | ||
1060 | conf = dsp->conf; | ||
1061 | err = dsp_cmx_del_conf_member(dsp); | ||
1062 | if (err) | ||
1063 | return err; | ||
1064 | dsp->conf_id = 0; | ||
1065 | |||
1066 | /* update hardware */ | ||
1067 | dsp_cmx_hardware(NULL, dsp); | ||
1068 | |||
1069 | /* conf now empty? */ | ||
1070 | if (list_empty(&conf->mlist)) { | ||
1071 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1072 | printk(KERN_DEBUG | ||
1073 | "conference is empty, so we remove it.\n"); | ||
1074 | err = dsp_cmx_del_conf(conf); | ||
1075 | if (err) | ||
1076 | return err; | ||
1077 | } else { | ||
1078 | /* update members left on conf */ | ||
1079 | dsp_cmx_hardware(conf, NULL); | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1083 | /* if split */ | ||
1084 | if (!conf_id) | ||
1085 | return 0; | ||
1086 | |||
1087 | /* now add us to conf */ | ||
1088 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1089 | printk(KERN_DEBUG "searching conference %d\n", | ||
1090 | conf_id); | ||
1091 | conf = dsp_cmx_search_conf(conf_id); | ||
1092 | if (!conf) { | ||
1093 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1094 | printk(KERN_DEBUG | ||
1095 | "conference doesn't exist yet, creating.\n"); | ||
1096 | /* the conference doesn't exist, so we create */ | ||
1097 | conf = dsp_cmx_new_conf(conf_id); | ||
1098 | if (!conf) | ||
1099 | return -EINVAL; | ||
1100 | } else if (!list_empty(&conf->mlist)) { | ||
1101 | member = list_entry(conf->mlist.next, struct dsp_conf_member, | ||
1102 | list); | ||
1103 | if (dsp->hdlc && !member->dsp->hdlc) { | ||
1104 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1105 | printk(KERN_DEBUG | ||
1106 | "cannot join transparent conference.\n"); | ||
1107 | return -EINVAL; | ||
1108 | } | ||
1109 | if (!dsp->hdlc && member->dsp->hdlc) { | ||
1110 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1111 | printk(KERN_DEBUG | ||
1112 | "cannot join hdlc conference.\n"); | ||
1113 | return -EINVAL; | ||
1114 | } | ||
1115 | } | ||
1116 | /* add conference member */ | ||
1117 | err = dsp_cmx_add_conf_member(dsp, conf); | ||
1118 | if (err) | ||
1119 | return err; | ||
1120 | dsp->conf_id = conf_id; | ||
1121 | |||
1122 | /* if we are alone, we do nothing! */ | ||
1123 | if (list_empty(&conf->mlist)) { | ||
1124 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1125 | printk(KERN_DEBUG | ||
1126 | "we are alone in this conference, so exit.\n"); | ||
1127 | /* update hardware */ | ||
1128 | dsp_cmx_hardware(NULL, dsp); | ||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | /* update members on conf */ | ||
1133 | dsp_cmx_hardware(conf, NULL); | ||
1134 | |||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | |||
1139 | /* | ||
1140 | * audio data is received from card | ||
1141 | */ | ||
1142 | void | ||
1143 | dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) | ||
1144 | { | ||
1145 | u8 *d, *p; | ||
1146 | int len = skb->len; | ||
1147 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1148 | int w, i, ii; | ||
1149 | |||
1150 | /* check if we have sompen */ | ||
1151 | if (len < 1) | ||
1152 | return; | ||
1153 | |||
1154 | /* half of the buffer should be larger than maximum packet size */ | ||
1155 | if (len >= CMX_BUFF_HALF) { | ||
1156 | printk(KERN_ERR | ||
1157 | "%s line %d: packet from card is too large (%d bytes). " | ||
1158 | "please make card send smaller packets OR increase " | ||
1159 | "CMX_BUFF_SIZE\n", __FILE__, __LINE__, len); | ||
1160 | return; | ||
1161 | } | ||
1162 | |||
1163 | /* | ||
1164 | * initialize pointers if not already - | ||
1165 | * also add delay if requested by PH_SIGNAL | ||
1166 | */ | ||
1167 | if (dsp->rx_init) { | ||
1168 | dsp->rx_init = 0; | ||
1169 | if (dsp->features.unordered) { | ||
1170 | dsp->rx_R = (hh->id & CMX_BUFF_MASK); | ||
1171 | dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) | ||
1172 | & CMX_BUFF_MASK; | ||
1173 | } else { | ||
1174 | dsp->rx_R = 0; | ||
1175 | dsp->rx_W = dsp->cmx_delay; | ||
1176 | } | ||
1177 | } | ||
1178 | /* if frame contains time code, write directly */ | ||
1179 | if (dsp->features.unordered) { | ||
1180 | dsp->rx_W = (hh->id & CMX_BUFF_MASK); | ||
1181 | /* printk(KERN_DEBUG "%s %08x\n", dsp->name, hh->id); */ | ||
1182 | } | ||
1183 | /* | ||
1184 | * if we underrun (or maybe overrun), | ||
1185 | * we set our new read pointer, and write silence to buffer | ||
1186 | */ | ||
1187 | if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) { | ||
1188 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1189 | printk(KERN_DEBUG | ||
1190 | "cmx_receive(dsp=%lx): UNDERRUN (or overrun the " | ||
1191 | "maximum delay), adjusting read pointer! " | ||
1192 | "(inst %s)\n", (u_long)dsp, dsp->name); | ||
1193 | /* flush buffer */ | ||
1194 | if (dsp->features.unordered) { | ||
1195 | dsp->rx_R = (hh->id & CMX_BUFF_MASK); | ||
1196 | dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) | ||
1197 | & CMX_BUFF_MASK; | ||
1198 | } else { | ||
1199 | dsp->rx_R = 0; | ||
1200 | dsp->rx_W = dsp->cmx_delay; | ||
1201 | } | ||
1202 | memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); | ||
1203 | } | ||
1204 | /* if we have reached double delay, jump back to middle */ | ||
1205 | if (dsp->cmx_delay) | ||
1206 | if (((dsp->rx_W - dsp->rx_R) & CMX_BUFF_MASK) >= | ||
1207 | (dsp->cmx_delay << 1)) { | ||
1208 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1209 | printk(KERN_DEBUG | ||
1210 | "cmx_receive(dsp=%lx): OVERRUN (because " | ||
1211 | "twice the delay is reached), adjusting " | ||
1212 | "read pointer! (inst %s)\n", | ||
1213 | (u_long)dsp, dsp->name); | ||
1214 | /* flush buffer */ | ||
1215 | if (dsp->features.unordered) { | ||
1216 | dsp->rx_R = (hh->id & CMX_BUFF_MASK); | ||
1217 | dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) | ||
1218 | & CMX_BUFF_MASK; | ||
1219 | } else { | ||
1220 | dsp->rx_R = 0; | ||
1221 | dsp->rx_W = dsp->cmx_delay; | ||
1222 | } | ||
1223 | memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); | ||
1224 | } | ||
1225 | |||
1226 | /* show where to write */ | ||
1227 | #ifdef CMX_DEBUG | ||
1228 | printk(KERN_DEBUG | ||
1229 | "cmx_receive(dsp=%lx): rx_R(dsp)=%05x rx_W(dsp)=%05x len=%d %s\n", | ||
1230 | (u_long)dsp, dsp->rx_R, dsp->rx_W, len, dsp->name); | ||
1231 | #endif | ||
1232 | |||
1233 | /* write data into rx_buffer */ | ||
1234 | p = skb->data; | ||
1235 | d = dsp->rx_buff; | ||
1236 | w = dsp->rx_W; | ||
1237 | i = 0; | ||
1238 | ii = len; | ||
1239 | while (i < ii) { | ||
1240 | d[w++ & CMX_BUFF_MASK] = *p++; | ||
1241 | i++; | ||
1242 | } | ||
1243 | |||
1244 | /* increase write-pointer */ | ||
1245 | dsp->rx_W = ((dsp->rx_W+len) & CMX_BUFF_MASK); | ||
1246 | } | ||
1247 | |||
1248 | |||
1249 | /* | ||
1250 | * send (mixed) audio data to card and control jitter | ||
1251 | */ | ||
1252 | static void | ||
1253 | dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) | ||
1254 | { | ||
1255 | struct dsp_conf *conf = dsp->conf; | ||
1256 | struct dsp *member, *other; | ||
1257 | register s32 sample; | ||
1258 | u8 *d, *p, *q, *o_q; | ||
1259 | struct sk_buff *nskb, *txskb; | ||
1260 | int r, rr, t, tt, o_r, o_rr; | ||
1261 | int preload = 0; | ||
1262 | struct mISDNhead *hh, *thh; | ||
1263 | |||
1264 | /* don't process if: */ | ||
1265 | if (!dsp->b_active) { /* if not active */ | ||
1266 | dsp->last_tx = 0; | ||
1267 | return; | ||
1268 | } | ||
1269 | if (dsp->pcm_slot_tx >= 0 && /* connected to pcm slot */ | ||
1270 | dsp->tx_R == dsp->tx_W && /* AND no tx-data */ | ||
1271 | !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ | ||
1272 | dsp->last_tx = 0; | ||
1273 | return; | ||
1274 | } | ||
1275 | |||
1276 | #ifdef CMX_DEBUG | ||
1277 | printk(KERN_DEBUG | ||
1278 | "SEND members=%d dsp=%s, conf=%p, rx_R=%05x rx_W=%05x\n", | ||
1279 | members, dsp->name, conf, dsp->rx_R, dsp->rx_W); | ||
1280 | #endif | ||
1281 | |||
1282 | /* preload if we have delay set */ | ||
1283 | if (dsp->cmx_delay && !dsp->last_tx) { | ||
1284 | preload = len; | ||
1285 | if (preload < 128) | ||
1286 | preload = 128; | ||
1287 | } | ||
1288 | |||
1289 | /* PREPARE RESULT */ | ||
1290 | nskb = mI_alloc_skb(len + preload, GFP_ATOMIC); | ||
1291 | if (!nskb) { | ||
1292 | printk(KERN_ERR | ||
1293 | "FATAL ERROR in mISDN_dsp.o: cannot alloc %d bytes\n", | ||
1294 | len + preload); | ||
1295 | return; | ||
1296 | } | ||
1297 | hh = mISDN_HEAD_P(nskb); | ||
1298 | hh->prim = PH_DATA_REQ; | ||
1299 | hh->id = 0; | ||
1300 | dsp->last_tx = 1; | ||
1301 | |||
1302 | /* set pointers, indexes and stuff */ | ||
1303 | member = dsp; | ||
1304 | p = dsp->tx_buff; /* transmit data */ | ||
1305 | q = dsp->rx_buff; /* received data */ | ||
1306 | d = skb_put(nskb, preload + len); /* result */ | ||
1307 | t = dsp->tx_R; /* tx-pointers */ | ||
1308 | tt = dsp->tx_W; | ||
1309 | r = dsp->rx_R; /* rx-pointers */ | ||
1310 | rr = (r + len) & CMX_BUFF_MASK; | ||
1311 | |||
1312 | /* preload with silence, if required */ | ||
1313 | if (preload) { | ||
1314 | memset(d, dsp_silence, preload); | ||
1315 | d += preload; | ||
1316 | } | ||
1317 | |||
1318 | /* PROCESS TONES/TX-DATA ONLY */ | ||
1319 | if (dsp->tone.tone && dsp->tone.software) { | ||
1320 | /* -> copy tone */ | ||
1321 | dsp_tone_copy(dsp, d, len); | ||
1322 | dsp->tx_R = 0; /* clear tx buffer */ | ||
1323 | dsp->tx_W = 0; | ||
1324 | goto send_packet; | ||
1325 | } | ||
1326 | /* if we have tx-data but do not use mixing */ | ||
1327 | if (!dsp->tx_mix && t != tt) { | ||
1328 | /* -> send tx-data and continue when not enough */ | ||
1329 | #ifdef CMX_TX_DEBUG | ||
1330 | sprintf(debugbuf, "TX sending (%04x-%04x)%p: ", t, tt, p); | ||
1331 | #endif | ||
1332 | while (r != rr && t != tt) { | ||
1333 | #ifdef CMX_TX_DEBUG | ||
1334 | if (strlen(debugbuf) < 48) | ||
1335 | sprintf(debugbuf+strlen(debugbuf), " %02x", p[t]); | ||
1336 | #endif | ||
1337 | *d++ = p[t]; /* write tx_buff */ | ||
1338 | t = (t+1) & CMX_BUFF_MASK; | ||
1339 | r = (r+1) & CMX_BUFF_MASK; | ||
1340 | } | ||
1341 | if (r == rr) { | ||
1342 | dsp->tx_R = t; | ||
1343 | #ifdef CMX_TX_DEBUG | ||
1344 | printk(KERN_DEBUG "%s\n", debugbuf); | ||
1345 | #endif | ||
1346 | goto send_packet; | ||
1347 | } | ||
1348 | } | ||
1349 | #ifdef CMX_TX_DEBUG | ||
1350 | printk(KERN_DEBUG "%s\n", debugbuf); | ||
1351 | #endif | ||
1352 | |||
1353 | /* PROCESS DATA (one member / no conf) */ | ||
1354 | if (!conf || members <= 1) { | ||
1355 | /* -> if echo is NOT enabled */ | ||
1356 | if (!dsp->echo) { | ||
1357 | /* -> send tx-data if available or use 0-volume */ | ||
1358 | while (r != rr && t != tt) { | ||
1359 | *d++ = p[t]; /* write tx_buff */ | ||
1360 | t = (t+1) & CMX_BUFF_MASK; | ||
1361 | r = (r+1) & CMX_BUFF_MASK; | ||
1362 | } | ||
1363 | if (r != rr) | ||
1364 | memset(d, dsp_silence, (rr-r)&CMX_BUFF_MASK); | ||
1365 | /* -> if echo is enabled */ | ||
1366 | } else { | ||
1367 | /* | ||
1368 | * -> mix tx-data with echo if available, | ||
1369 | * or use echo only | ||
1370 | */ | ||
1371 | while (r != rr && t != tt) { | ||
1372 | *d++ = dsp_audio_mix_law[(p[t]<<8)|q[r]]; | ||
1373 | t = (t+1) & CMX_BUFF_MASK; | ||
1374 | r = (r+1) & CMX_BUFF_MASK; | ||
1375 | } | ||
1376 | while (r != rr) { | ||
1377 | *d++ = q[r]; /* echo */ | ||
1378 | r = (r+1) & CMX_BUFF_MASK; | ||
1379 | } | ||
1380 | } | ||
1381 | dsp->tx_R = t; | ||
1382 | goto send_packet; | ||
1383 | } | ||
1384 | /* PROCESS DATA (two members) */ | ||
1385 | #ifdef CMX_CONF_DEBUG | ||
1386 | if (0) { | ||
1387 | #else | ||
1388 | if (members == 2) { | ||
1389 | #endif | ||
1390 | /* "other" becomes other party */ | ||
1391 | other = (list_entry(conf->mlist.next, | ||
1392 | struct dsp_conf_member, list))->dsp; | ||
1393 | if (other == member) | ||
1394 | other = (list_entry(conf->mlist.prev, | ||
1395 | struct dsp_conf_member, list))->dsp; | ||
1396 | o_q = other->rx_buff; /* received data */ | ||
1397 | o_rr = (other->rx_R + len) & CMX_BUFF_MASK; | ||
1398 | /* end of rx-pointer */ | ||
1399 | o_r = (o_rr - rr + r) & CMX_BUFF_MASK; | ||
1400 | /* start rx-pointer at current read position*/ | ||
1401 | /* -> if echo is NOT enabled */ | ||
1402 | if (!dsp->echo) { | ||
1403 | /* | ||
1404 | * -> copy other member's rx-data, | ||
1405 | * if tx-data is available, mix | ||
1406 | */ | ||
1407 | while (o_r != o_rr && t != tt) { | ||
1408 | *d++ = dsp_audio_mix_law[(p[t]<<8)|o_q[o_r]]; | ||
1409 | t = (t+1) & CMX_BUFF_MASK; | ||
1410 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
1411 | } | ||
1412 | while (o_r != o_rr) { | ||
1413 | *d++ = o_q[o_r]; | ||
1414 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
1415 | } | ||
1416 | /* -> if echo is enabled */ | ||
1417 | } else { | ||
1418 | /* | ||
1419 | * -> mix other member's rx-data with echo, | ||
1420 | * if tx-data is available, mix | ||
1421 | */ | ||
1422 | while (r != rr && t != tt) { | ||
1423 | sample = dsp_audio_law_to_s32[p[t]] + | ||
1424 | dsp_audio_law_to_s32[q[r]] + | ||
1425 | dsp_audio_law_to_s32[o_q[o_r]]; | ||
1426 | if (sample < -32768) | ||
1427 | sample = -32768; | ||
1428 | else if (sample > 32767) | ||
1429 | sample = 32767; | ||
1430 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
1431 | /* tx-data + rx_data + echo */ | ||
1432 | t = (t+1) & CMX_BUFF_MASK; | ||
1433 | r = (r+1) & CMX_BUFF_MASK; | ||
1434 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
1435 | } | ||
1436 | while (r != rr) { | ||
1437 | *d++ = dsp_audio_mix_law[(q[r]<<8)|o_q[o_r]]; | ||
1438 | r = (r+1) & CMX_BUFF_MASK; | ||
1439 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
1440 | } | ||
1441 | } | ||
1442 | dsp->tx_R = t; | ||
1443 | goto send_packet; | ||
1444 | } | ||
1445 | #ifdef DSP_NEVER_DEFINED | ||
1446 | } | ||
1447 | #endif | ||
1448 | /* PROCESS DATA (three or more members) */ | ||
1449 | /* -> if echo is NOT enabled */ | ||
1450 | if (!dsp->echo) { | ||
1451 | /* | ||
1452 | * -> substract rx-data from conf-data, | ||
1453 | * if tx-data is available, mix | ||
1454 | */ | ||
1455 | while (r != rr && t != tt) { | ||
1456 | sample = dsp_audio_law_to_s32[p[t]] + *c++ - | ||
1457 | dsp_audio_law_to_s32[q[r]]; | ||
1458 | if (sample < -32768) | ||
1459 | sample = -32768; | ||
1460 | else if (sample > 32767) | ||
1461 | sample = 32767; | ||
1462 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
1463 | /* conf-rx+tx */ | ||
1464 | r = (r+1) & CMX_BUFF_MASK; | ||
1465 | t = (t+1) & CMX_BUFF_MASK; | ||
1466 | } | ||
1467 | while (r != rr) { | ||
1468 | sample = *c++ - dsp_audio_law_to_s32[q[r]]; | ||
1469 | if (sample < -32768) | ||
1470 | sample = -32768; | ||
1471 | else if (sample > 32767) | ||
1472 | sample = 32767; | ||
1473 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
1474 | /* conf-rx */ | ||
1475 | r = (r+1) & CMX_BUFF_MASK; | ||
1476 | } | ||
1477 | /* -> if echo is enabled */ | ||
1478 | } else { | ||
1479 | /* | ||
1480 | * -> encode conf-data, if tx-data | ||
1481 | * is available, mix | ||
1482 | */ | ||
1483 | while (r != rr && t != tt) { | ||
1484 | sample = dsp_audio_law_to_s32[p[t]] + *c++; | ||
1485 | if (sample < -32768) | ||
1486 | sample = -32768; | ||
1487 | else if (sample > 32767) | ||
1488 | sample = 32767; | ||
1489 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
1490 | /* conf(echo)+tx */ | ||
1491 | t = (t+1) & CMX_BUFF_MASK; | ||
1492 | r = (r+1) & CMX_BUFF_MASK; | ||
1493 | } | ||
1494 | while (r != rr) { | ||
1495 | sample = *c++; | ||
1496 | if (sample < -32768) | ||
1497 | sample = -32768; | ||
1498 | else if (sample > 32767) | ||
1499 | sample = 32767; | ||
1500 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
1501 | /* conf(echo) */ | ||
1502 | r = (r+1) & CMX_BUFF_MASK; | ||
1503 | } | ||
1504 | } | ||
1505 | dsp->tx_R = t; | ||
1506 | goto send_packet; | ||
1507 | |||
1508 | send_packet: | ||
1509 | /* | ||
1510 | * send tx-data if enabled - don't filter, | ||
1511 | * becuase we want what we send, not what we filtered | ||
1512 | */ | ||
1513 | if (dsp->tx_data) { | ||
1514 | /* PREPARE RESULT */ | ||
1515 | txskb = mI_alloc_skb(len, GFP_ATOMIC); | ||
1516 | if (!txskb) { | ||
1517 | printk(KERN_ERR | ||
1518 | "FATAL ERROR in mISDN_dsp.o: " | ||
1519 | "cannot alloc %d bytes\n", len); | ||
1520 | } else { | ||
1521 | thh = mISDN_HEAD_P(txskb); | ||
1522 | thh->prim = DL_DATA_REQ; | ||
1523 | thh->id = 0; | ||
1524 | memcpy(skb_put(txskb, len), nskb->data+preload, len); | ||
1525 | /* queue (trigger later) */ | ||
1526 | skb_queue_tail(&dsp->sendq, txskb); | ||
1527 | } | ||
1528 | } | ||
1529 | /* adjust volume */ | ||
1530 | if (dsp->tx_volume) | ||
1531 | dsp_change_volume(nskb, dsp->tx_volume); | ||
1532 | /* pipeline */ | ||
1533 | if (dsp->pipeline.inuse) | ||
1534 | dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, nskb->len); | ||
1535 | /* crypt */ | ||
1536 | if (dsp->bf_enable) | ||
1537 | dsp_bf_encrypt(dsp, nskb->data, nskb->len); | ||
1538 | /* queue and trigger */ | ||
1539 | skb_queue_tail(&dsp->sendq, nskb); | ||
1540 | schedule_work(&dsp->workq); | ||
1541 | } | ||
1542 | |||
1543 | u32 samplecount; | ||
1544 | struct timer_list dsp_spl_tl; | ||
1545 | u32 dsp_spl_jiffies; /* calculate the next time to fire */ | ||
1546 | u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */ | ||
1547 | struct timeval dsp_start_tv; /* time at start of calculation */ | ||
1548 | |||
1549 | void | ||
1550 | dsp_cmx_send(void *arg) | ||
1551 | { | ||
1552 | struct dsp_conf *conf; | ||
1553 | struct dsp_conf_member *member; | ||
1554 | struct dsp *dsp; | ||
1555 | int mustmix, members; | ||
1556 | s32 mixbuffer[MAX_POLL+100], *c; | ||
1557 | u8 *p, *q; | ||
1558 | int r, rr; | ||
1559 | int jittercheck = 0, delay, i; | ||
1560 | u_long flags; | ||
1561 | struct timeval tv; | ||
1562 | u32 elapsed; | ||
1563 | s16 length; | ||
1564 | |||
1565 | /* lock */ | ||
1566 | spin_lock_irqsave(&dsp_lock, flags); | ||
1567 | |||
1568 | if (!dsp_start_tv.tv_sec) { | ||
1569 | do_gettimeofday(&dsp_start_tv); | ||
1570 | length = dsp_poll; | ||
1571 | } else { | ||
1572 | do_gettimeofday(&tv); | ||
1573 | elapsed = ((tv.tv_sec - dsp_start_tv.tv_sec) * 8000) | ||
1574 | + ((s32)(tv.tv_usec / 125) - (dsp_start_tv.tv_usec / 125)); | ||
1575 | dsp_start_tv.tv_sec = tv.tv_sec; | ||
1576 | dsp_start_tv.tv_usec = tv.tv_usec; | ||
1577 | length = elapsed; | ||
1578 | } | ||
1579 | if (length > MAX_POLL + 100) | ||
1580 | length = MAX_POLL + 100; | ||
1581 | /* printk(KERN_DEBUG "len=%d dsp_count=0x%x.%04x dsp_poll_diff=0x%x.%04x\n", | ||
1582 | length, dsp_count >> 16, dsp_count & 0xffff, dsp_poll_diff >> 16, | ||
1583 | dsp_poll_diff & 0xffff); | ||
1584 | */ | ||
1585 | |||
1586 | /* | ||
1587 | * check if jitter needs to be checked | ||
1588 | * (this is about every second = 8192 samples) | ||
1589 | */ | ||
1590 | samplecount += length; | ||
1591 | if ((samplecount & 8191) < length) | ||
1592 | jittercheck = 1; | ||
1593 | |||
1594 | /* loop all members that do not require conference mixing */ | ||
1595 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
1596 | if (dsp->hdlc) | ||
1597 | continue; | ||
1598 | conf = dsp->conf; | ||
1599 | mustmix = 0; | ||
1600 | members = 0; | ||
1601 | if (conf) { | ||
1602 | members = count_list_member(&conf->mlist); | ||
1603 | #ifdef CMX_CONF_DEBUG | ||
1604 | if (conf->software && members > 1) | ||
1605 | #else | ||
1606 | if (conf->software && members > 2) | ||
1607 | #endif | ||
1608 | mustmix = 1; | ||
1609 | } | ||
1610 | |||
1611 | /* transmission required */ | ||
1612 | if (!mustmix) { | ||
1613 | dsp_cmx_send_member(dsp, length, mixbuffer, members); | ||
1614 | |||
1615 | /* | ||
1616 | * unused mixbuffer is given to prevent a | ||
1617 | * potential null-pointer-bug | ||
1618 | */ | ||
1619 | } | ||
1620 | } | ||
1621 | |||
1622 | /* loop all members that require conference mixing */ | ||
1623 | list_for_each_entry(conf, &conf_ilist, list) { | ||
1624 | /* count members and check hardware */ | ||
1625 | members = count_list_member(&conf->mlist); | ||
1626 | #ifdef CMX_CONF_DEBUG | ||
1627 | if (conf->software && members > 1) { | ||
1628 | #else | ||
1629 | if (conf->software && members > 2) { | ||
1630 | #endif | ||
1631 | /* check for hdlc conf */ | ||
1632 | member = list_entry(conf->mlist.next, | ||
1633 | struct dsp_conf_member, list); | ||
1634 | if (member->dsp->hdlc) | ||
1635 | continue; | ||
1636 | /* mix all data */ | ||
1637 | memset(mixbuffer, 0, length*sizeof(s32)); | ||
1638 | list_for_each_entry(member, &conf->mlist, list) { | ||
1639 | dsp = member->dsp; | ||
1640 | /* get range of data to mix */ | ||
1641 | c = mixbuffer; | ||
1642 | q = dsp->rx_buff; | ||
1643 | r = dsp->rx_R; | ||
1644 | rr = (r + length) & CMX_BUFF_MASK; | ||
1645 | /* add member's data */ | ||
1646 | while (r != rr) { | ||
1647 | *c++ += dsp_audio_law_to_s32[q[r]]; | ||
1648 | r = (r+1) & CMX_BUFF_MASK; | ||
1649 | } | ||
1650 | } | ||
1651 | |||
1652 | /* process each member */ | ||
1653 | list_for_each_entry(member, &conf->mlist, list) { | ||
1654 | /* transmission */ | ||
1655 | dsp_cmx_send_member(member->dsp, length, | ||
1656 | mixbuffer, members); | ||
1657 | } | ||
1658 | } | ||
1659 | } | ||
1660 | |||
1661 | /* delete rx-data, increment buffers, change pointers */ | ||
1662 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
1663 | if (dsp->hdlc) | ||
1664 | continue; | ||
1665 | p = dsp->rx_buff; | ||
1666 | q = dsp->tx_buff; | ||
1667 | r = dsp->rx_R; | ||
1668 | /* move receive pointer when receiving */ | ||
1669 | if (!dsp->rx_is_off) { | ||
1670 | rr = (r + length) & CMX_BUFF_MASK; | ||
1671 | /* delete rx-data */ | ||
1672 | while (r != rr) { | ||
1673 | p[r] = dsp_silence; | ||
1674 | r = (r+1) & CMX_BUFF_MASK; | ||
1675 | } | ||
1676 | /* increment rx-buffer pointer */ | ||
1677 | dsp->rx_R = r; /* write incremented read pointer */ | ||
1678 | } | ||
1679 | |||
1680 | /* check current rx_delay */ | ||
1681 | delay = (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK; | ||
1682 | if (delay >= CMX_BUFF_HALF) | ||
1683 | delay = 0; /* will be the delay before next write */ | ||
1684 | /* check for lower delay */ | ||
1685 | if (delay < dsp->rx_delay[0]) | ||
1686 | dsp->rx_delay[0] = delay; | ||
1687 | /* check current tx_delay */ | ||
1688 | delay = (dsp->tx_W-dsp->tx_R) & CMX_BUFF_MASK; | ||
1689 | if (delay >= CMX_BUFF_HALF) | ||
1690 | delay = 0; /* will be the delay before next write */ | ||
1691 | /* check for lower delay */ | ||
1692 | if (delay < dsp->tx_delay[0]) | ||
1693 | dsp->tx_delay[0] = delay; | ||
1694 | if (jittercheck) { | ||
1695 | /* find the lowest of all rx_delays */ | ||
1696 | delay = dsp->rx_delay[0]; | ||
1697 | i = 1; | ||
1698 | while (i < MAX_SECONDS_JITTER_CHECK) { | ||
1699 | if (delay > dsp->rx_delay[i]) | ||
1700 | delay = dsp->rx_delay[i]; | ||
1701 | i++; | ||
1702 | } | ||
1703 | /* | ||
1704 | * remove rx_delay only if we have delay AND we | ||
1705 | * have not preset cmx_delay | ||
1706 | */ | ||
1707 | if (delay && !dsp->cmx_delay) { | ||
1708 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1709 | printk(KERN_DEBUG | ||
1710 | "%s lowest rx_delay of %d bytes for" | ||
1711 | " dsp %s are now removed.\n", | ||
1712 | __func__, delay, | ||
1713 | dsp->name); | ||
1714 | r = dsp->rx_R; | ||
1715 | rr = (r + delay) & CMX_BUFF_MASK; | ||
1716 | /* delete rx-data */ | ||
1717 | while (r != rr) { | ||
1718 | p[r] = dsp_silence; | ||
1719 | r = (r+1) & CMX_BUFF_MASK; | ||
1720 | } | ||
1721 | /* increment rx-buffer pointer */ | ||
1722 | dsp->rx_R = r; | ||
1723 | /* write incremented read pointer */ | ||
1724 | } | ||
1725 | /* find the lowest of all tx_delays */ | ||
1726 | delay = dsp->tx_delay[0]; | ||
1727 | i = 1; | ||
1728 | while (i < MAX_SECONDS_JITTER_CHECK) { | ||
1729 | if (delay > dsp->tx_delay[i]) | ||
1730 | delay = dsp->tx_delay[i]; | ||
1731 | i++; | ||
1732 | } | ||
1733 | /* | ||
1734 | * remove delay only if we have delay AND we | ||
1735 | * have enabled tx_dejitter | ||
1736 | */ | ||
1737 | if (delay && dsp->tx_dejitter) { | ||
1738 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1739 | printk(KERN_DEBUG | ||
1740 | "%s lowest tx_delay of %d bytes for" | ||
1741 | " dsp %s are now removed.\n", | ||
1742 | __func__, delay, | ||
1743 | dsp->name); | ||
1744 | r = dsp->tx_R; | ||
1745 | rr = (r + delay) & CMX_BUFF_MASK; | ||
1746 | /* delete tx-data */ | ||
1747 | while (r != rr) { | ||
1748 | q[r] = dsp_silence; | ||
1749 | r = (r+1) & CMX_BUFF_MASK; | ||
1750 | } | ||
1751 | /* increment rx-buffer pointer */ | ||
1752 | dsp->tx_R = r; | ||
1753 | /* write incremented read pointer */ | ||
1754 | } | ||
1755 | /* scroll up delays */ | ||
1756 | i = MAX_SECONDS_JITTER_CHECK - 1; | ||
1757 | while (i) { | ||
1758 | dsp->rx_delay[i] = dsp->rx_delay[i-1]; | ||
1759 | dsp->tx_delay[i] = dsp->tx_delay[i-1]; | ||
1760 | i--; | ||
1761 | } | ||
1762 | dsp->tx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ | ||
1763 | dsp->rx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ | ||
1764 | } | ||
1765 | } | ||
1766 | |||
1767 | /* if next event would be in the past ... */ | ||
1768 | if ((s32)(dsp_spl_jiffies+dsp_tics-jiffies) <= 0) | ||
1769 | dsp_spl_jiffies = jiffies + 1; | ||
1770 | else | ||
1771 | dsp_spl_jiffies += dsp_tics; | ||
1772 | |||
1773 | dsp_spl_tl.expires = dsp_spl_jiffies; | ||
1774 | add_timer(&dsp_spl_tl); | ||
1775 | |||
1776 | /* unlock */ | ||
1777 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
1778 | } | ||
1779 | |||
1780 | /* | ||
1781 | * audio data is transmitted from upper layer to the dsp | ||
1782 | */ | ||
1783 | void | ||
1784 | dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) | ||
1785 | { | ||
1786 | u_int w, ww; | ||
1787 | u8 *d, *p; | ||
1788 | int space; /* todo: , l = skb->len; */ | ||
1789 | #ifdef CMX_TX_DEBUG | ||
1790 | char debugbuf[256] = ""; | ||
1791 | #endif | ||
1792 | |||
1793 | /* check if there is enough space, and then copy */ | ||
1794 | w = dsp->tx_W; | ||
1795 | ww = dsp->tx_R; | ||
1796 | p = dsp->tx_buff; | ||
1797 | d = skb->data; | ||
1798 | space = ww-w; | ||
1799 | if (space <= 0) | ||
1800 | space += CMX_BUFF_SIZE; | ||
1801 | /* write-pointer should not overrun nor reach read pointer */ | ||
1802 | if (space-1 < skb->len) | ||
1803 | /* write to the space we have left */ | ||
1804 | ww = (ww - 1) & CMX_BUFF_MASK; | ||
1805 | else | ||
1806 | /* write until all byte are copied */ | ||
1807 | ww = (w + skb->len) & CMX_BUFF_MASK; | ||
1808 | dsp->tx_W = ww; | ||
1809 | |||
1810 | /* show current buffer */ | ||
1811 | #ifdef CMX_DEBUG | ||
1812 | printk(KERN_DEBUG | ||
1813 | "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n", | ||
1814 | (u_long)dsp, (ww-w)&CMX_BUFF_MASK, w, ww, dsp->name); | ||
1815 | #endif | ||
1816 | |||
1817 | /* copy transmit data to tx-buffer */ | ||
1818 | #ifdef CMX_TX_DEBUG | ||
1819 | sprintf(debugbuf, "TX getting (%04x-%04x)%p: ", w, ww, p); | ||
1820 | #endif | ||
1821 | while (w != ww) { | ||
1822 | #ifdef CMX_TX_DEBUG | ||
1823 | if (strlen(debugbuf) < 48) | ||
1824 | sprintf(debugbuf+strlen(debugbuf), " %02x", *d); | ||
1825 | #endif | ||
1826 | p[w] = *d++; | ||
1827 | w = (w+1) & CMX_BUFF_MASK; | ||
1828 | } | ||
1829 | #ifdef CMX_TX_DEBUG | ||
1830 | printk(KERN_DEBUG "%s\n", debugbuf); | ||
1831 | #endif | ||
1832 | |||
1833 | } | ||
1834 | |||
1835 | /* | ||
1836 | * hdlc data is received from card and sent to all members. | ||
1837 | */ | ||
1838 | void | ||
1839 | dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) | ||
1840 | { | ||
1841 | struct sk_buff *nskb = NULL; | ||
1842 | struct dsp_conf_member *member; | ||
1843 | struct mISDNhead *hh; | ||
1844 | |||
1845 | /* not if not active */ | ||
1846 | if (!dsp->b_active) | ||
1847 | return; | ||
1848 | |||
1849 | /* check if we have sompen */ | ||
1850 | if (skb->len < 1) | ||
1851 | return; | ||
1852 | |||
1853 | /* no conf */ | ||
1854 | if (!dsp->conf) { | ||
1855 | /* in case of hardware (echo) */ | ||
1856 | if (dsp->pcm_slot_tx >= 0) | ||
1857 | return; | ||
1858 | if (dsp->echo) | ||
1859 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
1860 | if (nskb) { | ||
1861 | hh = mISDN_HEAD_P(nskb); | ||
1862 | hh->prim = PH_DATA_REQ; | ||
1863 | hh->id = 0; | ||
1864 | skb_queue_tail(&dsp->sendq, nskb); | ||
1865 | schedule_work(&dsp->workq); | ||
1866 | } | ||
1867 | return; | ||
1868 | } | ||
1869 | /* in case of hardware conference */ | ||
1870 | if (dsp->conf->hardware) | ||
1871 | return; | ||
1872 | list_for_each_entry(member, &dsp->conf->mlist, list) { | ||
1873 | if (dsp->echo || member->dsp != dsp) { | ||
1874 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
1875 | if (nskb) { | ||
1876 | hh = mISDN_HEAD_P(nskb); | ||
1877 | hh->prim = PH_DATA_REQ; | ||
1878 | hh->id = 0; | ||
1879 | skb_queue_tail(&member->dsp->sendq, nskb); | ||
1880 | schedule_work(&member->dsp->workq); | ||
1881 | } | ||
1882 | } | ||
1883 | } | ||
1884 | } | ||
1885 | |||
1886 | |||
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c new file mode 100644 index 000000000000..2f10ed82c0db --- /dev/null +++ b/drivers/isdn/mISDN/dsp_core.c | |||
@@ -0,0 +1,1191 @@ | |||
1 | /* | ||
2 | * Author Andreas Eversberg (jolly@eversberg.eu) | ||
3 | * Based on source code structure by | ||
4 | * Karsten Keil (keil@isdn4linux.de) | ||
5 | * | ||
6 | * This file is (c) under GNU PUBLIC LICENSE | ||
7 | * For changes and modifications please read | ||
8 | * ../../../Documentation/isdn/mISDN.cert | ||
9 | * | ||
10 | * Thanks to Karsten Keil (great drivers) | ||
11 | * Cologne Chip (great chips) | ||
12 | * | ||
13 | * This module does: | ||
14 | * Real-time tone generation | ||
15 | * DTMF detection | ||
16 | * Real-time cross-connection and conferrence | ||
17 | * Compensate jitter due to system load and hardware fault. | ||
18 | * All features are done in kernel space and will be realized | ||
19 | * using hardware, if available and supported by chip set. | ||
20 | * Blowfish encryption/decryption | ||
21 | */ | ||
22 | |||
23 | /* STRUCTURE: | ||
24 | * | ||
25 | * The dsp module provides layer 2 for b-channels (64kbit). It provides | ||
26 | * transparent audio forwarding with special digital signal processing: | ||
27 | * | ||
28 | * - (1) generation of tones | ||
29 | * - (2) detection of dtmf tones | ||
30 | * - (3) crossconnecting and conferences (clocking) | ||
31 | * - (4) echo generation for delay test | ||
32 | * - (5) volume control | ||
33 | * - (6) disable receive data | ||
34 | * - (7) pipeline | ||
35 | * - (8) encryption/decryption | ||
36 | * | ||
37 | * Look: | ||
38 | * TX RX | ||
39 | * ------upper layer------ | ||
40 | * | ^ | ||
41 | * | |(6) | ||
42 | * v | | ||
43 | * +-----+-------------+-----+ | ||
44 | * |(3)(4) | | ||
45 | * | CMX | | ||
46 | * | | | ||
47 | * | +-------------+ | ||
48 | * | | ^ | ||
49 | * | | | | ||
50 | * |+---------+| +----+----+ | ||
51 | * ||(1) || |(2) | | ||
52 | * || || | | | ||
53 | * || Tones || | DTMF | | ||
54 | * || || | | | ||
55 | * || || | | | ||
56 | * |+----+----+| +----+----+ | ||
57 | * +-----+-----+ ^ | ||
58 | * | | | ||
59 | * v | | ||
60 | * +----+----+ +----+----+ | ||
61 | * |(5) | |(5) | | ||
62 | * | | | | | ||
63 | * |TX Volume| |RX Volume| | ||
64 | * | | | | | ||
65 | * | | | | | ||
66 | * +----+----+ +----+----+ | ||
67 | * | ^ | ||
68 | * | | | ||
69 | * v | | ||
70 | * +----+-------------+----+ | ||
71 | * |(7) | | ||
72 | * | | | ||
73 | * | Pipeline Processing | | ||
74 | * | | | ||
75 | * | | | ||
76 | * +----+-------------+----+ | ||
77 | * | ^ | ||
78 | * | | | ||
79 | * v | | ||
80 | * +----+----+ +----+----+ | ||
81 | * |(8) | |(8) | | ||
82 | * | | | | | ||
83 | * | Encrypt | | Decrypt | | ||
84 | * | | | | | ||
85 | * | | | | | ||
86 | * +----+----+ +----+----+ | ||
87 | * | ^ | ||
88 | * | | | ||
89 | * v | | ||
90 | * ------card layer------ | ||
91 | * TX RX | ||
92 | * | ||
93 | * Above you can see the logical data flow. If software is used to do the | ||
94 | * process, it is actually the real data flow. If hardware is used, data | ||
95 | * may not flow, but hardware commands to the card, to provide the data flow | ||
96 | * as shown. | ||
97 | * | ||
98 | * NOTE: The channel must be activated in order to make dsp work, even if | ||
99 | * no data flow to the upper layer is intended. Activation can be done | ||
100 | * after and before controlling the setting using PH_CONTROL requests. | ||
101 | * | ||
102 | * DTMF: Will be detected by hardware if possible. It is done before CMX | ||
103 | * processing. | ||
104 | * | ||
105 | * Tones: Will be generated via software if endless looped audio fifos are | ||
106 | * not supported by hardware. Tones will override all data from CMX. | ||
107 | * It is not required to join a conference to use tones at any time. | ||
108 | * | ||
109 | * CMX: Is transparent when not used. When it is used, it will do | ||
110 | * crossconnections and conferences via software if not possible through | ||
111 | * hardware. If hardware capability is available, hardware is used. | ||
112 | * | ||
113 | * Echo: Is generated by CMX and is used to check performane of hard and | ||
114 | * software CMX. | ||
115 | * | ||
116 | * The CMX has special functions for conferences with one, two and more | ||
117 | * members. It will allow different types of data flow. Receive and transmit | ||
118 | * data to/form upper layer may be swithed on/off individually without loosing | ||
119 | * features of CMX, Tones and DTMF. | ||
120 | * | ||
121 | * Echo Cancellation: Sometimes we like to cancel echo from the interface. | ||
122 | * Note that a VoIP call may not have echo caused by the IP phone. The echo | ||
123 | * is generated by the telephone line connected to it. Because the delay | ||
124 | * is high, it becomes an echo. RESULT: Echo Cachelation is required if | ||
125 | * both echo AND delay is applied to an interface. | ||
126 | * Remember that software CMX always generates a more or less delay. | ||
127 | * | ||
128 | * If all used features can be realized in hardware, and if transmit and/or | ||
129 | * receive data ist disabled, the card may not send/receive any data at all. | ||
130 | * Not receiving is usefull if only announcements are played. Not sending is | ||
131 | * usefull if an answering machine records audio. Not sending and receiving is | ||
132 | * usefull during most states of the call. If supported by hardware, tones | ||
133 | * will be played without cpu load. Small PBXs and NT-Mode applications will | ||
134 | * not need expensive hardware when processing calls. | ||
135 | * | ||
136 | * | ||
137 | * LOCKING: | ||
138 | * | ||
139 | * When data is received from upper or lower layer (card), the complete dsp | ||
140 | * module is locked by a global lock. This lock MUST lock irq, because it | ||
141 | * must lock timer events by DSP poll timer. | ||
142 | * When data is ready to be transmitted down, the data is queued and sent | ||
143 | * outside lock and timer event. | ||
144 | * PH_CONTROL must not change any settings, join or split conference members | ||
145 | * during process of data. | ||
146 | * | ||
147 | * HDLC: | ||
148 | * | ||
149 | * It works quite the same as transparent, except that HDLC data is forwarded | ||
150 | * to all other conference members if no hardware bridging is possible. | ||
151 | * Send data will be writte to sendq. Sendq will be sent if confirm is received. | ||
152 | * Conference cannot join, if one member is not hdlc. | ||
153 | * | ||
154 | */ | ||
155 | |||
156 | #include <linux/delay.h> | ||
157 | #include <linux/mISDNif.h> | ||
158 | #include <linux/mISDNdsp.h> | ||
159 | #include <linux/module.h> | ||
160 | #include <linux/vmalloc.h> | ||
161 | #include "core.h" | ||
162 | #include "dsp.h" | ||
163 | |||
164 | const char *mISDN_dsp_revision = "2.0"; | ||
165 | |||
166 | static int debug; | ||
167 | static int options; | ||
168 | static int poll; | ||
169 | static int dtmfthreshold = 100; | ||
170 | |||
171 | MODULE_AUTHOR("Andreas Eversberg"); | ||
172 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
173 | module_param(options, uint, S_IRUGO | S_IWUSR); | ||
174 | module_param(poll, uint, S_IRUGO | S_IWUSR); | ||
175 | module_param(dtmfthreshold, uint, S_IRUGO | S_IWUSR); | ||
176 | MODULE_LICENSE("GPL"); | ||
177 | |||
178 | /*int spinnest = 0;*/ | ||
179 | |||
180 | spinlock_t dsp_lock; /* global dsp lock */ | ||
181 | struct list_head dsp_ilist; | ||
182 | struct list_head conf_ilist; | ||
183 | int dsp_debug; | ||
184 | int dsp_options; | ||
185 | int dsp_poll, dsp_tics; | ||
186 | |||
187 | /* check if rx may be turned off or must be turned on */ | ||
188 | static void | ||
189 | dsp_rx_off_member(struct dsp *dsp) | ||
190 | { | ||
191 | struct mISDN_ctrl_req cq; | ||
192 | int rx_off = 1; | ||
193 | |||
194 | if (!dsp->features_rx_off) | ||
195 | return; | ||
196 | |||
197 | /* not disabled */ | ||
198 | if (!dsp->rx_disabled) | ||
199 | rx_off = 0; | ||
200 | /* software dtmf */ | ||
201 | else if (dsp->dtmf.software) | ||
202 | rx_off = 0; | ||
203 | /* echo in software */ | ||
204 | else if (dsp->echo && dsp->pcm_slot_tx < 0) | ||
205 | rx_off = 0; | ||
206 | /* bridge in software */ | ||
207 | else if (dsp->conf) { | ||
208 | if (dsp->conf->software) | ||
209 | rx_off = 0; | ||
210 | } | ||
211 | |||
212 | if (rx_off == dsp->rx_is_off) | ||
213 | return; | ||
214 | |||
215 | if (!dsp->ch.peer) { | ||
216 | if (dsp_debug & DEBUG_DSP_CORE) | ||
217 | printk(KERN_DEBUG "%s: no peer, no rx_off\n", | ||
218 | __func__); | ||
219 | return; | ||
220 | } | ||
221 | cq.op = MISDN_CTRL_RX_OFF; | ||
222 | cq.p1 = rx_off; | ||
223 | if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { | ||
224 | printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n", | ||
225 | __func__); | ||
226 | return; | ||
227 | } | ||
228 | dsp->rx_is_off = rx_off; | ||
229 | if (dsp_debug & DEBUG_DSP_CORE) | ||
230 | printk(KERN_DEBUG "%s: %s set rx_off = %d\n", | ||
231 | __func__, dsp->name, rx_off); | ||
232 | } | ||
233 | static void | ||
234 | dsp_rx_off(struct dsp *dsp) | ||
235 | { | ||
236 | struct dsp_conf_member *member; | ||
237 | |||
238 | if (dsp_options & DSP_OPT_NOHARDWARE) | ||
239 | return; | ||
240 | |||
241 | /* no conf */ | ||
242 | if (!dsp->conf) { | ||
243 | dsp_rx_off_member(dsp); | ||
244 | return; | ||
245 | } | ||
246 | /* check all members in conf */ | ||
247 | list_for_each_entry(member, &dsp->conf->mlist, list) { | ||
248 | dsp_rx_off_member(member->dsp); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | static int | ||
253 | dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) | ||
254 | { | ||
255 | struct sk_buff *nskb; | ||
256 | int ret = 0; | ||
257 | int cont; | ||
258 | u8 *data; | ||
259 | int len; | ||
260 | |||
261 | if (skb->len < sizeof(int)) | ||
262 | printk(KERN_ERR "%s: PH_CONTROL message too short\n", __func__); | ||
263 | cont = *((int *)skb->data); | ||
264 | len = skb->len - sizeof(int); | ||
265 | data = skb->data + sizeof(int); | ||
266 | |||
267 | switch (cont) { | ||
268 | case DTMF_TONE_START: /* turn on DTMF */ | ||
269 | if (dsp->hdlc) { | ||
270 | ret = -EINVAL; | ||
271 | break; | ||
272 | } | ||
273 | if (dsp_debug & DEBUG_DSP_CORE) | ||
274 | printk(KERN_DEBUG "%s: start dtmf\n", __func__); | ||
275 | if (len == sizeof(int)) { | ||
276 | printk(KERN_NOTICE "changing DTMF Threshold " | ||
277 | "to %d\n", *((int *)data)); | ||
278 | dsp->dtmf.treshold = (*(int *)data) * 10000; | ||
279 | } | ||
280 | /* init goertzel */ | ||
281 | dsp_dtmf_goertzel_init(dsp); | ||
282 | |||
283 | /* check dtmf hardware */ | ||
284 | dsp_dtmf_hardware(dsp); | ||
285 | break; | ||
286 | case DTMF_TONE_STOP: /* turn off DTMF */ | ||
287 | if (dsp_debug & DEBUG_DSP_CORE) | ||
288 | printk(KERN_DEBUG "%s: stop dtmf\n", __func__); | ||
289 | dsp->dtmf.hardware = 0; | ||
290 | dsp->dtmf.software = 0; | ||
291 | break; | ||
292 | case DSP_CONF_JOIN: /* join / update conference */ | ||
293 | if (len < sizeof(int)) { | ||
294 | ret = -EINVAL; | ||
295 | break; | ||
296 | } | ||
297 | if (*((u32 *)data) == 0) | ||
298 | goto conf_split; | ||
299 | if (dsp_debug & DEBUG_DSP_CORE) | ||
300 | printk(KERN_DEBUG "%s: join conference %d\n", | ||
301 | __func__, *((u32 *)data)); | ||
302 | ret = dsp_cmx_conf(dsp, *((u32 *)data)); | ||
303 | /* dsp_cmx_hardware will also be called here */ | ||
304 | dsp_rx_off(dsp); | ||
305 | if (dsp_debug & DEBUG_DSP_CMX) | ||
306 | dsp_cmx_debug(dsp); | ||
307 | break; | ||
308 | case DSP_CONF_SPLIT: /* remove from conference */ | ||
309 | conf_split: | ||
310 | if (dsp_debug & DEBUG_DSP_CORE) | ||
311 | printk(KERN_DEBUG "%s: release conference\n", __func__); | ||
312 | ret = dsp_cmx_conf(dsp, 0); | ||
313 | /* dsp_cmx_hardware will also be called here */ | ||
314 | if (dsp_debug & DEBUG_DSP_CMX) | ||
315 | dsp_cmx_debug(dsp); | ||
316 | dsp_rx_off(dsp); | ||
317 | break; | ||
318 | case DSP_TONE_PATT_ON: /* play tone */ | ||
319 | if (dsp->hdlc) { | ||
320 | ret = -EINVAL; | ||
321 | break; | ||
322 | } | ||
323 | if (len < sizeof(int)) { | ||
324 | ret = -EINVAL; | ||
325 | break; | ||
326 | } | ||
327 | if (dsp_debug & DEBUG_DSP_CORE) | ||
328 | printk(KERN_DEBUG "%s: turn tone 0x%x on\n", | ||
329 | __func__, *((int *)skb->data)); | ||
330 | ret = dsp_tone(dsp, *((int *)data)); | ||
331 | if (!ret) { | ||
332 | dsp_cmx_hardware(dsp->conf, dsp); | ||
333 | dsp_rx_off(dsp); | ||
334 | } | ||
335 | if (!dsp->tone.tone) | ||
336 | goto tone_off; | ||
337 | break; | ||
338 | case DSP_TONE_PATT_OFF: /* stop tone */ | ||
339 | if (dsp->hdlc) { | ||
340 | ret = -EINVAL; | ||
341 | break; | ||
342 | } | ||
343 | if (dsp_debug & DEBUG_DSP_CORE) | ||
344 | printk(KERN_DEBUG "%s: turn tone off\n", __func__); | ||
345 | dsp_tone(dsp, 0); | ||
346 | dsp_cmx_hardware(dsp->conf, dsp); | ||
347 | dsp_rx_off(dsp); | ||
348 | /* reset tx buffers (user space data) */ | ||
349 | tone_off: | ||
350 | dsp->rx_W = 0; | ||
351 | dsp->rx_R = 0; | ||
352 | break; | ||
353 | case DSP_VOL_CHANGE_TX: /* change volume */ | ||
354 | if (dsp->hdlc) { | ||
355 | ret = -EINVAL; | ||
356 | break; | ||
357 | } | ||
358 | if (len < sizeof(int)) { | ||
359 | ret = -EINVAL; | ||
360 | break; | ||
361 | } | ||
362 | dsp->tx_volume = *((int *)data); | ||
363 | if (dsp_debug & DEBUG_DSP_CORE) | ||
364 | printk(KERN_DEBUG "%s: change tx vol to %d\n", | ||
365 | __func__, dsp->tx_volume); | ||
366 | dsp_cmx_hardware(dsp->conf, dsp); | ||
367 | dsp_dtmf_hardware(dsp); | ||
368 | dsp_rx_off(dsp); | ||
369 | break; | ||
370 | case DSP_VOL_CHANGE_RX: /* change volume */ | ||
371 | if (dsp->hdlc) { | ||
372 | ret = -EINVAL; | ||
373 | break; | ||
374 | } | ||
375 | if (len < sizeof(int)) { | ||
376 | ret = -EINVAL; | ||
377 | break; | ||
378 | } | ||
379 | dsp->rx_volume = *((int *)data); | ||
380 | if (dsp_debug & DEBUG_DSP_CORE) | ||
381 | printk(KERN_DEBUG "%s: change rx vol to %d\n", | ||
382 | __func__, dsp->tx_volume); | ||
383 | dsp_cmx_hardware(dsp->conf, dsp); | ||
384 | dsp_dtmf_hardware(dsp); | ||
385 | dsp_rx_off(dsp); | ||
386 | break; | ||
387 | case DSP_ECHO_ON: /* enable echo */ | ||
388 | dsp->echo = 1; /* soft echo */ | ||
389 | if (dsp_debug & DEBUG_DSP_CORE) | ||
390 | printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__); | ||
391 | dsp_cmx_hardware(dsp->conf, dsp); | ||
392 | dsp_rx_off(dsp); | ||
393 | if (dsp_debug & DEBUG_DSP_CMX) | ||
394 | dsp_cmx_debug(dsp); | ||
395 | break; | ||
396 | case DSP_ECHO_OFF: /* disable echo */ | ||
397 | dsp->echo = 0; | ||
398 | if (dsp_debug & DEBUG_DSP_CORE) | ||
399 | printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__); | ||
400 | dsp_cmx_hardware(dsp->conf, dsp); | ||
401 | dsp_rx_off(dsp); | ||
402 | if (dsp_debug & DEBUG_DSP_CMX) | ||
403 | dsp_cmx_debug(dsp); | ||
404 | break; | ||
405 | case DSP_RECEIVE_ON: /* enable receive to user space */ | ||
406 | if (dsp_debug & DEBUG_DSP_CORE) | ||
407 | printk(KERN_DEBUG "%s: enable receive to user " | ||
408 | "space\n", __func__); | ||
409 | dsp->rx_disabled = 0; | ||
410 | dsp_rx_off(dsp); | ||
411 | break; | ||
412 | case DSP_RECEIVE_OFF: /* disable receive to user space */ | ||
413 | if (dsp_debug & DEBUG_DSP_CORE) | ||
414 | printk(KERN_DEBUG "%s: disable receive to " | ||
415 | "user space\n", __func__); | ||
416 | dsp->rx_disabled = 1; | ||
417 | dsp_rx_off(dsp); | ||
418 | break; | ||
419 | case DSP_MIX_ON: /* enable mixing of tx data */ | ||
420 | if (dsp->hdlc) { | ||
421 | ret = -EINVAL; | ||
422 | break; | ||
423 | } | ||
424 | if (dsp_debug & DEBUG_DSP_CORE) | ||
425 | printk(KERN_DEBUG "%s: enable mixing of " | ||
426 | "tx-data with conf mebers\n", __func__); | ||
427 | dsp->tx_mix = 1; | ||
428 | dsp_cmx_hardware(dsp->conf, dsp); | ||
429 | dsp_rx_off(dsp); | ||
430 | if (dsp_debug & DEBUG_DSP_CMX) | ||
431 | dsp_cmx_debug(dsp); | ||
432 | break; | ||
433 | case DSP_MIX_OFF: /* disable mixing of tx data */ | ||
434 | if (dsp->hdlc) { | ||
435 | ret = -EINVAL; | ||
436 | break; | ||
437 | } | ||
438 | if (dsp_debug & DEBUG_DSP_CORE) | ||
439 | printk(KERN_DEBUG "%s: disable mixing of " | ||
440 | "tx-data with conf mebers\n", __func__); | ||
441 | dsp->tx_mix = 0; | ||
442 | dsp_cmx_hardware(dsp->conf, dsp); | ||
443 | dsp_rx_off(dsp); | ||
444 | if (dsp_debug & DEBUG_DSP_CMX) | ||
445 | dsp_cmx_debug(dsp); | ||
446 | break; | ||
447 | case DSP_TXDATA_ON: /* enable txdata */ | ||
448 | dsp->tx_data = 1; | ||
449 | if (dsp_debug & DEBUG_DSP_CORE) | ||
450 | printk(KERN_DEBUG "%s: enable tx-data\n", __func__); | ||
451 | dsp_cmx_hardware(dsp->conf, dsp); | ||
452 | dsp_rx_off(dsp); | ||
453 | if (dsp_debug & DEBUG_DSP_CMX) | ||
454 | dsp_cmx_debug(dsp); | ||
455 | break; | ||
456 | case DSP_TXDATA_OFF: /* disable txdata */ | ||
457 | dsp->tx_data = 0; | ||
458 | if (dsp_debug & DEBUG_DSP_CORE) | ||
459 | printk(KERN_DEBUG "%s: disable tx-data\n", __func__); | ||
460 | dsp_cmx_hardware(dsp->conf, dsp); | ||
461 | dsp_rx_off(dsp); | ||
462 | if (dsp_debug & DEBUG_DSP_CMX) | ||
463 | dsp_cmx_debug(dsp); | ||
464 | break; | ||
465 | case DSP_DELAY: /* use delay algorithm instead of dynamic | ||
466 | jitter algorithm */ | ||
467 | if (dsp->hdlc) { | ||
468 | ret = -EINVAL; | ||
469 | break; | ||
470 | } | ||
471 | if (len < sizeof(int)) { | ||
472 | ret = -EINVAL; | ||
473 | break; | ||
474 | } | ||
475 | dsp->cmx_delay = (*((int *)data)) << 3; | ||
476 | /* miliseconds to samples */ | ||
477 | if (dsp->cmx_delay >= (CMX_BUFF_HALF>>1)) | ||
478 | /* clip to half of maximum usable buffer | ||
479 | (half of half buffer) */ | ||
480 | dsp->cmx_delay = (CMX_BUFF_HALF>>1) - 1; | ||
481 | if (dsp_debug & DEBUG_DSP_CORE) | ||
482 | printk(KERN_DEBUG "%s: use delay algorithm to " | ||
483 | "compensate jitter (%d samples)\n", | ||
484 | __func__, dsp->cmx_delay); | ||
485 | break; | ||
486 | case DSP_JITTER: /* use dynamic jitter algorithm instead of | ||
487 | delay algorithm */ | ||
488 | if (dsp->hdlc) { | ||
489 | ret = -EINVAL; | ||
490 | break; | ||
491 | } | ||
492 | dsp->cmx_delay = 0; | ||
493 | if (dsp_debug & DEBUG_DSP_CORE) | ||
494 | printk(KERN_DEBUG "%s: use jitter algorithm to " | ||
495 | "compensate jitter\n", __func__); | ||
496 | break; | ||
497 | case DSP_TX_DEJITTER: /* use dynamic jitter algorithm for tx-buffer */ | ||
498 | if (dsp->hdlc) { | ||
499 | ret = -EINVAL; | ||
500 | break; | ||
501 | } | ||
502 | dsp->tx_dejitter = 1; | ||
503 | if (dsp_debug & DEBUG_DSP_CORE) | ||
504 | printk(KERN_DEBUG "%s: use dejitter on TX " | ||
505 | "buffer\n", __func__); | ||
506 | break; | ||
507 | case DSP_TX_DEJ_OFF: /* use tx-buffer without dejittering*/ | ||
508 | if (dsp->hdlc) { | ||
509 | ret = -EINVAL; | ||
510 | break; | ||
511 | } | ||
512 | dsp->tx_dejitter = 0; | ||
513 | if (dsp_debug & DEBUG_DSP_CORE) | ||
514 | printk(KERN_DEBUG "%s: use TX buffer without " | ||
515 | "dejittering\n", __func__); | ||
516 | break; | ||
517 | case DSP_PIPELINE_CFG: | ||
518 | if (dsp->hdlc) { | ||
519 | ret = -EINVAL; | ||
520 | break; | ||
521 | } | ||
522 | if (len > 0 && ((char *)data)[len - 1]) { | ||
523 | printk(KERN_DEBUG "%s: pipeline config string " | ||
524 | "is not NULL terminated!\n", __func__); | ||
525 | ret = -EINVAL; | ||
526 | } else { | ||
527 | dsp->pipeline.inuse = 1; | ||
528 | dsp_cmx_hardware(dsp->conf, dsp); | ||
529 | ret = dsp_pipeline_build(&dsp->pipeline, | ||
530 | len > 0 ? (char *)data : NULL); | ||
531 | dsp_cmx_hardware(dsp->conf, dsp); | ||
532 | dsp_rx_off(dsp); | ||
533 | } | ||
534 | break; | ||
535 | case DSP_BF_ENABLE_KEY: /* turn blowfish on */ | ||
536 | if (dsp->hdlc) { | ||
537 | ret = -EINVAL; | ||
538 | break; | ||
539 | } | ||
540 | if (len < 4 || len > 56) { | ||
541 | ret = -EINVAL; | ||
542 | break; | ||
543 | } | ||
544 | if (dsp_debug & DEBUG_DSP_CORE) | ||
545 | printk(KERN_DEBUG "%s: turn blowfish on (key " | ||
546 | "not shown)\n", __func__); | ||
547 | ret = dsp_bf_init(dsp, (u8 *)data, len); | ||
548 | /* set new cont */ | ||
549 | if (!ret) | ||
550 | cont = DSP_BF_ACCEPT; | ||
551 | else | ||
552 | cont = DSP_BF_REJECT; | ||
553 | /* send indication if it worked to set it */ | ||
554 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, MISDN_ID_ANY, | ||
555 | sizeof(int), &cont, GFP_ATOMIC); | ||
556 | if (nskb) { | ||
557 | if (dsp->up) { | ||
558 | if (dsp->up->send(dsp->up, nskb)) | ||
559 | dev_kfree_skb(nskb); | ||
560 | } else | ||
561 | dev_kfree_skb(nskb); | ||
562 | } | ||
563 | if (!ret) { | ||
564 | dsp_cmx_hardware(dsp->conf, dsp); | ||
565 | dsp_dtmf_hardware(dsp); | ||
566 | dsp_rx_off(dsp); | ||
567 | } | ||
568 | break; | ||
569 | case DSP_BF_DISABLE: /* turn blowfish off */ | ||
570 | if (dsp->hdlc) { | ||
571 | ret = -EINVAL; | ||
572 | break; | ||
573 | } | ||
574 | if (dsp_debug & DEBUG_DSP_CORE) | ||
575 | printk(KERN_DEBUG "%s: turn blowfish off\n", __func__); | ||
576 | dsp_bf_cleanup(dsp); | ||
577 | dsp_cmx_hardware(dsp->conf, dsp); | ||
578 | dsp_dtmf_hardware(dsp); | ||
579 | dsp_rx_off(dsp); | ||
580 | break; | ||
581 | default: | ||
582 | if (dsp_debug & DEBUG_DSP_CORE) | ||
583 | printk(KERN_DEBUG "%s: ctrl req %x unhandled\n", | ||
584 | __func__, cont); | ||
585 | ret = -EINVAL; | ||
586 | } | ||
587 | return ret; | ||
588 | } | ||
589 | |||
590 | static void | ||
591 | get_features(struct mISDNchannel *ch) | ||
592 | { | ||
593 | struct dsp *dsp = container_of(ch, struct dsp, ch); | ||
594 | struct mISDN_ctrl_req cq; | ||
595 | |||
596 | if (dsp_options & DSP_OPT_NOHARDWARE) | ||
597 | return; | ||
598 | if (!ch->peer) { | ||
599 | if (dsp_debug & DEBUG_DSP_CORE) | ||
600 | printk(KERN_DEBUG "%s: no peer, no features\n", | ||
601 | __func__); | ||
602 | return; | ||
603 | } | ||
604 | memset(&cq, 0, sizeof(cq)); | ||
605 | cq.op = MISDN_CTRL_GETOP; | ||
606 | if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq) < 0) { | ||
607 | printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", | ||
608 | __func__); | ||
609 | return; | ||
610 | } | ||
611 | if (cq.op & MISDN_CTRL_RX_OFF) | ||
612 | dsp->features_rx_off = 1; | ||
613 | if ((cq.op & MISDN_CTRL_HW_FEATURES_OP)) { | ||
614 | cq.op = MISDN_CTRL_HW_FEATURES; | ||
615 | *((u_long *)&cq.p1) = (u_long)&dsp->features; | ||
616 | if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq)) { | ||
617 | printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n", | ||
618 | __func__); | ||
619 | } | ||
620 | } else | ||
621 | if (dsp_debug & DEBUG_DSP_CORE) | ||
622 | printk(KERN_DEBUG "%s: features not supported for %s\n", | ||
623 | __func__, dsp->name); | ||
624 | } | ||
625 | |||
626 | static int | ||
627 | dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) | ||
628 | { | ||
629 | struct dsp *dsp = container_of(ch, struct dsp, ch); | ||
630 | struct mISDNhead *hh; | ||
631 | int ret = 0; | ||
632 | u8 *digits; | ||
633 | int cont; | ||
634 | struct sk_buff *nskb; | ||
635 | u_long flags; | ||
636 | |||
637 | hh = mISDN_HEAD_P(skb); | ||
638 | switch (hh->prim) { | ||
639 | /* FROM DOWN */ | ||
640 | case (PH_DATA_CNF): | ||
641 | dsp->data_pending = 0; | ||
642 | /* trigger next hdlc frame, if any */ | ||
643 | if (dsp->hdlc) { | ||
644 | spin_lock_irqsave(&dsp_lock, flags); | ||
645 | if (dsp->b_active) | ||
646 | schedule_work(&dsp->workq); | ||
647 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
648 | } | ||
649 | break; | ||
650 | case (PH_DATA_IND): | ||
651 | case (DL_DATA_IND): | ||
652 | if (skb->len < 1) { | ||
653 | ret = -EINVAL; | ||
654 | break; | ||
655 | } | ||
656 | if (dsp->rx_is_off) { | ||
657 | if (dsp_debug & DEBUG_DSP_CORE) | ||
658 | printk(KERN_DEBUG "%s: rx-data during rx_off" | ||
659 | " for %s\n", | ||
660 | __func__, dsp->name); | ||
661 | } | ||
662 | if (dsp->hdlc) { | ||
663 | /* hdlc */ | ||
664 | spin_lock_irqsave(&dsp_lock, flags); | ||
665 | dsp_cmx_hdlc(dsp, skb); | ||
666 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
667 | if (dsp->rx_disabled) { | ||
668 | /* if receive is not allowed */ | ||
669 | break; | ||
670 | } | ||
671 | hh->prim = DL_DATA_IND; | ||
672 | if (dsp->up) | ||
673 | return dsp->up->send(dsp->up, skb); | ||
674 | break; | ||
675 | } | ||
676 | |||
677 | /* decrypt if enabled */ | ||
678 | if (dsp->bf_enable) | ||
679 | dsp_bf_decrypt(dsp, skb->data, skb->len); | ||
680 | /* pipeline */ | ||
681 | if (dsp->pipeline.inuse) | ||
682 | dsp_pipeline_process_rx(&dsp->pipeline, skb->data, | ||
683 | skb->len); | ||
684 | /* change volume if requested */ | ||
685 | if (dsp->rx_volume) | ||
686 | dsp_change_volume(skb, dsp->rx_volume); | ||
687 | |||
688 | /* check if dtmf soft decoding is turned on */ | ||
689 | if (dsp->dtmf.software) { | ||
690 | digits = dsp_dtmf_goertzel_decode(dsp, skb->data, | ||
691 | skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); | ||
692 | while (*digits) { | ||
693 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
694 | printk(KERN_DEBUG "%s: digit" | ||
695 | "(%c) to layer %s\n", | ||
696 | __func__, *digits, dsp->name); | ||
697 | cont = DTMF_TONE_VAL | *digits; | ||
698 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, | ||
699 | MISDN_ID_ANY, sizeof(int), &cont, | ||
700 | GFP_ATOMIC); | ||
701 | if (nskb) { | ||
702 | if (dsp->up) { | ||
703 | if (dsp->up->send( | ||
704 | dsp->up, nskb)) | ||
705 | dev_kfree_skb(nskb); | ||
706 | } else | ||
707 | dev_kfree_skb(nskb); | ||
708 | } | ||
709 | digits++; | ||
710 | } | ||
711 | } | ||
712 | /* we need to process receive data if software */ | ||
713 | spin_lock_irqsave(&dsp_lock, flags); | ||
714 | if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) { | ||
715 | /* process data from card at cmx */ | ||
716 | dsp_cmx_receive(dsp, skb); | ||
717 | } | ||
718 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
719 | |||
720 | if (dsp->rx_disabled) { | ||
721 | /* if receive is not allowed */ | ||
722 | break; | ||
723 | } | ||
724 | hh->prim = DL_DATA_IND; | ||
725 | if (dsp->up) | ||
726 | return dsp->up->send(dsp->up, skb); | ||
727 | break; | ||
728 | case (PH_CONTROL_IND): | ||
729 | if (dsp_debug & DEBUG_DSP_DTMFCOEFF) | ||
730 | printk(KERN_DEBUG "%s: PH_CONTROL INDICATION " | ||
731 | "received: %x (len %d) %s\n", __func__, | ||
732 | hh->id, skb->len, dsp->name); | ||
733 | switch (hh->id) { | ||
734 | case (DTMF_HFC_COEF): /* getting coefficients */ | ||
735 | if (!dsp->dtmf.hardware) { | ||
736 | if (dsp_debug & DEBUG_DSP_DTMFCOEFF) | ||
737 | printk(KERN_DEBUG "%s: ignoring DTMF " | ||
738 | "coefficients from HFC\n", | ||
739 | __func__); | ||
740 | break; | ||
741 | } | ||
742 | digits = dsp_dtmf_goertzel_decode(dsp, skb->data, | ||
743 | skb->len, 2); | ||
744 | while (*digits) { | ||
745 | int k; | ||
746 | struct sk_buff *nskb; | ||
747 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
748 | printk(KERN_DEBUG "%s: digit" | ||
749 | "(%c) to layer %s\n", | ||
750 | __func__, *digits, dsp->name); | ||
751 | k = *digits | DTMF_TONE_VAL; | ||
752 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, | ||
753 | MISDN_ID_ANY, sizeof(int), &k, | ||
754 | GFP_ATOMIC); | ||
755 | if (nskb) { | ||
756 | if (dsp->up) { | ||
757 | if (dsp->up->send( | ||
758 | dsp->up, nskb)) | ||
759 | dev_kfree_skb(nskb); | ||
760 | } else | ||
761 | dev_kfree_skb(nskb); | ||
762 | } | ||
763 | digits++; | ||
764 | } | ||
765 | break; | ||
766 | case (HFC_VOL_CHANGE_TX): /* change volume */ | ||
767 | if (skb->len != sizeof(int)) { | ||
768 | ret = -EINVAL; | ||
769 | break; | ||
770 | } | ||
771 | spin_lock_irqsave(&dsp_lock, flags); | ||
772 | dsp->tx_volume = *((int *)skb->data); | ||
773 | if (dsp_debug & DEBUG_DSP_CORE) | ||
774 | printk(KERN_DEBUG "%s: change tx volume to " | ||
775 | "%d\n", __func__, dsp->tx_volume); | ||
776 | dsp_cmx_hardware(dsp->conf, dsp); | ||
777 | dsp_dtmf_hardware(dsp); | ||
778 | dsp_rx_off(dsp); | ||
779 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
780 | break; | ||
781 | default: | ||
782 | if (dsp_debug & DEBUG_DSP_CORE) | ||
783 | printk(KERN_DEBUG "%s: ctrl ind %x unhandled " | ||
784 | "%s\n", __func__, hh->id, dsp->name); | ||
785 | ret = -EINVAL; | ||
786 | } | ||
787 | break; | ||
788 | case (PH_ACTIVATE_IND): | ||
789 | case (PH_ACTIVATE_CNF): | ||
790 | if (dsp_debug & DEBUG_DSP_CORE) | ||
791 | printk(KERN_DEBUG "%s: b_channel is now active %s\n", | ||
792 | __func__, dsp->name); | ||
793 | /* bchannel now active */ | ||
794 | spin_lock_irqsave(&dsp_lock, flags); | ||
795 | dsp->b_active = 1; | ||
796 | dsp->data_pending = 0; | ||
797 | dsp->rx_init = 1; | ||
798 | /* rx_W and rx_R will be adjusted on first frame */ | ||
799 | dsp->rx_W = 0; | ||
800 | dsp->rx_R = 0; | ||
801 | memset(dsp->rx_buff, 0, sizeof(dsp->rx_buff)); | ||
802 | dsp_cmx_hardware(dsp->conf, dsp); | ||
803 | dsp_dtmf_hardware(dsp); | ||
804 | dsp_rx_off(dsp); | ||
805 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
806 | if (dsp_debug & DEBUG_DSP_CORE) | ||
807 | printk(KERN_DEBUG "%s: done with activation, sending " | ||
808 | "confirm to user space. %s\n", __func__, | ||
809 | dsp->name); | ||
810 | /* send activation to upper layer */ | ||
811 | hh->prim = DL_ESTABLISH_CNF; | ||
812 | if (dsp->up) | ||
813 | return dsp->up->send(dsp->up, skb); | ||
814 | break; | ||
815 | case (PH_DEACTIVATE_IND): | ||
816 | case (PH_DEACTIVATE_CNF): | ||
817 | if (dsp_debug & DEBUG_DSP_CORE) | ||
818 | printk(KERN_DEBUG "%s: b_channel is now inactive %s\n", | ||
819 | __func__, dsp->name); | ||
820 | /* bchannel now inactive */ | ||
821 | spin_lock_irqsave(&dsp_lock, flags); | ||
822 | dsp->b_active = 0; | ||
823 | dsp->data_pending = 0; | ||
824 | dsp_cmx_hardware(dsp->conf, dsp); | ||
825 | dsp_rx_off(dsp); | ||
826 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
827 | hh->prim = DL_RELEASE_CNF; | ||
828 | if (dsp->up) | ||
829 | return dsp->up->send(dsp->up, skb); | ||
830 | break; | ||
831 | /* FROM UP */ | ||
832 | case (DL_DATA_REQ): | ||
833 | case (PH_DATA_REQ): | ||
834 | if (skb->len < 1) { | ||
835 | ret = -EINVAL; | ||
836 | break; | ||
837 | } | ||
838 | if (dsp->hdlc) { | ||
839 | /* hdlc */ | ||
840 | spin_lock_irqsave(&dsp_lock, flags); | ||
841 | if (dsp->b_active) { | ||
842 | skb_queue_tail(&dsp->sendq, skb); | ||
843 | schedule_work(&dsp->workq); | ||
844 | } | ||
845 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
846 | return 0; | ||
847 | } | ||
848 | /* send data to tx-buffer (if no tone is played) */ | ||
849 | if (!dsp->tone.tone) { | ||
850 | spin_lock_irqsave(&dsp_lock, flags); | ||
851 | dsp_cmx_transmit(dsp, skb); | ||
852 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
853 | } | ||
854 | break; | ||
855 | case (PH_CONTROL_REQ): | ||
856 | spin_lock_irqsave(&dsp_lock, flags); | ||
857 | ret = dsp_control_req(dsp, hh, skb); | ||
858 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
859 | break; | ||
860 | case (DL_ESTABLISH_REQ): | ||
861 | case (PH_ACTIVATE_REQ): | ||
862 | if (dsp_debug & DEBUG_DSP_CORE) | ||
863 | printk(KERN_DEBUG "%s: activating b_channel %s\n", | ||
864 | __func__, dsp->name); | ||
865 | if (dsp->dtmf.hardware || dsp->dtmf.software) | ||
866 | dsp_dtmf_goertzel_init(dsp); | ||
867 | get_features(ch); | ||
868 | /* send ph_activate */ | ||
869 | hh->prim = PH_ACTIVATE_REQ; | ||
870 | if (ch->peer) | ||
871 | return ch->recv(ch->peer, skb); | ||
872 | break; | ||
873 | case (DL_RELEASE_REQ): | ||
874 | case (PH_DEACTIVATE_REQ): | ||
875 | if (dsp_debug & DEBUG_DSP_CORE) | ||
876 | printk(KERN_DEBUG "%s: releasing b_channel %s\n", | ||
877 | __func__, dsp->name); | ||
878 | spin_lock_irqsave(&dsp_lock, flags); | ||
879 | dsp->tone.tone = 0; | ||
880 | dsp->tone.hardware = 0; | ||
881 | dsp->tone.software = 0; | ||
882 | if (timer_pending(&dsp->tone.tl)) | ||
883 | del_timer(&dsp->tone.tl); | ||
884 | if (dsp->conf) | ||
885 | dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be | ||
886 | called here */ | ||
887 | skb_queue_purge(&dsp->sendq); | ||
888 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
889 | hh->prim = PH_DEACTIVATE_REQ; | ||
890 | if (ch->peer) | ||
891 | return ch->recv(ch->peer, skb); | ||
892 | break; | ||
893 | default: | ||
894 | if (dsp_debug & DEBUG_DSP_CORE) | ||
895 | printk(KERN_DEBUG "%s: msg %x unhandled %s\n", | ||
896 | __func__, hh->prim, dsp->name); | ||
897 | ret = -EINVAL; | ||
898 | } | ||
899 | if (!ret) | ||
900 | dev_kfree_skb(skb); | ||
901 | return ret; | ||
902 | } | ||
903 | |||
904 | static int | ||
905 | dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
906 | { | ||
907 | struct dsp *dsp = container_of(ch, struct dsp, ch); | ||
908 | u_long flags; | ||
909 | int err = 0; | ||
910 | |||
911 | if (debug & DEBUG_DSP_CTRL) | ||
912 | printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); | ||
913 | |||
914 | switch (cmd) { | ||
915 | case OPEN_CHANNEL: | ||
916 | break; | ||
917 | case CLOSE_CHANNEL: | ||
918 | if (dsp->ch.peer) | ||
919 | dsp->ch.peer->ctrl(dsp->ch.peer, CLOSE_CHANNEL, NULL); | ||
920 | |||
921 | /* wait until workqueue has finished, | ||
922 | * must lock here, or we may hit send-process currently | ||
923 | * queueing. */ | ||
924 | spin_lock_irqsave(&dsp_lock, flags); | ||
925 | dsp->b_active = 0; | ||
926 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
927 | /* MUST not be locked, because it waits until queue is done. */ | ||
928 | cancel_work_sync(&dsp->workq); | ||
929 | spin_lock_irqsave(&dsp_lock, flags); | ||
930 | if (timer_pending(&dsp->tone.tl)) | ||
931 | del_timer(&dsp->tone.tl); | ||
932 | skb_queue_purge(&dsp->sendq); | ||
933 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
934 | printk(KERN_DEBUG "%s: releasing member %s\n", | ||
935 | __func__, dsp->name); | ||
936 | dsp->b_active = 0; | ||
937 | dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be called | ||
938 | here */ | ||
939 | dsp_pipeline_destroy(&dsp->pipeline); | ||
940 | |||
941 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
942 | printk(KERN_DEBUG "%s: remove & destroy object %s\n", | ||
943 | __func__, dsp->name); | ||
944 | list_del(&dsp->list); | ||
945 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
946 | |||
947 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
948 | printk(KERN_DEBUG "%s: dsp instance released\n", | ||
949 | __func__); | ||
950 | vfree(dsp); | ||
951 | module_put(THIS_MODULE); | ||
952 | break; | ||
953 | } | ||
954 | return err; | ||
955 | } | ||
956 | |||
957 | static void | ||
958 | dsp_send_bh(struct work_struct *work) | ||
959 | { | ||
960 | struct dsp *dsp = container_of(work, struct dsp, workq); | ||
961 | struct sk_buff *skb; | ||
962 | struct mISDNhead *hh; | ||
963 | |||
964 | if (dsp->hdlc && dsp->data_pending) | ||
965 | return; /* wait until data has been acknowledged */ | ||
966 | |||
967 | /* send queued data */ | ||
968 | while ((skb = skb_dequeue(&dsp->sendq))) { | ||
969 | /* in locked date, we must have still data in queue */ | ||
970 | if (dsp->data_pending) { | ||
971 | if (dsp_debug & DEBUG_DSP_CORE) | ||
972 | printk(KERN_DEBUG "%s: fifo full %s, this is " | ||
973 | "no bug!\n", __func__, dsp->name); | ||
974 | /* flush transparent data, if not acked */ | ||
975 | dev_kfree_skb(skb); | ||
976 | continue; | ||
977 | } | ||
978 | hh = mISDN_HEAD_P(skb); | ||
979 | if (hh->prim == DL_DATA_REQ) { | ||
980 | /* send packet up */ | ||
981 | if (dsp->up) { | ||
982 | if (dsp->up->send(dsp->up, skb)) | ||
983 | dev_kfree_skb(skb); | ||
984 | } else | ||
985 | dev_kfree_skb(skb); | ||
986 | } else { | ||
987 | /* send packet down */ | ||
988 | if (dsp->ch.peer) { | ||
989 | dsp->data_pending = 1; | ||
990 | if (dsp->ch.recv(dsp->ch.peer, skb)) { | ||
991 | dev_kfree_skb(skb); | ||
992 | dsp->data_pending = 0; | ||
993 | } | ||
994 | } else | ||
995 | dev_kfree_skb(skb); | ||
996 | } | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | static int | ||
1001 | dspcreate(struct channel_req *crq) | ||
1002 | { | ||
1003 | struct dsp *ndsp; | ||
1004 | u_long flags; | ||
1005 | |||
1006 | if (crq->protocol != ISDN_P_B_L2DSP | ||
1007 | && crq->protocol != ISDN_P_B_L2DSPHDLC) | ||
1008 | return -EPROTONOSUPPORT; | ||
1009 | ndsp = vmalloc(sizeof(struct dsp)); | ||
1010 | if (!ndsp) { | ||
1011 | printk(KERN_ERR "%s: vmalloc struct dsp failed\n", __func__); | ||
1012 | return -ENOMEM; | ||
1013 | } | ||
1014 | memset(ndsp, 0, sizeof(struct dsp)); | ||
1015 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
1016 | printk(KERN_DEBUG "%s: creating new dsp instance\n", __func__); | ||
1017 | |||
1018 | /* default enabled */ | ||
1019 | INIT_WORK(&ndsp->workq, (void *)dsp_send_bh); | ||
1020 | skb_queue_head_init(&ndsp->sendq); | ||
1021 | ndsp->ch.send = dsp_function; | ||
1022 | ndsp->ch.ctrl = dsp_ctrl; | ||
1023 | ndsp->up = crq->ch; | ||
1024 | crq->ch = &ndsp->ch; | ||
1025 | if (crq->protocol == ISDN_P_B_L2DSP) { | ||
1026 | crq->protocol = ISDN_P_B_RAW; | ||
1027 | ndsp->hdlc = 0; | ||
1028 | } else { | ||
1029 | crq->protocol = ISDN_P_B_HDLC; | ||
1030 | ndsp->hdlc = 1; | ||
1031 | } | ||
1032 | if (!try_module_get(THIS_MODULE)) | ||
1033 | printk(KERN_WARNING "%s:cannot get module\n", | ||
1034 | __func__); | ||
1035 | |||
1036 | sprintf(ndsp->name, "DSP_C%x(0x%p)", | ||
1037 | ndsp->up->st->dev->id + 1, ndsp); | ||
1038 | /* set frame size to start */ | ||
1039 | ndsp->features.hfc_id = -1; /* current PCM id */ | ||
1040 | ndsp->features.pcm_id = -1; /* current PCM id */ | ||
1041 | ndsp->pcm_slot_rx = -1; /* current CPM slot */ | ||
1042 | ndsp->pcm_slot_tx = -1; | ||
1043 | ndsp->pcm_bank_rx = -1; | ||
1044 | ndsp->pcm_bank_tx = -1; | ||
1045 | ndsp->hfc_conf = -1; /* current conference number */ | ||
1046 | /* set tone timer */ | ||
1047 | ndsp->tone.tl.function = (void *)dsp_tone_timeout; | ||
1048 | ndsp->tone.tl.data = (long) ndsp; | ||
1049 | init_timer(&ndsp->tone.tl); | ||
1050 | |||
1051 | if (dtmfthreshold < 20 || dtmfthreshold > 500) | ||
1052 | dtmfthreshold = 200; | ||
1053 | ndsp->dtmf.treshold = dtmfthreshold*10000; | ||
1054 | |||
1055 | /* init pipeline append to list */ | ||
1056 | spin_lock_irqsave(&dsp_lock, flags); | ||
1057 | dsp_pipeline_init(&ndsp->pipeline); | ||
1058 | list_add_tail(&ndsp->list, &dsp_ilist); | ||
1059 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
1060 | |||
1061 | return 0; | ||
1062 | } | ||
1063 | |||
1064 | |||
1065 | static struct Bprotocol DSP = { | ||
1066 | .Bprotocols = (1 << (ISDN_P_B_L2DSP & ISDN_P_B_MASK)) | ||
1067 | | (1 << (ISDN_P_B_L2DSPHDLC & ISDN_P_B_MASK)), | ||
1068 | .name = "dsp", | ||
1069 | .create = dspcreate | ||
1070 | }; | ||
1071 | |||
1072 | static int dsp_init(void) | ||
1073 | { | ||
1074 | int err; | ||
1075 | int tics; | ||
1076 | |||
1077 | printk(KERN_INFO "DSP modul %s\n", mISDN_dsp_revision); | ||
1078 | |||
1079 | dsp_options = options; | ||
1080 | dsp_debug = debug; | ||
1081 | |||
1082 | /* set packet size */ | ||
1083 | dsp_poll = poll; | ||
1084 | if (dsp_poll) { | ||
1085 | if (dsp_poll > MAX_POLL) { | ||
1086 | printk(KERN_ERR "%s: Wrong poll value (%d), use %d " | ||
1087 | "maximum.\n", __func__, poll, MAX_POLL); | ||
1088 | err = -EINVAL; | ||
1089 | return err; | ||
1090 | } | ||
1091 | if (dsp_poll < 8) { | ||
1092 | printk(KERN_ERR "%s: Wrong poll value (%d), use 8 " | ||
1093 | "minimum.\n", __func__, dsp_poll); | ||
1094 | err = -EINVAL; | ||
1095 | return err; | ||
1096 | } | ||
1097 | dsp_tics = poll * HZ / 8000; | ||
1098 | if (dsp_tics * 8000 != poll * HZ) { | ||
1099 | printk(KERN_INFO "mISDN_dsp: Cannot clock every %d " | ||
1100 | "samples (0,125 ms). It is not a multiple of " | ||
1101 | "%d HZ.\n", poll, HZ); | ||
1102 | err = -EINVAL; | ||
1103 | return err; | ||
1104 | } | ||
1105 | } else { | ||
1106 | poll = 8; | ||
1107 | while (poll <= MAX_POLL) { | ||
1108 | tics = poll * HZ / 8000; | ||
1109 | if (tics * 8000 == poll * HZ) { | ||
1110 | dsp_tics = tics; | ||
1111 | dsp_poll = poll; | ||
1112 | if (poll >= 64) | ||
1113 | break; | ||
1114 | } | ||
1115 | poll++; | ||
1116 | } | ||
1117 | } | ||
1118 | if (dsp_poll == 0) { | ||
1119 | printk(KERN_INFO "mISDN_dsp: There is no multiple of kernel " | ||
1120 | "clock that equals exactly the duration of 8-256 " | ||
1121 | "samples. (Choose kernel clock speed like 100, 250, " | ||
1122 | "300, 1000)\n"); | ||
1123 | err = -EINVAL; | ||
1124 | return err; | ||
1125 | } | ||
1126 | printk(KERN_INFO "mISDN_dsp: DSP clocks every %d samples. This equals " | ||
1127 | "%d jiffies.\n", dsp_poll, dsp_tics); | ||
1128 | |||
1129 | spin_lock_init(&dsp_lock); | ||
1130 | INIT_LIST_HEAD(&dsp_ilist); | ||
1131 | INIT_LIST_HEAD(&conf_ilist); | ||
1132 | |||
1133 | /* init conversion tables */ | ||
1134 | dsp_audio_generate_law_tables(); | ||
1135 | dsp_silence = (dsp_options&DSP_OPT_ULAW)?0xff:0x2a; | ||
1136 | dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW)?dsp_audio_ulaw_to_s32: | ||
1137 | dsp_audio_alaw_to_s32; | ||
1138 | dsp_audio_generate_s2law_table(); | ||
1139 | dsp_audio_generate_seven(); | ||
1140 | dsp_audio_generate_mix_table(); | ||
1141 | if (dsp_options & DSP_OPT_ULAW) | ||
1142 | dsp_audio_generate_ulaw_samples(); | ||
1143 | dsp_audio_generate_volume_changes(); | ||
1144 | |||
1145 | err = dsp_pipeline_module_init(); | ||
1146 | if (err) { | ||
1147 | printk(KERN_ERR "mISDN_dsp: Can't initialize pipeline, " | ||
1148 | "error(%d)\n", err); | ||
1149 | return err; | ||
1150 | } | ||
1151 | |||
1152 | err = mISDN_register_Bprotocol(&DSP); | ||
1153 | if (err) { | ||
1154 | printk(KERN_ERR "Can't register %s error(%d)\n", DSP.name, err); | ||
1155 | return err; | ||
1156 | } | ||
1157 | |||
1158 | /* set sample timer */ | ||
1159 | dsp_spl_tl.function = (void *)dsp_cmx_send; | ||
1160 | dsp_spl_tl.data = 0; | ||
1161 | init_timer(&dsp_spl_tl); | ||
1162 | dsp_spl_tl.expires = jiffies + dsp_tics; | ||
1163 | dsp_spl_jiffies = dsp_spl_tl.expires; | ||
1164 | add_timer(&dsp_spl_tl); | ||
1165 | |||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | |||
1170 | static void dsp_cleanup(void) | ||
1171 | { | ||
1172 | mISDN_unregister_Bprotocol(&DSP); | ||
1173 | |||
1174 | if (timer_pending(&dsp_spl_tl)) | ||
1175 | del_timer(&dsp_spl_tl); | ||
1176 | |||
1177 | if (!list_empty(&dsp_ilist)) { | ||
1178 | printk(KERN_ERR "mISDN_dsp: Audio DSP object inst list not " | ||
1179 | "empty.\n"); | ||
1180 | } | ||
1181 | if (!list_empty(&conf_ilist)) { | ||
1182 | printk(KERN_ERR "mISDN_dsp: Conference list not empty. Not " | ||
1183 | "all memory freed.\n"); | ||
1184 | } | ||
1185 | |||
1186 | dsp_pipeline_module_exit(); | ||
1187 | } | ||
1188 | |||
1189 | module_init(dsp_init); | ||
1190 | module_exit(dsp_cleanup); | ||
1191 | |||
diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c new file mode 100644 index 000000000000..efc371c1f0dc --- /dev/null +++ b/drivers/isdn/mISDN/dsp_dtmf.c | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | * DTMF decoder. | ||
3 | * | ||
4 | * Copyright by Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * based on different decoders such as ISDN4Linux | ||
6 | * | ||
7 | * This software may be used and distributed according to the terms | ||
8 | * of the GNU General Public License, incorporated herein by reference. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/mISDNif.h> | ||
13 | #include <linux/mISDNdsp.h> | ||
14 | #include "core.h" | ||
15 | #include "dsp.h" | ||
16 | |||
17 | #define NCOEFF 8 /* number of frequencies to be analyzed */ | ||
18 | |||
19 | /* For DTMF recognition: | ||
20 | * 2 * cos(2 * PI * k / N) precalculated for all k | ||
21 | */ | ||
22 | static u64 cos2pik[NCOEFF] = | ||
23 | { | ||
24 | /* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */ | ||
25 | 55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630 | ||
26 | }; | ||
27 | |||
28 | /* digit matrix */ | ||
29 | static char dtmf_matrix[4][4] = | ||
30 | { | ||
31 | {'1', '2', '3', 'A'}, | ||
32 | {'4', '5', '6', 'B'}, | ||
33 | {'7', '8', '9', 'C'}, | ||
34 | {'*', '0', '#', 'D'} | ||
35 | }; | ||
36 | |||
37 | /* dtmf detection using goertzel algorithm | ||
38 | * init function | ||
39 | */ | ||
40 | void dsp_dtmf_goertzel_init(struct dsp *dsp) | ||
41 | { | ||
42 | dsp->dtmf.size = 0; | ||
43 | dsp->dtmf.lastwhat = '\0'; | ||
44 | dsp->dtmf.lastdigit = '\0'; | ||
45 | dsp->dtmf.count = 0; | ||
46 | } | ||
47 | |||
48 | /* check for hardware or software features | ||
49 | */ | ||
50 | void dsp_dtmf_hardware(struct dsp *dsp) | ||
51 | { | ||
52 | int hardware = 1; | ||
53 | |||
54 | if (!dsp->features.hfc_dtmf) | ||
55 | hardware = 0; | ||
56 | |||
57 | /* check for volume change */ | ||
58 | if (dsp->tx_volume) { | ||
59 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
60 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
61 | "because tx_volume is changed\n", | ||
62 | __func__, dsp->name); | ||
63 | hardware = 0; | ||
64 | } | ||
65 | if (dsp->rx_volume) { | ||
66 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
67 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
68 | "because rx_volume is changed\n", | ||
69 | __func__, dsp->name); | ||
70 | hardware = 0; | ||
71 | } | ||
72 | /* check if encryption is enabled */ | ||
73 | if (dsp->bf_enable) { | ||
74 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
75 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
76 | "because encryption is enabled\n", | ||
77 | __func__, dsp->name); | ||
78 | hardware = 0; | ||
79 | } | ||
80 | /* check if pipeline exists */ | ||
81 | if (dsp->pipeline.inuse) { | ||
82 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
83 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
84 | "because pipeline exists.\n", | ||
85 | __func__, dsp->name); | ||
86 | hardware = 0; | ||
87 | } | ||
88 | |||
89 | dsp->dtmf.hardware = hardware; | ||
90 | dsp->dtmf.software = !hardware; | ||
91 | } | ||
92 | |||
93 | |||
94 | /************************************************************* | ||
95 | * calculate the coefficients of the given sample and decode * | ||
96 | *************************************************************/ | ||
97 | |||
98 | /* the given sample is decoded. if the sample is not long enough for a | ||
99 | * complete frame, the decoding is finished and continued with the next | ||
100 | * call of this function. | ||
101 | * | ||
102 | * the algorithm is very good for detection with a minimum of errors. i | ||
103 | * tested it allot. it even works with very short tones (40ms). the only | ||
104 | * disadvantage is, that it doesn't work good with different volumes of both | ||
105 | * tones. this will happen, if accoustically coupled dialers are used. | ||
106 | * it sometimes detects tones during speach, which is normal for decoders. | ||
107 | * use sequences to given commands during calls. | ||
108 | * | ||
109 | * dtmf - points to a structure of the current dtmf state | ||
110 | * spl and len - the sample | ||
111 | * fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder | ||
112 | */ | ||
113 | |||
114 | u8 | ||
115 | *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, int fmt) | ||
116 | { | ||
117 | u8 what; | ||
118 | int size; | ||
119 | signed short *buf; | ||
120 | s32 sk, sk1, sk2; | ||
121 | int k, n, i; | ||
122 | s32 *hfccoeff; | ||
123 | s32 result[NCOEFF], tresh, treshl; | ||
124 | int lowgroup, highgroup; | ||
125 | s64 cos2pik_; | ||
126 | |||
127 | dsp->dtmf.digits[0] = '\0'; | ||
128 | |||
129 | /* Note: The function will loop until the buffer has not enough samples | ||
130 | * left to decode a full frame. | ||
131 | */ | ||
132 | again: | ||
133 | /* convert samples */ | ||
134 | size = dsp->dtmf.size; | ||
135 | buf = dsp->dtmf.buffer; | ||
136 | switch (fmt) { | ||
137 | case 0: /* alaw */ | ||
138 | case 1: /* ulaw */ | ||
139 | while (size < DSP_DTMF_NPOINTS && len) { | ||
140 | buf[size++] = dsp_audio_law_to_s32[*data++]; | ||
141 | len--; | ||
142 | } | ||
143 | break; | ||
144 | |||
145 | case 2: /* HFC coefficients */ | ||
146 | default: | ||
147 | if (len < 64) { | ||
148 | if (len > 0) | ||
149 | printk(KERN_ERR "%s: coefficients have invalid " | ||
150 | "size. (is=%d < must=%d)\n", | ||
151 | __func__, len, 64); | ||
152 | return dsp->dtmf.digits; | ||
153 | } | ||
154 | hfccoeff = (s32 *)data; | ||
155 | for (k = 0; k < NCOEFF; k++) { | ||
156 | sk2 = (*hfccoeff++)>>4; | ||
157 | sk = (*hfccoeff++)>>4; | ||
158 | if (sk > 32767 || sk < -32767 || sk2 > 32767 | ||
159 | || sk2 < -32767) | ||
160 | printk(KERN_WARNING | ||
161 | "DTMF-Detection overflow\n"); | ||
162 | /* compute |X(k)|**2 */ | ||
163 | result[k] = | ||
164 | (sk * sk) - | ||
165 | (((cos2pik[k] * sk) >> 15) * sk2) + | ||
166 | (sk2 * sk2); | ||
167 | } | ||
168 | data += 64; | ||
169 | len -= 64; | ||
170 | goto coefficients; | ||
171 | break; | ||
172 | } | ||
173 | dsp->dtmf.size = size; | ||
174 | |||
175 | if (size < DSP_DTMF_NPOINTS) | ||
176 | return dsp->dtmf.digits; | ||
177 | |||
178 | dsp->dtmf.size = 0; | ||
179 | |||
180 | /* now we have a full buffer of signed long samples - we do goertzel */ | ||
181 | for (k = 0; k < NCOEFF; k++) { | ||
182 | sk = 0; | ||
183 | sk1 = 0; | ||
184 | sk2 = 0; | ||
185 | buf = dsp->dtmf.buffer; | ||
186 | cos2pik_ = cos2pik[k]; | ||
187 | for (n = 0; n < DSP_DTMF_NPOINTS; n++) { | ||
188 | sk = ((cos2pik_*sk1)>>15) - sk2 + (*buf++); | ||
189 | sk2 = sk1; | ||
190 | sk1 = sk; | ||
191 | } | ||
192 | sk >>= 8; | ||
193 | sk2 >>= 8; | ||
194 | if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767) | ||
195 | printk(KERN_WARNING "DTMF-Detection overflow\n"); | ||
196 | /* compute |X(k)|**2 */ | ||
197 | result[k] = | ||
198 | (sk * sk) - | ||
199 | (((cos2pik[k] * sk) >> 15) * sk2) + | ||
200 | (sk2 * sk2); | ||
201 | } | ||
202 | |||
203 | /* our (squared) coefficients have been calculated, we need to process | ||
204 | * them. | ||
205 | */ | ||
206 | coefficients: | ||
207 | tresh = 0; | ||
208 | for (i = 0; i < NCOEFF; i++) { | ||
209 | if (result[i] < 0) | ||
210 | result[i] = 0; | ||
211 | if (result[i] > dsp->dtmf.treshold) { | ||
212 | if (result[i] > tresh) | ||
213 | tresh = result[i]; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | if (tresh == 0) { | ||
218 | what = 0; | ||
219 | goto storedigit; | ||
220 | } | ||
221 | |||
222 | if (dsp_debug & DEBUG_DSP_DTMFCOEFF) | ||
223 | printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d" | ||
224 | " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n", | ||
225 | result[0]/10000, result[1]/10000, result[2]/10000, | ||
226 | result[3]/10000, result[4]/10000, result[5]/10000, | ||
227 | result[6]/10000, result[7]/10000, tresh/10000, | ||
228 | result[0]/(tresh/100), result[1]/(tresh/100), | ||
229 | result[2]/(tresh/100), result[3]/(tresh/100), | ||
230 | result[4]/(tresh/100), result[5]/(tresh/100), | ||
231 | result[6]/(tresh/100), result[7]/(tresh/100)); | ||
232 | |||
233 | /* calc digit (lowgroup/highgroup) */ | ||
234 | lowgroup = -1; | ||
235 | highgroup = -1; | ||
236 | treshl = tresh >> 3; /* tones which are not on, must be below 9 dB */ | ||
237 | tresh = tresh >> 2; /* touchtones must match within 6 dB */ | ||
238 | for (i = 0; i < NCOEFF; i++) { | ||
239 | if (result[i] < treshl) | ||
240 | continue; /* ignore */ | ||
241 | if (result[i] < tresh) { | ||
242 | lowgroup = -1; | ||
243 | highgroup = -1; | ||
244 | break; /* noise inbetween */ | ||
245 | } | ||
246 | /* good level found. This is allowed only one time per group */ | ||
247 | if (i < NCOEFF/2) { | ||
248 | /* lowgroup */ | ||
249 | if (lowgroup >= 0) { | ||
250 | /* Bad. Another tone found. */ | ||
251 | lowgroup = -1; | ||
252 | break; | ||
253 | } else | ||
254 | lowgroup = i; | ||
255 | } else { | ||
256 | /* higroup */ | ||
257 | if (highgroup >= 0) { | ||
258 | /* Bad. Another tone found. */ | ||
259 | highgroup = -1; | ||
260 | break; | ||
261 | } else | ||
262 | highgroup = i-(NCOEFF/2); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /* get digit or null */ | ||
267 | what = 0; | ||
268 | if (lowgroup >= 0 && highgroup >= 0) | ||
269 | what = dtmf_matrix[lowgroup][highgroup]; | ||
270 | |||
271 | storedigit: | ||
272 | if (what && (dsp_debug & DEBUG_DSP_DTMF)) | ||
273 | printk(KERN_DEBUG "DTMF what: %c\n", what); | ||
274 | |||
275 | if (dsp->dtmf.lastwhat != what) | ||
276 | dsp->dtmf.count = 0; | ||
277 | |||
278 | /* the tone (or no tone) must remain 3 times without change */ | ||
279 | if (dsp->dtmf.count == 2) { | ||
280 | if (dsp->dtmf.lastdigit != what) { | ||
281 | dsp->dtmf.lastdigit = what; | ||
282 | if (what) { | ||
283 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
284 | printk(KERN_DEBUG "DTMF digit: %c\n", | ||
285 | what); | ||
286 | if ((strlen(dsp->dtmf.digits)+1) | ||
287 | < sizeof(dsp->dtmf.digits)) { | ||
288 | dsp->dtmf.digits[strlen( | ||
289 | dsp->dtmf.digits)+1] = '\0'; | ||
290 | dsp->dtmf.digits[strlen( | ||
291 | dsp->dtmf.digits)] = what; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | } else | ||
296 | dsp->dtmf.count++; | ||
297 | |||
298 | dsp->dtmf.lastwhat = what; | ||
299 | |||
300 | goto again; | ||
301 | } | ||
302 | |||
303 | |||
diff --git a/drivers/isdn/mISDN/dsp_ecdis.h b/drivers/isdn/mISDN/dsp_ecdis.h new file mode 100644 index 000000000000..8a20af43308b --- /dev/null +++ b/drivers/isdn/mISDN/dsp_ecdis.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * SpanDSP - a series of DSP components for telephony | ||
3 | * | ||
4 | * ec_disable_detector.h - A detector which should eventually meet the | ||
5 | * G.164/G.165 requirements for detecting the | ||
6 | * 2100Hz echo cancellor disable tone. | ||
7 | * | ||
8 | * Written by Steve Underwood <steveu@coppice.org> | ||
9 | * | ||
10 | * Copyright (C) 2001 Steve Underwood | ||
11 | * | ||
12 | * All rights reserved. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #include "dsp_biquad.h" | ||
31 | |||
32 | struct ec_disable_detector_state { | ||
33 | struct biquad2_state notch; | ||
34 | int notch_level; | ||
35 | int channel_level; | ||
36 | int tone_present; | ||
37 | int tone_cycle_duration; | ||
38 | int good_cycles; | ||
39 | int hit; | ||
40 | }; | ||
41 | |||
42 | |||
43 | #define FALSE 0 | ||
44 | #define TRUE (!FALSE) | ||
45 | |||
46 | static inline void | ||
47 | echo_can_disable_detector_init(struct ec_disable_detector_state *det) | ||
48 | { | ||
49 | /* Elliptic notch */ | ||
50 | /* This is actually centred at 2095Hz, but gets the balance we want, due | ||
51 | to the asymmetric walls of the notch */ | ||
52 | biquad2_init(&det->notch, | ||
53 | (int32_t) (-0.7600000*32768.0), | ||
54 | (int32_t) (-0.1183852*32768.0), | ||
55 | (int32_t) (-0.5104039*32768.0), | ||
56 | (int32_t) (0.1567596*32768.0), | ||
57 | (int32_t) (1.0000000*32768.0)); | ||
58 | |||
59 | det->channel_level = 0; | ||
60 | det->notch_level = 0; | ||
61 | det->tone_present = FALSE; | ||
62 | det->tone_cycle_duration = 0; | ||
63 | det->good_cycles = 0; | ||
64 | det->hit = 0; | ||
65 | } | ||
66 | /*- End of function --------------------------------------------------------*/ | ||
67 | |||
68 | static inline int | ||
69 | echo_can_disable_detector_update(struct ec_disable_detector_state *det, | ||
70 | int16_t amp) | ||
71 | { | ||
72 | int16_t notched; | ||
73 | |||
74 | notched = biquad2(&det->notch, amp); | ||
75 | /* Estimate the overall energy in the channel, and the energy in | ||
76 | the notch (i.e. overall channel energy - tone energy => noise). | ||
77 | Use abs instead of multiply for speed (is it really faster?). | ||
78 | Damp the overall energy a little more for a stable result. | ||
79 | Damp the notch energy a little less, so we don't damp out the | ||
80 | blip every time the phase reverses */ | ||
81 | det->channel_level += ((abs(amp) - det->channel_level) >> 5); | ||
82 | det->notch_level += ((abs(notched) - det->notch_level) >> 4); | ||
83 | if (det->channel_level > 280) { | ||
84 | /* There is adequate energy in the channel. | ||
85 | Is it mostly at 2100Hz? */ | ||
86 | if (det->notch_level*6 < det->channel_level) { | ||
87 | /* The notch says yes, so we have the tone. */ | ||
88 | if (!det->tone_present) { | ||
89 | /* Do we get a kick every 450+-25ms? */ | ||
90 | if (det->tone_cycle_duration >= 425*8 | ||
91 | && det->tone_cycle_duration <= 475*8) { | ||
92 | det->good_cycles++; | ||
93 | if (det->good_cycles > 2) | ||
94 | det->hit = TRUE; | ||
95 | } | ||
96 | det->tone_cycle_duration = 0; | ||
97 | } | ||
98 | det->tone_present = TRUE; | ||
99 | } else | ||
100 | det->tone_present = FALSE; | ||
101 | det->tone_cycle_duration++; | ||
102 | } else { | ||
103 | det->tone_present = FALSE; | ||
104 | det->tone_cycle_duration = 0; | ||
105 | det->good_cycles = 0; | ||
106 | } | ||
107 | return det->hit; | ||
108 | } | ||
109 | /*- End of function --------------------------------------------------------*/ | ||
110 | /*- End of file ------------------------------------------------------------*/ | ||
diff --git a/drivers/isdn/mISDN/dsp_hwec.c b/drivers/isdn/mISDN/dsp_hwec.c new file mode 100644 index 000000000000..eb892d9dd5c6 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_hwec.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * dsp_hwec.c: | ||
3 | * builtin mISDN dsp pipeline element for enabling the hw echocanceller | ||
4 | * | ||
5 | * Copyright (C) 2007, Nadi Sarrar | ||
6 | * | ||
7 | * Nadi Sarrar <nadi@beronet.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the Free | ||
11 | * Software Foundation; either version 2 of the License, or (at your option) | ||
12 | * any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along with | ||
20 | * this program; if not, write to the Free Software Foundation, Inc., 59 | ||
21 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
22 | * | ||
23 | * The full GNU General Public License is included in this distribution in the | ||
24 | * file called LICENSE. | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/mISDNdsp.h> | ||
31 | #include <linux/mISDNif.h> | ||
32 | #include "core.h" | ||
33 | #include "dsp.h" | ||
34 | #include "dsp_hwec.h" | ||
35 | |||
36 | static struct mISDN_dsp_element_arg args[] = { | ||
37 | { "deftaps", "128", "Set the number of taps of cancellation." }, | ||
38 | }; | ||
39 | |||
40 | static struct mISDN_dsp_element dsp_hwec_p = { | ||
41 | .name = "hwec", | ||
42 | .new = NULL, | ||
43 | .free = NULL, | ||
44 | .process_tx = NULL, | ||
45 | .process_rx = NULL, | ||
46 | .num_args = sizeof(args) / sizeof(struct mISDN_dsp_element_arg), | ||
47 | .args = args, | ||
48 | }; | ||
49 | struct mISDN_dsp_element *dsp_hwec = &dsp_hwec_p; | ||
50 | |||
51 | void dsp_hwec_enable(struct dsp *dsp, const char *arg) | ||
52 | { | ||
53 | int deftaps = 128, | ||
54 | len; | ||
55 | struct mISDN_ctrl_req cq; | ||
56 | |||
57 | if (!dsp) { | ||
58 | printk(KERN_ERR "%s: failed to enable hwec: dsp is NULL\n", | ||
59 | __func__); | ||
60 | return; | ||
61 | } | ||
62 | |||
63 | if (!arg) | ||
64 | goto _do; | ||
65 | |||
66 | len = strlen(arg); | ||
67 | if (!len) | ||
68 | goto _do; | ||
69 | |||
70 | { | ||
71 | char _dup[len + 1]; | ||
72 | char *dup, *tok, *name, *val; | ||
73 | int tmp; | ||
74 | |||
75 | strcpy(_dup, arg); | ||
76 | dup = _dup; | ||
77 | |||
78 | while ((tok = strsep(&dup, ","))) { | ||
79 | if (!strlen(tok)) | ||
80 | continue; | ||
81 | name = strsep(&tok, "="); | ||
82 | val = tok; | ||
83 | |||
84 | if (!val) | ||
85 | continue; | ||
86 | |||
87 | if (!strcmp(name, "deftaps")) { | ||
88 | if (sscanf(val, "%d", &tmp) == 1) | ||
89 | deftaps = tmp; | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | _do: | ||
95 | printk(KERN_DEBUG "%s: enabling hwec with deftaps=%d\n", | ||
96 | __func__, deftaps); | ||
97 | memset(&cq, 0, sizeof(cq)); | ||
98 | cq.op = MISDN_CTRL_HFC_ECHOCAN_ON; | ||
99 | cq.p1 = deftaps; | ||
100 | if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) { | ||
101 | printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", | ||
102 | __func__); | ||
103 | return; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | void dsp_hwec_disable(struct dsp *dsp) | ||
108 | { | ||
109 | struct mISDN_ctrl_req cq; | ||
110 | |||
111 | if (!dsp) { | ||
112 | printk(KERN_ERR "%s: failed to disable hwec: dsp is NULL\n", | ||
113 | __func__); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | printk(KERN_DEBUG "%s: disabling hwec\n", __func__); | ||
118 | memset(&cq, 0, sizeof(cq)); | ||
119 | cq.op = MISDN_CTRL_HFC_ECHOCAN_OFF; | ||
120 | if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) { | ||
121 | printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", | ||
122 | __func__); | ||
123 | return; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | int dsp_hwec_init(void) | ||
128 | { | ||
129 | mISDN_dsp_element_register(dsp_hwec); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | void dsp_hwec_exit(void) | ||
135 | { | ||
136 | mISDN_dsp_element_unregister(dsp_hwec); | ||
137 | } | ||
138 | |||
diff --git a/drivers/isdn/mISDN/dsp_hwec.h b/drivers/isdn/mISDN/dsp_hwec.h new file mode 100644 index 000000000000..eebe80c3f713 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_hwec.h | |||
@@ -0,0 +1,10 @@ | |||
1 | /* | ||
2 | * dsp_hwec.h | ||
3 | */ | ||
4 | |||
5 | extern struct mISDN_dsp_element *dsp_hwec; | ||
6 | extern void dsp_hwec_enable(struct dsp *dsp, const char *arg); | ||
7 | extern void dsp_hwec_disable(struct dsp *dsp); | ||
8 | extern int dsp_hwec_init(void); | ||
9 | extern void dsp_hwec_exit(void); | ||
10 | |||
diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c new file mode 100644 index 000000000000..850260ab57d0 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_pipeline.c | |||
@@ -0,0 +1,348 @@ | |||
1 | /* | ||
2 | * dsp_pipeline.c: pipelined audio processing | ||
3 | * | ||
4 | * Copyright (C) 2007, Nadi Sarrar | ||
5 | * | ||
6 | * Nadi Sarrar <nadi@beronet.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the Free | ||
10 | * Software Foundation; either version 2 of the License, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program; if not, write to the Free Software Foundation, Inc., 59 | ||
20 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | * | ||
22 | * The full GNU General Public License is included in this distribution in the | ||
23 | * file called LICENSE. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/list.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/mISDNif.h> | ||
31 | #include <linux/mISDNdsp.h> | ||
32 | #include "dsp.h" | ||
33 | #include "dsp_hwec.h" | ||
34 | |||
35 | /* uncomment for debugging */ | ||
36 | /*#define PIPELINE_DEBUG*/ | ||
37 | |||
38 | struct dsp_pipeline_entry { | ||
39 | struct mISDN_dsp_element *elem; | ||
40 | void *p; | ||
41 | struct list_head list; | ||
42 | }; | ||
43 | struct dsp_element_entry { | ||
44 | struct mISDN_dsp_element *elem; | ||
45 | struct device dev; | ||
46 | struct list_head list; | ||
47 | }; | ||
48 | |||
49 | static LIST_HEAD(dsp_elements); | ||
50 | |||
51 | /* sysfs */ | ||
52 | static struct class *elements_class; | ||
53 | |||
54 | static ssize_t | ||
55 | attr_show_args(struct device *dev, struct device_attribute *attr, char *buf) | ||
56 | { | ||
57 | struct mISDN_dsp_element *elem = dev_get_drvdata(dev); | ||
58 | ssize_t len = 0; | ||
59 | int i = 0; | ||
60 | |||
61 | *buf = 0; | ||
62 | for (; i < elem->num_args; ++i) | ||
63 | len = sprintf(buf, "%sName: %s\n%s%s%sDescription: %s\n" | ||
64 | "\n", buf, | ||
65 | elem->args[i].name, | ||
66 | elem->args[i].def ? "Default: " : "", | ||
67 | elem->args[i].def ? elem->args[i].def : "", | ||
68 | elem->args[i].def ? "\n" : "", | ||
69 | elem->args[i].desc); | ||
70 | |||
71 | return len; | ||
72 | } | ||
73 | |||
74 | static struct device_attribute element_attributes[] = { | ||
75 | __ATTR(args, 0444, attr_show_args, NULL), | ||
76 | }; | ||
77 | |||
78 | int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) | ||
79 | { | ||
80 | struct dsp_element_entry *entry; | ||
81 | int ret, i; | ||
82 | |||
83 | if (!elem) | ||
84 | return -EINVAL; | ||
85 | |||
86 | entry = kzalloc(sizeof(struct dsp_element_entry), GFP_KERNEL); | ||
87 | if (!entry) | ||
88 | return -ENOMEM; | ||
89 | |||
90 | entry->elem = elem; | ||
91 | |||
92 | entry->dev.class = elements_class; | ||
93 | dev_set_drvdata(&entry->dev, elem); | ||
94 | snprintf(entry->dev.bus_id, BUS_ID_SIZE, elem->name); | ||
95 | ret = device_register(&entry->dev); | ||
96 | if (ret) { | ||
97 | printk(KERN_ERR "%s: failed to register %s\n", | ||
98 | __func__, elem->name); | ||
99 | goto err1; | ||
100 | } | ||
101 | |||
102 | for (i = 0; i < (sizeof(element_attributes) | ||
103 | / sizeof(struct device_attribute)); ++i) | ||
104 | ret = device_create_file(&entry->dev, | ||
105 | &element_attributes[i]); | ||
106 | if (ret) { | ||
107 | printk(KERN_ERR "%s: failed to create device file\n", | ||
108 | __func__); | ||
109 | goto err2; | ||
110 | } | ||
111 | |||
112 | list_add_tail(&entry->list, &dsp_elements); | ||
113 | |||
114 | printk(KERN_DEBUG "%s: %s registered\n", __func__, elem->name); | ||
115 | |||
116 | return 0; | ||
117 | |||
118 | err2: | ||
119 | device_unregister(&entry->dev); | ||
120 | err1: | ||
121 | kfree(entry); | ||
122 | return ret; | ||
123 | } | ||
124 | EXPORT_SYMBOL(mISDN_dsp_element_register); | ||
125 | |||
126 | void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem) | ||
127 | { | ||
128 | struct dsp_element_entry *entry, *n; | ||
129 | |||
130 | if (!elem) | ||
131 | return; | ||
132 | |||
133 | list_for_each_entry_safe(entry, n, &dsp_elements, list) | ||
134 | if (entry->elem == elem) { | ||
135 | list_del(&entry->list); | ||
136 | device_unregister(&entry->dev); | ||
137 | kfree(entry); | ||
138 | printk(KERN_DEBUG "%s: %s unregistered\n", | ||
139 | __func__, elem->name); | ||
140 | return; | ||
141 | } | ||
142 | printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name); | ||
143 | } | ||
144 | EXPORT_SYMBOL(mISDN_dsp_element_unregister); | ||
145 | |||
146 | int dsp_pipeline_module_init(void) | ||
147 | { | ||
148 | elements_class = class_create(THIS_MODULE, "dsp_pipeline"); | ||
149 | if (IS_ERR(elements_class)) | ||
150 | return PTR_ERR(elements_class); | ||
151 | |||
152 | #ifdef PIPELINE_DEBUG | ||
153 | printk(KERN_DEBUG "%s: dsp pipeline module initialized\n", __func__); | ||
154 | #endif | ||
155 | |||
156 | dsp_hwec_init(); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | void dsp_pipeline_module_exit(void) | ||
162 | { | ||
163 | struct dsp_element_entry *entry, *n; | ||
164 | |||
165 | dsp_hwec_exit(); | ||
166 | |||
167 | class_destroy(elements_class); | ||
168 | |||
169 | list_for_each_entry_safe(entry, n, &dsp_elements, list) { | ||
170 | list_del(&entry->list); | ||
171 | printk(KERN_WARNING "%s: element was still registered: %s\n", | ||
172 | __func__, entry->elem->name); | ||
173 | kfree(entry); | ||
174 | } | ||
175 | |||
176 | printk(KERN_DEBUG "%s: dsp pipeline module exited\n", __func__); | ||
177 | } | ||
178 | |||
179 | int dsp_pipeline_init(struct dsp_pipeline *pipeline) | ||
180 | { | ||
181 | if (!pipeline) | ||
182 | return -EINVAL; | ||
183 | |||
184 | INIT_LIST_HEAD(&pipeline->list); | ||
185 | |||
186 | #ifdef PIPELINE_DEBUG | ||
187 | printk(KERN_DEBUG "%s: dsp pipeline ready\n", __func__); | ||
188 | #endif | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static inline void _dsp_pipeline_destroy(struct dsp_pipeline *pipeline) | ||
194 | { | ||
195 | struct dsp_pipeline_entry *entry, *n; | ||
196 | |||
197 | list_for_each_entry_safe(entry, n, &pipeline->list, list) { | ||
198 | list_del(&entry->list); | ||
199 | if (entry->elem == dsp_hwec) | ||
200 | dsp_hwec_disable(container_of(pipeline, struct dsp, | ||
201 | pipeline)); | ||
202 | else | ||
203 | entry->elem->free(entry->p); | ||
204 | kfree(entry); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | void dsp_pipeline_destroy(struct dsp_pipeline *pipeline) | ||
209 | { | ||
210 | |||
211 | if (!pipeline) | ||
212 | return; | ||
213 | |||
214 | _dsp_pipeline_destroy(pipeline); | ||
215 | |||
216 | #ifdef PIPELINE_DEBUG | ||
217 | printk(KERN_DEBUG "%s: dsp pipeline destroyed\n", __func__); | ||
218 | #endif | ||
219 | } | ||
220 | |||
221 | int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) | ||
222 | { | ||
223 | int len, incomplete = 0, found = 0; | ||
224 | char *dup, *tok, *name, *args; | ||
225 | struct dsp_element_entry *entry, *n; | ||
226 | struct dsp_pipeline_entry *pipeline_entry; | ||
227 | struct mISDN_dsp_element *elem; | ||
228 | |||
229 | if (!pipeline) | ||
230 | return -EINVAL; | ||
231 | |||
232 | if (!list_empty(&pipeline->list)) | ||
233 | _dsp_pipeline_destroy(pipeline); | ||
234 | |||
235 | if (!cfg) | ||
236 | return 0; | ||
237 | |||
238 | len = strlen(cfg); | ||
239 | if (!len) | ||
240 | return 0; | ||
241 | |||
242 | dup = kmalloc(len + 1, GFP_KERNEL); | ||
243 | if (!dup) | ||
244 | return 0; | ||
245 | strcpy(dup, cfg); | ||
246 | while ((tok = strsep(&dup, "|"))) { | ||
247 | if (!strlen(tok)) | ||
248 | continue; | ||
249 | name = strsep(&tok, "("); | ||
250 | args = strsep(&tok, ")"); | ||
251 | if (args && !*args) | ||
252 | args = 0; | ||
253 | |||
254 | list_for_each_entry_safe(entry, n, &dsp_elements, list) | ||
255 | if (!strcmp(entry->elem->name, name)) { | ||
256 | elem = entry->elem; | ||
257 | |||
258 | pipeline_entry = kmalloc(sizeof(struct | ||
259 | dsp_pipeline_entry), GFP_KERNEL); | ||
260 | if (!pipeline_entry) { | ||
261 | printk(KERN_DEBUG "%s: failed to add " | ||
262 | "entry to pipeline: %s (out of " | ||
263 | "memory)\n", __func__, elem->name); | ||
264 | incomplete = 1; | ||
265 | goto _out; | ||
266 | } | ||
267 | pipeline_entry->elem = elem; | ||
268 | |||
269 | if (elem == dsp_hwec) { | ||
270 | /* This is a hack to make the hwec | ||
271 | available as a pipeline module */ | ||
272 | dsp_hwec_enable(container_of(pipeline, | ||
273 | struct dsp, pipeline), args); | ||
274 | list_add_tail(&pipeline_entry->list, | ||
275 | &pipeline->list); | ||
276 | } else { | ||
277 | pipeline_entry->p = elem->new(args); | ||
278 | if (pipeline_entry->p) { | ||
279 | list_add_tail(&pipeline_entry-> | ||
280 | list, &pipeline->list); | ||
281 | #ifdef PIPELINE_DEBUG | ||
282 | printk(KERN_DEBUG "%s: created " | ||
283 | "instance of %s%s%s\n", | ||
284 | __func__, name, args ? | ||
285 | " with args " : "", args ? | ||
286 | args : ""); | ||
287 | #endif | ||
288 | } else { | ||
289 | printk(KERN_DEBUG "%s: failed " | ||
290 | "to add entry to pipeline: " | ||
291 | "%s (new() returned NULL)\n", | ||
292 | __func__, elem->name); | ||
293 | kfree(pipeline_entry); | ||
294 | incomplete = 1; | ||
295 | } | ||
296 | } | ||
297 | found = 1; | ||
298 | break; | ||
299 | } | ||
300 | |||
301 | if (found) | ||
302 | found = 0; | ||
303 | else { | ||
304 | printk(KERN_DEBUG "%s: element not found, skipping: " | ||
305 | "%s\n", __func__, name); | ||
306 | incomplete = 1; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | _out: | ||
311 | if (!list_empty(&pipeline->list)) | ||
312 | pipeline->inuse = 1; | ||
313 | else | ||
314 | pipeline->inuse = 0; | ||
315 | |||
316 | #ifdef PIPELINE_DEBUG | ||
317 | printk(KERN_DEBUG "%s: dsp pipeline built%s: %s\n", | ||
318 | __func__, incomplete ? " incomplete" : "", cfg); | ||
319 | #endif | ||
320 | kfree(dup); | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len) | ||
325 | { | ||
326 | struct dsp_pipeline_entry *entry; | ||
327 | |||
328 | if (!pipeline) | ||
329 | return; | ||
330 | |||
331 | list_for_each_entry(entry, &pipeline->list, list) | ||
332 | if (entry->elem->process_tx) | ||
333 | entry->elem->process_tx(entry->p, data, len); | ||
334 | } | ||
335 | |||
336 | void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len) | ||
337 | { | ||
338 | struct dsp_pipeline_entry *entry; | ||
339 | |||
340 | if (!pipeline) | ||
341 | return; | ||
342 | |||
343 | list_for_each_entry_reverse(entry, &pipeline->list, list) | ||
344 | if (entry->elem->process_rx) | ||
345 | entry->elem->process_rx(entry->p, data, len); | ||
346 | } | ||
347 | |||
348 | |||
diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c new file mode 100644 index 000000000000..23dd0dd21524 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_tones.c | |||
@@ -0,0 +1,551 @@ | |||
1 | /* | ||
2 | * Audio support data for ISDN4Linux. | ||
3 | * | ||
4 | * Copyright Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * | ||
6 | * This software may be used and distributed according to the terms | ||
7 | * of the GNU General Public License, incorporated herein by reference. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/mISDNif.h> | ||
12 | #include <linux/mISDNdsp.h> | ||
13 | #include "core.h" | ||
14 | #include "dsp.h" | ||
15 | |||
16 | |||
17 | #define DATA_S sample_silence | ||
18 | #define SIZE_S (&sizeof_silence) | ||
19 | #define DATA_GA sample_german_all | ||
20 | #define SIZE_GA (&sizeof_german_all) | ||
21 | #define DATA_GO sample_german_old | ||
22 | #define SIZE_GO (&sizeof_german_old) | ||
23 | #define DATA_DT sample_american_dialtone | ||
24 | #define SIZE_DT (&sizeof_american_dialtone) | ||
25 | #define DATA_RI sample_american_ringing | ||
26 | #define SIZE_RI (&sizeof_american_ringing) | ||
27 | #define DATA_BU sample_american_busy | ||
28 | #define SIZE_BU (&sizeof_american_busy) | ||
29 | #define DATA_S1 sample_special1 | ||
30 | #define SIZE_S1 (&sizeof_special1) | ||
31 | #define DATA_S2 sample_special2 | ||
32 | #define SIZE_S2 (&sizeof_special2) | ||
33 | #define DATA_S3 sample_special3 | ||
34 | #define SIZE_S3 (&sizeof_special3) | ||
35 | |||
36 | /***************/ | ||
37 | /* tones loops */ | ||
38 | /***************/ | ||
39 | |||
40 | /* all tones are alaw encoded */ | ||
41 | /* the last sample+1 is in phase with the first sample. the error is low */ | ||
42 | |||
43 | static u8 sample_german_all[] = { | ||
44 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
45 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
46 | 0xdc, 0xfc, 0x6c, | ||
47 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
48 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
49 | 0xdc, 0xfc, 0x6c, | ||
50 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
51 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
52 | 0xdc, 0xfc, 0x6c, | ||
53 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
54 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
55 | 0xdc, 0xfc, 0x6c, | ||
56 | }; | ||
57 | static u32 sizeof_german_all = sizeof(sample_german_all); | ||
58 | |||
59 | static u8 sample_german_old[] = { | ||
60 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
61 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
62 | 0x8c, | ||
63 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
64 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
65 | 0x8c, | ||
66 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
67 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
68 | 0x8c, | ||
69 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
70 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
71 | 0x8c, | ||
72 | }; | ||
73 | static u32 sizeof_german_old = sizeof(sample_german_old); | ||
74 | |||
75 | static u8 sample_american_dialtone[] = { | ||
76 | 0x2a, 0x18, 0x90, 0x6c, 0x4c, 0xbc, 0x4c, 0x6c, | ||
77 | 0x10, 0x58, 0x32, 0xb9, 0x31, 0x2d, 0x8d, 0x0d, | ||
78 | 0x8d, 0x2d, 0x31, 0x99, 0x0f, 0x28, 0x60, 0xf0, | ||
79 | 0xd0, 0x50, 0xd0, 0x30, 0x60, 0x08, 0x8e, 0x67, | ||
80 | 0x09, 0x19, 0x21, 0xe1, 0xd9, 0xb9, 0x29, 0x67, | ||
81 | 0x83, 0x02, 0xce, 0xbe, 0xee, 0x1a, 0x1b, 0xef, | ||
82 | 0xbf, 0xcf, 0x03, 0x82, 0x66, 0x28, 0xb8, 0xd8, | ||
83 | 0xe0, 0x20, 0x18, 0x08, 0x66, 0x8f, 0x09, 0x61, | ||
84 | 0x31, 0xd1, 0x51, 0xd1, 0xf1, 0x61, 0x29, 0x0e, | ||
85 | 0x98, 0x30, 0x2c, 0x8c, 0x0c, 0x8c, 0x2c, 0x30, | ||
86 | 0xb8, 0x33, 0x59, 0x11, 0x6d, 0x4d, 0xbd, 0x4d, | ||
87 | 0x6d, 0x91, 0x19, | ||
88 | }; | ||
89 | static u32 sizeof_american_dialtone = sizeof(sample_american_dialtone); | ||
90 | |||
91 | static u8 sample_american_ringing[] = { | ||
92 | 0x2a, 0xe0, 0xac, 0x0c, 0xbc, 0x4c, 0x8c, 0x90, | ||
93 | 0x48, 0xc7, 0xc1, 0xed, 0xcd, 0x4d, 0xcd, 0xed, | ||
94 | 0xc1, 0xb7, 0x08, 0x30, 0xec, 0xcc, 0xcc, 0x8c, | ||
95 | 0x10, 0x58, 0x1a, 0x99, 0x71, 0xed, 0x8d, 0x8d, | ||
96 | 0x2d, 0x41, 0x89, 0x9e, 0x20, 0x70, 0x2c, 0xec, | ||
97 | 0x2c, 0x70, 0x20, 0x86, 0x77, 0xe1, 0x31, 0x11, | ||
98 | 0xd1, 0xf1, 0x81, 0x09, 0xa3, 0x56, 0x58, 0x00, | ||
99 | 0x40, 0xc0, 0x60, 0x38, 0x46, 0x43, 0x57, 0x39, | ||
100 | 0xd9, 0x59, 0x99, 0xc9, 0x77, 0x2f, 0x2e, 0xc6, | ||
101 | 0xd6, 0x28, 0xd6, 0x36, 0x26, 0x2e, 0x8a, 0xa3, | ||
102 | 0x43, 0x63, 0x4b, 0x4a, 0x62, 0x42, 0xa2, 0x8b, | ||
103 | 0x2f, 0x27, 0x37, 0xd7, 0x29, 0xd7, 0xc7, 0x2f, | ||
104 | 0x2e, 0x76, 0xc8, 0x98, 0x58, 0xd8, 0x38, 0x56, | ||
105 | 0x42, 0x47, 0x39, 0x61, 0xc1, 0x41, 0x01, 0x59, | ||
106 | 0x57, 0xa2, 0x08, 0x80, 0xf0, 0xd0, 0x10, 0x30, | ||
107 | 0xe0, 0x76, 0x87, 0x21, 0x71, 0x2d, 0xed, 0x2d, | ||
108 | 0x71, 0x21, 0x9f, 0x88, 0x40, 0x2c, 0x8c, 0x8c, | ||
109 | 0xec, 0x70, 0x98, 0x1b, 0x59, 0x11, 0x8d, 0xcd, | ||
110 | 0xcd, 0xed, 0x31, 0x09, 0xb6, 0xc0, 0xec, 0xcc, | ||
111 | 0x4c, 0xcc, 0xec, 0xc0, 0xc6, 0x49, 0x91, 0x8d, | ||
112 | 0x4d, 0xbd, 0x0d, 0xad, 0xe1, | ||
113 | }; | ||
114 | static u32 sizeof_american_ringing = sizeof(sample_american_ringing); | ||
115 | |||
116 | static u8 sample_american_busy[] = { | ||
117 | 0x2a, 0x00, 0x6c, 0x4c, 0x4c, 0x6c, 0xb0, 0x66, | ||
118 | 0x99, 0x11, 0x6d, 0x8d, 0x2d, 0x41, 0xd7, 0x96, | ||
119 | 0x60, 0xf0, 0x70, 0x40, 0x58, 0xf6, 0x53, 0x57, | ||
120 | 0x09, 0x89, 0xd7, 0x5f, 0xe3, 0x2a, 0xe3, 0x5f, | ||
121 | 0xd7, 0x89, 0x09, 0x57, 0x53, 0xf6, 0x58, 0x40, | ||
122 | 0x70, 0xf0, 0x60, 0x96, 0xd7, 0x41, 0x2d, 0x8d, | ||
123 | 0x6d, 0x11, 0x99, 0x66, 0xb0, 0x6c, 0x4c, 0x4c, | ||
124 | 0x6c, 0x00, 0x2a, 0x01, 0x6d, 0x4d, 0x4d, 0x6d, | ||
125 | 0xb1, 0x67, 0x98, 0x10, 0x6c, 0x8c, 0x2c, 0x40, | ||
126 | 0xd6, 0x97, 0x61, 0xf1, 0x71, 0x41, 0x59, 0xf7, | ||
127 | 0x52, 0x56, 0x08, 0x88, 0xd6, 0x5e, 0xe2, 0x2a, | ||
128 | 0xe2, 0x5e, 0xd6, 0x88, 0x08, 0x56, 0x52, 0xf7, | ||
129 | 0x59, 0x41, 0x71, 0xf1, 0x61, 0x97, 0xd6, 0x40, | ||
130 | 0x2c, 0x8c, 0x6c, 0x10, 0x98, 0x67, 0xb1, 0x6d, | ||
131 | 0x4d, 0x4d, 0x6d, 0x01, | ||
132 | }; | ||
133 | static u32 sizeof_american_busy = sizeof(sample_american_busy); | ||
134 | |||
135 | static u8 sample_special1[] = { | ||
136 | 0x2a, 0x2c, 0xbc, 0x6c, 0xd6, 0x71, 0xbd, 0x0d, | ||
137 | 0xd9, 0x80, 0xcc, 0x4c, 0x40, 0x39, 0x0d, 0xbd, | ||
138 | 0x11, 0x86, 0xec, 0xbc, 0xec, 0x0e, 0x51, 0xbd, | ||
139 | 0x8d, 0x89, 0x30, 0x4c, 0xcc, 0xe0, 0xe1, 0xcd, | ||
140 | 0x4d, 0x31, 0x88, 0x8c, 0xbc, 0x50, 0x0f, 0xed, | ||
141 | 0xbd, 0xed, 0x87, 0x10, 0xbc, 0x0c, 0x38, 0x41, | ||
142 | 0x4d, 0xcd, 0x81, 0xd8, 0x0c, 0xbc, 0x70, 0xd7, | ||
143 | 0x6d, 0xbd, 0x2d, | ||
144 | }; | ||
145 | static u32 sizeof_special1 = sizeof(sample_special1); | ||
146 | |||
147 | static u8 sample_special2[] = { | ||
148 | 0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc, | ||
149 | 0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d, | ||
150 | 0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6, | ||
151 | 0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0, | ||
152 | 0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd, | ||
153 | 0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc, | ||
154 | 0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d, | ||
155 | 0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6, | ||
156 | 0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0, | ||
157 | 0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd, | ||
158 | }; | ||
159 | static u32 sizeof_special2 = sizeof(sample_special2); | ||
160 | |||
161 | static u8 sample_special3[] = { | ||
162 | 0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1, | ||
163 | 0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c, | ||
164 | 0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc, | ||
165 | 0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7, | ||
166 | 0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd, | ||
167 | 0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1, | ||
168 | 0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c, | ||
169 | 0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc, | ||
170 | 0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7, | ||
171 | 0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd, | ||
172 | }; | ||
173 | static u32 sizeof_special3 = sizeof(sample_special3); | ||
174 | |||
175 | static u8 sample_silence[] = { | ||
176 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
177 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
178 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
179 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
180 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
181 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
182 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
183 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
184 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
185 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
186 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
187 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
188 | }; | ||
189 | static u32 sizeof_silence = sizeof(sample_silence); | ||
190 | |||
191 | struct tones_samples { | ||
192 | u32 *len; | ||
193 | u8 *data; | ||
194 | }; | ||
195 | static struct | ||
196 | tones_samples samples[] = { | ||
197 | {&sizeof_german_all, sample_german_all}, | ||
198 | {&sizeof_german_old, sample_german_old}, | ||
199 | {&sizeof_american_dialtone, sample_american_dialtone}, | ||
200 | {&sizeof_american_ringing, sample_american_ringing}, | ||
201 | {&sizeof_american_busy, sample_american_busy}, | ||
202 | {&sizeof_special1, sample_special1}, | ||
203 | {&sizeof_special2, sample_special2}, | ||
204 | {&sizeof_special3, sample_special3}, | ||
205 | {NULL, NULL}, | ||
206 | }; | ||
207 | |||
208 | /*********************************** | ||
209 | * generate ulaw from alaw samples * | ||
210 | ***********************************/ | ||
211 | |||
212 | void | ||
213 | dsp_audio_generate_ulaw_samples(void) | ||
214 | { | ||
215 | int i, j; | ||
216 | |||
217 | i = 0; | ||
218 | while (samples[i].len) { | ||
219 | j = 0; | ||
220 | while (j < (*samples[i].len)) { | ||
221 | samples[i].data[j] = | ||
222 | dsp_audio_alaw_to_ulaw[samples[i].data[j]]; | ||
223 | j++; | ||
224 | } | ||
225 | i++; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | |||
230 | /**************************** | ||
231 | * tone sequence definition * | ||
232 | ****************************/ | ||
233 | |||
234 | struct pattern { | ||
235 | int tone; | ||
236 | u8 *data[10]; | ||
237 | u32 *siz[10]; | ||
238 | u32 seq[10]; | ||
239 | } pattern[] = { | ||
240 | {TONE_GERMAN_DIALTONE, | ||
241 | {DATA_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
242 | {SIZE_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
243 | {1900, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
244 | |||
245 | {TONE_GERMAN_OLDDIALTONE, | ||
246 | {DATA_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
247 | {SIZE_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
248 | {1998, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
249 | |||
250 | {TONE_AMERICAN_DIALTONE, | ||
251 | {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
252 | {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
253 | {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
254 | |||
255 | {TONE_GERMAN_DIALPBX, | ||
256 | {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0}, | ||
257 | {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0}, | ||
258 | {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, | ||
259 | |||
260 | {TONE_GERMAN_OLDDIALPBX, | ||
261 | {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0}, | ||
262 | {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0}, | ||
263 | {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, | ||
264 | |||
265 | {TONE_AMERICAN_DIALPBX, | ||
266 | {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, 0, 0, 0, 0}, | ||
267 | {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, 0, 0, 0, 0}, | ||
268 | {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, | ||
269 | |||
270 | {TONE_GERMAN_RINGING, | ||
271 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
272 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
273 | {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
274 | |||
275 | {TONE_GERMAN_OLDRINGING, | ||
276 | {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
277 | {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
278 | {8000, 40000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
279 | |||
280 | {TONE_AMERICAN_RINGING, | ||
281 | {DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
282 | {SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
283 | {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
284 | |||
285 | {TONE_GERMAN_RINGPBX, | ||
286 | {DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
287 | {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
288 | {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, | ||
289 | |||
290 | {TONE_GERMAN_OLDRINGPBX, | ||
291 | {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
292 | {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
293 | {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, | ||
294 | |||
295 | {TONE_AMERICAN_RINGPBX, | ||
296 | {DATA_RI, DATA_S, DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
297 | {SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
298 | {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, | ||
299 | |||
300 | {TONE_GERMAN_BUSY, | ||
301 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
302 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
303 | {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
304 | |||
305 | {TONE_GERMAN_OLDBUSY, | ||
306 | {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
307 | {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
308 | {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
309 | |||
310 | {TONE_AMERICAN_BUSY, | ||
311 | {DATA_BU, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
312 | {SIZE_BU, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
313 | {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
314 | |||
315 | {TONE_GERMAN_HANGUP, | ||
316 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
317 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
318 | {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
319 | |||
320 | {TONE_GERMAN_OLDHANGUP, | ||
321 | {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
322 | {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
323 | {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
324 | |||
325 | {TONE_AMERICAN_HANGUP, | ||
326 | {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
327 | {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
328 | {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
329 | |||
330 | {TONE_SPECIAL_INFO, | ||
331 | {DATA_S1, DATA_S2, DATA_S3, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
332 | {SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
333 | {2666, 2666, 2666, 8002, 0, 0, 0, 0, 0, 0} }, | ||
334 | |||
335 | {TONE_GERMAN_GASSENBESETZT, | ||
336 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
337 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
338 | {2000, 2000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
339 | |||
340 | {TONE_GERMAN_AUFSCHALTTON, | ||
341 | {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
342 | {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
343 | {1000, 5000, 1000, 17000, 0, 0, 0, 0, 0, 0} }, | ||
344 | |||
345 | {0, | ||
346 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
347 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
348 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
349 | }; | ||
350 | |||
351 | /****************** | ||
352 | * copy tone data * | ||
353 | ******************/ | ||
354 | |||
355 | /* an sk_buff is generated from the number of samples needed. | ||
356 | * the count will be changed and may begin from 0 each pattern period. | ||
357 | * the clue is to precalculate the pointers and legths to use only one | ||
358 | * memcpy per function call, or two memcpy if the tone sequence changes. | ||
359 | * | ||
360 | * pattern - the type of the pattern | ||
361 | * count - the sample from the beginning of the pattern (phase) | ||
362 | * len - the number of bytes | ||
363 | * | ||
364 | * return - the sk_buff with the sample | ||
365 | * | ||
366 | * if tones has finished (e.g. knocking tone), dsp->tones is turned off | ||
367 | */ | ||
368 | void dsp_tone_copy(struct dsp *dsp, u8 *data, int len) | ||
369 | { | ||
370 | int index, count, start, num; | ||
371 | struct pattern *pat; | ||
372 | struct dsp_tone *tone = &dsp->tone; | ||
373 | |||
374 | /* if we have no tone, we copy silence */ | ||
375 | if (!tone->tone) { | ||
376 | memset(data, dsp_silence, len); | ||
377 | return; | ||
378 | } | ||
379 | |||
380 | /* process pattern */ | ||
381 | pat = (struct pattern *)tone->pattern; | ||
382 | /* points to the current pattern */ | ||
383 | index = tone->index; /* gives current sequence index */ | ||
384 | count = tone->count; /* gives current sample */ | ||
385 | |||
386 | /* copy sample */ | ||
387 | while (len) { | ||
388 | /* find sample to start with */ | ||
389 | while (42) { | ||
390 | /* warp arround */ | ||
391 | if (!pat->seq[index]) { | ||
392 | count = 0; | ||
393 | index = 0; | ||
394 | } | ||
395 | /* check if we are currently playing this tone */ | ||
396 | if (count < pat->seq[index]) | ||
397 | break; | ||
398 | if (dsp_debug & DEBUG_DSP_TONE) | ||
399 | printk(KERN_DEBUG "%s: reaching next sequence " | ||
400 | "(index=%d)\n", __func__, index); | ||
401 | count -= pat->seq[index]; | ||
402 | index++; | ||
403 | } | ||
404 | /* calculate start and number of samples */ | ||
405 | start = count % (*(pat->siz[index])); | ||
406 | num = len; | ||
407 | if (num+count > pat->seq[index]) | ||
408 | num = pat->seq[index] - count; | ||
409 | if (num+start > (*(pat->siz[index]))) | ||
410 | num = (*(pat->siz[index])) - start; | ||
411 | /* copy memory */ | ||
412 | memcpy(data, pat->data[index]+start, num); | ||
413 | /* reduce length */ | ||
414 | data += num; | ||
415 | count += num; | ||
416 | len -= num; | ||
417 | } | ||
418 | tone->index = index; | ||
419 | tone->count = count; | ||
420 | |||
421 | /* return sk_buff */ | ||
422 | return; | ||
423 | } | ||
424 | |||
425 | |||
426 | /******************************* | ||
427 | * send HW message to hfc card * | ||
428 | *******************************/ | ||
429 | |||
430 | static void | ||
431 | dsp_tone_hw_message(struct dsp *dsp, u8 *sample, int len) | ||
432 | { | ||
433 | struct sk_buff *nskb; | ||
434 | |||
435 | /* unlocking is not required, because we don't expect a response */ | ||
436 | nskb = _alloc_mISDN_skb(PH_CONTROL_REQ, | ||
437 | (len)?HFC_SPL_LOOP_ON:HFC_SPL_LOOP_OFF, len, sample, | ||
438 | GFP_ATOMIC); | ||
439 | if (nskb) { | ||
440 | if (dsp->ch.peer) { | ||
441 | if (dsp->ch.recv(dsp->ch.peer, nskb)) | ||
442 | dev_kfree_skb(nskb); | ||
443 | } else | ||
444 | dev_kfree_skb(nskb); | ||
445 | } | ||
446 | } | ||
447 | |||
448 | |||
449 | /***************** | ||
450 | * timer expires * | ||
451 | *****************/ | ||
452 | void | ||
453 | dsp_tone_timeout(void *arg) | ||
454 | { | ||
455 | struct dsp *dsp = arg; | ||
456 | struct dsp_tone *tone = &dsp->tone; | ||
457 | struct pattern *pat = (struct pattern *)tone->pattern; | ||
458 | int index = tone->index; | ||
459 | |||
460 | if (!tone->tone) | ||
461 | return; | ||
462 | |||
463 | index++; | ||
464 | if (!pat->seq[index]) | ||
465 | index = 0; | ||
466 | tone->index = index; | ||
467 | |||
468 | /* set next tone */ | ||
469 | if (pat->data[index] == DATA_S) | ||
470 | dsp_tone_hw_message(dsp, 0, 0); | ||
471 | else | ||
472 | dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index])); | ||
473 | /* set timer */ | ||
474 | init_timer(&tone->tl); | ||
475 | tone->tl.expires = jiffies + (pat->seq[index] * HZ) / 8000; | ||
476 | add_timer(&tone->tl); | ||
477 | } | ||
478 | |||
479 | |||
480 | /******************** | ||
481 | * set/release tone * | ||
482 | ********************/ | ||
483 | |||
484 | /* | ||
485 | * tones are relaized by streaming or by special loop commands if supported | ||
486 | * by hardware. when hardware is used, the patterns will be controlled by | ||
487 | * timers. | ||
488 | */ | ||
489 | int | ||
490 | dsp_tone(struct dsp *dsp, int tone) | ||
491 | { | ||
492 | struct pattern *pat; | ||
493 | int i; | ||
494 | struct dsp_tone *tonet = &dsp->tone; | ||
495 | |||
496 | tonet->software = 0; | ||
497 | tonet->hardware = 0; | ||
498 | |||
499 | /* we turn off the tone */ | ||
500 | if (!tone) { | ||
501 | if (dsp->features.hfc_loops) | ||
502 | if (timer_pending(&tonet->tl)) | ||
503 | del_timer(&tonet->tl); | ||
504 | if (dsp->features.hfc_loops) | ||
505 | dsp_tone_hw_message(dsp, NULL, 0); | ||
506 | tonet->tone = 0; | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | pat = NULL; | ||
511 | i = 0; | ||
512 | while (pattern[i].tone) { | ||
513 | if (pattern[i].tone == tone) { | ||
514 | pat = &pattern[i]; | ||
515 | break; | ||
516 | } | ||
517 | i++; | ||
518 | } | ||
519 | if (!pat) { | ||
520 | printk(KERN_WARNING "dsp: given tone 0x%x is invalid\n", tone); | ||
521 | return -EINVAL; | ||
522 | } | ||
523 | if (dsp_debug & DEBUG_DSP_TONE) | ||
524 | printk(KERN_DEBUG "%s: now starting tone %d (index=%d)\n", | ||
525 | __func__, tone, 0); | ||
526 | tonet->tone = tone; | ||
527 | tonet->pattern = pat; | ||
528 | tonet->index = 0; | ||
529 | tonet->count = 0; | ||
530 | |||
531 | if (dsp->features.hfc_loops) { | ||
532 | tonet->hardware = 1; | ||
533 | /* set first tone */ | ||
534 | dsp_tone_hw_message(dsp, pat->data[0], *(pat->siz[0])); | ||
535 | /* set timer */ | ||
536 | if (timer_pending(&tonet->tl)) | ||
537 | del_timer(&tonet->tl); | ||
538 | init_timer(&tonet->tl); | ||
539 | tonet->tl.expires = jiffies + (pat->seq[0] * HZ) / 8000; | ||
540 | add_timer(&tonet->tl); | ||
541 | } else { | ||
542 | tonet->software = 1; | ||
543 | } | ||
544 | |||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | |||
549 | |||
550 | |||
551 | |||
diff --git a/include/linux/mISDNdsp.h b/include/linux/mISDNdsp.h new file mode 100644 index 000000000000..6b71d2dce508 --- /dev/null +++ b/include/linux/mISDNdsp.h | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef __mISDNdsp_H__ | ||
2 | #define __mISDNdsp_H__ | ||
3 | |||
4 | struct mISDN_dsp_element_arg { | ||
5 | char *name; | ||
6 | char *def; | ||
7 | char *desc; | ||
8 | }; | ||
9 | |||
10 | struct mISDN_dsp_element { | ||
11 | char *name; | ||
12 | void *(*new)(const char *arg); | ||
13 | void (*free)(void *p); | ||
14 | void (*process_tx)(void *p, unsigned char *data, int len); | ||
15 | void (*process_rx)(void *p, unsigned char *data, int len); | ||
16 | int num_args; | ||
17 | struct mISDN_dsp_element_arg | ||
18 | *args; | ||
19 | }; | ||
20 | |||
21 | extern int mISDN_dsp_element_register(struct mISDN_dsp_element *elem); | ||
22 | extern void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem); | ||
23 | |||
24 | struct dsp_features { | ||
25 | int hfc_id; /* unique id to identify the chip (or -1) */ | ||
26 | int hfc_dtmf; /* set if HFCmulti card supports dtmf */ | ||
27 | int hfc_loops; /* set if card supports tone loops */ | ||
28 | int hfc_echocanhw; /* set if card supports echocancelation*/ | ||
29 | int pcm_id; /* unique id to identify the pcm bus (or -1) */ | ||
30 | int pcm_slots; /* number of slots on the pcm bus */ | ||
31 | int pcm_banks; /* number of IO banks of pcm bus */ | ||
32 | int unclocked; /* data is not clocked (has jitter/loss) */ | ||
33 | int unordered; /* data is unordered (packets have index) */ | ||
34 | }; | ||
35 | |||
36 | #endif | ||
37 | |||