diff options
Diffstat (limited to 'drivers/isdn/mISDN')
30 files changed, 14828 insertions, 0 deletions
diff --git a/drivers/isdn/mISDN/Kconfig b/drivers/isdn/mISDN/Kconfig new file mode 100644 index 000000000000..4938355c4072 --- /dev/null +++ b/drivers/isdn/mISDN/Kconfig | |||
@@ -0,0 +1,44 @@ | |||
1 | # | ||
2 | # modularer ISDN driver | ||
3 | # | ||
4 | |||
5 | menuconfig MISDN | ||
6 | tristate "Modular ISDN driver" | ||
7 | help | ||
8 | Enable support for the modular ISDN driver. | ||
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 | config MISDN_L1OIP | ||
27 | tristate "ISDN over IP tunnel" | ||
28 | depends on MISDN | ||
29 | help | ||
30 | Enable support for ISDN over IP tunnel. | ||
31 | |||
32 | It features: | ||
33 | - dynamic IP exchange, if one or both peers have dynamic IPs | ||
34 | - BRI (S0) and PRI (S2M) interface | ||
35 | - layer 1 control via network keepalive frames | ||
36 | - direct tunneling of physical interface via IP | ||
37 | |||
38 | NOTE: This protocol is called 'Layer 1 over IP' and is not | ||
39 | compatible with ISDNoIP (Agfeo) or TDMoIP. Protocol description is | ||
40 | provided in the source code. | ||
41 | |||
42 | source "drivers/isdn/hardware/mISDN/Kconfig" | ||
43 | |||
44 | endif #MISDN | ||
diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile new file mode 100644 index 000000000000..1cb5e633cf75 --- /dev/null +++ b/drivers/isdn/mISDN/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # | ||
2 | # Makefile for the modular ISDN driver | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_MISDN) += mISDN_core.o | ||
6 | obj-$(CONFIG_MISDN_DSP) += mISDN_dsp.o | ||
7 | obj-$(CONFIG_MISDN_L1OIP) += l1oip.o | ||
8 | |||
9 | # multi objects | ||
10 | |||
11 | mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o | ||
12 | 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 | ||
13 | l1oip-objs := l1oip_core.o l1oip_codec.o | ||
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c new file mode 100644 index 000000000000..33068177b7c9 --- /dev/null +++ b/drivers/isdn/mISDN/core.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/types.h> | ||
16 | #include <linux/stddef.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/mISDNif.h> | ||
20 | #include "core.h" | ||
21 | |||
22 | static u_int debug; | ||
23 | |||
24 | MODULE_AUTHOR("Karsten Keil"); | ||
25 | MODULE_LICENSE("GPL"); | ||
26 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
27 | |||
28 | static LIST_HEAD(devices); | ||
29 | DEFINE_RWLOCK(device_lock); | ||
30 | static u64 device_ids; | ||
31 | #define MAX_DEVICE_ID 63 | ||
32 | |||
33 | static LIST_HEAD(Bprotocols); | ||
34 | DEFINE_RWLOCK(bp_lock); | ||
35 | |||
36 | struct mISDNdevice | ||
37 | *get_mdevice(u_int id) | ||
38 | { | ||
39 | struct mISDNdevice *dev; | ||
40 | |||
41 | read_lock(&device_lock); | ||
42 | list_for_each_entry(dev, &devices, D.list) | ||
43 | if (dev->id == id) { | ||
44 | read_unlock(&device_lock); | ||
45 | return dev; | ||
46 | } | ||
47 | read_unlock(&device_lock); | ||
48 | return NULL; | ||
49 | } | ||
50 | |||
51 | int | ||
52 | get_mdevice_count(void) | ||
53 | { | ||
54 | struct mISDNdevice *dev; | ||
55 | int cnt = 0; | ||
56 | |||
57 | read_lock(&device_lock); | ||
58 | list_for_each_entry(dev, &devices, D.list) | ||
59 | cnt++; | ||
60 | read_unlock(&device_lock); | ||
61 | return cnt; | ||
62 | } | ||
63 | |||
64 | static int | ||
65 | get_free_devid(void) | ||
66 | { | ||
67 | u_int i; | ||
68 | |||
69 | for (i = 0; i <= MAX_DEVICE_ID; i++) | ||
70 | if (!test_and_set_bit(i, (u_long *)&device_ids)) | ||
71 | return i; | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | int | ||
76 | mISDN_register_device(struct mISDNdevice *dev, char *name) | ||
77 | { | ||
78 | u_long flags; | ||
79 | int err; | ||
80 | |||
81 | dev->id = get_free_devid(); | ||
82 | if (dev->id < 0) | ||
83 | return -EBUSY; | ||
84 | if (name && name[0]) | ||
85 | strcpy(dev->name, name); | ||
86 | else | ||
87 | sprintf(dev->name, "mISDN%d", dev->id); | ||
88 | if (debug & DEBUG_CORE) | ||
89 | printk(KERN_DEBUG "mISDN_register %s %d\n", | ||
90 | dev->name, dev->id); | ||
91 | err = create_stack(dev); | ||
92 | if (err) | ||
93 | return err; | ||
94 | write_lock_irqsave(&device_lock, flags); | ||
95 | list_add_tail(&dev->D.list, &devices); | ||
96 | write_unlock_irqrestore(&device_lock, flags); | ||
97 | return 0; | ||
98 | } | ||
99 | EXPORT_SYMBOL(mISDN_register_device); | ||
100 | |||
101 | void | ||
102 | mISDN_unregister_device(struct mISDNdevice *dev) { | ||
103 | u_long flags; | ||
104 | |||
105 | if (debug & DEBUG_CORE) | ||
106 | printk(KERN_DEBUG "mISDN_unregister %s %d\n", | ||
107 | dev->name, dev->id); | ||
108 | write_lock_irqsave(&device_lock, flags); | ||
109 | list_del(&dev->D.list); | ||
110 | write_unlock_irqrestore(&device_lock, flags); | ||
111 | test_and_clear_bit(dev->id, (u_long *)&device_ids); | ||
112 | delete_stack(dev); | ||
113 | } | ||
114 | EXPORT_SYMBOL(mISDN_unregister_device); | ||
115 | |||
116 | u_int | ||
117 | get_all_Bprotocols(void) | ||
118 | { | ||
119 | struct Bprotocol *bp; | ||
120 | u_int m = 0; | ||
121 | |||
122 | read_lock(&bp_lock); | ||
123 | list_for_each_entry(bp, &Bprotocols, list) | ||
124 | m |= bp->Bprotocols; | ||
125 | read_unlock(&bp_lock); | ||
126 | return m; | ||
127 | } | ||
128 | |||
129 | struct Bprotocol * | ||
130 | get_Bprotocol4mask(u_int m) | ||
131 | { | ||
132 | struct Bprotocol *bp; | ||
133 | |||
134 | read_lock(&bp_lock); | ||
135 | list_for_each_entry(bp, &Bprotocols, list) | ||
136 | if (bp->Bprotocols & m) { | ||
137 | read_unlock(&bp_lock); | ||
138 | return bp; | ||
139 | } | ||
140 | read_unlock(&bp_lock); | ||
141 | return NULL; | ||
142 | } | ||
143 | |||
144 | struct Bprotocol * | ||
145 | get_Bprotocol4id(u_int id) | ||
146 | { | ||
147 | u_int m; | ||
148 | |||
149 | if (id < ISDN_P_B_START || id > 63) { | ||
150 | printk(KERN_WARNING "%s id not in range %d\n", | ||
151 | __func__, id); | ||
152 | return NULL; | ||
153 | } | ||
154 | m = 1 << (id & ISDN_P_B_MASK); | ||
155 | return get_Bprotocol4mask(m); | ||
156 | } | ||
157 | |||
158 | int | ||
159 | mISDN_register_Bprotocol(struct Bprotocol *bp) | ||
160 | { | ||
161 | u_long flags; | ||
162 | struct Bprotocol *old; | ||
163 | |||
164 | if (debug & DEBUG_CORE) | ||
165 | printk(KERN_DEBUG "%s: %s/%x\n", __func__, | ||
166 | bp->name, bp->Bprotocols); | ||
167 | old = get_Bprotocol4mask(bp->Bprotocols); | ||
168 | if (old) { | ||
169 | printk(KERN_WARNING | ||
170 | "register duplicate protocol old %s/%x new %s/%x\n", | ||
171 | old->name, old->Bprotocols, bp->name, bp->Bprotocols); | ||
172 | return -EBUSY; | ||
173 | } | ||
174 | write_lock_irqsave(&bp_lock, flags); | ||
175 | list_add_tail(&bp->list, &Bprotocols); | ||
176 | write_unlock_irqrestore(&bp_lock, flags); | ||
177 | return 0; | ||
178 | } | ||
179 | EXPORT_SYMBOL(mISDN_register_Bprotocol); | ||
180 | |||
181 | void | ||
182 | mISDN_unregister_Bprotocol(struct Bprotocol *bp) | ||
183 | { | ||
184 | u_long flags; | ||
185 | |||
186 | if (debug & DEBUG_CORE) | ||
187 | printk(KERN_DEBUG "%s: %s/%x\n", __func__, bp->name, | ||
188 | bp->Bprotocols); | ||
189 | write_lock_irqsave(&bp_lock, flags); | ||
190 | list_del(&bp->list); | ||
191 | write_unlock_irqrestore(&bp_lock, flags); | ||
192 | } | ||
193 | EXPORT_SYMBOL(mISDN_unregister_Bprotocol); | ||
194 | |||
195 | int | ||
196 | mISDNInit(void) | ||
197 | { | ||
198 | int err; | ||
199 | |||
200 | printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n", | ||
201 | MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); | ||
202 | mISDN_initstack(&debug); | ||
203 | err = mISDN_inittimer(&debug); | ||
204 | if (err) | ||
205 | goto error; | ||
206 | err = l1_init(&debug); | ||
207 | if (err) { | ||
208 | mISDN_timer_cleanup(); | ||
209 | goto error; | ||
210 | } | ||
211 | err = Isdnl2_Init(&debug); | ||
212 | if (err) { | ||
213 | mISDN_timer_cleanup(); | ||
214 | l1_cleanup(); | ||
215 | goto error; | ||
216 | } | ||
217 | err = misdn_sock_init(&debug); | ||
218 | if (err) { | ||
219 | mISDN_timer_cleanup(); | ||
220 | l1_cleanup(); | ||
221 | Isdnl2_cleanup(); | ||
222 | } | ||
223 | error: | ||
224 | return err; | ||
225 | } | ||
226 | |||
227 | void mISDN_cleanup(void) | ||
228 | { | ||
229 | misdn_sock_cleanup(); | ||
230 | mISDN_timer_cleanup(); | ||
231 | l1_cleanup(); | ||
232 | Isdnl2_cleanup(); | ||
233 | |||
234 | if (!list_empty(&devices)) | ||
235 | printk(KERN_ERR "%s devices still registered\n", __func__); | ||
236 | |||
237 | if (!list_empty(&Bprotocols)) | ||
238 | printk(KERN_ERR "%s Bprotocols still registered\n", __func__); | ||
239 | printk(KERN_DEBUG "mISDNcore unloaded\n"); | ||
240 | } | ||
241 | |||
242 | module_init(mISDNInit); | ||
243 | module_exit(mISDN_cleanup); | ||
244 | |||
diff --git a/drivers/isdn/mISDN/core.h b/drivers/isdn/mISDN/core.h new file mode 100644 index 000000000000..7da7233b4c1a --- /dev/null +++ b/drivers/isdn/mISDN/core.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef mISDN_CORE_H | ||
16 | #define mISDN_CORE_H | ||
17 | |||
18 | extern struct mISDNdevice *get_mdevice(u_int); | ||
19 | extern int get_mdevice_count(void); | ||
20 | |||
21 | /* stack status flag */ | ||
22 | #define mISDN_STACK_ACTION_MASK 0x0000ffff | ||
23 | #define mISDN_STACK_COMMAND_MASK 0x000f0000 | ||
24 | #define mISDN_STACK_STATUS_MASK 0xfff00000 | ||
25 | /* action bits 0-15 */ | ||
26 | #define mISDN_STACK_WORK 0 | ||
27 | #define mISDN_STACK_SETUP 1 | ||
28 | #define mISDN_STACK_CLEARING 2 | ||
29 | #define mISDN_STACK_RESTART 3 | ||
30 | #define mISDN_STACK_WAKEUP 4 | ||
31 | #define mISDN_STACK_ABORT 15 | ||
32 | /* command bits 16-19 */ | ||
33 | #define mISDN_STACK_STOPPED 16 | ||
34 | #define mISDN_STACK_INIT 17 | ||
35 | #define mISDN_STACK_THREADSTART 18 | ||
36 | /* status bits 20-31 */ | ||
37 | #define mISDN_STACK_BCHANNEL 20 | ||
38 | #define mISDN_STACK_ACTIVE 29 | ||
39 | #define mISDN_STACK_RUNNING 30 | ||
40 | #define mISDN_STACK_KILLED 31 | ||
41 | |||
42 | |||
43 | /* manager options */ | ||
44 | #define MGR_OPT_USER 24 | ||
45 | #define MGR_OPT_NETWORK 25 | ||
46 | |||
47 | extern int connect_Bstack(struct mISDNdevice *, struct mISDNchannel *, | ||
48 | u_int, struct sockaddr_mISDN *); | ||
49 | extern int connect_layer1(struct mISDNdevice *, struct mISDNchannel *, | ||
50 | u_int, struct sockaddr_mISDN *); | ||
51 | extern int create_l2entity(struct mISDNdevice *, struct mISDNchannel *, | ||
52 | u_int, struct sockaddr_mISDN *); | ||
53 | |||
54 | extern int create_stack(struct mISDNdevice *); | ||
55 | extern int create_teimanager(struct mISDNdevice *); | ||
56 | extern void delete_teimanager(struct mISDNchannel *); | ||
57 | extern void delete_channel(struct mISDNchannel *); | ||
58 | extern void delete_stack(struct mISDNdevice *); | ||
59 | extern void mISDN_initstack(u_int *); | ||
60 | extern int misdn_sock_init(u_int *); | ||
61 | extern void misdn_sock_cleanup(void); | ||
62 | extern void add_layer2(struct mISDNchannel *, struct mISDNstack *); | ||
63 | extern void __add_layer2(struct mISDNchannel *, struct mISDNstack *); | ||
64 | |||
65 | extern u_int get_all_Bprotocols(void); | ||
66 | struct Bprotocol *get_Bprotocol4mask(u_int); | ||
67 | struct Bprotocol *get_Bprotocol4id(u_int); | ||
68 | |||
69 | extern int mISDN_inittimer(u_int *); | ||
70 | extern void mISDN_timer_cleanup(void); | ||
71 | |||
72 | extern int l1_init(u_int *); | ||
73 | extern void l1_cleanup(void); | ||
74 | extern int Isdnl2_Init(u_int *); | ||
75 | extern void Isdnl2_cleanup(void); | ||
76 | |||
77 | #endif | ||
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/drivers/isdn/mISDN/fsm.c b/drivers/isdn/mISDN/fsm.c new file mode 100644 index 000000000000..b5d6553f2dc8 --- /dev/null +++ b/drivers/isdn/mISDN/fsm.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * finite state machine implementation | ||
3 | * | ||
4 | * Author Karsten Keil <kkeil@novell.com> | ||
5 | * | ||
6 | * Thanks to Jan den Ouden | ||
7 | * Fritz Elfert | ||
8 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/string.h> | ||
25 | #include "fsm.h" | ||
26 | |||
27 | #define FSM_TIMER_DEBUG 0 | ||
28 | |||
29 | void | ||
30 | mISDN_FsmNew(struct Fsm *fsm, | ||
31 | struct FsmNode *fnlist, int fncount) | ||
32 | { | ||
33 | int i; | ||
34 | |||
35 | fsm->jumpmatrix = kzalloc(sizeof(FSMFNPTR) * fsm->state_count * | ||
36 | fsm->event_count, GFP_KERNEL); | ||
37 | |||
38 | for (i = 0; i < fncount; i++) | ||
39 | if ((fnlist[i].state >= fsm->state_count) || | ||
40 | (fnlist[i].event >= fsm->event_count)) { | ||
41 | printk(KERN_ERR | ||
42 | "mISDN_FsmNew Error: %d st(%ld/%ld) ev(%ld/%ld)\n", | ||
43 | i, (long)fnlist[i].state, (long)fsm->state_count, | ||
44 | (long)fnlist[i].event, (long)fsm->event_count); | ||
45 | } else | ||
46 | fsm->jumpmatrix[fsm->state_count * fnlist[i].event + | ||
47 | fnlist[i].state] = (FSMFNPTR) fnlist[i].routine; | ||
48 | } | ||
49 | EXPORT_SYMBOL(mISDN_FsmNew); | ||
50 | |||
51 | void | ||
52 | mISDN_FsmFree(struct Fsm *fsm) | ||
53 | { | ||
54 | kfree((void *) fsm->jumpmatrix); | ||
55 | } | ||
56 | EXPORT_SYMBOL(mISDN_FsmFree); | ||
57 | |||
58 | int | ||
59 | mISDN_FsmEvent(struct FsmInst *fi, int event, void *arg) | ||
60 | { | ||
61 | FSMFNPTR r; | ||
62 | |||
63 | if ((fi->state >= fi->fsm->state_count) || | ||
64 | (event >= fi->fsm->event_count)) { | ||
65 | printk(KERN_ERR | ||
66 | "mISDN_FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n", | ||
67 | (long)fi->state, (long)fi->fsm->state_count, event, | ||
68 | (long)fi->fsm->event_count); | ||
69 | return 1; | ||
70 | } | ||
71 | r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; | ||
72 | if (r) { | ||
73 | if (fi->debug) | ||
74 | fi->printdebug(fi, "State %s Event %s", | ||
75 | fi->fsm->strState[fi->state], | ||
76 | fi->fsm->strEvent[event]); | ||
77 | r(fi, event, arg); | ||
78 | return 0; | ||
79 | } else { | ||
80 | if (fi->debug) | ||
81 | fi->printdebug(fi, "State %s Event %s no action", | ||
82 | fi->fsm->strState[fi->state], | ||
83 | fi->fsm->strEvent[event]); | ||
84 | return 1; | ||
85 | } | ||
86 | } | ||
87 | EXPORT_SYMBOL(mISDN_FsmEvent); | ||
88 | |||
89 | void | ||
90 | mISDN_FsmChangeState(struct FsmInst *fi, int newstate) | ||
91 | { | ||
92 | fi->state = newstate; | ||
93 | if (fi->debug) | ||
94 | fi->printdebug(fi, "ChangeState %s", | ||
95 | fi->fsm->strState[newstate]); | ||
96 | } | ||
97 | EXPORT_SYMBOL(mISDN_FsmChangeState); | ||
98 | |||
99 | static void | ||
100 | FsmExpireTimer(struct FsmTimer *ft) | ||
101 | { | ||
102 | #if FSM_TIMER_DEBUG | ||
103 | if (ft->fi->debug) | ||
104 | ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft); | ||
105 | #endif | ||
106 | mISDN_FsmEvent(ft->fi, ft->event, ft->arg); | ||
107 | } | ||
108 | |||
109 | void | ||
110 | mISDN_FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft) | ||
111 | { | ||
112 | ft->fi = fi; | ||
113 | ft->tl.function = (void *) FsmExpireTimer; | ||
114 | ft->tl.data = (long) ft; | ||
115 | #if FSM_TIMER_DEBUG | ||
116 | if (ft->fi->debug) | ||
117 | ft->fi->printdebug(ft->fi, "mISDN_FsmInitTimer %lx", (long) ft); | ||
118 | #endif | ||
119 | init_timer(&ft->tl); | ||
120 | } | ||
121 | EXPORT_SYMBOL(mISDN_FsmInitTimer); | ||
122 | |||
123 | void | ||
124 | mISDN_FsmDelTimer(struct FsmTimer *ft, int where) | ||
125 | { | ||
126 | #if FSM_TIMER_DEBUG | ||
127 | if (ft->fi->debug) | ||
128 | ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d", | ||
129 | (long) ft, where); | ||
130 | #endif | ||
131 | del_timer(&ft->tl); | ||
132 | } | ||
133 | EXPORT_SYMBOL(mISDN_FsmDelTimer); | ||
134 | |||
135 | int | ||
136 | mISDN_FsmAddTimer(struct FsmTimer *ft, | ||
137 | int millisec, int event, void *arg, int where) | ||
138 | { | ||
139 | |||
140 | #if FSM_TIMER_DEBUG | ||
141 | if (ft->fi->debug) | ||
142 | ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d", | ||
143 | (long) ft, millisec, where); | ||
144 | #endif | ||
145 | |||
146 | if (timer_pending(&ft->tl)) { | ||
147 | if (ft->fi->debug) { | ||
148 | printk(KERN_WARNING | ||
149 | "mISDN_FsmAddTimer: timer already active!\n"); | ||
150 | ft->fi->printdebug(ft->fi, | ||
151 | "mISDN_FsmAddTimer already active!"); | ||
152 | } | ||
153 | return -1; | ||
154 | } | ||
155 | init_timer(&ft->tl); | ||
156 | ft->event = event; | ||
157 | ft->arg = arg; | ||
158 | ft->tl.expires = jiffies + (millisec * HZ) / 1000; | ||
159 | add_timer(&ft->tl); | ||
160 | return 0; | ||
161 | } | ||
162 | EXPORT_SYMBOL(mISDN_FsmAddTimer); | ||
163 | |||
164 | void | ||
165 | mISDN_FsmRestartTimer(struct FsmTimer *ft, | ||
166 | int millisec, int event, void *arg, int where) | ||
167 | { | ||
168 | |||
169 | #if FSM_TIMER_DEBUG | ||
170 | if (ft->fi->debug) | ||
171 | ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d", | ||
172 | (long) ft, millisec, where); | ||
173 | #endif | ||
174 | |||
175 | if (timer_pending(&ft->tl)) | ||
176 | del_timer(&ft->tl); | ||
177 | init_timer(&ft->tl); | ||
178 | ft->event = event; | ||
179 | ft->arg = arg; | ||
180 | ft->tl.expires = jiffies + (millisec * HZ) / 1000; | ||
181 | add_timer(&ft->tl); | ||
182 | } | ||
183 | EXPORT_SYMBOL(mISDN_FsmRestartTimer); | ||
diff --git a/drivers/isdn/mISDN/fsm.h b/drivers/isdn/mISDN/fsm.h new file mode 100644 index 000000000000..928f5be192c1 --- /dev/null +++ b/drivers/isdn/mISDN/fsm.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Thanks to Jan den Ouden | ||
6 | * Fritz Elfert | ||
7 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #ifndef _MISDN_FSM_H | ||
21 | #define _MISDN_FSM_H | ||
22 | |||
23 | #include <linux/timer.h> | ||
24 | |||
25 | /* Statemachine */ | ||
26 | |||
27 | struct FsmInst; | ||
28 | |||
29 | typedef void (*FSMFNPTR)(struct FsmInst *, int, void *); | ||
30 | |||
31 | struct Fsm { | ||
32 | FSMFNPTR *jumpmatrix; | ||
33 | int state_count, event_count; | ||
34 | char **strEvent, **strState; | ||
35 | }; | ||
36 | |||
37 | struct FsmInst { | ||
38 | struct Fsm *fsm; | ||
39 | int state; | ||
40 | int debug; | ||
41 | void *userdata; | ||
42 | int userint; | ||
43 | void (*printdebug) (struct FsmInst *, char *, ...); | ||
44 | }; | ||
45 | |||
46 | struct FsmNode { | ||
47 | int state, event; | ||
48 | void (*routine) (struct FsmInst *, int, void *); | ||
49 | }; | ||
50 | |||
51 | struct FsmTimer { | ||
52 | struct FsmInst *fi; | ||
53 | struct timer_list tl; | ||
54 | int event; | ||
55 | void *arg; | ||
56 | }; | ||
57 | |||
58 | extern void mISDN_FsmNew(struct Fsm *, struct FsmNode *, int); | ||
59 | extern void mISDN_FsmFree(struct Fsm *); | ||
60 | extern int mISDN_FsmEvent(struct FsmInst *, int , void *); | ||
61 | extern void mISDN_FsmChangeState(struct FsmInst *, int); | ||
62 | extern void mISDN_FsmInitTimer(struct FsmInst *, struct FsmTimer *); | ||
63 | extern int mISDN_FsmAddTimer(struct FsmTimer *, int, int, void *, int); | ||
64 | extern void mISDN_FsmRestartTimer(struct FsmTimer *, int, int, void *, int); | ||
65 | extern void mISDN_FsmDelTimer(struct FsmTimer *, int); | ||
66 | |||
67 | #endif | ||
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c new file mode 100644 index 000000000000..2596fba4e614 --- /dev/null +++ b/drivers/isdn/mISDN/hwchannel.c | |||
@@ -0,0 +1,365 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/mISDNhw.h> | ||
20 | |||
21 | static void | ||
22 | dchannel_bh(struct work_struct *ws) | ||
23 | { | ||
24 | struct dchannel *dch = container_of(ws, struct dchannel, workq); | ||
25 | struct sk_buff *skb; | ||
26 | int err; | ||
27 | |||
28 | if (test_and_clear_bit(FLG_RECVQUEUE, &dch->Flags)) { | ||
29 | while ((skb = skb_dequeue(&dch->rqueue))) { | ||
30 | if (likely(dch->dev.D.peer)) { | ||
31 | err = dch->dev.D.recv(dch->dev.D.peer, skb); | ||
32 | if (err) | ||
33 | dev_kfree_skb(skb); | ||
34 | } else | ||
35 | dev_kfree_skb(skb); | ||
36 | } | ||
37 | } | ||
38 | if (test_and_clear_bit(FLG_PHCHANGE, &dch->Flags)) { | ||
39 | if (dch->phfunc) | ||
40 | dch->phfunc(dch); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | static void | ||
45 | bchannel_bh(struct work_struct *ws) | ||
46 | { | ||
47 | struct bchannel *bch = container_of(ws, struct bchannel, workq); | ||
48 | struct sk_buff *skb; | ||
49 | int err; | ||
50 | |||
51 | if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) { | ||
52 | while ((skb = skb_dequeue(&bch->rqueue))) { | ||
53 | if (bch->rcount >= 64) | ||
54 | printk(KERN_WARNING "B-channel %p receive " | ||
55 | "queue if full, but empties...\n", bch); | ||
56 | bch->rcount--; | ||
57 | if (likely(bch->ch.peer)) { | ||
58 | err = bch->ch.recv(bch->ch.peer, skb); | ||
59 | if (err) | ||
60 | dev_kfree_skb(skb); | ||
61 | } else | ||
62 | dev_kfree_skb(skb); | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | |||
67 | int | ||
68 | mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf) | ||
69 | { | ||
70 | test_and_set_bit(FLG_HDLC, &ch->Flags); | ||
71 | ch->maxlen = maxlen; | ||
72 | ch->hw = NULL; | ||
73 | ch->rx_skb = NULL; | ||
74 | ch->tx_skb = NULL; | ||
75 | ch->tx_idx = 0; | ||
76 | ch->phfunc = phf; | ||
77 | skb_queue_head_init(&ch->squeue); | ||
78 | skb_queue_head_init(&ch->rqueue); | ||
79 | INIT_LIST_HEAD(&ch->dev.bchannels); | ||
80 | INIT_WORK(&ch->workq, dchannel_bh); | ||
81 | return 0; | ||
82 | } | ||
83 | EXPORT_SYMBOL(mISDN_initdchannel); | ||
84 | |||
85 | int | ||
86 | mISDN_initbchannel(struct bchannel *ch, int maxlen) | ||
87 | { | ||
88 | ch->Flags = 0; | ||
89 | ch->maxlen = maxlen; | ||
90 | ch->hw = NULL; | ||
91 | ch->rx_skb = NULL; | ||
92 | ch->tx_skb = NULL; | ||
93 | ch->tx_idx = 0; | ||
94 | skb_queue_head_init(&ch->rqueue); | ||
95 | ch->rcount = 0; | ||
96 | ch->next_skb = NULL; | ||
97 | INIT_WORK(&ch->workq, bchannel_bh); | ||
98 | return 0; | ||
99 | } | ||
100 | EXPORT_SYMBOL(mISDN_initbchannel); | ||
101 | |||
102 | int | ||
103 | mISDN_freedchannel(struct dchannel *ch) | ||
104 | { | ||
105 | if (ch->tx_skb) { | ||
106 | dev_kfree_skb(ch->tx_skb); | ||
107 | ch->tx_skb = NULL; | ||
108 | } | ||
109 | if (ch->rx_skb) { | ||
110 | dev_kfree_skb(ch->rx_skb); | ||
111 | ch->rx_skb = NULL; | ||
112 | } | ||
113 | skb_queue_purge(&ch->squeue); | ||
114 | skb_queue_purge(&ch->rqueue); | ||
115 | flush_scheduled_work(); | ||
116 | return 0; | ||
117 | } | ||
118 | EXPORT_SYMBOL(mISDN_freedchannel); | ||
119 | |||
120 | int | ||
121 | mISDN_freebchannel(struct bchannel *ch) | ||
122 | { | ||
123 | if (ch->tx_skb) { | ||
124 | dev_kfree_skb(ch->tx_skb); | ||
125 | ch->tx_skb = NULL; | ||
126 | } | ||
127 | if (ch->rx_skb) { | ||
128 | dev_kfree_skb(ch->rx_skb); | ||
129 | ch->rx_skb = NULL; | ||
130 | } | ||
131 | if (ch->next_skb) { | ||
132 | dev_kfree_skb(ch->next_skb); | ||
133 | ch->next_skb = NULL; | ||
134 | } | ||
135 | skb_queue_purge(&ch->rqueue); | ||
136 | ch->rcount = 0; | ||
137 | flush_scheduled_work(); | ||
138 | return 0; | ||
139 | } | ||
140 | EXPORT_SYMBOL(mISDN_freebchannel); | ||
141 | |||
142 | static inline u_int | ||
143 | get_sapi_tei(u_char *p) | ||
144 | { | ||
145 | u_int sapi, tei; | ||
146 | |||
147 | sapi = *p >> 2; | ||
148 | tei = p[1] >> 1; | ||
149 | return sapi | (tei << 8); | ||
150 | } | ||
151 | |||
152 | void | ||
153 | recv_Dchannel(struct dchannel *dch) | ||
154 | { | ||
155 | struct mISDNhead *hh; | ||
156 | |||
157 | if (dch->rx_skb->len < 2) { /* at least 2 for sapi / tei */ | ||
158 | dev_kfree_skb(dch->rx_skb); | ||
159 | dch->rx_skb = NULL; | ||
160 | return; | ||
161 | } | ||
162 | hh = mISDN_HEAD_P(dch->rx_skb); | ||
163 | hh->prim = PH_DATA_IND; | ||
164 | hh->id = get_sapi_tei(dch->rx_skb->data); | ||
165 | skb_queue_tail(&dch->rqueue, dch->rx_skb); | ||
166 | dch->rx_skb = NULL; | ||
167 | schedule_event(dch, FLG_RECVQUEUE); | ||
168 | } | ||
169 | EXPORT_SYMBOL(recv_Dchannel); | ||
170 | |||
171 | void | ||
172 | recv_Bchannel(struct bchannel *bch) | ||
173 | { | ||
174 | struct mISDNhead *hh; | ||
175 | |||
176 | hh = mISDN_HEAD_P(bch->rx_skb); | ||
177 | hh->prim = PH_DATA_IND; | ||
178 | hh->id = MISDN_ID_ANY; | ||
179 | if (bch->rcount >= 64) { | ||
180 | dev_kfree_skb(bch->rx_skb); | ||
181 | bch->rx_skb = NULL; | ||
182 | return; | ||
183 | } | ||
184 | bch->rcount++; | ||
185 | skb_queue_tail(&bch->rqueue, bch->rx_skb); | ||
186 | bch->rx_skb = NULL; | ||
187 | schedule_event(bch, FLG_RECVQUEUE); | ||
188 | } | ||
189 | EXPORT_SYMBOL(recv_Bchannel); | ||
190 | |||
191 | void | ||
192 | recv_Dchannel_skb(struct dchannel *dch, struct sk_buff *skb) | ||
193 | { | ||
194 | skb_queue_tail(&dch->rqueue, skb); | ||
195 | schedule_event(dch, FLG_RECVQUEUE); | ||
196 | } | ||
197 | EXPORT_SYMBOL(recv_Dchannel_skb); | ||
198 | |||
199 | void | ||
200 | recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb) | ||
201 | { | ||
202 | if (bch->rcount >= 64) { | ||
203 | dev_kfree_skb(skb); | ||
204 | return; | ||
205 | } | ||
206 | bch->rcount++; | ||
207 | skb_queue_tail(&bch->rqueue, skb); | ||
208 | schedule_event(bch, FLG_RECVQUEUE); | ||
209 | } | ||
210 | EXPORT_SYMBOL(recv_Bchannel_skb); | ||
211 | |||
212 | static void | ||
213 | confirm_Dsend(struct dchannel *dch) | ||
214 | { | ||
215 | struct sk_buff *skb; | ||
216 | |||
217 | skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(dch->tx_skb), | ||
218 | 0, NULL, GFP_ATOMIC); | ||
219 | if (!skb) { | ||
220 | printk(KERN_ERR "%s: no skb id %x\n", __func__, | ||
221 | mISDN_HEAD_ID(dch->tx_skb)); | ||
222 | return; | ||
223 | } | ||
224 | skb_queue_tail(&dch->rqueue, skb); | ||
225 | schedule_event(dch, FLG_RECVQUEUE); | ||
226 | } | ||
227 | |||
228 | int | ||
229 | get_next_dframe(struct dchannel *dch) | ||
230 | { | ||
231 | dch->tx_idx = 0; | ||
232 | dch->tx_skb = skb_dequeue(&dch->squeue); | ||
233 | if (dch->tx_skb) { | ||
234 | confirm_Dsend(dch); | ||
235 | return 1; | ||
236 | } | ||
237 | dch->tx_skb = NULL; | ||
238 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
239 | return 0; | ||
240 | } | ||
241 | EXPORT_SYMBOL(get_next_dframe); | ||
242 | |||
243 | void | ||
244 | confirm_Bsend(struct bchannel *bch) | ||
245 | { | ||
246 | struct sk_buff *skb; | ||
247 | |||
248 | if (bch->rcount >= 64) | ||
249 | return; | ||
250 | skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb), | ||
251 | 0, NULL, GFP_ATOMIC); | ||
252 | if (!skb) { | ||
253 | printk(KERN_ERR "%s: no skb id %x\n", __func__, | ||
254 | mISDN_HEAD_ID(bch->tx_skb)); | ||
255 | return; | ||
256 | } | ||
257 | bch->rcount++; | ||
258 | skb_queue_tail(&bch->rqueue, skb); | ||
259 | schedule_event(bch, FLG_RECVQUEUE); | ||
260 | } | ||
261 | EXPORT_SYMBOL(confirm_Bsend); | ||
262 | |||
263 | int | ||
264 | get_next_bframe(struct bchannel *bch) | ||
265 | { | ||
266 | bch->tx_idx = 0; | ||
267 | if (test_bit(FLG_TX_NEXT, &bch->Flags)) { | ||
268 | bch->tx_skb = bch->next_skb; | ||
269 | if (bch->tx_skb) { | ||
270 | bch->next_skb = NULL; | ||
271 | test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); | ||
272 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
273 | confirm_Bsend(bch); /* not for transparent */ | ||
274 | return 1; | ||
275 | } else { | ||
276 | test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); | ||
277 | printk(KERN_WARNING "B TX_NEXT without skb\n"); | ||
278 | } | ||
279 | } | ||
280 | bch->tx_skb = NULL; | ||
281 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
282 | return 0; | ||
283 | } | ||
284 | EXPORT_SYMBOL(get_next_bframe); | ||
285 | |||
286 | void | ||
287 | queue_ch_frame(struct mISDNchannel *ch, u_int pr, int id, struct sk_buff *skb) | ||
288 | { | ||
289 | struct mISDNhead *hh; | ||
290 | |||
291 | if (!skb) { | ||
292 | _queue_data(ch, pr, id, 0, NULL, GFP_ATOMIC); | ||
293 | } else { | ||
294 | if (ch->peer) { | ||
295 | hh = mISDN_HEAD_P(skb); | ||
296 | hh->prim = pr; | ||
297 | hh->id = id; | ||
298 | if (!ch->recv(ch->peer, skb)) | ||
299 | return; | ||
300 | } | ||
301 | dev_kfree_skb(skb); | ||
302 | } | ||
303 | } | ||
304 | EXPORT_SYMBOL(queue_ch_frame); | ||
305 | |||
306 | int | ||
307 | dchannel_senddata(struct dchannel *ch, struct sk_buff *skb) | ||
308 | { | ||
309 | /* check oversize */ | ||
310 | if (skb->len <= 0) { | ||
311 | printk(KERN_WARNING "%s: skb too small\n", __func__); | ||
312 | return -EINVAL; | ||
313 | } | ||
314 | if (skb->len > ch->maxlen) { | ||
315 | printk(KERN_WARNING "%s: skb too large(%d/%d)\n", | ||
316 | __func__, skb->len, ch->maxlen); | ||
317 | return -EINVAL; | ||
318 | } | ||
319 | /* HW lock must be obtained */ | ||
320 | if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { | ||
321 | skb_queue_tail(&ch->squeue, skb); | ||
322 | return 0; | ||
323 | } else { | ||
324 | /* write to fifo */ | ||
325 | ch->tx_skb = skb; | ||
326 | ch->tx_idx = 0; | ||
327 | return 1; | ||
328 | } | ||
329 | } | ||
330 | EXPORT_SYMBOL(dchannel_senddata); | ||
331 | |||
332 | int | ||
333 | bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) | ||
334 | { | ||
335 | |||
336 | /* check oversize */ | ||
337 | if (skb->len <= 0) { | ||
338 | printk(KERN_WARNING "%s: skb too small\n", __func__); | ||
339 | return -EINVAL; | ||
340 | } | ||
341 | if (skb->len > ch->maxlen) { | ||
342 | printk(KERN_WARNING "%s: skb too large(%d/%d)\n", | ||
343 | __func__, skb->len, ch->maxlen); | ||
344 | return -EINVAL; | ||
345 | } | ||
346 | /* HW lock must be obtained */ | ||
347 | /* check for pending next_skb */ | ||
348 | if (ch->next_skb) { | ||
349 | printk(KERN_WARNING | ||
350 | "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", | ||
351 | __func__, skb->len, ch->next_skb->len); | ||
352 | return -EBUSY; | ||
353 | } | ||
354 | if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { | ||
355 | test_and_set_bit(FLG_TX_NEXT, &ch->Flags); | ||
356 | ch->next_skb = skb; | ||
357 | return 0; | ||
358 | } else { | ||
359 | /* write to fifo */ | ||
360 | ch->tx_skb = skb; | ||
361 | ch->tx_idx = 0; | ||
362 | return 1; | ||
363 | } | ||
364 | } | ||
365 | EXPORT_SYMBOL(bchannel_senddata); | ||
diff --git a/drivers/isdn/mISDN/l1oip.h b/drivers/isdn/mISDN/l1oip.h new file mode 100644 index 000000000000..a23d575449f6 --- /dev/null +++ b/drivers/isdn/mISDN/l1oip.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * see notice in l1oip.c | ||
3 | */ | ||
4 | |||
5 | /* debugging */ | ||
6 | #define DEBUG_L1OIP_INIT 0x00010000 | ||
7 | #define DEBUG_L1OIP_SOCKET 0x00020000 | ||
8 | #define DEBUG_L1OIP_MGR 0x00040000 | ||
9 | #define DEBUG_L1OIP_MSG 0x00080000 | ||
10 | |||
11 | /* enable to disorder received bchannels by sequence 2143658798... */ | ||
12 | /* | ||
13 | #define REORDER_DEBUG | ||
14 | */ | ||
15 | |||
16 | /* frames */ | ||
17 | #define L1OIP_MAX_LEN 2048 /* max packet size form l2 */ | ||
18 | #define L1OIP_MAX_PERFRAME 1400 /* max data size in one frame */ | ||
19 | |||
20 | |||
21 | /* timers */ | ||
22 | #define L1OIP_KEEPALIVE 15 | ||
23 | #define L1OIP_TIMEOUT 65 | ||
24 | |||
25 | |||
26 | /* socket */ | ||
27 | #define L1OIP_DEFAULTPORT 931 | ||
28 | |||
29 | |||
30 | /* channel structure */ | ||
31 | struct l1oip_chan { | ||
32 | struct dchannel *dch; | ||
33 | struct bchannel *bch; | ||
34 | u32 tx_counter; /* counts xmit bytes/packets */ | ||
35 | u32 rx_counter; /* counts recv bytes/packets */ | ||
36 | u32 codecstate; /* used by codec to save data */ | ||
37 | #ifdef REORDER_DEBUG | ||
38 | int disorder_flag; | ||
39 | struct sk_buff *disorder_skb; | ||
40 | u32 disorder_cnt; | ||
41 | #endif | ||
42 | }; | ||
43 | |||
44 | |||
45 | /* card structure */ | ||
46 | struct l1oip { | ||
47 | struct list_head list; | ||
48 | |||
49 | /* card */ | ||
50 | int registered; /* if registered with mISDN */ | ||
51 | char name[MISDN_MAX_IDLEN]; | ||
52 | int idx; /* card index */ | ||
53 | int pri; /* 1=pri, 0=bri */ | ||
54 | int d_idx; /* current dchannel number */ | ||
55 | int b_num; /* number of bchannels */ | ||
56 | u32 id; /* id of connection */ | ||
57 | int ondemand; /* if transmis. is on demand */ | ||
58 | int bundle; /* bundle channels in one frm */ | ||
59 | int codec; /* codec to use for transmis. */ | ||
60 | int limit; /* limit number of bchannels */ | ||
61 | |||
62 | /* timer */ | ||
63 | struct timer_list keep_tl; | ||
64 | struct timer_list timeout_tl; | ||
65 | int timeout_on; | ||
66 | struct work_struct workq; | ||
67 | |||
68 | /* socket */ | ||
69 | struct socket *socket; /* if set, socket is created */ | ||
70 | struct completion socket_complete;/* completion of sock thread */ | ||
71 | struct task_struct *socket_thread; | ||
72 | spinlock_t socket_lock; /* access sock outside thread */ | ||
73 | u32 remoteip; /* if all set, ip is assigned */ | ||
74 | u16 localport; /* must always be set */ | ||
75 | u16 remoteport; /* must always be set */ | ||
76 | struct sockaddr_in sin_local; /* local socket name */ | ||
77 | struct sockaddr_in sin_remote; /* remote socket name */ | ||
78 | struct msghdr sendmsg; /* ip message to send */ | ||
79 | struct iovec sendiov; /* iov for message */ | ||
80 | |||
81 | /* frame */ | ||
82 | struct l1oip_chan chan[128]; /* channel instances */ | ||
83 | }; | ||
84 | |||
85 | extern int l1oip_law_to_4bit(u8 *data, int len, u8 *result, u32 *state); | ||
86 | extern int l1oip_4bit_to_law(u8 *data, int len, u8 *result); | ||
87 | extern int l1oip_alaw_to_ulaw(u8 *data, int len, u8 *result); | ||
88 | extern int l1oip_ulaw_to_alaw(u8 *data, int len, u8 *result); | ||
89 | extern void l1oip_4bit_free(void); | ||
90 | extern int l1oip_4bit_alloc(int ulaw); | ||
91 | |||
diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c new file mode 100644 index 000000000000..a2dc4570ef43 --- /dev/null +++ b/drivers/isdn/mISDN/l1oip_codec.c | |||
@@ -0,0 +1,374 @@ | |||
1 | /* | ||
2 | |||
3 | * l1oip_codec.c generic codec using lookup table | ||
4 | * -> conversion from a-Law to u-Law | ||
5 | * -> conversion from u-Law to a-Law | ||
6 | * -> compression by reducing the number of sample resolution to 4 | ||
7 | * | ||
8 | * NOTE: It is not compatible with any standard codec like ADPCM. | ||
9 | * | ||
10 | * Author Andreas Eversberg (jolly@eversberg.eu) | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2, or (at your option) | ||
15 | * any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | |||
26 | */ | ||
27 | |||
28 | /* | ||
29 | |||
30 | How the codec works: | ||
31 | -------------------- | ||
32 | |||
33 | The volume is increased to increase the dynamic range of the audio signal. | ||
34 | Each sample is converted to a-LAW with only 16 steps of level resolution. | ||
35 | A pair of two samples are stored in one byte. | ||
36 | |||
37 | The first byte is stored in the upper bits, the second byte is stored in the | ||
38 | lower bits. | ||
39 | |||
40 | To speed up compression and decompression, two lookup tables are formed: | ||
41 | |||
42 | - 16 bits index for two samples (law encoded) with 8 bit compressed result. | ||
43 | - 8 bits index for one compressed data with 16 bits decompressed result. | ||
44 | |||
45 | NOTE: The bytes are handled as they are law-encoded. | ||
46 | |||
47 | */ | ||
48 | |||
49 | #include <linux/vmalloc.h> | ||
50 | #include <linux/mISDNif.h> | ||
51 | #include "core.h" | ||
52 | |||
53 | /* definitions of codec. don't use calculations, code may run slower. */ | ||
54 | |||
55 | static u8 *table_com; | ||
56 | static u16 *table_dec; | ||
57 | |||
58 | |||
59 | /* alaw -> ulaw */ | ||
60 | static u8 alaw_to_ulaw[256] = | ||
61 | { | ||
62 | 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49, | ||
63 | 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57, | ||
64 | 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41, | ||
65 | 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f, | ||
66 | 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d, | ||
67 | 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b, | ||
68 | 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45, | ||
69 | 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53, | ||
70 | 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47, | ||
71 | 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55, | ||
72 | 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f, | ||
73 | 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e, | ||
74 | 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b, | ||
75 | 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59, | ||
76 | 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43, | ||
77 | 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51, | ||
78 | 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a, | ||
79 | 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58, | ||
80 | 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42, | ||
81 | 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50, | ||
82 | 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e, | ||
83 | 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c, | ||
84 | 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46, | ||
85 | 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54, | ||
86 | 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48, | ||
87 | 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56, | ||
88 | 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40, | ||
89 | 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f, | ||
90 | 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c, | ||
91 | 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a, | ||
92 | 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44, | ||
93 | 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52 | ||
94 | }; | ||
95 | |||
96 | /* ulaw -> alaw */ | ||
97 | static u8 ulaw_to_alaw[256] = | ||
98 | { | ||
99 | 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35, | ||
100 | 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25, | ||
101 | 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d, | ||
102 | 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d, | ||
103 | 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31, | ||
104 | 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21, | ||
105 | 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9, | ||
106 | 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9, | ||
107 | 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47, | ||
108 | 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf, | ||
109 | 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f, | ||
110 | 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33, | ||
111 | 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23, | ||
112 | 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b, | ||
113 | 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b, | ||
114 | 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b, | ||
115 | 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34, | ||
116 | 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24, | ||
117 | 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c, | ||
118 | 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c, | ||
119 | 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30, | ||
120 | 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20, | ||
121 | 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8, | ||
122 | 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8, | ||
123 | 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46, | ||
124 | 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde, | ||
125 | 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e, | ||
126 | 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32, | ||
127 | 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22, | ||
128 | 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a, | ||
129 | 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a, | ||
130 | 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a | ||
131 | }; | ||
132 | |||
133 | /* alaw -> 4bit compression */ | ||
134 | static u8 alaw_to_4bit[256] = { | ||
135 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
136 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
137 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
138 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
139 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
140 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
141 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
142 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
143 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
144 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
145 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0d, 0x02, | ||
146 | 0x0e, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
147 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
148 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
149 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
150 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
151 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
152 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
153 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
154 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
155 | 0x0e, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
156 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x01, 0x0a, 0x05, | ||
157 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
158 | 0x0d, 0x02, 0x09, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
159 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
160 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
161 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
162 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
163 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
164 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
165 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
166 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
167 | }; | ||
168 | |||
169 | /* 4bit -> alaw decompression */ | ||
170 | static u8 _4bit_to_alaw[16] = { | ||
171 | 0x5d, 0x51, 0xd9, 0xd7, 0x5f, 0x53, 0xa3, 0x4b, | ||
172 | 0x2a, 0x3a, 0x22, 0x2e, 0x26, 0x56, 0x20, 0x2c, | ||
173 | }; | ||
174 | |||
175 | /* ulaw -> 4bit compression */ | ||
176 | static u8 ulaw_to_4bit[256] = { | ||
177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
181 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
182 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
183 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, | ||
184 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, | ||
185 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, | ||
186 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, | ||
187 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, | ||
188 | 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, | ||
189 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, | ||
190 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, | ||
191 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, | ||
192 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, | ||
193 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
194 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
195 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
196 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
197 | 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, | ||
198 | 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, | ||
199 | 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
200 | 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
201 | 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, | ||
202 | 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, | ||
203 | 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, | ||
204 | 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, | ||
205 | 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, | ||
206 | 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, | ||
207 | 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, | ||
208 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, | ||
209 | }; | ||
210 | |||
211 | /* 4bit -> ulaw decompression */ | ||
212 | static u8 _4bit_to_ulaw[16] = { | ||
213 | 0x11, 0x21, 0x31, 0x40, 0x4e, 0x5c, 0x68, 0x71, | ||
214 | 0xfe, 0xef, 0xe7, 0xdb, 0xcd, 0xbf, 0xaf, 0x9f, | ||
215 | }; | ||
216 | |||
217 | |||
218 | /* | ||
219 | * Compresses data to the result buffer | ||
220 | * The result size must be at least half of the input buffer. | ||
221 | * The number of samples also must be even! | ||
222 | */ | ||
223 | int | ||
224 | l1oip_law_to_4bit(u8 *data, int len, u8 *result, u32 *state) | ||
225 | { | ||
226 | int ii, i = 0, o = 0; | ||
227 | |||
228 | if (!len) | ||
229 | return 0; | ||
230 | |||
231 | /* send saved byte and first input byte */ | ||
232 | if (*state) { | ||
233 | *result++ = table_com[(((*state)<<8)&0xff00) | (*data++)]; | ||
234 | len--; | ||
235 | o++; | ||
236 | } | ||
237 | |||
238 | ii = len >> 1; | ||
239 | |||
240 | while (i < ii) { | ||
241 | *result++ = table_com[(data[0]<<8) | (data[1])]; | ||
242 | data += 2; | ||
243 | i++; | ||
244 | o++; | ||
245 | } | ||
246 | |||
247 | /* if len has an odd number, we save byte for next call */ | ||
248 | if (len & 1) | ||
249 | *state = 0x100 + *data; | ||
250 | else | ||
251 | *state = 0; | ||
252 | |||
253 | return o; | ||
254 | } | ||
255 | |||
256 | /* Decompress data to the result buffer | ||
257 | * The result size must be the number of sample in packet. (2 * input data) | ||
258 | * The number of samples in the result are even! | ||
259 | */ | ||
260 | int | ||
261 | l1oip_4bit_to_law(u8 *data, int len, u8 *result) | ||
262 | { | ||
263 | int i = 0; | ||
264 | u16 r; | ||
265 | |||
266 | while (i < len) { | ||
267 | r = table_dec[*data++]; | ||
268 | *result++ = r>>8; | ||
269 | *result++ = r; | ||
270 | i++; | ||
271 | } | ||
272 | |||
273 | return len << 1; | ||
274 | } | ||
275 | |||
276 | |||
277 | /* | ||
278 | * law conversion | ||
279 | */ | ||
280 | int | ||
281 | l1oip_alaw_to_ulaw(u8 *data, int len, u8 *result) | ||
282 | { | ||
283 | int i = 0; | ||
284 | |||
285 | while (i < len) { | ||
286 | *result++ = alaw_to_ulaw[*data++]; | ||
287 | i++; | ||
288 | } | ||
289 | |||
290 | return len; | ||
291 | } | ||
292 | |||
293 | int | ||
294 | l1oip_ulaw_to_alaw(u8 *data, int len, u8 *result) | ||
295 | { | ||
296 | int i = 0; | ||
297 | |||
298 | while (i < len) { | ||
299 | *result++ = ulaw_to_alaw[*data++]; | ||
300 | i++; | ||
301 | } | ||
302 | |||
303 | return len; | ||
304 | } | ||
305 | |||
306 | |||
307 | /* | ||
308 | * generate/free compression and decompression table | ||
309 | */ | ||
310 | void | ||
311 | l1oip_4bit_free(void) | ||
312 | { | ||
313 | if (table_dec) | ||
314 | vfree(table_dec); | ||
315 | if (table_com) | ||
316 | vfree(table_com); | ||
317 | table_com = NULL; | ||
318 | table_dec = NULL; | ||
319 | } | ||
320 | |||
321 | int | ||
322 | l1oip_4bit_alloc(int ulaw) | ||
323 | { | ||
324 | int i1, i2, c, sample; | ||
325 | |||
326 | /* in case, it is called again */ | ||
327 | if (table_dec) | ||
328 | return 0; | ||
329 | |||
330 | /* alloc conversion tables */ | ||
331 | table_com = vmalloc(65536); | ||
332 | table_dec = vmalloc(512); | ||
333 | if (!table_com | !table_dec) { | ||
334 | l1oip_4bit_free(); | ||
335 | return -ENOMEM; | ||
336 | } | ||
337 | memset(table_com, 0, 65536); | ||
338 | memset(table_dec, 0, 512); | ||
339 | /* generate compression table */ | ||
340 | i1 = 0; | ||
341 | while (i1 < 256) { | ||
342 | if (ulaw) | ||
343 | c = ulaw_to_4bit[i1]; | ||
344 | else | ||
345 | c = alaw_to_4bit[i1]; | ||
346 | i2 = 0; | ||
347 | while (i2 < 256) { | ||
348 | table_com[(i1<<8) | i2] |= (c<<4); | ||
349 | table_com[(i2<<8) | i1] |= c; | ||
350 | i2++; | ||
351 | } | ||
352 | i1++; | ||
353 | } | ||
354 | |||
355 | /* generate decompression table */ | ||
356 | i1 = 0; | ||
357 | while (i1 < 16) { | ||
358 | if (ulaw) | ||
359 | sample = _4bit_to_ulaw[i1]; | ||
360 | else | ||
361 | sample = _4bit_to_alaw[i1]; | ||
362 | i2 = 0; | ||
363 | while (i2 < 16) { | ||
364 | table_dec[(i1<<4) | i2] |= (sample<<8); | ||
365 | table_dec[(i2<<4) | i1] |= sample; | ||
366 | i2++; | ||
367 | } | ||
368 | i1++; | ||
369 | } | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | |||
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c new file mode 100644 index 000000000000..155b99780c4f --- /dev/null +++ b/drivers/isdn/mISDN/l1oip_core.c | |||
@@ -0,0 +1,1518 @@ | |||
1 | /* | ||
2 | |||
3 | * l1oip.c low level driver for tunneling layer 1 over IP | ||
4 | * | ||
5 | * NOTE: It is not compatible with TDMoIP nor "ISDN over IP". | ||
6 | * | ||
7 | * Author Andreas Eversberg (jolly@eversberg.eu) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2, or (at your option) | ||
12 | * any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | /* module parameters: | ||
26 | * type: | ||
27 | Value 1 = BRI | ||
28 | Value 2 = PRI | ||
29 | Value 3 = BRI (multi channel frame, not supported yet) | ||
30 | Value 4 = PRI (multi channel frame, not supported yet) | ||
31 | A multi channel frame reduces overhead to a single frame for all | ||
32 | b-channels, but increases delay. | ||
33 | (NOTE: Multi channel frames are not implemented yet.) | ||
34 | |||
35 | * codec: | ||
36 | Value 0 = transparent (default) | ||
37 | Value 1 = transfer ALAW | ||
38 | Value 2 = transfer ULAW | ||
39 | Value 3 = transfer generic 4 bit compression. | ||
40 | |||
41 | * ulaw: | ||
42 | 0 = we use a-Law (default) | ||
43 | 1 = we use u-Law | ||
44 | |||
45 | * limit: | ||
46 | limitation of B-channels to control bandwidth (1...126) | ||
47 | BRI: 1 or 2 | ||
48 | PRI: 1-30, 31-126 (126, because dchannel ist not counted here) | ||
49 | Also limited ressources are used for stack, resulting in less channels. | ||
50 | It is possible to have more channels than 30 in PRI mode, this must | ||
51 | be supported by the application. | ||
52 | |||
53 | * ip: | ||
54 | byte representation of remote ip address (127.0.0.1 -> 127,0,0,1) | ||
55 | If not given or four 0, no remote address is set. | ||
56 | For multiple interfaces, concat ip addresses. (127,0,0,1,127,0,0,1) | ||
57 | |||
58 | * port: | ||
59 | port number (local interface) | ||
60 | If not given or 0, port 931 is used for fist instance, 932 for next... | ||
61 | For multiple interfaces, different ports must be given. | ||
62 | |||
63 | * remoteport: | ||
64 | port number (remote interface) | ||
65 | If not given or 0, remote port equals local port | ||
66 | For multiple interfaces on equal sites, different ports must be given. | ||
67 | |||
68 | * ondemand: | ||
69 | 0 = fixed (always transmit packets, even when remote side timed out) | ||
70 | 1 = on demand (only transmit packets, when remote side is detected) | ||
71 | the default is 0 | ||
72 | NOTE: ID must also be set for on demand. | ||
73 | |||
74 | * id: | ||
75 | optional value to identify frames. This value must be equal on both | ||
76 | peers and should be random. If omitted or 0, no ID is transmitted. | ||
77 | |||
78 | * debug: | ||
79 | NOTE: only one debug value must be given for all cards | ||
80 | enable debugging (see l1oip.h for debug options) | ||
81 | |||
82 | |||
83 | Special mISDN controls: | ||
84 | |||
85 | op = MISDN_CTRL_SETPEER* | ||
86 | p1 = bytes 0-3 : remote IP address in network order (left element first) | ||
87 | p2 = bytes 1-2 : remote port in network order (high byte first) | ||
88 | optional: | ||
89 | p2 = bytes 3-4 : local port in network order (high byte first) | ||
90 | |||
91 | op = MISDN_CTRL_UNSETPEER* | ||
92 | |||
93 | * Use l1oipctrl for comfortable setting or removing ip address. | ||
94 | (Layer 1 Over IP CTRL) | ||
95 | |||
96 | |||
97 | L1oIP-Protocol | ||
98 | -------------- | ||
99 | |||
100 | Frame Header: | ||
101 | |||
102 | 7 6 5 4 3 2 1 0 | ||
103 | +---------------+ | ||
104 | |Ver|T|I|Coding | | ||
105 | +---------------+ | ||
106 | | ID byte 3 * | | ||
107 | +---------------+ | ||
108 | | ID byte 2 * | | ||
109 | +---------------+ | ||
110 | | ID byte 1 * | | ||
111 | +---------------+ | ||
112 | | ID byte 0 * | | ||
113 | +---------------+ | ||
114 | |M| Channel | | ||
115 | +---------------+ | ||
116 | | Length * | | ||
117 | +---------------+ | ||
118 | | Time Base MSB | | ||
119 | +---------------+ | ||
120 | | Time Base LSB | | ||
121 | +---------------+ | ||
122 | | Data.... | | ||
123 | |||
124 | ... | ||
125 | |||
126 | | | | ||
127 | +---------------+ | ||
128 | |M| Channel | | ||
129 | +---------------+ | ||
130 | | Length * | | ||
131 | +---------------+ | ||
132 | | Time Base MSB | | ||
133 | +---------------+ | ||
134 | | Time Base LSB | | ||
135 | +---------------+ | ||
136 | | Data.... | | ||
137 | |||
138 | ... | ||
139 | |||
140 | |||
141 | * Only included in some cases. | ||
142 | |||
143 | - Ver = Version | ||
144 | If version is missmatch, the frame must be ignored. | ||
145 | |||
146 | - T = Type of interface | ||
147 | Must be 0 for S0 or 1 for E1. | ||
148 | |||
149 | - I = Id present | ||
150 | If bit is set, four ID bytes are included in frame. | ||
151 | |||
152 | - ID = Connection ID | ||
153 | Additional ID to prevent Denial of Service attacs. Also it prevents hijacking | ||
154 | connections with dynamic IP. The ID should be random and must not be 0. | ||
155 | |||
156 | - Coding = Type of codec | ||
157 | Must be 0 for no transcoding. Also for D-channel and other HDLC frames. | ||
158 | 1 and 2 are reserved for explicitly use of a-LAW or u-LAW codec. | ||
159 | 3 is used for generic table compressor. | ||
160 | |||
161 | - M = More channels to come. If this flag is 1, the following byte contains | ||
162 | the length of the channel data. After the data block, the next channel will | ||
163 | be defined. The flag for the last channel block (or if only one channel is | ||
164 | transmitted), must be 0 and no length is given. | ||
165 | |||
166 | - Channel = Channel number | ||
167 | 0 reserved | ||
168 | 1-3 channel data for S0 (3 is D-channel) | ||
169 | 1-31 channel data for E1 (16 is D-channel) | ||
170 | 32-127 channel data for extended E1 (16 is D-channel) | ||
171 | |||
172 | - The length is used if the M-flag is 1. It is used to find the next channel | ||
173 | inside frame. | ||
174 | NOTE: A value of 0 equals 256 bytes of data. | ||
175 | -> For larger data blocks, a single frame must be used. | ||
176 | -> For larger streams, a single frame or multiple blocks with same channel ID | ||
177 | must be used. | ||
178 | |||
179 | - Time Base = Timestamp of first sample in frame | ||
180 | The "Time Base" is used to rearange packets and to detect packet loss. | ||
181 | The 16 bits are sent in network order (MSB first) and count 1/8000 th of a | ||
182 | second. This causes a wrap arround each 8,192 seconds. There is no requirement | ||
183 | for the initial "Time Base", but 0 should be used for the first packet. | ||
184 | In case of HDLC data, this timestamp counts the packet or byte number. | ||
185 | |||
186 | |||
187 | Two Timers: | ||
188 | |||
189 | After initialisation, a timer of 15 seconds is started. Whenever a packet is | ||
190 | transmitted, the timer is reset to 15 seconds again. If the timer expires, an | ||
191 | empty packet is transmitted. This keep the connection alive. | ||
192 | |||
193 | When a valid packet is received, a timer 65 seconds is started. The interface | ||
194 | become ACTIVE. If the timer expires, the interface becomes INACTIVE. | ||
195 | |||
196 | |||
197 | Dynamic IP handling: | ||
198 | |||
199 | To allow dynamic IP, the ID must be non 0. In this case, any packet with the | ||
200 | correct port number and ID will be accepted. If the remote side changes its IP | ||
201 | the new IP is used for all transmitted packets until it changes again. | ||
202 | |||
203 | |||
204 | On Demand: | ||
205 | |||
206 | If the ondemand parameter is given, the remote IP is set to 0 on timeout. | ||
207 | This will stop keepalive traffic to remote. If the remote is online again, | ||
208 | traffic will continue to the remote address. This is usefull for road warriors. | ||
209 | This feature only works with ID set, otherwhise it is highly unsecure. | ||
210 | |||
211 | |||
212 | Socket and Thread | ||
213 | ----------------- | ||
214 | |||
215 | The complete socket opening and closing is done by a thread. | ||
216 | When the thread opened a socket, the hc->socket descriptor is set. Whenever a | ||
217 | packet shall be sent to the socket, the hc->socket must be checked wheter not | ||
218 | NULL. To prevent change in socket descriptor, the hc->socket_lock must be used. | ||
219 | To change the socket, a recall of l1oip_socket_open() will safely kill the | ||
220 | socket process and create a new one. | ||
221 | |||
222 | */ | ||
223 | |||
224 | #define L1OIP_VERSION 0 /* 0...3 */ | ||
225 | |||
226 | #include <linux/module.h> | ||
227 | #include <linux/delay.h> | ||
228 | #include <linux/mISDNif.h> | ||
229 | #include <linux/mISDNhw.h> | ||
230 | #include <linux/mISDNdsp.h> | ||
231 | #include <linux/init.h> | ||
232 | #include <linux/in.h> | ||
233 | #include <linux/inet.h> | ||
234 | #include <linux/workqueue.h> | ||
235 | #include <linux/kthread.h> | ||
236 | #include <net/sock.h> | ||
237 | #include "core.h" | ||
238 | #include "l1oip.h" | ||
239 | |||
240 | static const char *l1oip_revision = "2.00"; | ||
241 | |||
242 | static int l1oip_cnt; | ||
243 | static spinlock_t l1oip_lock; | ||
244 | static struct list_head l1oip_ilist; | ||
245 | |||
246 | #define MAX_CARDS 16 | ||
247 | static u_int type[MAX_CARDS]; | ||
248 | static u_int codec[MAX_CARDS]; | ||
249 | static u_int ip[MAX_CARDS*4]; | ||
250 | static u_int port[MAX_CARDS]; | ||
251 | static u_int remoteport[MAX_CARDS]; | ||
252 | static u_int ondemand[MAX_CARDS]; | ||
253 | static u_int limit[MAX_CARDS]; | ||
254 | static u_int id[MAX_CARDS]; | ||
255 | static int debug; | ||
256 | static int ulaw; | ||
257 | |||
258 | MODULE_AUTHOR("Andreas Eversberg"); | ||
259 | MODULE_LICENSE("GPL"); | ||
260 | module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); | ||
261 | module_param_array(codec, uint, NULL, S_IRUGO | S_IWUSR); | ||
262 | module_param_array(ip, uint, NULL, S_IRUGO | S_IWUSR); | ||
263 | module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); | ||
264 | module_param_array(remoteport, uint, NULL, S_IRUGO | S_IWUSR); | ||
265 | module_param_array(ondemand, uint, NULL, S_IRUGO | S_IWUSR); | ||
266 | module_param_array(limit, uint, NULL, S_IRUGO | S_IWUSR); | ||
267 | module_param_array(id, uint, NULL, S_IRUGO | S_IWUSR); | ||
268 | module_param(ulaw, uint, S_IRUGO | S_IWUSR); | ||
269 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
270 | |||
271 | /* | ||
272 | * send a frame via socket, if open and restart timer | ||
273 | */ | ||
274 | static int | ||
275 | l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, | ||
276 | u16 timebase, u8 *buf, int len) | ||
277 | { | ||
278 | u8 *p; | ||
279 | int multi = 0; | ||
280 | u8 frame[len+32]; | ||
281 | struct socket *socket = NULL; | ||
282 | mm_segment_t oldfs; | ||
283 | |||
284 | if (debug & DEBUG_L1OIP_MSG) | ||
285 | printk(KERN_DEBUG "%s: sending data to socket (len = %d)\n", | ||
286 | __func__, len); | ||
287 | |||
288 | p = frame; | ||
289 | |||
290 | /* restart timer */ | ||
291 | if ((int)(hc->keep_tl.expires-jiffies) < 5*HZ) { | ||
292 | del_timer(&hc->keep_tl); | ||
293 | hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE*HZ; | ||
294 | add_timer(&hc->keep_tl); | ||
295 | } else | ||
296 | hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE*HZ; | ||
297 | |||
298 | if (debug & DEBUG_L1OIP_MSG) | ||
299 | printk(KERN_DEBUG "%s: resetting timer\n", __func__); | ||
300 | |||
301 | /* drop if we have no remote ip or port */ | ||
302 | if (!hc->sin_remote.sin_addr.s_addr || !hc->sin_remote.sin_port) { | ||
303 | if (debug & DEBUG_L1OIP_MSG) | ||
304 | printk(KERN_DEBUG "%s: dropping frame, because remote " | ||
305 | "IP is not set.\n", __func__); | ||
306 | return len; | ||
307 | } | ||
308 | |||
309 | /* assemble frame */ | ||
310 | *p++ = (L1OIP_VERSION<<6) /* version and coding */ | ||
311 | | (hc->pri?0x20:0x00) /* type */ | ||
312 | | (hc->id?0x10:0x00) /* id */ | ||
313 | | localcodec; | ||
314 | if (hc->id) { | ||
315 | *p++ = hc->id>>24; /* id */ | ||
316 | *p++ = hc->id>>16; | ||
317 | *p++ = hc->id>>8; | ||
318 | *p++ = hc->id; | ||
319 | } | ||
320 | *p++ = (multi == 1)?0x80:0x00 + channel; /* m-flag, channel */ | ||
321 | if (multi == 1) | ||
322 | *p++ = len; /* length */ | ||
323 | *p++ = timebase>>8; /* time base */ | ||
324 | *p++ = timebase; | ||
325 | |||
326 | if (buf && len) { /* add data to frame */ | ||
327 | if (localcodec == 1 && ulaw) | ||
328 | l1oip_ulaw_to_alaw(buf, len, p); | ||
329 | else if (localcodec == 2 && !ulaw) | ||
330 | l1oip_alaw_to_ulaw(buf, len, p); | ||
331 | else if (localcodec == 3) | ||
332 | len = l1oip_law_to_4bit(buf, len, p, | ||
333 | &hc->chan[channel].codecstate); | ||
334 | else | ||
335 | memcpy(p, buf, len); | ||
336 | } | ||
337 | len += p - frame; | ||
338 | |||
339 | /* check for socket in safe condition */ | ||
340 | spin_lock(&hc->socket_lock); | ||
341 | if (!hc->socket) { | ||
342 | spin_unlock(&hc->socket_lock); | ||
343 | return 0; | ||
344 | } | ||
345 | /* seize socket */ | ||
346 | socket = hc->socket; | ||
347 | hc->socket = NULL; | ||
348 | spin_unlock(&hc->socket_lock); | ||
349 | /* send packet */ | ||
350 | if (debug & DEBUG_L1OIP_MSG) | ||
351 | printk(KERN_DEBUG "%s: sending packet to socket (len " | ||
352 | "= %d)\n", __func__, len); | ||
353 | hc->sendiov.iov_base = frame; | ||
354 | hc->sendiov.iov_len = len; | ||
355 | oldfs = get_fs(); | ||
356 | set_fs(KERNEL_DS); | ||
357 | len = sock_sendmsg(socket, &hc->sendmsg, len); | ||
358 | set_fs(oldfs); | ||
359 | /* give socket back */ | ||
360 | hc->socket = socket; /* no locking required */ | ||
361 | |||
362 | return len; | ||
363 | } | ||
364 | |||
365 | |||
366 | /* | ||
367 | * receive channel data from socket | ||
368 | */ | ||
369 | static void | ||
370 | l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, | ||
371 | u8 *buf, int len) | ||
372 | { | ||
373 | struct sk_buff *nskb; | ||
374 | struct bchannel *bch; | ||
375 | struct dchannel *dch; | ||
376 | u8 *p; | ||
377 | u32 rx_counter; | ||
378 | |||
379 | if (len == 0) { | ||
380 | if (debug & DEBUG_L1OIP_MSG) | ||
381 | printk(KERN_DEBUG "%s: received empty keepalive data, " | ||
382 | "ignoring\n", __func__); | ||
383 | return; | ||
384 | } | ||
385 | |||
386 | if (debug & DEBUG_L1OIP_MSG) | ||
387 | printk(KERN_DEBUG "%s: received data, sending to mISDN (%d)\n", | ||
388 | __func__, len); | ||
389 | |||
390 | if (channel < 1 || channel > 127) { | ||
391 | printk(KERN_WARNING "%s: packet error - channel %d out of " | ||
392 | "range\n", __func__, channel); | ||
393 | return; | ||
394 | } | ||
395 | dch = hc->chan[channel].dch; | ||
396 | bch = hc->chan[channel].bch; | ||
397 | if (!dch && !bch) { | ||
398 | printk(KERN_WARNING "%s: packet error - channel %d not in " | ||
399 | "stack\n", __func__, channel); | ||
400 | return; | ||
401 | } | ||
402 | |||
403 | /* prepare message */ | ||
404 | nskb = mI_alloc_skb((remotecodec == 3)?(len<<1):len, GFP_ATOMIC); | ||
405 | if (!nskb) { | ||
406 | printk(KERN_ERR "%s: No mem for skb.\n", __func__); | ||
407 | return; | ||
408 | } | ||
409 | p = skb_put(nskb, (remotecodec == 3)?(len<<1):len); | ||
410 | |||
411 | if (remotecodec == 1 && ulaw) | ||
412 | l1oip_alaw_to_ulaw(buf, len, p); | ||
413 | else if (remotecodec == 2 && !ulaw) | ||
414 | l1oip_ulaw_to_alaw(buf, len, p); | ||
415 | else if (remotecodec == 3) | ||
416 | len = l1oip_4bit_to_law(buf, len, p); | ||
417 | else | ||
418 | memcpy(p, buf, len); | ||
419 | |||
420 | /* send message up */ | ||
421 | if (dch && len >= 2) { | ||
422 | dch->rx_skb = nskb; | ||
423 | recv_Dchannel(dch); | ||
424 | } | ||
425 | if (bch) { | ||
426 | /* expand 16 bit sequence number to 32 bit sequence number */ | ||
427 | rx_counter = hc->chan[channel].rx_counter; | ||
428 | if (((s16)(timebase - rx_counter)) >= 0) { | ||
429 | /* time has changed forward */ | ||
430 | if (timebase >= (rx_counter & 0xffff)) | ||
431 | rx_counter = | ||
432 | (rx_counter & 0xffff0000) | timebase; | ||
433 | else | ||
434 | rx_counter = ((rx_counter & 0xffff0000)+0x10000) | ||
435 | | timebase; | ||
436 | } else { | ||
437 | /* time has changed backwards */ | ||
438 | if (timebase < (rx_counter & 0xffff)) | ||
439 | rx_counter = | ||
440 | (rx_counter & 0xffff0000) | timebase; | ||
441 | else | ||
442 | rx_counter = ((rx_counter & 0xffff0000)-0x10000) | ||
443 | | timebase; | ||
444 | } | ||
445 | hc->chan[channel].rx_counter = rx_counter; | ||
446 | |||
447 | #ifdef REORDER_DEBUG | ||
448 | if (hc->chan[channel].disorder_flag) { | ||
449 | struct sk_buff *skb; | ||
450 | int cnt; | ||
451 | skb = hc->chan[channel].disorder_skb; | ||
452 | hc->chan[channel].disorder_skb = nskb; | ||
453 | nskb = skb; | ||
454 | cnt = hc->chan[channel].disorder_cnt; | ||
455 | hc->chan[channel].disorder_cnt = rx_counter; | ||
456 | rx_counter = cnt; | ||
457 | } | ||
458 | hc->chan[channel].disorder_flag ^= 1; | ||
459 | if (nskb) | ||
460 | #endif | ||
461 | queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb); | ||
462 | } | ||
463 | } | ||
464 | |||
465 | |||
466 | /* | ||
467 | * parse frame and extract channel data | ||
468 | */ | ||
469 | static void | ||
470 | l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) | ||
471 | { | ||
472 | u32 id; | ||
473 | u8 channel; | ||
474 | u8 remotecodec; | ||
475 | u16 timebase; | ||
476 | int m, mlen; | ||
477 | int len_start = len; /* initial frame length */ | ||
478 | struct dchannel *dch = hc->chan[hc->d_idx].dch; | ||
479 | |||
480 | if (debug & DEBUG_L1OIP_MSG) | ||
481 | printk(KERN_DEBUG "%s: received frame, parsing... (%d)\n", | ||
482 | __func__, len); | ||
483 | |||
484 | /* check lenght */ | ||
485 | if (len < 1+1+2) { | ||
486 | printk(KERN_WARNING "%s: packet error - length %d below " | ||
487 | "4 bytes\n", __func__, len); | ||
488 | return; | ||
489 | } | ||
490 | |||
491 | /* check version */ | ||
492 | if (((*buf)>>6) != L1OIP_VERSION) { | ||
493 | printk(KERN_WARNING "%s: packet error - unknown version %d\n", | ||
494 | __func__, buf[0]>>6); | ||
495 | return; | ||
496 | } | ||
497 | |||
498 | /* check type */ | ||
499 | if (((*buf)&0x20) && !hc->pri) { | ||
500 | printk(KERN_WARNING "%s: packet error - received E1 packet " | ||
501 | "on S0 interface\n", __func__); | ||
502 | return; | ||
503 | } | ||
504 | if (!((*buf)&0x20) && hc->pri) { | ||
505 | printk(KERN_WARNING "%s: packet error - received S0 packet " | ||
506 | "on E1 interface\n", __func__); | ||
507 | return; | ||
508 | } | ||
509 | |||
510 | /* get id flag */ | ||
511 | id = (*buf>>4)&1; | ||
512 | |||
513 | /* check coding */ | ||
514 | remotecodec = (*buf) & 0x0f; | ||
515 | if (remotecodec > 3) { | ||
516 | printk(KERN_WARNING "%s: packet error - remotecodec %d " | ||
517 | "unsupported\n", __func__, remotecodec); | ||
518 | return; | ||
519 | } | ||
520 | buf++; | ||
521 | len--; | ||
522 | |||
523 | /* check id */ | ||
524 | if (id) { | ||
525 | if (!hc->id) { | ||
526 | printk(KERN_WARNING "%s: packet error - packet has id " | ||
527 | "0x%x, but we have not\n", __func__, id); | ||
528 | return; | ||
529 | } | ||
530 | if (len < 4) { | ||
531 | printk(KERN_WARNING "%s: packet error - packet too " | ||
532 | "short for ID value\n", __func__); | ||
533 | return; | ||
534 | } | ||
535 | id = (*buf++) << 24; | ||
536 | id += (*buf++) << 16; | ||
537 | id += (*buf++) << 8; | ||
538 | id += (*buf++); | ||
539 | len -= 4; | ||
540 | |||
541 | if (id != hc->id) { | ||
542 | printk(KERN_WARNING "%s: packet error - ID mismatch, " | ||
543 | "got 0x%x, we 0x%x\n", | ||
544 | __func__, id, hc->id); | ||
545 | return; | ||
546 | } | ||
547 | } else { | ||
548 | if (hc->id) { | ||
549 | printk(KERN_WARNING "%s: packet error - packet has no " | ||
550 | "ID, but we have\n", __func__); | ||
551 | return; | ||
552 | } | ||
553 | } | ||
554 | |||
555 | multiframe: | ||
556 | if (len < 1) { | ||
557 | printk(KERN_WARNING "%s: packet error - packet too short, " | ||
558 | "channel expected at position %d.\n", | ||
559 | __func__, len-len_start+1); | ||
560 | return; | ||
561 | } | ||
562 | |||
563 | /* get channel and multiframe flag */ | ||
564 | channel = *buf&0x7f; | ||
565 | m = *buf >> 7; | ||
566 | buf++; | ||
567 | len--; | ||
568 | |||
569 | /* check length on multiframe */ | ||
570 | if (m) { | ||
571 | if (len < 1) { | ||
572 | printk(KERN_WARNING "%s: packet error - packet too " | ||
573 | "short, length expected at position %d.\n", | ||
574 | __func__, len_start-len-1); | ||
575 | return; | ||
576 | } | ||
577 | |||
578 | mlen = *buf++; | ||
579 | len--; | ||
580 | if (mlen == 0) | ||
581 | mlen = 256; | ||
582 | if (len < mlen+3) { | ||
583 | printk(KERN_WARNING "%s: packet error - length %d at " | ||
584 | "position %d exceeds total length %d.\n", | ||
585 | __func__, mlen, len_start-len-1, len_start); | ||
586 | return; | ||
587 | } | ||
588 | if (len == mlen+3) { | ||
589 | printk(KERN_WARNING "%s: packet error - length %d at " | ||
590 | "position %d will not allow additional " | ||
591 | "packet.\n", | ||
592 | __func__, mlen, len_start-len+1); | ||
593 | return; | ||
594 | } | ||
595 | } else | ||
596 | mlen = len-2; /* single frame, substract timebase */ | ||
597 | |||
598 | if (len < 2) { | ||
599 | printk(KERN_WARNING "%s: packet error - packet too short, time " | ||
600 | "base expected at position %d.\n", | ||
601 | __func__, len-len_start+1); | ||
602 | return; | ||
603 | } | ||
604 | |||
605 | /* get time base */ | ||
606 | timebase = (*buf++) << 8; | ||
607 | timebase |= (*buf++); | ||
608 | len -= 2; | ||
609 | |||
610 | /* if inactive, we send up a PH_ACTIVATE and activate */ | ||
611 | if (!test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
612 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
613 | printk(KERN_DEBUG "%s: interface become active due to " | ||
614 | "received packet\n", __func__); | ||
615 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
616 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, | ||
617 | NULL, GFP_ATOMIC); | ||
618 | } | ||
619 | |||
620 | /* distribute packet */ | ||
621 | l1oip_socket_recv(hc, remotecodec, channel, timebase, buf, mlen); | ||
622 | buf += mlen; | ||
623 | len -= mlen; | ||
624 | |||
625 | /* multiframe */ | ||
626 | if (m) | ||
627 | goto multiframe; | ||
628 | |||
629 | /* restart timer */ | ||
630 | if ((int)(hc->timeout_tl.expires-jiffies) < 5*HZ || !hc->timeout_on) { | ||
631 | hc->timeout_on = 1; | ||
632 | del_timer(&hc->timeout_tl); | ||
633 | hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT*HZ; | ||
634 | add_timer(&hc->timeout_tl); | ||
635 | } else /* only adjust timer */ | ||
636 | hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT*HZ; | ||
637 | |||
638 | /* if ip or source port changes */ | ||
639 | if ((hc->sin_remote.sin_addr.s_addr != sin->sin_addr.s_addr) | ||
640 | || (hc->sin_remote.sin_port != sin->sin_port)) { | ||
641 | if (debug & DEBUG_L1OIP_SOCKET) | ||
642 | printk(KERN_DEBUG "%s: remote address changes from " | ||
643 | "0x%08x to 0x%08x (port %d to %d)\n", __func__, | ||
644 | ntohl(hc->sin_remote.sin_addr.s_addr), | ||
645 | ntohl(sin->sin_addr.s_addr), | ||
646 | ntohs(hc->sin_remote.sin_port), | ||
647 | ntohs(sin->sin_port)); | ||
648 | hc->sin_remote.sin_addr.s_addr = sin->sin_addr.s_addr; | ||
649 | hc->sin_remote.sin_port = sin->sin_port; | ||
650 | } | ||
651 | } | ||
652 | |||
653 | |||
654 | /* | ||
655 | * socket stuff | ||
656 | */ | ||
657 | static int | ||
658 | l1oip_socket_thread(void *data) | ||
659 | { | ||
660 | struct l1oip *hc = (struct l1oip *)data; | ||
661 | int ret = 0; | ||
662 | struct msghdr msg; | ||
663 | struct iovec iov; | ||
664 | mm_segment_t oldfs; | ||
665 | struct sockaddr_in sin_rx; | ||
666 | unsigned char recvbuf[1500]; | ||
667 | int recvlen; | ||
668 | struct socket *socket = NULL; | ||
669 | DECLARE_COMPLETION(wait); | ||
670 | |||
671 | /* make daemon */ | ||
672 | allow_signal(SIGTERM); | ||
673 | |||
674 | /* create socket */ | ||
675 | if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &socket)) { | ||
676 | printk(KERN_ERR "%s: Failed to create socket.\n", __func__); | ||
677 | return -EIO; | ||
678 | } | ||
679 | |||
680 | /* set incoming address */ | ||
681 | hc->sin_local.sin_family = AF_INET; | ||
682 | hc->sin_local.sin_addr.s_addr = INADDR_ANY; | ||
683 | hc->sin_local.sin_port = htons((unsigned short)hc->localport); | ||
684 | |||
685 | /* set outgoing address */ | ||
686 | hc->sin_remote.sin_family = AF_INET; | ||
687 | hc->sin_remote.sin_addr.s_addr = htonl(hc->remoteip); | ||
688 | hc->sin_remote.sin_port = htons((unsigned short)hc->remoteport); | ||
689 | |||
690 | /* bind to incomming port */ | ||
691 | if (socket->ops->bind(socket, (struct sockaddr *)&hc->sin_local, | ||
692 | sizeof(hc->sin_local))) { | ||
693 | printk(KERN_ERR "%s: Failed to bind socket to port %d.\n", | ||
694 | __func__, hc->localport); | ||
695 | ret = -EINVAL; | ||
696 | goto fail; | ||
697 | } | ||
698 | |||
699 | /* check sk */ | ||
700 | if (socket->sk == NULL) { | ||
701 | printk(KERN_ERR "%s: socket->sk == NULL\n", __func__); | ||
702 | ret = -EIO; | ||
703 | goto fail; | ||
704 | } | ||
705 | |||
706 | /* build receive message */ | ||
707 | msg.msg_name = &sin_rx; | ||
708 | msg.msg_namelen = sizeof(sin_rx); | ||
709 | msg.msg_control = NULL; | ||
710 | msg.msg_controllen = 0; | ||
711 | msg.msg_iov = &iov; | ||
712 | msg.msg_iovlen = 1; | ||
713 | |||
714 | /* build send message */ | ||
715 | hc->sendmsg.msg_name = &hc->sin_remote; | ||
716 | hc->sendmsg.msg_namelen = sizeof(hc->sin_remote); | ||
717 | hc->sendmsg.msg_control = NULL; | ||
718 | hc->sendmsg.msg_controllen = 0; | ||
719 | hc->sendmsg.msg_iov = &hc->sendiov; | ||
720 | hc->sendmsg.msg_iovlen = 1; | ||
721 | |||
722 | /* give away socket */ | ||
723 | spin_lock(&hc->socket_lock); | ||
724 | hc->socket = socket; | ||
725 | spin_unlock(&hc->socket_lock); | ||
726 | |||
727 | /* read loop */ | ||
728 | if (debug & DEBUG_L1OIP_SOCKET) | ||
729 | printk(KERN_DEBUG "%s: socket created and open\n", | ||
730 | __func__); | ||
731 | while (!signal_pending(current)) { | ||
732 | iov.iov_base = recvbuf; | ||
733 | iov.iov_len = sizeof(recvbuf); | ||
734 | oldfs = get_fs(); | ||
735 | set_fs(KERNEL_DS); | ||
736 | recvlen = sock_recvmsg(socket, &msg, sizeof(recvbuf), 0); | ||
737 | set_fs(oldfs); | ||
738 | if (recvlen > 0) { | ||
739 | l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen); | ||
740 | } else { | ||
741 | if (debug & DEBUG_L1OIP_SOCKET) | ||
742 | printk(KERN_WARNING "%s: broken pipe on socket\n", | ||
743 | __func__); | ||
744 | } | ||
745 | } | ||
746 | |||
747 | /* get socket back, check first if in use, maybe by send function */ | ||
748 | spin_lock(&hc->socket_lock); | ||
749 | /* if hc->socket is NULL, it is in use until it is given back */ | ||
750 | while (!hc->socket) { | ||
751 | spin_unlock(&hc->socket_lock); | ||
752 | schedule_timeout(HZ/10); | ||
753 | spin_lock(&hc->socket_lock); | ||
754 | } | ||
755 | hc->socket = NULL; | ||
756 | spin_unlock(&hc->socket_lock); | ||
757 | |||
758 | if (debug & DEBUG_L1OIP_SOCKET) | ||
759 | printk(KERN_DEBUG "%s: socket thread terminating\n", | ||
760 | __func__); | ||
761 | |||
762 | fail: | ||
763 | /* close socket */ | ||
764 | if (socket) | ||
765 | sock_release(socket); | ||
766 | |||
767 | /* if we got killed, signal completion */ | ||
768 | complete(&hc->socket_complete); | ||
769 | hc->socket_thread = NULL; /* show termination of thread */ | ||
770 | |||
771 | if (debug & DEBUG_L1OIP_SOCKET) | ||
772 | printk(KERN_DEBUG "%s: socket thread terminated\n", | ||
773 | __func__); | ||
774 | return ret; | ||
775 | } | ||
776 | |||
777 | static void | ||
778 | l1oip_socket_close(struct l1oip *hc) | ||
779 | { | ||
780 | /* kill thread */ | ||
781 | if (hc->socket_thread) { | ||
782 | if (debug & DEBUG_L1OIP_SOCKET) | ||
783 | printk(KERN_DEBUG "%s: socket thread exists, " | ||
784 | "killing...\n", __func__); | ||
785 | send_sig(SIGTERM, hc->socket_thread, 0); | ||
786 | wait_for_completion(&hc->socket_complete); | ||
787 | } | ||
788 | } | ||
789 | |||
790 | static int | ||
791 | l1oip_socket_open(struct l1oip *hc) | ||
792 | { | ||
793 | /* in case of reopen, we need to close first */ | ||
794 | l1oip_socket_close(hc); | ||
795 | |||
796 | init_completion(&hc->socket_complete); | ||
797 | |||
798 | /* create receive process */ | ||
799 | hc->socket_thread = kthread_run(l1oip_socket_thread, hc, "l1oip_%s", | ||
800 | hc->name); | ||
801 | if (IS_ERR(hc->socket_thread)) { | ||
802 | int err = PTR_ERR(hc->socket_thread); | ||
803 | printk(KERN_ERR "%s: Failed (%d) to create socket process.\n", | ||
804 | __func__, err); | ||
805 | hc->socket_thread = NULL; | ||
806 | sock_release(hc->socket); | ||
807 | return err; | ||
808 | } | ||
809 | if (debug & DEBUG_L1OIP_SOCKET) | ||
810 | printk(KERN_DEBUG "%s: socket thread created\n", __func__); | ||
811 | |||
812 | return 0; | ||
813 | } | ||
814 | |||
815 | |||
816 | static void | ||
817 | l1oip_send_bh(struct work_struct *work) | ||
818 | { | ||
819 | struct l1oip *hc = container_of(work, struct l1oip, workq); | ||
820 | |||
821 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
822 | printk(KERN_DEBUG "%s: keepalive timer expired, sending empty " | ||
823 | "frame on dchannel\n", __func__); | ||
824 | |||
825 | /* send an empty l1oip frame at D-channel */ | ||
826 | l1oip_socket_send(hc, 0, hc->d_idx, 0, 0, NULL, 0); | ||
827 | } | ||
828 | |||
829 | |||
830 | /* | ||
831 | * timer stuff | ||
832 | */ | ||
833 | static void | ||
834 | l1oip_keepalive(void *data) | ||
835 | { | ||
836 | struct l1oip *hc = (struct l1oip *)data; | ||
837 | |||
838 | schedule_work(&hc->workq); | ||
839 | } | ||
840 | |||
841 | static void | ||
842 | l1oip_timeout(void *data) | ||
843 | { | ||
844 | struct l1oip *hc = (struct l1oip *)data; | ||
845 | struct dchannel *dch = hc->chan[hc->d_idx].dch; | ||
846 | |||
847 | if (debug & DEBUG_L1OIP_MSG) | ||
848 | printk(KERN_DEBUG "%s: timeout timer expired, turn layer one " | ||
849 | "down.\n", __func__); | ||
850 | |||
851 | hc->timeout_on = 0; /* state that timer must be initialized next time */ | ||
852 | |||
853 | /* if timeout, we send up a PH_DEACTIVATE and deactivate */ | ||
854 | if (test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
855 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
856 | printk(KERN_DEBUG "%s: interface become deactivated " | ||
857 | "due to timeout\n", __func__); | ||
858 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
859 | _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, | ||
860 | NULL, GFP_ATOMIC); | ||
861 | } | ||
862 | |||
863 | /* if we have ondemand set, we remove ip address */ | ||
864 | if (hc->ondemand) { | ||
865 | if (debug & DEBUG_L1OIP_MSG) | ||
866 | printk(KERN_DEBUG "%s: on demand causes ip address to " | ||
867 | "be removed\n", __func__); | ||
868 | hc->sin_remote.sin_addr.s_addr = 0; | ||
869 | } | ||
870 | } | ||
871 | |||
872 | |||
873 | /* | ||
874 | * message handling | ||
875 | */ | ||
876 | static int | ||
877 | handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) | ||
878 | { | ||
879 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
880 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
881 | struct l1oip *hc = dch->hw; | ||
882 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
883 | int ret = -EINVAL; | ||
884 | int l, ll; | ||
885 | unsigned char *p; | ||
886 | |||
887 | switch (hh->prim) { | ||
888 | case PH_DATA_REQ: | ||
889 | if (skb->len < 1) { | ||
890 | printk(KERN_WARNING "%s: skb too small\n", | ||
891 | __func__); | ||
892 | break; | ||
893 | } | ||
894 | if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) { | ||
895 | printk(KERN_WARNING "%s: skb too large\n", | ||
896 | __func__); | ||
897 | break; | ||
898 | } | ||
899 | /* send frame */ | ||
900 | p = skb->data; | ||
901 | l = skb->len; | ||
902 | while (l) { | ||
903 | ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; | ||
904 | l1oip_socket_send(hc, 0, dch->slot, 0, | ||
905 | hc->chan[dch->slot].tx_counter++, p, ll); | ||
906 | p += ll; | ||
907 | l -= ll; | ||
908 | } | ||
909 | skb_trim(skb, 0); | ||
910 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
911 | return 0; | ||
912 | case PH_ACTIVATE_REQ: | ||
913 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
914 | printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n" | ||
915 | , __func__, dch->slot, hc->b_num+1); | ||
916 | skb_trim(skb, 0); | ||
917 | if (test_bit(FLG_ACTIVE, &dch->Flags)) | ||
918 | queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); | ||
919 | else | ||
920 | queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); | ||
921 | return 0; | ||
922 | case PH_DEACTIVATE_REQ: | ||
923 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
924 | printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d " | ||
925 | "(1..%d)\n", __func__, dch->slot, | ||
926 | hc->b_num+1); | ||
927 | skb_trim(skb, 0); | ||
928 | if (test_bit(FLG_ACTIVE, &dch->Flags)) | ||
929 | queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); | ||
930 | else | ||
931 | queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); | ||
932 | return 0; | ||
933 | } | ||
934 | if (!ret) | ||
935 | dev_kfree_skb(skb); | ||
936 | return ret; | ||
937 | } | ||
938 | |||
939 | static int | ||
940 | channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) | ||
941 | { | ||
942 | int ret = 0; | ||
943 | struct l1oip *hc = dch->hw; | ||
944 | |||
945 | switch (cq->op) { | ||
946 | case MISDN_CTRL_GETOP: | ||
947 | cq->op = MISDN_CTRL_SETPEER | MISDN_CTRL_UNSETPEER; | ||
948 | break; | ||
949 | case MISDN_CTRL_SETPEER: | ||
950 | hc->remoteip = (u32)cq->p1; | ||
951 | hc->remoteport = cq->p2 & 0xffff; | ||
952 | hc->localport = cq->p2 >> 16; | ||
953 | if (!hc->remoteport) | ||
954 | hc->remoteport = hc->localport; | ||
955 | if (debug & DEBUG_L1OIP_SOCKET) | ||
956 | printk(KERN_DEBUG "%s: got new ip address from user " | ||
957 | "space.\n", __func__); | ||
958 | l1oip_socket_open(hc); | ||
959 | break; | ||
960 | case MISDN_CTRL_UNSETPEER: | ||
961 | if (debug & DEBUG_L1OIP_SOCKET) | ||
962 | printk(KERN_DEBUG "%s: removing ip address.\n", | ||
963 | __func__); | ||
964 | hc->remoteip = 0; | ||
965 | l1oip_socket_open(hc); | ||
966 | break; | ||
967 | default: | ||
968 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
969 | __func__, cq->op); | ||
970 | ret = -EINVAL; | ||
971 | break; | ||
972 | } | ||
973 | return ret; | ||
974 | } | ||
975 | |||
976 | static int | ||
977 | open_dchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) | ||
978 | { | ||
979 | if (debug & DEBUG_HW_OPEN) | ||
980 | printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, | ||
981 | dch->dev.id, __builtin_return_address(0)); | ||
982 | if (rq->protocol == ISDN_P_NONE) | ||
983 | return -EINVAL; | ||
984 | if ((dch->dev.D.protocol != ISDN_P_NONE) && | ||
985 | (dch->dev.D.protocol != rq->protocol)) { | ||
986 | if (debug & DEBUG_HW_OPEN) | ||
987 | printk(KERN_WARNING "%s: change protocol %x to %x\n", | ||
988 | __func__, dch->dev.D.protocol, rq->protocol); | ||
989 | } | ||
990 | if (dch->dev.D.protocol != rq->protocol) | ||
991 | dch->dev.D.protocol = rq->protocol; | ||
992 | |||
993 | if (test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
994 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, | ||
995 | 0, NULL, GFP_KERNEL); | ||
996 | } | ||
997 | rq->ch = &dch->dev.D; | ||
998 | if (!try_module_get(THIS_MODULE)) | ||
999 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
1000 | return 0; | ||
1001 | } | ||
1002 | |||
1003 | static int | ||
1004 | open_bchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) | ||
1005 | { | ||
1006 | struct bchannel *bch; | ||
1007 | int ch; | ||
1008 | |||
1009 | if (!test_bit(rq->adr.channel & 0x1f, | ||
1010 | &dch->dev.channelmap[rq->adr.channel >> 5])) | ||
1011 | return -EINVAL; | ||
1012 | if (rq->protocol == ISDN_P_NONE) | ||
1013 | return -EINVAL; | ||
1014 | ch = rq->adr.channel; /* BRI: 1=B1 2=B2 PRI: 1..15,17.. */ | ||
1015 | bch = hc->chan[ch].bch; | ||
1016 | if (!bch) { | ||
1017 | printk(KERN_ERR "%s:internal error ch %d has no bch\n", | ||
1018 | __func__, ch); | ||
1019 | return -EINVAL; | ||
1020 | } | ||
1021 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
1022 | return -EBUSY; /* b-channel can be only open once */ | ||
1023 | bch->ch.protocol = rq->protocol; | ||
1024 | rq->ch = &bch->ch; | ||
1025 | if (!try_module_get(THIS_MODULE)) | ||
1026 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
1027 | return 0; | ||
1028 | } | ||
1029 | |||
1030 | static int | ||
1031 | l1oip_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1032 | { | ||
1033 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
1034 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
1035 | struct l1oip *hc = dch->hw; | ||
1036 | struct channel_req *rq; | ||
1037 | int err = 0; | ||
1038 | |||
1039 | if (dch->debug & DEBUG_HW) | ||
1040 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
1041 | __func__, cmd, arg); | ||
1042 | switch (cmd) { | ||
1043 | case OPEN_CHANNEL: | ||
1044 | rq = arg; | ||
1045 | switch (rq->protocol) { | ||
1046 | case ISDN_P_TE_S0: | ||
1047 | case ISDN_P_NT_S0: | ||
1048 | if (hc->pri) { | ||
1049 | err = -EINVAL; | ||
1050 | break; | ||
1051 | } | ||
1052 | err = open_dchannel(hc, dch, rq); | ||
1053 | break; | ||
1054 | case ISDN_P_TE_E1: | ||
1055 | case ISDN_P_NT_E1: | ||
1056 | if (!hc->pri) { | ||
1057 | err = -EINVAL; | ||
1058 | break; | ||
1059 | } | ||
1060 | err = open_dchannel(hc, dch, rq); | ||
1061 | break; | ||
1062 | default: | ||
1063 | err = open_bchannel(hc, dch, rq); | ||
1064 | } | ||
1065 | break; | ||
1066 | case CLOSE_CHANNEL: | ||
1067 | if (debug & DEBUG_HW_OPEN) | ||
1068 | printk(KERN_DEBUG "%s: dev(%d) close from %p\n", | ||
1069 | __func__, dch->dev.id, | ||
1070 | __builtin_return_address(0)); | ||
1071 | module_put(THIS_MODULE); | ||
1072 | break; | ||
1073 | case CONTROL_CHANNEL: | ||
1074 | err = channel_dctrl(dch, arg); | ||
1075 | break; | ||
1076 | default: | ||
1077 | if (dch->debug & DEBUG_HW) | ||
1078 | printk(KERN_DEBUG "%s: unknown command %x\n", | ||
1079 | __func__, cmd); | ||
1080 | err = -EINVAL; | ||
1081 | } | ||
1082 | return err; | ||
1083 | } | ||
1084 | |||
1085 | static int | ||
1086 | handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1087 | { | ||
1088 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
1089 | struct l1oip *hc = bch->hw; | ||
1090 | int ret = -EINVAL; | ||
1091 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1092 | int l, ll, i; | ||
1093 | unsigned char *p; | ||
1094 | |||
1095 | switch (hh->prim) { | ||
1096 | case PH_DATA_REQ: | ||
1097 | if (skb->len <= 0) { | ||
1098 | printk(KERN_WARNING "%s: skb too small\n", | ||
1099 | __func__); | ||
1100 | break; | ||
1101 | } | ||
1102 | if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) { | ||
1103 | printk(KERN_WARNING "%s: skb too large\n", | ||
1104 | __func__); | ||
1105 | break; | ||
1106 | } | ||
1107 | /* check for AIS / ulaw-silence */ | ||
1108 | p = skb->data; | ||
1109 | l = skb->len; | ||
1110 | for (i = 0; i < l; i++) { | ||
1111 | if (*p++ != 0xff) | ||
1112 | break; | ||
1113 | } | ||
1114 | if (i == l) { | ||
1115 | if (debug & DEBUG_L1OIP_MSG) | ||
1116 | printk(KERN_DEBUG "%s: got AIS, not sending, " | ||
1117 | "but counting\n", __func__); | ||
1118 | hc->chan[bch->slot].tx_counter += l; | ||
1119 | skb_trim(skb, 0); | ||
1120 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
1121 | return 0; | ||
1122 | } | ||
1123 | /* check for silence */ | ||
1124 | p = skb->data; | ||
1125 | l = skb->len; | ||
1126 | for (i = 0; i < l; i++) { | ||
1127 | if (*p++ != 0x2a) | ||
1128 | break; | ||
1129 | } | ||
1130 | if (i == l) { | ||
1131 | if (debug & DEBUG_L1OIP_MSG) | ||
1132 | printk(KERN_DEBUG "%s: got silence, not sending" | ||
1133 | ", but counting\n", __func__); | ||
1134 | hc->chan[bch->slot].tx_counter += l; | ||
1135 | skb_trim(skb, 0); | ||
1136 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
1137 | return 0; | ||
1138 | } | ||
1139 | |||
1140 | /* send frame */ | ||
1141 | p = skb->data; | ||
1142 | l = skb->len; | ||
1143 | while (l) { | ||
1144 | ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; | ||
1145 | l1oip_socket_send(hc, hc->codec, bch->slot, 0, | ||
1146 | hc->chan[bch->slot].tx_counter, p, ll); | ||
1147 | hc->chan[bch->slot].tx_counter += ll; | ||
1148 | p += ll; | ||
1149 | l -= ll; | ||
1150 | } | ||
1151 | skb_trim(skb, 0); | ||
1152 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
1153 | return 0; | ||
1154 | case PH_ACTIVATE_REQ: | ||
1155 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
1156 | printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n" | ||
1157 | , __func__, bch->slot, hc->b_num+1); | ||
1158 | hc->chan[bch->slot].codecstate = 0; | ||
1159 | test_and_set_bit(FLG_ACTIVE, &bch->Flags); | ||
1160 | skb_trim(skb, 0); | ||
1161 | queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); | ||
1162 | return 0; | ||
1163 | case PH_DEACTIVATE_REQ: | ||
1164 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
1165 | printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d " | ||
1166 | "(1..%d)\n", __func__, bch->slot, | ||
1167 | hc->b_num+1); | ||
1168 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
1169 | skb_trim(skb, 0); | ||
1170 | queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); | ||
1171 | return 0; | ||
1172 | } | ||
1173 | if (!ret) | ||
1174 | dev_kfree_skb(skb); | ||
1175 | return ret; | ||
1176 | } | ||
1177 | |||
1178 | static int | ||
1179 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | ||
1180 | { | ||
1181 | int ret = 0; | ||
1182 | struct dsp_features *features = | ||
1183 | (struct dsp_features *)(*((u_long *)&cq->p1)); | ||
1184 | |||
1185 | switch (cq->op) { | ||
1186 | case MISDN_CTRL_GETOP: | ||
1187 | cq->op = MISDN_CTRL_HW_FEATURES_OP; | ||
1188 | break; | ||
1189 | case MISDN_CTRL_HW_FEATURES: /* fill features structure */ | ||
1190 | if (debug & DEBUG_L1OIP_MSG) | ||
1191 | printk(KERN_DEBUG "%s: HW_FEATURE request\n", | ||
1192 | __func__); | ||
1193 | /* create confirm */ | ||
1194 | features->unclocked = 1; | ||
1195 | features->unordered = 1; | ||
1196 | break; | ||
1197 | default: | ||
1198 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
1199 | __func__, cq->op); | ||
1200 | ret = -EINVAL; | ||
1201 | break; | ||
1202 | } | ||
1203 | return ret; | ||
1204 | } | ||
1205 | |||
1206 | static int | ||
1207 | l1oip_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1208 | { | ||
1209 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
1210 | int err = -EINVAL; | ||
1211 | |||
1212 | if (bch->debug & DEBUG_HW) | ||
1213 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
1214 | __func__, cmd, arg); | ||
1215 | switch (cmd) { | ||
1216 | case CLOSE_CHANNEL: | ||
1217 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
1218 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
1219 | ch->protocol = ISDN_P_NONE; | ||
1220 | ch->peer = NULL; | ||
1221 | module_put(THIS_MODULE); | ||
1222 | err = 0; | ||
1223 | break; | ||
1224 | case CONTROL_CHANNEL: | ||
1225 | err = channel_bctrl(bch, arg); | ||
1226 | break; | ||
1227 | default: | ||
1228 | printk(KERN_WARNING "%s: unknown prim(%x)\n", | ||
1229 | __func__, cmd); | ||
1230 | } | ||
1231 | return err; | ||
1232 | } | ||
1233 | |||
1234 | |||
1235 | /* | ||
1236 | * cleanup module and stack | ||
1237 | */ | ||
1238 | static void | ||
1239 | release_card(struct l1oip *hc) | ||
1240 | { | ||
1241 | int ch; | ||
1242 | |||
1243 | if (timer_pending(&hc->keep_tl)) | ||
1244 | del_timer(&hc->keep_tl); | ||
1245 | |||
1246 | if (timer_pending(&hc->timeout_tl)) | ||
1247 | del_timer(&hc->timeout_tl); | ||
1248 | |||
1249 | if (hc->socket_thread) | ||
1250 | l1oip_socket_close(hc); | ||
1251 | |||
1252 | if (hc->registered && hc->chan[hc->d_idx].dch) | ||
1253 | mISDN_unregister_device(&hc->chan[hc->d_idx].dch->dev); | ||
1254 | for (ch = 0; ch < 128; ch++) { | ||
1255 | if (hc->chan[ch].dch) { | ||
1256 | mISDN_freedchannel(hc->chan[ch].dch); | ||
1257 | kfree(hc->chan[ch].dch); | ||
1258 | } | ||
1259 | if (hc->chan[ch].bch) { | ||
1260 | mISDN_freebchannel(hc->chan[ch].bch); | ||
1261 | kfree(hc->chan[ch].bch); | ||
1262 | #ifdef REORDER_DEBUG | ||
1263 | if (hc->chan[ch].disorder_skb) | ||
1264 | dev_kfree_skb(hc->chan[ch].disorder_skb); | ||
1265 | #endif | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1269 | spin_lock(&l1oip_lock); | ||
1270 | list_del(&hc->list); | ||
1271 | spin_unlock(&l1oip_lock); | ||
1272 | |||
1273 | kfree(hc); | ||
1274 | } | ||
1275 | |||
1276 | static void | ||
1277 | l1oip_cleanup(void) | ||
1278 | { | ||
1279 | struct l1oip *hc, *next; | ||
1280 | |||
1281 | list_for_each_entry_safe(hc, next, &l1oip_ilist, list) | ||
1282 | release_card(hc); | ||
1283 | |||
1284 | l1oip_4bit_free(); | ||
1285 | } | ||
1286 | |||
1287 | |||
1288 | /* | ||
1289 | * module and stack init | ||
1290 | */ | ||
1291 | static int | ||
1292 | init_card(struct l1oip *hc, int pri, int bundle) | ||
1293 | { | ||
1294 | struct dchannel *dch; | ||
1295 | struct bchannel *bch; | ||
1296 | int ret; | ||
1297 | int i, ch; | ||
1298 | |||
1299 | spin_lock_init(&hc->socket_lock); | ||
1300 | hc->idx = l1oip_cnt; | ||
1301 | hc->pri = pri; | ||
1302 | hc->d_idx = pri?16:3; | ||
1303 | hc->b_num = pri?30:2; | ||
1304 | hc->bundle = bundle; | ||
1305 | if (hc->pri) | ||
1306 | sprintf(hc->name, "l1oip-e1.%d", l1oip_cnt + 1); | ||
1307 | else | ||
1308 | sprintf(hc->name, "l1oip-s0.%d", l1oip_cnt + 1); | ||
1309 | |||
1310 | switch (codec[l1oip_cnt]) { | ||
1311 | case 0: /* as is */ | ||
1312 | case 1: /* alaw */ | ||
1313 | case 2: /* ulaw */ | ||
1314 | case 3: /* 4bit */ | ||
1315 | break; | ||
1316 | default: | ||
1317 | printk(KERN_ERR "Codec(%d) not supported.\n", | ||
1318 | codec[l1oip_cnt]); | ||
1319 | return -EINVAL; | ||
1320 | } | ||
1321 | hc->codec = codec[l1oip_cnt]; | ||
1322 | if (debug & DEBUG_L1OIP_INIT) | ||
1323 | printk(KERN_DEBUG "%s: using codec %d\n", | ||
1324 | __func__, hc->codec); | ||
1325 | |||
1326 | if (id[l1oip_cnt] == 0) { | ||
1327 | printk(KERN_WARNING "Warning: No 'id' value given or " | ||
1328 | "0, this is highly unsecure. Please use 32 " | ||
1329 | "bit randmom number 0x...\n"); | ||
1330 | } | ||
1331 | hc->id = id[l1oip_cnt]; | ||
1332 | if (debug & DEBUG_L1OIP_INIT) | ||
1333 | printk(KERN_DEBUG "%s: using id 0x%x\n", __func__, hc->id); | ||
1334 | |||
1335 | hc->ondemand = ondemand[l1oip_cnt]; | ||
1336 | if (hc->ondemand && !hc->id) { | ||
1337 | printk(KERN_ERR "%s: ondemand option only allowed in " | ||
1338 | "conjunction with non 0 ID\n", __func__); | ||
1339 | return -EINVAL; | ||
1340 | } | ||
1341 | |||
1342 | if (limit[l1oip_cnt]) | ||
1343 | hc->b_num = limit[l1oip_cnt]; | ||
1344 | if (!pri && hc->b_num > 2) { | ||
1345 | printk(KERN_ERR "Maximum limit for BRI interface is 2 " | ||
1346 | "channels.\n"); | ||
1347 | return -EINVAL; | ||
1348 | } | ||
1349 | if (pri && hc->b_num > 126) { | ||
1350 | printk(KERN_ERR "Maximum limit for PRI interface is 126 " | ||
1351 | "channels.\n"); | ||
1352 | return -EINVAL; | ||
1353 | } | ||
1354 | if (pri && hc->b_num > 30) { | ||
1355 | printk(KERN_WARNING "Maximum limit for BRI interface is 30 " | ||
1356 | "channels.\n"); | ||
1357 | printk(KERN_WARNING "Your selection of %d channels must be " | ||
1358 | "supported by application.\n", hc->limit); | ||
1359 | } | ||
1360 | |||
1361 | hc->remoteip = ip[l1oip_cnt<<2] << 24 | ||
1362 | | ip[(l1oip_cnt<<2)+1] << 16 | ||
1363 | | ip[(l1oip_cnt<<2)+2] << 8 | ||
1364 | | ip[(l1oip_cnt<<2)+3]; | ||
1365 | hc->localport = port[l1oip_cnt]?:(L1OIP_DEFAULTPORT+l1oip_cnt); | ||
1366 | if (remoteport[l1oip_cnt]) | ||
1367 | hc->remoteport = remoteport[l1oip_cnt]; | ||
1368 | else | ||
1369 | hc->remoteport = hc->localport; | ||
1370 | if (debug & DEBUG_L1OIP_INIT) | ||
1371 | printk(KERN_DEBUG "%s: using local port %d remote ip " | ||
1372 | "%d.%d.%d.%d port %d ondemand %d\n", __func__, | ||
1373 | hc->localport, hc->remoteip >> 24, | ||
1374 | (hc->remoteip >> 16) & 0xff, | ||
1375 | (hc->remoteip >> 8) & 0xff, hc->remoteip & 0xff, | ||
1376 | hc->remoteport, hc->ondemand); | ||
1377 | |||
1378 | dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); | ||
1379 | if (!dch) | ||
1380 | return -ENOMEM; | ||
1381 | dch->debug = debug; | ||
1382 | mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, NULL); | ||
1383 | dch->hw = hc; | ||
1384 | if (pri) | ||
1385 | dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); | ||
1386 | else | ||
1387 | dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); | ||
1388 | dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
1389 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
1390 | dch->dev.D.send = handle_dmsg; | ||
1391 | dch->dev.D.ctrl = l1oip_dctrl; | ||
1392 | dch->dev.nrbchan = hc->b_num; | ||
1393 | dch->slot = hc->d_idx; | ||
1394 | hc->chan[hc->d_idx].dch = dch; | ||
1395 | i = 1; | ||
1396 | for (ch = 0; ch < dch->dev.nrbchan; ch++) { | ||
1397 | if (ch == 15) | ||
1398 | i++; | ||
1399 | bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); | ||
1400 | if (!bch) { | ||
1401 | printk(KERN_ERR "%s: no memory for bchannel\n", | ||
1402 | __func__); | ||
1403 | return -ENOMEM; | ||
1404 | } | ||
1405 | bch->nr = i + ch; | ||
1406 | bch->slot = i + ch; | ||
1407 | bch->debug = debug; | ||
1408 | mISDN_initbchannel(bch, MAX_DATA_MEM); | ||
1409 | bch->hw = hc; | ||
1410 | bch->ch.send = handle_bmsg; | ||
1411 | bch->ch.ctrl = l1oip_bctrl; | ||
1412 | bch->ch.nr = i + ch; | ||
1413 | list_add(&bch->ch.list, &dch->dev.bchannels); | ||
1414 | hc->chan[i + ch].bch = bch; | ||
1415 | test_and_set_bit(bch->nr & 0x1f, | ||
1416 | &dch->dev.channelmap[bch->nr >> 5]); | ||
1417 | } | ||
1418 | ret = mISDN_register_device(&dch->dev, hc->name); | ||
1419 | if (ret) | ||
1420 | return ret; | ||
1421 | hc->registered = 1; | ||
1422 | |||
1423 | if (debug & DEBUG_L1OIP_INIT) | ||
1424 | printk(KERN_DEBUG "%s: Setting up network card(%d)\n", | ||
1425 | __func__, l1oip_cnt + 1); | ||
1426 | ret = l1oip_socket_open(hc); | ||
1427 | if (ret) | ||
1428 | return ret; | ||
1429 | |||
1430 | hc->keep_tl.function = (void *)l1oip_keepalive; | ||
1431 | hc->keep_tl.data = (ulong)hc; | ||
1432 | init_timer(&hc->keep_tl); | ||
1433 | hc->keep_tl.expires = jiffies + 2*HZ; /* two seconds first time */ | ||
1434 | add_timer(&hc->keep_tl); | ||
1435 | |||
1436 | hc->timeout_tl.function = (void *)l1oip_timeout; | ||
1437 | hc->timeout_tl.data = (ulong)hc; | ||
1438 | init_timer(&hc->timeout_tl); | ||
1439 | hc->timeout_on = 0; /* state that we have timer off */ | ||
1440 | |||
1441 | return 0; | ||
1442 | } | ||
1443 | |||
1444 | static int __init | ||
1445 | l1oip_init(void) | ||
1446 | { | ||
1447 | int pri, bundle; | ||
1448 | struct l1oip *hc; | ||
1449 | int ret; | ||
1450 | |||
1451 | printk(KERN_INFO "mISDN: Layer-1-over-IP driver Rev. %s\n", | ||
1452 | l1oip_revision); | ||
1453 | |||
1454 | INIT_LIST_HEAD(&l1oip_ilist); | ||
1455 | spin_lock_init(&l1oip_lock); | ||
1456 | |||
1457 | if (l1oip_4bit_alloc(ulaw)) | ||
1458 | return -ENOMEM; | ||
1459 | |||
1460 | l1oip_cnt = 0; | ||
1461 | while (type[l1oip_cnt] && l1oip_cnt < MAX_CARDS) { | ||
1462 | switch (type[l1oip_cnt] & 0xff) { | ||
1463 | case 1: | ||
1464 | pri = 0; | ||
1465 | bundle = 0; | ||
1466 | break; | ||
1467 | case 2: | ||
1468 | pri = 1; | ||
1469 | bundle = 0; | ||
1470 | break; | ||
1471 | case 3: | ||
1472 | pri = 0; | ||
1473 | bundle = 1; | ||
1474 | break; | ||
1475 | case 4: | ||
1476 | pri = 1; | ||
1477 | bundle = 1; | ||
1478 | break; | ||
1479 | default: | ||
1480 | printk(KERN_ERR "Card type(%d) not supported.\n", | ||
1481 | type[l1oip_cnt] & 0xff); | ||
1482 | l1oip_cleanup(); | ||
1483 | return -EINVAL; | ||
1484 | } | ||
1485 | |||
1486 | if (debug & DEBUG_L1OIP_INIT) | ||
1487 | printk(KERN_DEBUG "%s: interface %d is %s with %s.\n", | ||
1488 | __func__, l1oip_cnt, pri?"PRI":"BRI", | ||
1489 | bundle?"bundled IP packet for all B-channels" | ||
1490 | :"seperate IP packets for every B-channel"); | ||
1491 | |||
1492 | hc = kzalloc(sizeof(struct l1oip), GFP_ATOMIC); | ||
1493 | if (!hc) { | ||
1494 | printk(KERN_ERR "No kmem for L1-over-IP driver.\n"); | ||
1495 | l1oip_cleanup(); | ||
1496 | return -ENOMEM; | ||
1497 | } | ||
1498 | INIT_WORK(&hc->workq, (void *)l1oip_send_bh); | ||
1499 | |||
1500 | spin_lock(&l1oip_lock); | ||
1501 | list_add_tail(&hc->list, &l1oip_ilist); | ||
1502 | spin_unlock(&l1oip_lock); | ||
1503 | |||
1504 | ret = init_card(hc, pri, bundle); | ||
1505 | if (ret) { | ||
1506 | l1oip_cleanup(); | ||
1507 | return ret; | ||
1508 | } | ||
1509 | |||
1510 | l1oip_cnt++; | ||
1511 | } | ||
1512 | printk(KERN_INFO "%d virtual devices registered\n", l1oip_cnt); | ||
1513 | return 0; | ||
1514 | } | ||
1515 | |||
1516 | module_init(l1oip_init); | ||
1517 | module_exit(l1oip_cleanup); | ||
1518 | |||
diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c new file mode 100644 index 000000000000..fced1a2755f8 --- /dev/null +++ b/drivers/isdn/mISDN/layer1.c | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/mISDNhw.h> | ||
21 | #include "layer1.h" | ||
22 | #include "fsm.h" | ||
23 | |||
24 | static int *debug; | ||
25 | |||
26 | struct layer1 { | ||
27 | u_long Flags; | ||
28 | struct FsmInst l1m; | ||
29 | struct FsmTimer timer; | ||
30 | int delay; | ||
31 | struct dchannel *dch; | ||
32 | dchannel_l1callback *dcb; | ||
33 | }; | ||
34 | |||
35 | #define TIMER3_VALUE 7000 | ||
36 | |||
37 | static | ||
38 | struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL}; | ||
39 | |||
40 | enum { | ||
41 | ST_L1_F2, | ||
42 | ST_L1_F3, | ||
43 | ST_L1_F4, | ||
44 | ST_L1_F5, | ||
45 | ST_L1_F6, | ||
46 | ST_L1_F7, | ||
47 | ST_L1_F8, | ||
48 | }; | ||
49 | |||
50 | #define L1S_STATE_COUNT (ST_L1_F8+1) | ||
51 | |||
52 | static char *strL1SState[] = | ||
53 | { | ||
54 | "ST_L1_F2", | ||
55 | "ST_L1_F3", | ||
56 | "ST_L1_F4", | ||
57 | "ST_L1_F5", | ||
58 | "ST_L1_F6", | ||
59 | "ST_L1_F7", | ||
60 | "ST_L1_F8", | ||
61 | }; | ||
62 | |||
63 | enum { | ||
64 | EV_PH_ACTIVATE, | ||
65 | EV_PH_DEACTIVATE, | ||
66 | EV_RESET_IND, | ||
67 | EV_DEACT_CNF, | ||
68 | EV_DEACT_IND, | ||
69 | EV_POWER_UP, | ||
70 | EV_ANYSIG_IND, | ||
71 | EV_INFO2_IND, | ||
72 | EV_INFO4_IND, | ||
73 | EV_TIMER_DEACT, | ||
74 | EV_TIMER_ACT, | ||
75 | EV_TIMER3, | ||
76 | }; | ||
77 | |||
78 | #define L1_EVENT_COUNT (EV_TIMER3 + 1) | ||
79 | |||
80 | static char *strL1Event[] = | ||
81 | { | ||
82 | "EV_PH_ACTIVATE", | ||
83 | "EV_PH_DEACTIVATE", | ||
84 | "EV_RESET_IND", | ||
85 | "EV_DEACT_CNF", | ||
86 | "EV_DEACT_IND", | ||
87 | "EV_POWER_UP", | ||
88 | "EV_ANYSIG_IND", | ||
89 | "EV_INFO2_IND", | ||
90 | "EV_INFO4_IND", | ||
91 | "EV_TIMER_DEACT", | ||
92 | "EV_TIMER_ACT", | ||
93 | "EV_TIMER3", | ||
94 | }; | ||
95 | |||
96 | static void | ||
97 | l1m_debug(struct FsmInst *fi, char *fmt, ...) | ||
98 | { | ||
99 | struct layer1 *l1 = fi->userdata; | ||
100 | va_list va; | ||
101 | |||
102 | va_start(va, fmt); | ||
103 | printk(KERN_DEBUG "%s: ", l1->dch->dev.name); | ||
104 | vprintk(fmt, va); | ||
105 | printk("\n"); | ||
106 | va_end(va); | ||
107 | } | ||
108 | |||
109 | static void | ||
110 | l1_reset(struct FsmInst *fi, int event, void *arg) | ||
111 | { | ||
112 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
113 | } | ||
114 | |||
115 | static void | ||
116 | l1_deact_cnf(struct FsmInst *fi, int event, void *arg) | ||
117 | { | ||
118 | struct layer1 *l1 = fi->userdata; | ||
119 | |||
120 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
121 | if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) | ||
122 | l1->dcb(l1->dch, HW_POWERUP_REQ); | ||
123 | } | ||
124 | |||
125 | static void | ||
126 | l1_deact_req_s(struct FsmInst *fi, int event, void *arg) | ||
127 | { | ||
128 | struct layer1 *l1 = fi->userdata; | ||
129 | |||
130 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
131 | mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2); | ||
132 | test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags); | ||
133 | } | ||
134 | |||
135 | static void | ||
136 | l1_power_up_s(struct FsmInst *fi, int event, void *arg) | ||
137 | { | ||
138 | struct layer1 *l1 = fi->userdata; | ||
139 | |||
140 | if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) { | ||
141 | mISDN_FsmChangeState(fi, ST_L1_F4); | ||
142 | l1->dcb(l1->dch, INFO3_P8); | ||
143 | } else | ||
144 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
145 | } | ||
146 | |||
147 | static void | ||
148 | l1_go_F5(struct FsmInst *fi, int event, void *arg) | ||
149 | { | ||
150 | mISDN_FsmChangeState(fi, ST_L1_F5); | ||
151 | } | ||
152 | |||
153 | static void | ||
154 | l1_go_F8(struct FsmInst *fi, int event, void *arg) | ||
155 | { | ||
156 | mISDN_FsmChangeState(fi, ST_L1_F8); | ||
157 | } | ||
158 | |||
159 | static void | ||
160 | l1_info2_ind(struct FsmInst *fi, int event, void *arg) | ||
161 | { | ||
162 | struct layer1 *l1 = fi->userdata; | ||
163 | |||
164 | mISDN_FsmChangeState(fi, ST_L1_F6); | ||
165 | l1->dcb(l1->dch, INFO3_P8); | ||
166 | } | ||
167 | |||
168 | static void | ||
169 | l1_info4_ind(struct FsmInst *fi, int event, void *arg) | ||
170 | { | ||
171 | struct layer1 *l1 = fi->userdata; | ||
172 | |||
173 | mISDN_FsmChangeState(fi, ST_L1_F7); | ||
174 | l1->dcb(l1->dch, INFO3_P8); | ||
175 | if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags)) | ||
176 | mISDN_FsmDelTimer(&l1->timer, 4); | ||
177 | if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) { | ||
178 | if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags)) | ||
179 | mISDN_FsmDelTimer(&l1->timer, 3); | ||
180 | mISDN_FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2); | ||
181 | test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | static void | ||
186 | l1_timer3(struct FsmInst *fi, int event, void *arg) | ||
187 | { | ||
188 | struct layer1 *l1 = fi->userdata; | ||
189 | |||
190 | test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags); | ||
191 | if (test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags)) { | ||
192 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
193 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
194 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
195 | } | ||
196 | if (l1->l1m.state != ST_L1_F6) { | ||
197 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
198 | l1->dcb(l1->dch, HW_POWERUP_REQ); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | static void | ||
203 | l1_timer_act(struct FsmInst *fi, int event, void *arg) | ||
204 | { | ||
205 | struct layer1 *l1 = fi->userdata; | ||
206 | |||
207 | test_and_clear_bit(FLG_L1_ACTTIMER, &l1->Flags); | ||
208 | test_and_set_bit(FLG_L1_ACTIVATED, &l1->Flags); | ||
209 | l1->dcb(l1->dch, PH_ACTIVATE_IND); | ||
210 | } | ||
211 | |||
212 | static void | ||
213 | l1_timer_deact(struct FsmInst *fi, int event, void *arg) | ||
214 | { | ||
215 | struct layer1 *l1 = fi->userdata; | ||
216 | |||
217 | test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags); | ||
218 | test_and_clear_bit(FLG_L1_ACTIVATED, &l1->Flags); | ||
219 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
220 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
221 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
222 | l1->dcb(l1->dch, HW_DEACT_REQ); | ||
223 | } | ||
224 | |||
225 | static void | ||
226 | l1_activate_s(struct FsmInst *fi, int event, void *arg) | ||
227 | { | ||
228 | struct layer1 *l1 = fi->userdata; | ||
229 | |||
230 | mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); | ||
231 | test_and_set_bit(FLG_L1_T3RUN, &l1->Flags); | ||
232 | l1->dcb(l1->dch, HW_RESET_REQ); | ||
233 | } | ||
234 | |||
235 | static void | ||
236 | l1_activate_no(struct FsmInst *fi, int event, void *arg) | ||
237 | { | ||
238 | struct layer1 *l1 = fi->userdata; | ||
239 | |||
240 | if ((!test_bit(FLG_L1_DEACTTIMER, &l1->Flags)) && | ||
241 | (!test_bit(FLG_L1_T3RUN, &l1->Flags))) { | ||
242 | test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags); | ||
243 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
244 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
245 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static struct FsmNode L1SFnList[] = | ||
250 | { | ||
251 | {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, | ||
252 | {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, | ||
253 | {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, | ||
254 | {ST_L1_F3, EV_RESET_IND, l1_reset}, | ||
255 | {ST_L1_F4, EV_RESET_IND, l1_reset}, | ||
256 | {ST_L1_F5, EV_RESET_IND, l1_reset}, | ||
257 | {ST_L1_F6, EV_RESET_IND, l1_reset}, | ||
258 | {ST_L1_F7, EV_RESET_IND, l1_reset}, | ||
259 | {ST_L1_F8, EV_RESET_IND, l1_reset}, | ||
260 | {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf}, | ||
261 | {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf}, | ||
262 | {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf}, | ||
263 | {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, | ||
264 | {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, | ||
265 | {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, | ||
266 | {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, | ||
267 | {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, | ||
268 | {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, | ||
269 | {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, | ||
270 | {ST_L1_F4, EV_ANYSIG_IND, l1_go_F5}, | ||
271 | {ST_L1_F6, EV_ANYSIG_IND, l1_go_F8}, | ||
272 | {ST_L1_F7, EV_ANYSIG_IND, l1_go_F8}, | ||
273 | {ST_L1_F3, EV_INFO2_IND, l1_info2_ind}, | ||
274 | {ST_L1_F4, EV_INFO2_IND, l1_info2_ind}, | ||
275 | {ST_L1_F5, EV_INFO2_IND, l1_info2_ind}, | ||
276 | {ST_L1_F7, EV_INFO2_IND, l1_info2_ind}, | ||
277 | {ST_L1_F8, EV_INFO2_IND, l1_info2_ind}, | ||
278 | {ST_L1_F3, EV_INFO4_IND, l1_info4_ind}, | ||
279 | {ST_L1_F4, EV_INFO4_IND, l1_info4_ind}, | ||
280 | {ST_L1_F5, EV_INFO4_IND, l1_info4_ind}, | ||
281 | {ST_L1_F6, EV_INFO4_IND, l1_info4_ind}, | ||
282 | {ST_L1_F8, EV_INFO4_IND, l1_info4_ind}, | ||
283 | {ST_L1_F3, EV_TIMER3, l1_timer3}, | ||
284 | {ST_L1_F4, EV_TIMER3, l1_timer3}, | ||
285 | {ST_L1_F5, EV_TIMER3, l1_timer3}, | ||
286 | {ST_L1_F6, EV_TIMER3, l1_timer3}, | ||
287 | {ST_L1_F8, EV_TIMER3, l1_timer3}, | ||
288 | {ST_L1_F7, EV_TIMER_ACT, l1_timer_act}, | ||
289 | {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact}, | ||
290 | {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact}, | ||
291 | {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact}, | ||
292 | {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact}, | ||
293 | {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact}, | ||
294 | {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, | ||
295 | }; | ||
296 | |||
297 | static void | ||
298 | release_l1(struct layer1 *l1) { | ||
299 | mISDN_FsmDelTimer(&l1->timer, 0); | ||
300 | if (l1->dch) | ||
301 | l1->dch->l1 = NULL; | ||
302 | module_put(THIS_MODULE); | ||
303 | kfree(l1); | ||
304 | } | ||
305 | |||
306 | int | ||
307 | l1_event(struct layer1 *l1, u_int event) | ||
308 | { | ||
309 | int err = 0; | ||
310 | |||
311 | if (!l1) | ||
312 | return -EINVAL; | ||
313 | switch (event) { | ||
314 | case HW_RESET_IND: | ||
315 | mISDN_FsmEvent(&l1->l1m, EV_RESET_IND, NULL); | ||
316 | break; | ||
317 | case HW_DEACT_IND: | ||
318 | mISDN_FsmEvent(&l1->l1m, EV_DEACT_IND, NULL); | ||
319 | break; | ||
320 | case HW_POWERUP_IND: | ||
321 | mISDN_FsmEvent(&l1->l1m, EV_POWER_UP, NULL); | ||
322 | break; | ||
323 | case HW_DEACT_CNF: | ||
324 | mISDN_FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL); | ||
325 | break; | ||
326 | case ANYSIGNAL: | ||
327 | mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL); | ||
328 | break; | ||
329 | case LOSTFRAMING: | ||
330 | mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL); | ||
331 | break; | ||
332 | case INFO2: | ||
333 | mISDN_FsmEvent(&l1->l1m, EV_INFO2_IND, NULL); | ||
334 | break; | ||
335 | case INFO4_P8: | ||
336 | mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL); | ||
337 | break; | ||
338 | case INFO4_P10: | ||
339 | mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL); | ||
340 | break; | ||
341 | case PH_ACTIVATE_REQ: | ||
342 | if (test_bit(FLG_L1_ACTIVATED, &l1->Flags)) | ||
343 | l1->dcb(l1->dch, PH_ACTIVATE_IND); | ||
344 | else { | ||
345 | test_and_set_bit(FLG_L1_ACTIVATING, &l1->Flags); | ||
346 | mISDN_FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL); | ||
347 | } | ||
348 | break; | ||
349 | case CLOSE_CHANNEL: | ||
350 | release_l1(l1); | ||
351 | break; | ||
352 | default: | ||
353 | if (*debug & DEBUG_L1) | ||
354 | printk(KERN_DEBUG "%s %x unhandled\n", | ||
355 | __func__, event); | ||
356 | err = -EINVAL; | ||
357 | } | ||
358 | return err; | ||
359 | } | ||
360 | EXPORT_SYMBOL(l1_event); | ||
361 | |||
362 | int | ||
363 | create_l1(struct dchannel *dch, dchannel_l1callback *dcb) { | ||
364 | struct layer1 *nl1; | ||
365 | |||
366 | nl1 = kzalloc(sizeof(struct layer1), GFP_ATOMIC); | ||
367 | if (!nl1) { | ||
368 | printk(KERN_ERR "kmalloc struct layer1 failed\n"); | ||
369 | return -ENOMEM; | ||
370 | } | ||
371 | nl1->l1m.fsm = &l1fsm_s; | ||
372 | nl1->l1m.state = ST_L1_F3; | ||
373 | nl1->Flags = 0; | ||
374 | nl1->l1m.debug = *debug & DEBUG_L1_FSM; | ||
375 | nl1->l1m.userdata = nl1; | ||
376 | nl1->l1m.userint = 0; | ||
377 | nl1->l1m.printdebug = l1m_debug; | ||
378 | nl1->dch = dch; | ||
379 | nl1->dcb = dcb; | ||
380 | mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer); | ||
381 | __module_get(THIS_MODULE); | ||
382 | dch->l1 = nl1; | ||
383 | return 0; | ||
384 | } | ||
385 | EXPORT_SYMBOL(create_l1); | ||
386 | |||
387 | int | ||
388 | l1_init(u_int *deb) | ||
389 | { | ||
390 | debug = deb; | ||
391 | l1fsm_s.state_count = L1S_STATE_COUNT; | ||
392 | l1fsm_s.event_count = L1_EVENT_COUNT; | ||
393 | l1fsm_s.strEvent = strL1Event; | ||
394 | l1fsm_s.strState = strL1SState; | ||
395 | mISDN_FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList)); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | void | ||
400 | l1_cleanup(void) | ||
401 | { | ||
402 | mISDN_FsmFree(&l1fsm_s); | ||
403 | } | ||
diff --git a/drivers/isdn/mISDN/layer1.h b/drivers/isdn/mISDN/layer1.h new file mode 100644 index 000000000000..9c8125fd89af --- /dev/null +++ b/drivers/isdn/mISDN/layer1.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Layer 1 defines | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #define FLG_L1_ACTIVATING 1 | ||
19 | #define FLG_L1_ACTIVATED 2 | ||
20 | #define FLG_L1_DEACTTIMER 3 | ||
21 | #define FLG_L1_ACTTIMER 4 | ||
22 | #define FLG_L1_T3RUN 5 | ||
23 | #define FLG_L1_PULL_REQ 6 | ||
24 | #define FLG_L1_UINT 7 | ||
25 | #define FLG_L1_DBLOCKED 8 | ||
26 | |||
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c new file mode 100644 index 000000000000..f5ad888ee71e --- /dev/null +++ b/drivers/isdn/mISDN/layer2.c | |||
@@ -0,0 +1,2216 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include "fsm.h" | ||
19 | #include "layer2.h" | ||
20 | |||
21 | static int *debug; | ||
22 | |||
23 | static | ||
24 | struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL}; | ||
25 | |||
26 | static char *strL2State[] = | ||
27 | { | ||
28 | "ST_L2_1", | ||
29 | "ST_L2_2", | ||
30 | "ST_L2_3", | ||
31 | "ST_L2_4", | ||
32 | "ST_L2_5", | ||
33 | "ST_L2_6", | ||
34 | "ST_L2_7", | ||
35 | "ST_L2_8", | ||
36 | }; | ||
37 | |||
38 | enum { | ||
39 | EV_L2_UI, | ||
40 | EV_L2_SABME, | ||
41 | EV_L2_DISC, | ||
42 | EV_L2_DM, | ||
43 | EV_L2_UA, | ||
44 | EV_L2_FRMR, | ||
45 | EV_L2_SUPER, | ||
46 | EV_L2_I, | ||
47 | EV_L2_DL_DATA, | ||
48 | EV_L2_ACK_PULL, | ||
49 | EV_L2_DL_UNITDATA, | ||
50 | EV_L2_DL_ESTABLISH_REQ, | ||
51 | EV_L2_DL_RELEASE_REQ, | ||
52 | EV_L2_MDL_ASSIGN, | ||
53 | EV_L2_MDL_REMOVE, | ||
54 | EV_L2_MDL_ERROR, | ||
55 | EV_L1_DEACTIVATE, | ||
56 | EV_L2_T200, | ||
57 | EV_L2_T203, | ||
58 | EV_L2_SET_OWN_BUSY, | ||
59 | EV_L2_CLEAR_OWN_BUSY, | ||
60 | EV_L2_FRAME_ERROR, | ||
61 | }; | ||
62 | |||
63 | #define L2_EVENT_COUNT (EV_L2_FRAME_ERROR+1) | ||
64 | |||
65 | static char *strL2Event[] = | ||
66 | { | ||
67 | "EV_L2_UI", | ||
68 | "EV_L2_SABME", | ||
69 | "EV_L2_DISC", | ||
70 | "EV_L2_DM", | ||
71 | "EV_L2_UA", | ||
72 | "EV_L2_FRMR", | ||
73 | "EV_L2_SUPER", | ||
74 | "EV_L2_I", | ||
75 | "EV_L2_DL_DATA", | ||
76 | "EV_L2_ACK_PULL", | ||
77 | "EV_L2_DL_UNITDATA", | ||
78 | "EV_L2_DL_ESTABLISH_REQ", | ||
79 | "EV_L2_DL_RELEASE_REQ", | ||
80 | "EV_L2_MDL_ASSIGN", | ||
81 | "EV_L2_MDL_REMOVE", | ||
82 | "EV_L2_MDL_ERROR", | ||
83 | "EV_L1_DEACTIVATE", | ||
84 | "EV_L2_T200", | ||
85 | "EV_L2_T203", | ||
86 | "EV_L2_SET_OWN_BUSY", | ||
87 | "EV_L2_CLEAR_OWN_BUSY", | ||
88 | "EV_L2_FRAME_ERROR", | ||
89 | }; | ||
90 | |||
91 | static void | ||
92 | l2m_debug(struct FsmInst *fi, char *fmt, ...) | ||
93 | { | ||
94 | struct layer2 *l2 = fi->userdata; | ||
95 | va_list va; | ||
96 | |||
97 | if (!(*debug & DEBUG_L2_FSM)) | ||
98 | return; | ||
99 | va_start(va, fmt); | ||
100 | printk(KERN_DEBUG "l2 (tei %d): ", l2->tei); | ||
101 | vprintk(fmt, va); | ||
102 | printk("\n"); | ||
103 | va_end(va); | ||
104 | } | ||
105 | |||
106 | inline u_int | ||
107 | l2headersize(struct layer2 *l2, int ui) | ||
108 | { | ||
109 | return ((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) + | ||
110 | (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1); | ||
111 | } | ||
112 | |||
113 | inline u_int | ||
114 | l2addrsize(struct layer2 *l2) | ||
115 | { | ||
116 | return test_bit(FLG_LAPD, &l2->flag) ? 2 : 1; | ||
117 | } | ||
118 | |||
119 | static u_int | ||
120 | l2_newid(struct layer2 *l2) | ||
121 | { | ||
122 | u_int id; | ||
123 | |||
124 | id = l2->next_id++; | ||
125 | if (id == 0x7fff) | ||
126 | l2->next_id = 1; | ||
127 | id <<= 16; | ||
128 | id |= l2->tei << 8; | ||
129 | id |= l2->sapi; | ||
130 | return id; | ||
131 | } | ||
132 | |||
133 | static void | ||
134 | l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb) | ||
135 | { | ||
136 | int err; | ||
137 | |||
138 | if (!l2->up) | ||
139 | return; | ||
140 | mISDN_HEAD_PRIM(skb) = prim; | ||
141 | mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr; | ||
142 | err = l2->up->send(l2->up, skb); | ||
143 | if (err) { | ||
144 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
145 | dev_kfree_skb(skb); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void | ||
150 | l2up_create(struct layer2 *l2, u_int prim, int len, void *arg) | ||
151 | { | ||
152 | struct sk_buff *skb; | ||
153 | struct mISDNhead *hh; | ||
154 | int err; | ||
155 | |||
156 | if (!l2->up) | ||
157 | return; | ||
158 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
159 | if (!skb) | ||
160 | return; | ||
161 | hh = mISDN_HEAD_P(skb); | ||
162 | hh->prim = prim; | ||
163 | hh->id = (l2->ch.nr << 16) | l2->ch.addr; | ||
164 | if (len) | ||
165 | memcpy(skb_put(skb, len), arg, len); | ||
166 | err = l2->up->send(l2->up, skb); | ||
167 | if (err) { | ||
168 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
169 | dev_kfree_skb(skb); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | static int | ||
174 | l2down_skb(struct layer2 *l2, struct sk_buff *skb) { | ||
175 | int ret; | ||
176 | |||
177 | ret = l2->ch.recv(l2->ch.peer, skb); | ||
178 | if (ret && (*debug & DEBUG_L2_RECV)) | ||
179 | printk(KERN_DEBUG "l2down_skb: ret(%d)\n", ret); | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | static int | ||
184 | l2down_raw(struct layer2 *l2, struct sk_buff *skb) | ||
185 | { | ||
186 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
187 | |||
188 | if (hh->prim == PH_DATA_REQ) { | ||
189 | if (test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
190 | skb_queue_tail(&l2->down_queue, skb); | ||
191 | return 0; | ||
192 | } | ||
193 | l2->down_id = mISDN_HEAD_ID(skb); | ||
194 | } | ||
195 | return l2down_skb(l2, skb); | ||
196 | } | ||
197 | |||
198 | static int | ||
199 | l2down(struct layer2 *l2, u_int prim, u_int id, struct sk_buff *skb) | ||
200 | { | ||
201 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
202 | |||
203 | hh->prim = prim; | ||
204 | hh->id = id; | ||
205 | return l2down_raw(l2, skb); | ||
206 | } | ||
207 | |||
208 | static int | ||
209 | l2down_create(struct layer2 *l2, u_int prim, u_int id, int len, void *arg) | ||
210 | { | ||
211 | struct sk_buff *skb; | ||
212 | int err; | ||
213 | struct mISDNhead *hh; | ||
214 | |||
215 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
216 | if (!skb) | ||
217 | return -ENOMEM; | ||
218 | hh = mISDN_HEAD_P(skb); | ||
219 | hh->prim = prim; | ||
220 | hh->id = id; | ||
221 | if (len) | ||
222 | memcpy(skb_put(skb, len), arg, len); | ||
223 | err = l2down_raw(l2, skb); | ||
224 | if (err) | ||
225 | dev_kfree_skb(skb); | ||
226 | return err; | ||
227 | } | ||
228 | |||
229 | static int | ||
230 | ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) { | ||
231 | struct sk_buff *nskb = skb; | ||
232 | int ret = -EAGAIN; | ||
233 | |||
234 | if (test_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
235 | if (hh->id == l2->down_id) { | ||
236 | nskb = skb_dequeue(&l2->down_queue); | ||
237 | if (nskb) { | ||
238 | l2->down_id = mISDN_HEAD_ID(nskb); | ||
239 | if (l2down_skb(l2, nskb)) { | ||
240 | dev_kfree_skb(nskb); | ||
241 | l2->down_id = MISDN_ID_NONE; | ||
242 | } | ||
243 | } else | ||
244 | l2->down_id = MISDN_ID_NONE; | ||
245 | if (ret) { | ||
246 | dev_kfree_skb(skb); | ||
247 | ret = 0; | ||
248 | } | ||
249 | if (l2->down_id == MISDN_ID_NONE) { | ||
250 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
251 | mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | if (!test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
256 | nskb = skb_dequeue(&l2->down_queue); | ||
257 | if (nskb) { | ||
258 | l2->down_id = mISDN_HEAD_ID(nskb); | ||
259 | if (l2down_skb(l2, nskb)) { | ||
260 | dev_kfree_skb(nskb); | ||
261 | l2->down_id = MISDN_ID_NONE; | ||
262 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
263 | } | ||
264 | } else | ||
265 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
266 | } | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | static int | ||
271 | l2mgr(struct layer2 *l2, u_int prim, void *arg) { | ||
272 | long c = (long)arg; | ||
273 | |||
274 | printk(KERN_WARNING | ||
275 | "l2mgr: addr:%x prim %x %c\n", l2->id, prim, (char)c); | ||
276 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
277 | !test_bit(FLG_FIXED_TEI, &l2->flag)) { | ||
278 | switch (c) { | ||
279 | case 'C': | ||
280 | case 'D': | ||
281 | case 'G': | ||
282 | case 'H': | ||
283 | l2_tei(l2, prim, (u_long)arg); | ||
284 | break; | ||
285 | } | ||
286 | } | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static void | ||
291 | set_peer_busy(struct layer2 *l2) { | ||
292 | test_and_set_bit(FLG_PEER_BUSY, &l2->flag); | ||
293 | if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue)) | ||
294 | test_and_set_bit(FLG_L2BLOCK, &l2->flag); | ||
295 | } | ||
296 | |||
297 | static void | ||
298 | clear_peer_busy(struct layer2 *l2) { | ||
299 | if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag)) | ||
300 | test_and_clear_bit(FLG_L2BLOCK, &l2->flag); | ||
301 | } | ||
302 | |||
303 | static void | ||
304 | InitWin(struct layer2 *l2) | ||
305 | { | ||
306 | int i; | ||
307 | |||
308 | for (i = 0; i < MAX_WINDOW; i++) | ||
309 | l2->windowar[i] = NULL; | ||
310 | } | ||
311 | |||
312 | static int | ||
313 | freewin(struct layer2 *l2) | ||
314 | { | ||
315 | int i, cnt = 0; | ||
316 | |||
317 | for (i = 0; i < MAX_WINDOW; i++) { | ||
318 | if (l2->windowar[i]) { | ||
319 | cnt++; | ||
320 | dev_kfree_skb(l2->windowar[i]); | ||
321 | l2->windowar[i] = NULL; | ||
322 | } | ||
323 | } | ||
324 | return cnt; | ||
325 | } | ||
326 | |||
327 | static void | ||
328 | ReleaseWin(struct layer2 *l2) | ||
329 | { | ||
330 | int cnt = freewin(l2); | ||
331 | |||
332 | if (cnt) | ||
333 | printk(KERN_WARNING | ||
334 | "isdnl2 freed %d skbuffs in release\n", cnt); | ||
335 | } | ||
336 | |||
337 | inline unsigned int | ||
338 | cansend(struct layer2 *l2) | ||
339 | { | ||
340 | unsigned int p1; | ||
341 | |||
342 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
343 | p1 = (l2->vs - l2->va) % 128; | ||
344 | else | ||
345 | p1 = (l2->vs - l2->va) % 8; | ||
346 | return (p1 < l2->window) && !test_bit(FLG_PEER_BUSY, &l2->flag); | ||
347 | } | ||
348 | |||
349 | inline void | ||
350 | clear_exception(struct layer2 *l2) | ||
351 | { | ||
352 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
353 | test_and_clear_bit(FLG_REJEXC, &l2->flag); | ||
354 | test_and_clear_bit(FLG_OWN_BUSY, &l2->flag); | ||
355 | clear_peer_busy(l2); | ||
356 | } | ||
357 | |||
358 | static int | ||
359 | sethdraddr(struct layer2 *l2, u_char *header, int rsp) | ||
360 | { | ||
361 | u_char *ptr = header; | ||
362 | int crbit = rsp; | ||
363 | |||
364 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
365 | if (test_bit(FLG_LAPD_NET, &l2->flag)) | ||
366 | crbit = !crbit; | ||
367 | *ptr++ = (l2->sapi << 2) | (crbit ? 2 : 0); | ||
368 | *ptr++ = (l2->tei << 1) | 1; | ||
369 | return 2; | ||
370 | } else { | ||
371 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
372 | crbit = !crbit; | ||
373 | if (crbit) | ||
374 | *ptr++ = l2->addr.B; | ||
375 | else | ||
376 | *ptr++ = l2->addr.A; | ||
377 | return 1; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | static inline void | ||
382 | enqueue_super(struct layer2 *l2, struct sk_buff *skb) | ||
383 | { | ||
384 | if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb)) | ||
385 | dev_kfree_skb(skb); | ||
386 | } | ||
387 | |||
388 | static inline void | ||
389 | enqueue_ui(struct layer2 *l2, struct sk_buff *skb) | ||
390 | { | ||
391 | if (l2->tm) | ||
392 | l2_tei(l2, MDL_STATUS_UI_IND, 0); | ||
393 | if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb)) | ||
394 | dev_kfree_skb(skb); | ||
395 | } | ||
396 | |||
397 | inline int | ||
398 | IsUI(u_char *data) | ||
399 | { | ||
400 | return (data[0] & 0xef) == UI; | ||
401 | } | ||
402 | |||
403 | inline int | ||
404 | IsUA(u_char *data) | ||
405 | { | ||
406 | return (data[0] & 0xef) == UA; | ||
407 | } | ||
408 | |||
409 | inline int | ||
410 | IsDM(u_char *data) | ||
411 | { | ||
412 | return (data[0] & 0xef) == DM; | ||
413 | } | ||
414 | |||
415 | inline int | ||
416 | IsDISC(u_char *data) | ||
417 | { | ||
418 | return (data[0] & 0xef) == DISC; | ||
419 | } | ||
420 | |||
421 | inline int | ||
422 | IsRR(u_char *data, struct layer2 *l2) | ||
423 | { | ||
424 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
425 | return data[0] == RR; | ||
426 | else | ||
427 | return (data[0] & 0xf) == 1; | ||
428 | } | ||
429 | |||
430 | inline int | ||
431 | IsSFrame(u_char *data, struct layer2 *l2) | ||
432 | { | ||
433 | register u_char d = *data; | ||
434 | |||
435 | if (!test_bit(FLG_MOD128, &l2->flag)) | ||
436 | d &= 0xf; | ||
437 | return ((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c); | ||
438 | } | ||
439 | |||
440 | inline int | ||
441 | IsSABME(u_char *data, struct layer2 *l2) | ||
442 | { | ||
443 | u_char d = data[0] & ~0x10; | ||
444 | |||
445 | return test_bit(FLG_MOD128, &l2->flag) ? d == SABME : d == SABM; | ||
446 | } | ||
447 | |||
448 | inline int | ||
449 | IsREJ(u_char *data, struct layer2 *l2) | ||
450 | { | ||
451 | return test_bit(FLG_MOD128, &l2->flag) ? | ||
452 | data[0] == REJ : (data[0] & 0xf) == REJ; | ||
453 | } | ||
454 | |||
455 | inline int | ||
456 | IsFRMR(u_char *data) | ||
457 | { | ||
458 | return (data[0] & 0xef) == FRMR; | ||
459 | } | ||
460 | |||
461 | inline int | ||
462 | IsRNR(u_char *data, struct layer2 *l2) | ||
463 | { | ||
464 | return test_bit(FLG_MOD128, &l2->flag) ? | ||
465 | data[0] == RNR : (data[0] & 0xf) == RNR; | ||
466 | } | ||
467 | |||
468 | int | ||
469 | iframe_error(struct layer2 *l2, struct sk_buff *skb) | ||
470 | { | ||
471 | u_int i; | ||
472 | int rsp = *skb->data & 0x2; | ||
473 | |||
474 | i = l2addrsize(l2) + (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1); | ||
475 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
476 | rsp = !rsp; | ||
477 | if (rsp) | ||
478 | return 'L'; | ||
479 | if (skb->len < i) | ||
480 | return 'N'; | ||
481 | if ((skb->len - i) > l2->maxlen) | ||
482 | return 'O'; | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | int | ||
487 | super_error(struct layer2 *l2, struct sk_buff *skb) | ||
488 | { | ||
489 | if (skb->len != l2addrsize(l2) + | ||
490 | (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1)) | ||
491 | return 'N'; | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | int | ||
496 | unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp) | ||
497 | { | ||
498 | int rsp = (*skb->data & 0x2) >> 1; | ||
499 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
500 | rsp = !rsp; | ||
501 | if (rsp != wantrsp) | ||
502 | return 'L'; | ||
503 | if (skb->len != l2addrsize(l2) + 1) | ||
504 | return 'N'; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | int | ||
509 | UI_error(struct layer2 *l2, struct sk_buff *skb) | ||
510 | { | ||
511 | int rsp = *skb->data & 0x2; | ||
512 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
513 | rsp = !rsp; | ||
514 | if (rsp) | ||
515 | return 'L'; | ||
516 | if (skb->len > l2->maxlen + l2addrsize(l2) + 1) | ||
517 | return 'O'; | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | int | ||
522 | FRMR_error(struct layer2 *l2, struct sk_buff *skb) | ||
523 | { | ||
524 | u_int headers = l2addrsize(l2) + 1; | ||
525 | u_char *datap = skb->data + headers; | ||
526 | int rsp = *skb->data & 0x2; | ||
527 | |||
528 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
529 | rsp = !rsp; | ||
530 | if (!rsp) | ||
531 | return 'L'; | ||
532 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
533 | if (skb->len < headers + 5) | ||
534 | return 'N'; | ||
535 | else if (*debug & DEBUG_L2) | ||
536 | l2m_debug(&l2->l2m, | ||
537 | "FRMR information %2x %2x %2x %2x %2x", | ||
538 | datap[0], datap[1], datap[2], datap[3], datap[4]); | ||
539 | } else { | ||
540 | if (skb->len < headers + 3) | ||
541 | return 'N'; | ||
542 | else if (*debug & DEBUG_L2) | ||
543 | l2m_debug(&l2->l2m, | ||
544 | "FRMR information %2x %2x %2x", | ||
545 | datap[0], datap[1], datap[2]); | ||
546 | } | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static unsigned int | ||
551 | legalnr(struct layer2 *l2, unsigned int nr) | ||
552 | { | ||
553 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
554 | return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128); | ||
555 | else | ||
556 | return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8); | ||
557 | } | ||
558 | |||
559 | static void | ||
560 | setva(struct layer2 *l2, unsigned int nr) | ||
561 | { | ||
562 | struct sk_buff *skb; | ||
563 | |||
564 | while (l2->va != nr) { | ||
565 | l2->va++; | ||
566 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
567 | l2->va %= 128; | ||
568 | else | ||
569 | l2->va %= 8; | ||
570 | if (l2->windowar[l2->sow]) { | ||
571 | skb_trim(l2->windowar[l2->sow], 0); | ||
572 | skb_queue_tail(&l2->tmp_queue, l2->windowar[l2->sow]); | ||
573 | l2->windowar[l2->sow] = NULL; | ||
574 | } | ||
575 | l2->sow = (l2->sow + 1) % l2->window; | ||
576 | } | ||
577 | skb = skb_dequeue(&l2->tmp_queue); | ||
578 | while (skb) { | ||
579 | dev_kfree_skb(skb); | ||
580 | skb = skb_dequeue(&l2->tmp_queue); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | static void | ||
585 | send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr) | ||
586 | { | ||
587 | u_char tmp[MAX_L2HEADER_LEN]; | ||
588 | int i; | ||
589 | |||
590 | i = sethdraddr(l2, tmp, cr); | ||
591 | tmp[i++] = cmd; | ||
592 | if (skb) | ||
593 | skb_trim(skb, 0); | ||
594 | else { | ||
595 | skb = mI_alloc_skb(i, GFP_ATOMIC); | ||
596 | if (!skb) { | ||
597 | printk(KERN_WARNING "%s: can't alloc skbuff\n", | ||
598 | __func__); | ||
599 | return; | ||
600 | } | ||
601 | } | ||
602 | memcpy(skb_put(skb, i), tmp, i); | ||
603 | enqueue_super(l2, skb); | ||
604 | } | ||
605 | |||
606 | |||
607 | inline u_char | ||
608 | get_PollFlag(struct layer2 *l2, struct sk_buff *skb) | ||
609 | { | ||
610 | return skb->data[l2addrsize(l2)] & 0x10; | ||
611 | } | ||
612 | |||
613 | inline u_char | ||
614 | get_PollFlagFree(struct layer2 *l2, struct sk_buff *skb) | ||
615 | { | ||
616 | u_char PF; | ||
617 | |||
618 | PF = get_PollFlag(l2, skb); | ||
619 | dev_kfree_skb(skb); | ||
620 | return PF; | ||
621 | } | ||
622 | |||
623 | inline void | ||
624 | start_t200(struct layer2 *l2, int i) | ||
625 | { | ||
626 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i); | ||
627 | test_and_set_bit(FLG_T200_RUN, &l2->flag); | ||
628 | } | ||
629 | |||
630 | inline void | ||
631 | restart_t200(struct layer2 *l2, int i) | ||
632 | { | ||
633 | mISDN_FsmRestartTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i); | ||
634 | test_and_set_bit(FLG_T200_RUN, &l2->flag); | ||
635 | } | ||
636 | |||
637 | inline void | ||
638 | stop_t200(struct layer2 *l2, int i) | ||
639 | { | ||
640 | if (test_and_clear_bit(FLG_T200_RUN, &l2->flag)) | ||
641 | mISDN_FsmDelTimer(&l2->t200, i); | ||
642 | } | ||
643 | |||
644 | inline void | ||
645 | st5_dl_release_l2l3(struct layer2 *l2) | ||
646 | { | ||
647 | int pr; | ||
648 | |||
649 | if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) | ||
650 | pr = DL_RELEASE_CNF; | ||
651 | else | ||
652 | pr = DL_RELEASE_IND; | ||
653 | l2up_create(l2, pr, 0, NULL); | ||
654 | } | ||
655 | |||
656 | inline void | ||
657 | lapb_dl_release_l2l3(struct layer2 *l2, int f) | ||
658 | { | ||
659 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
660 | l2down_create(l2, PH_DEACTIVATE_REQ, l2_newid(l2), 0, NULL); | ||
661 | l2up_create(l2, f, 0, NULL); | ||
662 | } | ||
663 | |||
664 | static void | ||
665 | establishlink(struct FsmInst *fi) | ||
666 | { | ||
667 | struct layer2 *l2 = fi->userdata; | ||
668 | u_char cmd; | ||
669 | |||
670 | clear_exception(l2); | ||
671 | l2->rc = 0; | ||
672 | cmd = (test_bit(FLG_MOD128, &l2->flag) ? SABME : SABM) | 0x10; | ||
673 | send_uframe(l2, NULL, cmd, CMD); | ||
674 | mISDN_FsmDelTimer(&l2->t203, 1); | ||
675 | restart_t200(l2, 1); | ||
676 | test_and_clear_bit(FLG_PEND_REL, &l2->flag); | ||
677 | freewin(l2); | ||
678 | mISDN_FsmChangeState(fi, ST_L2_5); | ||
679 | } | ||
680 | |||
681 | static void | ||
682 | l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg) | ||
683 | { | ||
684 | struct sk_buff *skb = arg; | ||
685 | struct layer2 *l2 = fi->userdata; | ||
686 | |||
687 | if (get_PollFlagFree(l2, skb)) | ||
688 | l2mgr(l2, MDL_ERROR_IND, (void *) 'C'); | ||
689 | else | ||
690 | l2mgr(l2, MDL_ERROR_IND, (void *) 'D'); | ||
691 | |||
692 | } | ||
693 | |||
694 | static void | ||
695 | l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg) | ||
696 | { | ||
697 | struct sk_buff *skb = arg; | ||
698 | struct layer2 *l2 = fi->userdata; | ||
699 | |||
700 | if (get_PollFlagFree(l2, skb)) | ||
701 | l2mgr(l2, MDL_ERROR_IND, (void *) 'B'); | ||
702 | else { | ||
703 | l2mgr(l2, MDL_ERROR_IND, (void *) 'E'); | ||
704 | establishlink(fi); | ||
705 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
706 | } | ||
707 | } | ||
708 | |||
709 | static void | ||
710 | l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg) | ||
711 | { | ||
712 | struct sk_buff *skb = arg; | ||
713 | struct layer2 *l2 = fi->userdata; | ||
714 | |||
715 | if (get_PollFlagFree(l2, skb)) | ||
716 | l2mgr(l2, MDL_ERROR_IND, (void *) 'B'); | ||
717 | else | ||
718 | l2mgr(l2, MDL_ERROR_IND, (void *) 'E'); | ||
719 | establishlink(fi); | ||
720 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
721 | } | ||
722 | |||
723 | static void | ||
724 | l2_go_st3(struct FsmInst *fi, int event, void *arg) | ||
725 | { | ||
726 | dev_kfree_skb((struct sk_buff *)arg); | ||
727 | mISDN_FsmChangeState(fi, ST_L2_3); | ||
728 | } | ||
729 | |||
730 | static void | ||
731 | l2_mdl_assign(struct FsmInst *fi, int event, void *arg) | ||
732 | { | ||
733 | struct layer2 *l2 = fi->userdata; | ||
734 | |||
735 | mISDN_FsmChangeState(fi, ST_L2_3); | ||
736 | dev_kfree_skb((struct sk_buff *)arg); | ||
737 | l2_tei(l2, MDL_ASSIGN_IND, 0); | ||
738 | } | ||
739 | |||
740 | static void | ||
741 | l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg) | ||
742 | { | ||
743 | struct layer2 *l2 = fi->userdata; | ||
744 | struct sk_buff *skb = arg; | ||
745 | |||
746 | skb_queue_tail(&l2->ui_queue, skb); | ||
747 | mISDN_FsmChangeState(fi, ST_L2_2); | ||
748 | l2_tei(l2, MDL_ASSIGN_IND, 0); | ||
749 | } | ||
750 | |||
751 | static void | ||
752 | l2_queue_ui(struct FsmInst *fi, int event, void *arg) | ||
753 | { | ||
754 | struct layer2 *l2 = fi->userdata; | ||
755 | struct sk_buff *skb = arg; | ||
756 | |||
757 | skb_queue_tail(&l2->ui_queue, skb); | ||
758 | } | ||
759 | |||
760 | static void | ||
761 | tx_ui(struct layer2 *l2) | ||
762 | { | ||
763 | struct sk_buff *skb; | ||
764 | u_char header[MAX_L2HEADER_LEN]; | ||
765 | int i; | ||
766 | |||
767 | i = sethdraddr(l2, header, CMD); | ||
768 | if (test_bit(FLG_LAPD_NET, &l2->flag)) | ||
769 | header[1] = 0xff; /* tei 127 */ | ||
770 | header[i++] = UI; | ||
771 | while ((skb = skb_dequeue(&l2->ui_queue))) { | ||
772 | memcpy(skb_push(skb, i), header, i); | ||
773 | enqueue_ui(l2, skb); | ||
774 | } | ||
775 | } | ||
776 | |||
777 | static void | ||
778 | l2_send_ui(struct FsmInst *fi, int event, void *arg) | ||
779 | { | ||
780 | struct layer2 *l2 = fi->userdata; | ||
781 | struct sk_buff *skb = arg; | ||
782 | |||
783 | skb_queue_tail(&l2->ui_queue, skb); | ||
784 | tx_ui(l2); | ||
785 | } | ||
786 | |||
787 | static void | ||
788 | l2_got_ui(struct FsmInst *fi, int event, void *arg) | ||
789 | { | ||
790 | struct layer2 *l2 = fi->userdata; | ||
791 | struct sk_buff *skb = arg; | ||
792 | |||
793 | skb_pull(skb, l2headersize(l2, 1)); | ||
794 | /* | ||
795 | * in states 1-3 for broadcast | ||
796 | */ | ||
797 | |||
798 | if (l2->tm) | ||
799 | l2_tei(l2, MDL_STATUS_UI_IND, 0); | ||
800 | l2up(l2, DL_UNITDATA_IND, skb); | ||
801 | } | ||
802 | |||
803 | static void | ||
804 | l2_establish(struct FsmInst *fi, int event, void *arg) | ||
805 | { | ||
806 | struct sk_buff *skb = arg; | ||
807 | struct layer2 *l2 = fi->userdata; | ||
808 | |||
809 | establishlink(fi); | ||
810 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
811 | dev_kfree_skb(skb); | ||
812 | } | ||
813 | |||
814 | static void | ||
815 | l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg) | ||
816 | { | ||
817 | struct sk_buff *skb = arg; | ||
818 | struct layer2 *l2 = fi->userdata; | ||
819 | |||
820 | skb_queue_purge(&l2->i_queue); | ||
821 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
822 | test_and_clear_bit(FLG_PEND_REL, &l2->flag); | ||
823 | dev_kfree_skb(skb); | ||
824 | } | ||
825 | |||
826 | static void | ||
827 | l2_l3_reestablish(struct FsmInst *fi, int event, void *arg) | ||
828 | { | ||
829 | struct sk_buff *skb = arg; | ||
830 | struct layer2 *l2 = fi->userdata; | ||
831 | |||
832 | skb_queue_purge(&l2->i_queue); | ||
833 | establishlink(fi); | ||
834 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
835 | dev_kfree_skb(skb); | ||
836 | } | ||
837 | |||
838 | static void | ||
839 | l2_release(struct FsmInst *fi, int event, void *arg) | ||
840 | { | ||
841 | struct layer2 *l2 = fi->userdata; | ||
842 | struct sk_buff *skb = arg; | ||
843 | |||
844 | skb_trim(skb, 0); | ||
845 | l2up(l2, DL_RELEASE_CNF, skb); | ||
846 | } | ||
847 | |||
848 | static void | ||
849 | l2_pend_rel(struct FsmInst *fi, int event, void *arg) | ||
850 | { | ||
851 | struct sk_buff *skb = arg; | ||
852 | struct layer2 *l2 = fi->userdata; | ||
853 | |||
854 | test_and_set_bit(FLG_PEND_REL, &l2->flag); | ||
855 | dev_kfree_skb(skb); | ||
856 | } | ||
857 | |||
858 | static void | ||
859 | l2_disconnect(struct FsmInst *fi, int event, void *arg) | ||
860 | { | ||
861 | struct layer2 *l2 = fi->userdata; | ||
862 | struct sk_buff *skb = arg; | ||
863 | |||
864 | skb_queue_purge(&l2->i_queue); | ||
865 | freewin(l2); | ||
866 | mISDN_FsmChangeState(fi, ST_L2_6); | ||
867 | l2->rc = 0; | ||
868 | send_uframe(l2, NULL, DISC | 0x10, CMD); | ||
869 | mISDN_FsmDelTimer(&l2->t203, 1); | ||
870 | restart_t200(l2, 2); | ||
871 | if (skb) | ||
872 | dev_kfree_skb(skb); | ||
873 | } | ||
874 | |||
875 | static void | ||
876 | l2_start_multi(struct FsmInst *fi, int event, void *arg) | ||
877 | { | ||
878 | struct layer2 *l2 = fi->userdata; | ||
879 | struct sk_buff *skb = arg; | ||
880 | |||
881 | l2->vs = 0; | ||
882 | l2->va = 0; | ||
883 | l2->vr = 0; | ||
884 | l2->sow = 0; | ||
885 | clear_exception(l2); | ||
886 | send_uframe(l2, NULL, UA | get_PollFlag(l2, skb), RSP); | ||
887 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
888 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3); | ||
889 | skb_trim(skb, 0); | ||
890 | l2up(l2, DL_ESTABLISH_IND, skb); | ||
891 | if (l2->tm) | ||
892 | l2_tei(l2, MDL_STATUS_UP_IND, 0); | ||
893 | } | ||
894 | |||
895 | static void | ||
896 | l2_send_UA(struct FsmInst *fi, int event, void *arg) | ||
897 | { | ||
898 | struct layer2 *l2 = fi->userdata; | ||
899 | struct sk_buff *skb = arg; | ||
900 | |||
901 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
902 | } | ||
903 | |||
904 | static void | ||
905 | l2_send_DM(struct FsmInst *fi, int event, void *arg) | ||
906 | { | ||
907 | struct layer2 *l2 = fi->userdata; | ||
908 | struct sk_buff *skb = arg; | ||
909 | |||
910 | send_uframe(l2, skb, DM | get_PollFlag(l2, skb), RSP); | ||
911 | } | ||
912 | |||
913 | static void | ||
914 | l2_restart_multi(struct FsmInst *fi, int event, void *arg) | ||
915 | { | ||
916 | struct layer2 *l2 = fi->userdata; | ||
917 | struct sk_buff *skb = arg; | ||
918 | int est = 0; | ||
919 | |||
920 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
921 | |||
922 | l2mgr(l2, MDL_ERROR_IND, (void *) 'F'); | ||
923 | |||
924 | if (l2->vs != l2->va) { | ||
925 | skb_queue_purge(&l2->i_queue); | ||
926 | est = 1; | ||
927 | } | ||
928 | |||
929 | clear_exception(l2); | ||
930 | l2->vs = 0; | ||
931 | l2->va = 0; | ||
932 | l2->vr = 0; | ||
933 | l2->sow = 0; | ||
934 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
935 | stop_t200(l2, 3); | ||
936 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3); | ||
937 | |||
938 | if (est) | ||
939 | l2up_create(l2, DL_ESTABLISH_IND, 0, NULL); | ||
940 | /* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST, | ||
941 | * MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED, | ||
942 | * 0, NULL, 0); | ||
943 | */ | ||
944 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
945 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
946 | } | ||
947 | |||
948 | static void | ||
949 | l2_stop_multi(struct FsmInst *fi, int event, void *arg) | ||
950 | { | ||
951 | struct layer2 *l2 = fi->userdata; | ||
952 | struct sk_buff *skb = arg; | ||
953 | |||
954 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
955 | mISDN_FsmDelTimer(&l2->t203, 3); | ||
956 | stop_t200(l2, 4); | ||
957 | |||
958 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
959 | skb_queue_purge(&l2->i_queue); | ||
960 | freewin(l2); | ||
961 | lapb_dl_release_l2l3(l2, DL_RELEASE_IND); | ||
962 | if (l2->tm) | ||
963 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
964 | } | ||
965 | |||
966 | static void | ||
967 | l2_connected(struct FsmInst *fi, int event, void *arg) | ||
968 | { | ||
969 | struct layer2 *l2 = fi->userdata; | ||
970 | struct sk_buff *skb = arg; | ||
971 | int pr = -1; | ||
972 | |||
973 | if (!get_PollFlag(l2, skb)) { | ||
974 | l2_mdl_error_ua(fi, event, arg); | ||
975 | return; | ||
976 | } | ||
977 | dev_kfree_skb(skb); | ||
978 | if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) | ||
979 | l2_disconnect(fi, event, NULL); | ||
980 | if (test_and_clear_bit(FLG_L3_INIT, &l2->flag)) { | ||
981 | pr = DL_ESTABLISH_CNF; | ||
982 | } else if (l2->vs != l2->va) { | ||
983 | skb_queue_purge(&l2->i_queue); | ||
984 | pr = DL_ESTABLISH_IND; | ||
985 | } | ||
986 | stop_t200(l2, 5); | ||
987 | l2->vr = 0; | ||
988 | l2->vs = 0; | ||
989 | l2->va = 0; | ||
990 | l2->sow = 0; | ||
991 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
992 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4); | ||
993 | if (pr != -1) | ||
994 | l2up_create(l2, pr, 0, NULL); | ||
995 | |||
996 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
997 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
998 | |||
999 | if (l2->tm) | ||
1000 | l2_tei(l2, MDL_STATUS_UP_IND, 0); | ||
1001 | } | ||
1002 | |||
1003 | static void | ||
1004 | l2_released(struct FsmInst *fi, int event, void *arg) | ||
1005 | { | ||
1006 | struct layer2 *l2 = fi->userdata; | ||
1007 | struct sk_buff *skb = arg; | ||
1008 | |||
1009 | if (!get_PollFlag(l2, skb)) { | ||
1010 | l2_mdl_error_ua(fi, event, arg); | ||
1011 | return; | ||
1012 | } | ||
1013 | dev_kfree_skb(skb); | ||
1014 | stop_t200(l2, 6); | ||
1015 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
1016 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1017 | if (l2->tm) | ||
1018 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1019 | } | ||
1020 | |||
1021 | static void | ||
1022 | l2_reestablish(struct FsmInst *fi, int event, void *arg) | ||
1023 | { | ||
1024 | struct layer2 *l2 = fi->userdata; | ||
1025 | struct sk_buff *skb = arg; | ||
1026 | |||
1027 | if (!get_PollFlagFree(l2, skb)) { | ||
1028 | establishlink(fi); | ||
1029 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | static void | ||
1034 | l2_st5_dm_release(struct FsmInst *fi, int event, void *arg) | ||
1035 | { | ||
1036 | struct layer2 *l2 = fi->userdata; | ||
1037 | struct sk_buff *skb = arg; | ||
1038 | |||
1039 | if (get_PollFlagFree(l2, skb)) { | ||
1040 | stop_t200(l2, 7); | ||
1041 | if (!test_bit(FLG_L3_INIT, &l2->flag)) | ||
1042 | skb_queue_purge(&l2->i_queue); | ||
1043 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1044 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
1045 | l2_newid(l2), 0, NULL); | ||
1046 | st5_dl_release_l2l3(l2); | ||
1047 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1048 | if (l2->tm) | ||
1049 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | static void | ||
1054 | l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) | ||
1055 | { | ||
1056 | struct layer2 *l2 = fi->userdata; | ||
1057 | struct sk_buff *skb = arg; | ||
1058 | |||
1059 | if (get_PollFlagFree(l2, skb)) { | ||
1060 | stop_t200(l2, 8); | ||
1061 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
1062 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1063 | if (l2->tm) | ||
1064 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1065 | } | ||
1066 | } | ||
1067 | |||
1068 | void | ||
1069 | enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) | ||
1070 | { | ||
1071 | struct sk_buff *skb; | ||
1072 | u_char tmp[MAX_L2HEADER_LEN]; | ||
1073 | int i; | ||
1074 | |||
1075 | i = sethdraddr(l2, tmp, cr); | ||
1076 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1077 | tmp[i++] = typ; | ||
1078 | tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0); | ||
1079 | } else | ||
1080 | tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0); | ||
1081 | skb = mI_alloc_skb(i, GFP_ATOMIC); | ||
1082 | if (!skb) { | ||
1083 | printk(KERN_WARNING | ||
1084 | "isdnl2 can't alloc sbbuff for enquiry_cr\n"); | ||
1085 | return; | ||
1086 | } | ||
1087 | memcpy(skb_put(skb, i), tmp, i); | ||
1088 | enqueue_super(l2, skb); | ||
1089 | } | ||
1090 | |||
1091 | inline void | ||
1092 | enquiry_response(struct layer2 *l2) | ||
1093 | { | ||
1094 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) | ||
1095 | enquiry_cr(l2, RNR, RSP, 1); | ||
1096 | else | ||
1097 | enquiry_cr(l2, RR, RSP, 1); | ||
1098 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1099 | } | ||
1100 | |||
1101 | inline void | ||
1102 | transmit_enquiry(struct layer2 *l2) | ||
1103 | { | ||
1104 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) | ||
1105 | enquiry_cr(l2, RNR, CMD, 1); | ||
1106 | else | ||
1107 | enquiry_cr(l2, RR, CMD, 1); | ||
1108 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1109 | start_t200(l2, 9); | ||
1110 | } | ||
1111 | |||
1112 | |||
1113 | static void | ||
1114 | nrerrorrecovery(struct FsmInst *fi) | ||
1115 | { | ||
1116 | struct layer2 *l2 = fi->userdata; | ||
1117 | |||
1118 | l2mgr(l2, MDL_ERROR_IND, (void *) 'J'); | ||
1119 | establishlink(fi); | ||
1120 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1121 | } | ||
1122 | |||
1123 | static void | ||
1124 | invoke_retransmission(struct layer2 *l2, unsigned int nr) | ||
1125 | { | ||
1126 | u_int p1; | ||
1127 | |||
1128 | if (l2->vs != nr) { | ||
1129 | while (l2->vs != nr) { | ||
1130 | (l2->vs)--; | ||
1131 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1132 | l2->vs %= 128; | ||
1133 | p1 = (l2->vs - l2->va) % 128; | ||
1134 | } else { | ||
1135 | l2->vs %= 8; | ||
1136 | p1 = (l2->vs - l2->va) % 8; | ||
1137 | } | ||
1138 | p1 = (p1 + l2->sow) % l2->window; | ||
1139 | if (l2->windowar[p1]) | ||
1140 | skb_queue_head(&l2->i_queue, l2->windowar[p1]); | ||
1141 | else | ||
1142 | printk(KERN_WARNING | ||
1143 | "%s: windowar[%d] is NULL\n", | ||
1144 | __func__, p1); | ||
1145 | l2->windowar[p1] = NULL; | ||
1146 | } | ||
1147 | mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | static void | ||
1152 | l2_st7_got_super(struct FsmInst *fi, int event, void *arg) | ||
1153 | { | ||
1154 | struct layer2 *l2 = fi->userdata; | ||
1155 | struct sk_buff *skb = arg; | ||
1156 | int PollFlag, rsp, typ = RR; | ||
1157 | unsigned int nr; | ||
1158 | |||
1159 | rsp = *skb->data & 0x2; | ||
1160 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
1161 | rsp = !rsp; | ||
1162 | |||
1163 | skb_pull(skb, l2addrsize(l2)); | ||
1164 | if (IsRNR(skb->data, l2)) { | ||
1165 | set_peer_busy(l2); | ||
1166 | typ = RNR; | ||
1167 | } else | ||
1168 | clear_peer_busy(l2); | ||
1169 | if (IsREJ(skb->data, l2)) | ||
1170 | typ = REJ; | ||
1171 | |||
1172 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1173 | PollFlag = (skb->data[1] & 0x1) == 0x1; | ||
1174 | nr = skb->data[1] >> 1; | ||
1175 | } else { | ||
1176 | PollFlag = (skb->data[0] & 0x10); | ||
1177 | nr = (skb->data[0] >> 5) & 0x7; | ||
1178 | } | ||
1179 | dev_kfree_skb(skb); | ||
1180 | |||
1181 | if (PollFlag) { | ||
1182 | if (rsp) | ||
1183 | l2mgr(l2, MDL_ERROR_IND, (void *) 'A'); | ||
1184 | else | ||
1185 | enquiry_response(l2); | ||
1186 | } | ||
1187 | if (legalnr(l2, nr)) { | ||
1188 | if (typ == REJ) { | ||
1189 | setva(l2, nr); | ||
1190 | invoke_retransmission(l2, nr); | ||
1191 | stop_t200(l2, 10); | ||
1192 | if (mISDN_FsmAddTimer(&l2->t203, l2->T203, | ||
1193 | EV_L2_T203, NULL, 6)) | ||
1194 | l2m_debug(&l2->l2m, "Restart T203 ST7 REJ"); | ||
1195 | } else if ((nr == l2->vs) && (typ == RR)) { | ||
1196 | setva(l2, nr); | ||
1197 | stop_t200(l2, 11); | ||
1198 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, | ||
1199 | EV_L2_T203, NULL, 7); | ||
1200 | } else if ((l2->va != nr) || (typ == RNR)) { | ||
1201 | setva(l2, nr); | ||
1202 | if (typ != RR) | ||
1203 | mISDN_FsmDelTimer(&l2->t203, 9); | ||
1204 | restart_t200(l2, 12); | ||
1205 | } | ||
1206 | if (skb_queue_len(&l2->i_queue) && (typ == RR)) | ||
1207 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1208 | } else | ||
1209 | nrerrorrecovery(fi); | ||
1210 | } | ||
1211 | |||
1212 | static void | ||
1213 | l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg) | ||
1214 | { | ||
1215 | struct layer2 *l2 = fi->userdata; | ||
1216 | struct sk_buff *skb = arg; | ||
1217 | |||
1218 | if (!test_bit(FLG_L3_INIT, &l2->flag)) | ||
1219 | skb_queue_tail(&l2->i_queue, skb); | ||
1220 | else | ||
1221 | dev_kfree_skb(skb); | ||
1222 | } | ||
1223 | |||
1224 | static void | ||
1225 | l2_feed_i_pull(struct FsmInst *fi, int event, void *arg) | ||
1226 | { | ||
1227 | struct layer2 *l2 = fi->userdata; | ||
1228 | struct sk_buff *skb = arg; | ||
1229 | |||
1230 | skb_queue_tail(&l2->i_queue, skb); | ||
1231 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1232 | } | ||
1233 | |||
1234 | static void | ||
1235 | l2_feed_iqueue(struct FsmInst *fi, int event, void *arg) | ||
1236 | { | ||
1237 | struct layer2 *l2 = fi->userdata; | ||
1238 | struct sk_buff *skb = arg; | ||
1239 | |||
1240 | skb_queue_tail(&l2->i_queue, skb); | ||
1241 | } | ||
1242 | |||
1243 | static void | ||
1244 | l2_got_iframe(struct FsmInst *fi, int event, void *arg) | ||
1245 | { | ||
1246 | struct layer2 *l2 = fi->userdata; | ||
1247 | struct sk_buff *skb = arg; | ||
1248 | int PollFlag, i; | ||
1249 | u_int ns, nr; | ||
1250 | |||
1251 | i = l2addrsize(l2); | ||
1252 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1253 | PollFlag = ((skb->data[i + 1] & 0x1) == 0x1); | ||
1254 | ns = skb->data[i] >> 1; | ||
1255 | nr = (skb->data[i + 1] >> 1) & 0x7f; | ||
1256 | } else { | ||
1257 | PollFlag = (skb->data[i] & 0x10); | ||
1258 | ns = (skb->data[i] >> 1) & 0x7; | ||
1259 | nr = (skb->data[i] >> 5) & 0x7; | ||
1260 | } | ||
1261 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
1262 | dev_kfree_skb(skb); | ||
1263 | if (PollFlag) | ||
1264 | enquiry_response(l2); | ||
1265 | } else { | ||
1266 | if (l2->vr == ns) { | ||
1267 | l2->vr++; | ||
1268 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
1269 | l2->vr %= 128; | ||
1270 | else | ||
1271 | l2->vr %= 8; | ||
1272 | test_and_clear_bit(FLG_REJEXC, &l2->flag); | ||
1273 | if (PollFlag) | ||
1274 | enquiry_response(l2); | ||
1275 | else | ||
1276 | test_and_set_bit(FLG_ACK_PEND, &l2->flag); | ||
1277 | skb_pull(skb, l2headersize(l2, 0)); | ||
1278 | l2up(l2, DL_DATA_IND, skb); | ||
1279 | } else { | ||
1280 | /* n(s)!=v(r) */ | ||
1281 | dev_kfree_skb(skb); | ||
1282 | if (test_and_set_bit(FLG_REJEXC, &l2->flag)) { | ||
1283 | if (PollFlag) | ||
1284 | enquiry_response(l2); | ||
1285 | } else { | ||
1286 | enquiry_cr(l2, REJ, RSP, PollFlag); | ||
1287 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1288 | } | ||
1289 | } | ||
1290 | } | ||
1291 | if (legalnr(l2, nr)) { | ||
1292 | if (!test_bit(FLG_PEER_BUSY, &l2->flag) && | ||
1293 | (fi->state == ST_L2_7)) { | ||
1294 | if (nr == l2->vs) { | ||
1295 | stop_t200(l2, 13); | ||
1296 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, | ||
1297 | EV_L2_T203, NULL, 7); | ||
1298 | } else if (nr != l2->va) | ||
1299 | restart_t200(l2, 14); | ||
1300 | } | ||
1301 | setva(l2, nr); | ||
1302 | } else { | ||
1303 | nrerrorrecovery(fi); | ||
1304 | return; | ||
1305 | } | ||
1306 | if (skb_queue_len(&l2->i_queue) && (fi->state == ST_L2_7)) | ||
1307 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1308 | if (test_and_clear_bit(FLG_ACK_PEND, &l2->flag)) | ||
1309 | enquiry_cr(l2, RR, RSP, 0); | ||
1310 | } | ||
1311 | |||
1312 | static void | ||
1313 | l2_got_tei(struct FsmInst *fi, int event, void *arg) | ||
1314 | { | ||
1315 | struct layer2 *l2 = fi->userdata; | ||
1316 | u_int info; | ||
1317 | |||
1318 | l2->tei = (signed char)(long)arg; | ||
1319 | set_channel_address(&l2->ch, l2->sapi, l2->tei); | ||
1320 | info = DL_INFO_L2_CONNECT; | ||
1321 | l2up_create(l2, DL_INFORMATION_IND, sizeof(info), &info); | ||
1322 | if (fi->state == ST_L2_3) { | ||
1323 | establishlink(fi); | ||
1324 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
1325 | } else | ||
1326 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1327 | if (skb_queue_len(&l2->ui_queue)) | ||
1328 | tx_ui(l2); | ||
1329 | } | ||
1330 | |||
1331 | static void | ||
1332 | l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1333 | { | ||
1334 | struct layer2 *l2 = fi->userdata; | ||
1335 | |||
1336 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1337 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1338 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1339 | } else if (l2->rc == l2->N200) { | ||
1340 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1341 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1342 | skb_queue_purge(&l2->i_queue); | ||
1343 | l2mgr(l2, MDL_ERROR_IND, (void *) 'G'); | ||
1344 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1345 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
1346 | l2_newid(l2), 0, NULL); | ||
1347 | st5_dl_release_l2l3(l2); | ||
1348 | if (l2->tm) | ||
1349 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1350 | } else { | ||
1351 | l2->rc++; | ||
1352 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1353 | send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ? | ||
1354 | SABME : SABM) | 0x10, CMD); | ||
1355 | } | ||
1356 | } | ||
1357 | |||
1358 | static void | ||
1359 | l2_st6_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1360 | { | ||
1361 | struct layer2 *l2 = fi->userdata; | ||
1362 | |||
1363 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1364 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1365 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1366 | } else if (l2->rc == l2->N200) { | ||
1367 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1368 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1369 | l2mgr(l2, MDL_ERROR_IND, (void *) 'H'); | ||
1370 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
1371 | if (l2->tm) | ||
1372 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1373 | } else { | ||
1374 | l2->rc++; | ||
1375 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, | ||
1376 | NULL, 9); | ||
1377 | send_uframe(l2, NULL, DISC | 0x10, CMD); | ||
1378 | } | ||
1379 | } | ||
1380 | |||
1381 | static void | ||
1382 | l2_st7_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1383 | { | ||
1384 | struct layer2 *l2 = fi->userdata; | ||
1385 | |||
1386 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1387 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1388 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1389 | return; | ||
1390 | } | ||
1391 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1392 | l2->rc = 0; | ||
1393 | mISDN_FsmChangeState(fi, ST_L2_8); | ||
1394 | transmit_enquiry(l2); | ||
1395 | l2->rc++; | ||
1396 | } | ||
1397 | |||
1398 | static void | ||
1399 | l2_st8_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1400 | { | ||
1401 | struct layer2 *l2 = fi->userdata; | ||
1402 | |||
1403 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1404 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1405 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1406 | return; | ||
1407 | } | ||
1408 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1409 | if (l2->rc == l2->N200) { | ||
1410 | l2mgr(l2, MDL_ERROR_IND, (void *) 'I'); | ||
1411 | establishlink(fi); | ||
1412 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1413 | } else { | ||
1414 | transmit_enquiry(l2); | ||
1415 | l2->rc++; | ||
1416 | } | ||
1417 | } | ||
1418 | |||
1419 | static void | ||
1420 | l2_st7_tout_203(struct FsmInst *fi, int event, void *arg) | ||
1421 | { | ||
1422 | struct layer2 *l2 = fi->userdata; | ||
1423 | |||
1424 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1425 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1426 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9); | ||
1427 | return; | ||
1428 | } | ||
1429 | mISDN_FsmChangeState(fi, ST_L2_8); | ||
1430 | transmit_enquiry(l2); | ||
1431 | l2->rc = 0; | ||
1432 | } | ||
1433 | |||
1434 | static void | ||
1435 | l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) | ||
1436 | { | ||
1437 | struct layer2 *l2 = fi->userdata; | ||
1438 | struct sk_buff *skb, *nskb, *oskb; | ||
1439 | u_char header[MAX_L2HEADER_LEN]; | ||
1440 | u_int i, p1; | ||
1441 | |||
1442 | if (!cansend(l2)) | ||
1443 | return; | ||
1444 | |||
1445 | skb = skb_dequeue(&l2->i_queue); | ||
1446 | if (!skb) | ||
1447 | return; | ||
1448 | |||
1449 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
1450 | p1 = (l2->vs - l2->va) % 128; | ||
1451 | else | ||
1452 | p1 = (l2->vs - l2->va) % 8; | ||
1453 | p1 = (p1 + l2->sow) % l2->window; | ||
1454 | if (l2->windowar[p1]) { | ||
1455 | printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", | ||
1456 | p1); | ||
1457 | dev_kfree_skb(l2->windowar[p1]); | ||
1458 | } | ||
1459 | l2->windowar[p1] = skb; | ||
1460 | i = sethdraddr(l2, header, CMD); | ||
1461 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1462 | header[i++] = l2->vs << 1; | ||
1463 | header[i++] = l2->vr << 1; | ||
1464 | l2->vs = (l2->vs + 1) % 128; | ||
1465 | } else { | ||
1466 | header[i++] = (l2->vr << 5) | (l2->vs << 1); | ||
1467 | l2->vs = (l2->vs + 1) % 8; | ||
1468 | } | ||
1469 | |||
1470 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
1471 | p1 = skb_headroom(nskb); | ||
1472 | if (p1 >= i) | ||
1473 | memcpy(skb_push(nskb, i), header, i); | ||
1474 | else { | ||
1475 | printk(KERN_WARNING | ||
1476 | "isdnl2 pull_iqueue skb header(%d/%d) too short\n", i, p1); | ||
1477 | oskb = nskb; | ||
1478 | nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC); | ||
1479 | if (!nskb) { | ||
1480 | dev_kfree_skb(oskb); | ||
1481 | printk(KERN_WARNING "%s: no skb mem\n", __func__); | ||
1482 | return; | ||
1483 | } | ||
1484 | memcpy(skb_put(nskb, i), header, i); | ||
1485 | memcpy(skb_put(nskb, oskb->len), oskb->data, oskb->len); | ||
1486 | dev_kfree_skb(oskb); | ||
1487 | } | ||
1488 | l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb); | ||
1489 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1490 | if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) { | ||
1491 | mISDN_FsmDelTimer(&l2->t203, 13); | ||
1492 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 11); | ||
1493 | } | ||
1494 | } | ||
1495 | |||
1496 | static void | ||
1497 | l2_st8_got_super(struct FsmInst *fi, int event, void *arg) | ||
1498 | { | ||
1499 | struct layer2 *l2 = fi->userdata; | ||
1500 | struct sk_buff *skb = arg; | ||
1501 | int PollFlag, rsp, rnr = 0; | ||
1502 | unsigned int nr; | ||
1503 | |||
1504 | rsp = *skb->data & 0x2; | ||
1505 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
1506 | rsp = !rsp; | ||
1507 | |||
1508 | skb_pull(skb, l2addrsize(l2)); | ||
1509 | |||
1510 | if (IsRNR(skb->data, l2)) { | ||
1511 | set_peer_busy(l2); | ||
1512 | rnr = 1; | ||
1513 | } else | ||
1514 | clear_peer_busy(l2); | ||
1515 | |||
1516 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1517 | PollFlag = (skb->data[1] & 0x1) == 0x1; | ||
1518 | nr = skb->data[1] >> 1; | ||
1519 | } else { | ||
1520 | PollFlag = (skb->data[0] & 0x10); | ||
1521 | nr = (skb->data[0] >> 5) & 0x7; | ||
1522 | } | ||
1523 | dev_kfree_skb(skb); | ||
1524 | if (rsp && PollFlag) { | ||
1525 | if (legalnr(l2, nr)) { | ||
1526 | if (rnr) { | ||
1527 | restart_t200(l2, 15); | ||
1528 | } else { | ||
1529 | stop_t200(l2, 16); | ||
1530 | mISDN_FsmAddTimer(&l2->t203, l2->T203, | ||
1531 | EV_L2_T203, NULL, 5); | ||
1532 | setva(l2, nr); | ||
1533 | } | ||
1534 | invoke_retransmission(l2, nr); | ||
1535 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
1536 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
1537 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1538 | } else | ||
1539 | nrerrorrecovery(fi); | ||
1540 | } else { | ||
1541 | if (!rsp && PollFlag) | ||
1542 | enquiry_response(l2); | ||
1543 | if (legalnr(l2, nr)) | ||
1544 | setva(l2, nr); | ||
1545 | else | ||
1546 | nrerrorrecovery(fi); | ||
1547 | } | ||
1548 | } | ||
1549 | |||
1550 | static void | ||
1551 | l2_got_FRMR(struct FsmInst *fi, int event, void *arg) | ||
1552 | { | ||
1553 | struct layer2 *l2 = fi->userdata; | ||
1554 | struct sk_buff *skb = arg; | ||
1555 | |||
1556 | skb_pull(skb, l2addrsize(l2) + 1); | ||
1557 | |||
1558 | if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */ | ||
1559 | (IsUA(skb->data) && (fi->state == ST_L2_7))) { | ||
1560 | l2mgr(l2, MDL_ERROR_IND, (void *) 'K'); | ||
1561 | establishlink(fi); | ||
1562 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1563 | } | ||
1564 | dev_kfree_skb(skb); | ||
1565 | } | ||
1566 | |||
1567 | static void | ||
1568 | l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1569 | { | ||
1570 | struct layer2 *l2 = fi->userdata; | ||
1571 | |||
1572 | skb_queue_purge(&l2->ui_queue); | ||
1573 | l2->tei = GROUP_TEI; | ||
1574 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1575 | } | ||
1576 | |||
1577 | static void | ||
1578 | l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1579 | { | ||
1580 | struct layer2 *l2 = fi->userdata; | ||
1581 | |||
1582 | skb_queue_purge(&l2->ui_queue); | ||
1583 | l2->tei = GROUP_TEI; | ||
1584 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
1585 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1586 | } | ||
1587 | |||
1588 | static void | ||
1589 | l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1590 | { | ||
1591 | struct layer2 *l2 = fi->userdata; | ||
1592 | |||
1593 | skb_queue_purge(&l2->i_queue); | ||
1594 | skb_queue_purge(&l2->ui_queue); | ||
1595 | freewin(l2); | ||
1596 | l2->tei = GROUP_TEI; | ||
1597 | stop_t200(l2, 17); | ||
1598 | st5_dl_release_l2l3(l2); | ||
1599 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1600 | } | ||
1601 | |||
1602 | static void | ||
1603 | l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1604 | { | ||
1605 | struct layer2 *l2 = fi->userdata; | ||
1606 | |||
1607 | skb_queue_purge(&l2->ui_queue); | ||
1608 | l2->tei = GROUP_TEI; | ||
1609 | stop_t200(l2, 18); | ||
1610 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
1611 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1612 | } | ||
1613 | |||
1614 | static void | ||
1615 | l2_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1616 | { | ||
1617 | struct layer2 *l2 = fi->userdata; | ||
1618 | |||
1619 | skb_queue_purge(&l2->i_queue); | ||
1620 | skb_queue_purge(&l2->ui_queue); | ||
1621 | freewin(l2); | ||
1622 | l2->tei = GROUP_TEI; | ||
1623 | stop_t200(l2, 17); | ||
1624 | mISDN_FsmDelTimer(&l2->t203, 19); | ||
1625 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
1626 | /* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST, | ||
1627 | * MGR_SHORTSTATUS_IND, SSTATUS_L2_RELEASED, | ||
1628 | * 0, NULL, 0); | ||
1629 | */ | ||
1630 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1631 | } | ||
1632 | |||
1633 | static void | ||
1634 | l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1635 | { | ||
1636 | struct layer2 *l2 = fi->userdata; | ||
1637 | struct sk_buff *skb = arg; | ||
1638 | |||
1639 | skb_queue_purge(&l2->i_queue); | ||
1640 | skb_queue_purge(&l2->ui_queue); | ||
1641 | if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) | ||
1642 | l2up(l2, DL_RELEASE_IND, skb); | ||
1643 | else | ||
1644 | dev_kfree_skb(skb); | ||
1645 | } | ||
1646 | |||
1647 | static void | ||
1648 | l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1649 | { | ||
1650 | struct layer2 *l2 = fi->userdata; | ||
1651 | struct sk_buff *skb = arg; | ||
1652 | |||
1653 | skb_queue_purge(&l2->i_queue); | ||
1654 | skb_queue_purge(&l2->ui_queue); | ||
1655 | freewin(l2); | ||
1656 | stop_t200(l2, 19); | ||
1657 | st5_dl_release_l2l3(l2); | ||
1658 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1659 | if (l2->tm) | ||
1660 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1661 | dev_kfree_skb(skb); | ||
1662 | } | ||
1663 | |||
1664 | static void | ||
1665 | l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1666 | { | ||
1667 | struct layer2 *l2 = fi->userdata; | ||
1668 | struct sk_buff *skb = arg; | ||
1669 | |||
1670 | skb_queue_purge(&l2->ui_queue); | ||
1671 | stop_t200(l2, 20); | ||
1672 | l2up(l2, DL_RELEASE_CNF, skb); | ||
1673 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1674 | if (l2->tm) | ||
1675 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1676 | } | ||
1677 | |||
1678 | static void | ||
1679 | l2_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1680 | { | ||
1681 | struct layer2 *l2 = fi->userdata; | ||
1682 | struct sk_buff *skb = arg; | ||
1683 | |||
1684 | skb_queue_purge(&l2->i_queue); | ||
1685 | skb_queue_purge(&l2->ui_queue); | ||
1686 | freewin(l2); | ||
1687 | stop_t200(l2, 19); | ||
1688 | mISDN_FsmDelTimer(&l2->t203, 19); | ||
1689 | l2up(l2, DL_RELEASE_IND, skb); | ||
1690 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1691 | if (l2->tm) | ||
1692 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1693 | } | ||
1694 | |||
1695 | static void | ||
1696 | l2_set_own_busy(struct FsmInst *fi, int event, void *arg) | ||
1697 | { | ||
1698 | struct layer2 *l2 = fi->userdata; | ||
1699 | struct sk_buff *skb = arg; | ||
1700 | |||
1701 | if (!test_and_set_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
1702 | enquiry_cr(l2, RNR, RSP, 0); | ||
1703 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1704 | } | ||
1705 | if (skb) | ||
1706 | dev_kfree_skb(skb); | ||
1707 | } | ||
1708 | |||
1709 | static void | ||
1710 | l2_clear_own_busy(struct FsmInst *fi, int event, void *arg) | ||
1711 | { | ||
1712 | struct layer2 *l2 = fi->userdata; | ||
1713 | struct sk_buff *skb = arg; | ||
1714 | |||
1715 | if (!test_and_clear_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
1716 | enquiry_cr(l2, RR, RSP, 0); | ||
1717 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1718 | } | ||
1719 | if (skb) | ||
1720 | dev_kfree_skb(skb); | ||
1721 | } | ||
1722 | |||
1723 | static void | ||
1724 | l2_frame_error(struct FsmInst *fi, int event, void *arg) | ||
1725 | { | ||
1726 | struct layer2 *l2 = fi->userdata; | ||
1727 | |||
1728 | l2mgr(l2, MDL_ERROR_IND, arg); | ||
1729 | } | ||
1730 | |||
1731 | static void | ||
1732 | l2_frame_error_reest(struct FsmInst *fi, int event, void *arg) | ||
1733 | { | ||
1734 | struct layer2 *l2 = fi->userdata; | ||
1735 | |||
1736 | l2mgr(l2, MDL_ERROR_IND, arg); | ||
1737 | establishlink(fi); | ||
1738 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1739 | } | ||
1740 | |||
1741 | static struct FsmNode L2FnList[] = | ||
1742 | { | ||
1743 | {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign}, | ||
1744 | {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3}, | ||
1745 | {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish}, | ||
1746 | {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3}, | ||
1747 | {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, | ||
1748 | {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, | ||
1749 | {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release}, | ||
1750 | {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel}, | ||
1751 | {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect}, | ||
1752 | {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect}, | ||
1753 | {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest}, | ||
1754 | {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull}, | ||
1755 | {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue}, | ||
1756 | {ST_L2_1, EV_L2_DL_UNITDATA, l2_queue_ui_assign}, | ||
1757 | {ST_L2_2, EV_L2_DL_UNITDATA, l2_queue_ui}, | ||
1758 | {ST_L2_3, EV_L2_DL_UNITDATA, l2_queue_ui}, | ||
1759 | {ST_L2_4, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1760 | {ST_L2_5, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1761 | {ST_L2_6, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1762 | {ST_L2_7, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1763 | {ST_L2_8, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1764 | {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
1765 | {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
1766 | {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
1767 | {ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove}, | ||
1768 | {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove}, | ||
1769 | {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove}, | ||
1770 | {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove}, | ||
1771 | {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove}, | ||
1772 | {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove}, | ||
1773 | {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove}, | ||
1774 | {ST_L2_4, EV_L2_SABME, l2_start_multi}, | ||
1775 | {ST_L2_5, EV_L2_SABME, l2_send_UA}, | ||
1776 | {ST_L2_6, EV_L2_SABME, l2_send_DM}, | ||
1777 | {ST_L2_7, EV_L2_SABME, l2_restart_multi}, | ||
1778 | {ST_L2_8, EV_L2_SABME, l2_restart_multi}, | ||
1779 | {ST_L2_4, EV_L2_DISC, l2_send_DM}, | ||
1780 | {ST_L2_5, EV_L2_DISC, l2_send_DM}, | ||
1781 | {ST_L2_6, EV_L2_DISC, l2_send_UA}, | ||
1782 | {ST_L2_7, EV_L2_DISC, l2_stop_multi}, | ||
1783 | {ST_L2_8, EV_L2_DISC, l2_stop_multi}, | ||
1784 | {ST_L2_4, EV_L2_UA, l2_mdl_error_ua}, | ||
1785 | {ST_L2_5, EV_L2_UA, l2_connected}, | ||
1786 | {ST_L2_6, EV_L2_UA, l2_released}, | ||
1787 | {ST_L2_7, EV_L2_UA, l2_mdl_error_ua}, | ||
1788 | {ST_L2_8, EV_L2_UA, l2_mdl_error_ua}, | ||
1789 | {ST_L2_4, EV_L2_DM, l2_reestablish}, | ||
1790 | {ST_L2_5, EV_L2_DM, l2_st5_dm_release}, | ||
1791 | {ST_L2_6, EV_L2_DM, l2_st6_dm_release}, | ||
1792 | {ST_L2_7, EV_L2_DM, l2_mdl_error_dm}, | ||
1793 | {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm}, | ||
1794 | {ST_L2_1, EV_L2_UI, l2_got_ui}, | ||
1795 | {ST_L2_2, EV_L2_UI, l2_got_ui}, | ||
1796 | {ST_L2_3, EV_L2_UI, l2_got_ui}, | ||
1797 | {ST_L2_4, EV_L2_UI, l2_got_ui}, | ||
1798 | {ST_L2_5, EV_L2_UI, l2_got_ui}, | ||
1799 | {ST_L2_6, EV_L2_UI, l2_got_ui}, | ||
1800 | {ST_L2_7, EV_L2_UI, l2_got_ui}, | ||
1801 | {ST_L2_8, EV_L2_UI, l2_got_ui}, | ||
1802 | {ST_L2_7, EV_L2_FRMR, l2_got_FRMR}, | ||
1803 | {ST_L2_8, EV_L2_FRMR, l2_got_FRMR}, | ||
1804 | {ST_L2_7, EV_L2_SUPER, l2_st7_got_super}, | ||
1805 | {ST_L2_8, EV_L2_SUPER, l2_st8_got_super}, | ||
1806 | {ST_L2_7, EV_L2_I, l2_got_iframe}, | ||
1807 | {ST_L2_8, EV_L2_I, l2_got_iframe}, | ||
1808 | {ST_L2_5, EV_L2_T200, l2_st5_tout_200}, | ||
1809 | {ST_L2_6, EV_L2_T200, l2_st6_tout_200}, | ||
1810 | {ST_L2_7, EV_L2_T200, l2_st7_tout_200}, | ||
1811 | {ST_L2_8, EV_L2_T200, l2_st8_tout_200}, | ||
1812 | {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, | ||
1813 | {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, | ||
1814 | {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, | ||
1815 | {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, | ||
1816 | {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, | ||
1817 | {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, | ||
1818 | {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
1819 | {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
1820 | {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
1821 | {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, | ||
1822 | {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, | ||
1823 | {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da}, | ||
1824 | {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, | ||
1825 | {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, | ||
1826 | {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da}, | ||
1827 | {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da}, | ||
1828 | {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da}, | ||
1829 | {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da}, | ||
1830 | {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, | ||
1831 | }; | ||
1832 | |||
1833 | #define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) | ||
1834 | |||
1835 | static int | ||
1836 | ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) | ||
1837 | { | ||
1838 | u_char *datap = skb->data; | ||
1839 | int ret = -EINVAL; | ||
1840 | int psapi, ptei; | ||
1841 | u_int l; | ||
1842 | int c = 0; | ||
1843 | |||
1844 | l = l2addrsize(l2); | ||
1845 | if (skb->len <= l) { | ||
1846 | mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *) 'N'); | ||
1847 | return ret; | ||
1848 | } | ||
1849 | if (test_bit(FLG_LAPD, &l2->flag)) { /* Maybe not needed */ | ||
1850 | psapi = *datap++; | ||
1851 | ptei = *datap++; | ||
1852 | if ((psapi & 1) || !(ptei & 1)) { | ||
1853 | printk(KERN_WARNING | ||
1854 | "l2 D-channel frame wrong EA0/EA1\n"); | ||
1855 | return ret; | ||
1856 | } | ||
1857 | psapi >>= 2; | ||
1858 | ptei >>= 1; | ||
1859 | if (psapi != l2->sapi) { | ||
1860 | /* not our bussiness | ||
1861 | * printk(KERN_DEBUG "%s: sapi %d/%d sapi mismatch\n", | ||
1862 | * __func__, | ||
1863 | * psapi, l2->sapi); | ||
1864 | */ | ||
1865 | dev_kfree_skb(skb); | ||
1866 | return 0; | ||
1867 | } | ||
1868 | if ((ptei != l2->tei) && (ptei != GROUP_TEI)) { | ||
1869 | /* not our bussiness | ||
1870 | * printk(KERN_DEBUG "%s: tei %d/%d sapi %d mismatch\n", | ||
1871 | * __func__, | ||
1872 | * ptei, l2->tei, psapi); | ||
1873 | */ | ||
1874 | dev_kfree_skb(skb); | ||
1875 | return 0; | ||
1876 | } | ||
1877 | } else | ||
1878 | datap += l; | ||
1879 | if (!(*datap & 1)) { /* I-Frame */ | ||
1880 | c = iframe_error(l2, skb); | ||
1881 | if (!c) | ||
1882 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_I, skb); | ||
1883 | } else if (IsSFrame(datap, l2)) { /* S-Frame */ | ||
1884 | c = super_error(l2, skb); | ||
1885 | if (!c) | ||
1886 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SUPER, skb); | ||
1887 | } else if (IsUI(datap)) { | ||
1888 | c = UI_error(l2, skb); | ||
1889 | if (!c) | ||
1890 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UI, skb); | ||
1891 | } else if (IsSABME(datap, l2)) { | ||
1892 | c = unnum_error(l2, skb, CMD); | ||
1893 | if (!c) | ||
1894 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SABME, skb); | ||
1895 | } else if (IsUA(datap)) { | ||
1896 | c = unnum_error(l2, skb, RSP); | ||
1897 | if (!c) | ||
1898 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UA, skb); | ||
1899 | } else if (IsDISC(datap)) { | ||
1900 | c = unnum_error(l2, skb, CMD); | ||
1901 | if (!c) | ||
1902 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DISC, skb); | ||
1903 | } else if (IsDM(datap)) { | ||
1904 | c = unnum_error(l2, skb, RSP); | ||
1905 | if (!c) | ||
1906 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DM, skb); | ||
1907 | } else if (IsFRMR(datap)) { | ||
1908 | c = FRMR_error(l2, skb); | ||
1909 | if (!c) | ||
1910 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_FRMR, skb); | ||
1911 | } else | ||
1912 | c = 'L'; | ||
1913 | if (c) { | ||
1914 | printk(KERN_WARNING "l2 D-channel frame error %c\n", c); | ||
1915 | mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c); | ||
1916 | } | ||
1917 | return ret; | ||
1918 | } | ||
1919 | |||
1920 | static int | ||
1921 | l2_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1922 | { | ||
1923 | struct layer2 *l2 = container_of(ch, struct layer2, ch); | ||
1924 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1925 | int ret = -EINVAL; | ||
1926 | |||
1927 | if (*debug & DEBUG_L2_RECV) | ||
1928 | printk(KERN_DEBUG "%s: prim(%x) id(%x) tei(%d)\n", | ||
1929 | __func__, hh->prim, hh->id, l2->tei); | ||
1930 | switch (hh->prim) { | ||
1931 | case PH_DATA_IND: | ||
1932 | ret = ph_data_indication(l2, hh, skb); | ||
1933 | break; | ||
1934 | case PH_DATA_CNF: | ||
1935 | ret = ph_data_confirm(l2, hh, skb); | ||
1936 | break; | ||
1937 | case PH_ACTIVATE_IND: | ||
1938 | test_and_set_bit(FLG_L1_ACTIV, &l2->flag); | ||
1939 | l2up_create(l2, MPH_ACTIVATE_IND, 0, NULL); | ||
1940 | if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) | ||
1941 | ret = mISDN_FsmEvent(&l2->l2m, | ||
1942 | EV_L2_DL_ESTABLISH_REQ, skb); | ||
1943 | break; | ||
1944 | case PH_DEACTIVATE_IND: | ||
1945 | test_and_clear_bit(FLG_L1_ACTIV, &l2->flag); | ||
1946 | l2up_create(l2, MPH_DEACTIVATE_IND, 0, NULL); | ||
1947 | ret = mISDN_FsmEvent(&l2->l2m, EV_L1_DEACTIVATE, skb); | ||
1948 | break; | ||
1949 | case MPH_INFORMATION_IND: | ||
1950 | if (!l2->up) | ||
1951 | break; | ||
1952 | ret = l2->up->send(l2->up, skb); | ||
1953 | break; | ||
1954 | case DL_DATA_REQ: | ||
1955 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_DATA, skb); | ||
1956 | break; | ||
1957 | case DL_UNITDATA_REQ: | ||
1958 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_UNITDATA, skb); | ||
1959 | break; | ||
1960 | case DL_ESTABLISH_REQ: | ||
1961 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1962 | test_and_set_bit(FLG_ORIG, &l2->flag); | ||
1963 | if (test_bit(FLG_L1_ACTIV, &l2->flag)) { | ||
1964 | if (test_bit(FLG_LAPD, &l2->flag) || | ||
1965 | test_bit(FLG_ORIG, &l2->flag)) | ||
1966 | ret = mISDN_FsmEvent(&l2->l2m, | ||
1967 | EV_L2_DL_ESTABLISH_REQ, skb); | ||
1968 | } else { | ||
1969 | if (test_bit(FLG_LAPD, &l2->flag) || | ||
1970 | test_bit(FLG_ORIG, &l2->flag)) { | ||
1971 | test_and_set_bit(FLG_ESTAB_PEND, | ||
1972 | &l2->flag); | ||
1973 | } | ||
1974 | ret = l2down(l2, PH_ACTIVATE_REQ, l2_newid(l2), | ||
1975 | skb); | ||
1976 | } | ||
1977 | break; | ||
1978 | case DL_RELEASE_REQ: | ||
1979 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1980 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
1981 | l2_newid(l2), 0, NULL); | ||
1982 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ, | ||
1983 | skb); | ||
1984 | break; | ||
1985 | default: | ||
1986 | if (*debug & DEBUG_L2) | ||
1987 | l2m_debug(&l2->l2m, "l2 unknown pr %04x", | ||
1988 | hh->prim); | ||
1989 | } | ||
1990 | if (ret) { | ||
1991 | dev_kfree_skb(skb); | ||
1992 | ret = 0; | ||
1993 | } | ||
1994 | return ret; | ||
1995 | } | ||
1996 | |||
1997 | int | ||
1998 | tei_l2(struct layer2 *l2, u_int cmd, u_long arg) | ||
1999 | { | ||
2000 | int ret = -EINVAL; | ||
2001 | |||
2002 | if (*debug & DEBUG_L2_TEI) | ||
2003 | printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); | ||
2004 | switch (cmd) { | ||
2005 | case (MDL_ASSIGN_REQ): | ||
2006 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg); | ||
2007 | break; | ||
2008 | case (MDL_REMOVE_REQ): | ||
2009 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, NULL); | ||
2010 | break; | ||
2011 | case (MDL_ERROR_IND): | ||
2012 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); | ||
2013 | break; | ||
2014 | case (MDL_ERROR_RSP): | ||
2015 | /* ETS 300-125 5.3.2.1 Test: TC13010 */ | ||
2016 | printk(KERN_NOTICE "MDL_ERROR|REQ (tei_l2)\n"); | ||
2017 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); | ||
2018 | break; | ||
2019 | } | ||
2020 | return ret; | ||
2021 | } | ||
2022 | |||
2023 | static void | ||
2024 | release_l2(struct layer2 *l2) | ||
2025 | { | ||
2026 | mISDN_FsmDelTimer(&l2->t200, 21); | ||
2027 | mISDN_FsmDelTimer(&l2->t203, 16); | ||
2028 | skb_queue_purge(&l2->i_queue); | ||
2029 | skb_queue_purge(&l2->ui_queue); | ||
2030 | skb_queue_purge(&l2->down_queue); | ||
2031 | ReleaseWin(l2); | ||
2032 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
2033 | release_tei(l2); | ||
2034 | if (l2->ch.st) | ||
2035 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, | ||
2036 | CLOSE_CHANNEL, NULL); | ||
2037 | } | ||
2038 | kfree(l2); | ||
2039 | } | ||
2040 | |||
2041 | static int | ||
2042 | l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
2043 | { | ||
2044 | struct layer2 *l2 = container_of(ch, struct layer2, ch); | ||
2045 | u_int info; | ||
2046 | |||
2047 | if (*debug & DEBUG_L2_CTRL) | ||
2048 | printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); | ||
2049 | |||
2050 | switch (cmd) { | ||
2051 | case OPEN_CHANNEL: | ||
2052 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
2053 | set_channel_address(&l2->ch, l2->sapi, l2->tei); | ||
2054 | info = DL_INFO_L2_CONNECT; | ||
2055 | l2up_create(l2, DL_INFORMATION_IND, | ||
2056 | sizeof(info), &info); | ||
2057 | } | ||
2058 | break; | ||
2059 | case CLOSE_CHANNEL: | ||
2060 | if (l2->ch.peer) | ||
2061 | l2->ch.peer->ctrl(l2->ch.peer, CLOSE_CHANNEL, NULL); | ||
2062 | release_l2(l2); | ||
2063 | break; | ||
2064 | } | ||
2065 | return 0; | ||
2066 | } | ||
2067 | |||
2068 | struct layer2 * | ||
2069 | create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) | ||
2070 | { | ||
2071 | struct layer2 *l2; | ||
2072 | struct channel_req rq; | ||
2073 | |||
2074 | l2 = kzalloc(sizeof(struct layer2), GFP_KERNEL); | ||
2075 | if (!l2) { | ||
2076 | printk(KERN_ERR "kzalloc layer2 failed\n"); | ||
2077 | return NULL; | ||
2078 | } | ||
2079 | l2->next_id = 1; | ||
2080 | l2->down_id = MISDN_ID_NONE; | ||
2081 | l2->up = ch; | ||
2082 | l2->ch.st = ch->st; | ||
2083 | l2->ch.send = l2_send; | ||
2084 | l2->ch.ctrl = l2_ctrl; | ||
2085 | switch (protocol) { | ||
2086 | case ISDN_P_LAPD_NT: | ||
2087 | test_and_set_bit(FLG_LAPD, &l2->flag); | ||
2088 | test_and_set_bit(FLG_LAPD_NET, &l2->flag); | ||
2089 | test_and_set_bit(FLG_MOD128, &l2->flag); | ||
2090 | l2->sapi = 0; | ||
2091 | l2->maxlen = MAX_DFRAME_LEN; | ||
2092 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2093 | l2->window = 7; | ||
2094 | else | ||
2095 | l2->window = 1; | ||
2096 | if (test_bit(OPTION_L2_PTP, &options)) | ||
2097 | test_and_set_bit(FLG_PTP, &l2->flag); | ||
2098 | if (test_bit(OPTION_L2_FIXEDTEI, &options)) | ||
2099 | test_and_set_bit(FLG_FIXED_TEI, &l2->flag); | ||
2100 | l2->tei = (u_int)arg; | ||
2101 | l2->T200 = 1000; | ||
2102 | l2->N200 = 3; | ||
2103 | l2->T203 = 10000; | ||
2104 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2105 | rq.protocol = ISDN_P_NT_E1; | ||
2106 | else | ||
2107 | rq.protocol = ISDN_P_NT_S0; | ||
2108 | rq.adr.channel = 0; | ||
2109 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq); | ||
2110 | break; | ||
2111 | case ISDN_P_LAPD_TE: | ||
2112 | test_and_set_bit(FLG_LAPD, &l2->flag); | ||
2113 | test_and_set_bit(FLG_MOD128, &l2->flag); | ||
2114 | test_and_set_bit(FLG_ORIG, &l2->flag); | ||
2115 | l2->sapi = 0; | ||
2116 | l2->maxlen = MAX_DFRAME_LEN; | ||
2117 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2118 | l2->window = 7; | ||
2119 | else | ||
2120 | l2->window = 1; | ||
2121 | if (test_bit(OPTION_L2_PTP, &options)) | ||
2122 | test_and_set_bit(FLG_PTP, &l2->flag); | ||
2123 | if (test_bit(OPTION_L2_FIXEDTEI, &options)) | ||
2124 | test_and_set_bit(FLG_FIXED_TEI, &l2->flag); | ||
2125 | l2->tei = (u_int)arg; | ||
2126 | l2->T200 = 1000; | ||
2127 | l2->N200 = 3; | ||
2128 | l2->T203 = 10000; | ||
2129 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2130 | rq.protocol = ISDN_P_TE_E1; | ||
2131 | else | ||
2132 | rq.protocol = ISDN_P_TE_S0; | ||
2133 | rq.adr.channel = 0; | ||
2134 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq); | ||
2135 | break; | ||
2136 | case ISDN_P_B_X75SLP: | ||
2137 | test_and_set_bit(FLG_LAPB, &l2->flag); | ||
2138 | l2->window = 7; | ||
2139 | l2->maxlen = MAX_DATA_SIZE; | ||
2140 | l2->T200 = 1000; | ||
2141 | l2->N200 = 4; | ||
2142 | l2->T203 = 5000; | ||
2143 | l2->addr.A = 3; | ||
2144 | l2->addr.B = 1; | ||
2145 | break; | ||
2146 | default: | ||
2147 | printk(KERN_ERR "layer2 create failed prt %x\n", | ||
2148 | protocol); | ||
2149 | kfree(l2); | ||
2150 | return NULL; | ||
2151 | } | ||
2152 | skb_queue_head_init(&l2->i_queue); | ||
2153 | skb_queue_head_init(&l2->ui_queue); | ||
2154 | skb_queue_head_init(&l2->down_queue); | ||
2155 | skb_queue_head_init(&l2->tmp_queue); | ||
2156 | InitWin(l2); | ||
2157 | l2->l2m.fsm = &l2fsm; | ||
2158 | if (test_bit(FLG_LAPB, &l2->flag) || | ||
2159 | test_bit(FLG_PTP, &l2->flag) || | ||
2160 | test_bit(FLG_LAPD_NET, &l2->flag)) | ||
2161 | l2->l2m.state = ST_L2_4; | ||
2162 | else | ||
2163 | l2->l2m.state = ST_L2_1; | ||
2164 | l2->l2m.debug = *debug; | ||
2165 | l2->l2m.userdata = l2; | ||
2166 | l2->l2m.userint = 0; | ||
2167 | l2->l2m.printdebug = l2m_debug; | ||
2168 | |||
2169 | mISDN_FsmInitTimer(&l2->l2m, &l2->t200); | ||
2170 | mISDN_FsmInitTimer(&l2->l2m, &l2->t203); | ||
2171 | return l2; | ||
2172 | } | ||
2173 | |||
2174 | static int | ||
2175 | x75create(struct channel_req *crq) | ||
2176 | { | ||
2177 | struct layer2 *l2; | ||
2178 | |||
2179 | if (crq->protocol != ISDN_P_B_X75SLP) | ||
2180 | return -EPROTONOSUPPORT; | ||
2181 | l2 = create_l2(crq->ch, crq->protocol, 0, 0); | ||
2182 | if (!l2) | ||
2183 | return -ENOMEM; | ||
2184 | crq->ch = &l2->ch; | ||
2185 | crq->protocol = ISDN_P_B_HDLC; | ||
2186 | return 0; | ||
2187 | } | ||
2188 | |||
2189 | static struct Bprotocol X75SLP = { | ||
2190 | .Bprotocols = (1 << (ISDN_P_B_X75SLP & ISDN_P_B_MASK)), | ||
2191 | .name = "X75SLP", | ||
2192 | .create = x75create | ||
2193 | }; | ||
2194 | |||
2195 | int | ||
2196 | Isdnl2_Init(u_int *deb) | ||
2197 | { | ||
2198 | debug = deb; | ||
2199 | mISDN_register_Bprotocol(&X75SLP); | ||
2200 | l2fsm.state_count = L2_STATE_COUNT; | ||
2201 | l2fsm.event_count = L2_EVENT_COUNT; | ||
2202 | l2fsm.strEvent = strL2Event; | ||
2203 | l2fsm.strState = strL2State; | ||
2204 | mISDN_FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList)); | ||
2205 | TEIInit(deb); | ||
2206 | return 0; | ||
2207 | } | ||
2208 | |||
2209 | void | ||
2210 | Isdnl2_cleanup(void) | ||
2211 | { | ||
2212 | mISDN_unregister_Bprotocol(&X75SLP); | ||
2213 | TEIFree(); | ||
2214 | mISDN_FsmFree(&l2fsm); | ||
2215 | } | ||
2216 | |||
diff --git a/drivers/isdn/mISDN/layer2.h b/drivers/isdn/mISDN/layer2.h new file mode 100644 index 000000000000..de2dd02056a3 --- /dev/null +++ b/drivers/isdn/mISDN/layer2.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Layer 2 defines | ||
3 | * | ||
4 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/mISDNif.h> | ||
18 | #include <linux/skbuff.h> | ||
19 | #include "fsm.h" | ||
20 | |||
21 | #define MAX_WINDOW 8 | ||
22 | |||
23 | struct manager { | ||
24 | struct mISDNchannel ch; | ||
25 | struct mISDNchannel bcast; | ||
26 | u_long options; | ||
27 | struct list_head layer2; | ||
28 | rwlock_t lock; | ||
29 | struct FsmInst deact; | ||
30 | struct FsmTimer datimer; | ||
31 | struct sk_buff_head sendq; | ||
32 | struct mISDNchannel *up; | ||
33 | u_int nextid; | ||
34 | u_int lastid; | ||
35 | }; | ||
36 | |||
37 | struct teimgr { | ||
38 | int ri; | ||
39 | int rcnt; | ||
40 | struct FsmInst tei_m; | ||
41 | struct FsmTimer timer; | ||
42 | int tval, nval; | ||
43 | struct layer2 *l2; | ||
44 | struct manager *mgr; | ||
45 | }; | ||
46 | |||
47 | struct laddr { | ||
48 | u_char A; | ||
49 | u_char B; | ||
50 | }; | ||
51 | |||
52 | struct layer2 { | ||
53 | struct list_head list; | ||
54 | struct mISDNchannel ch; | ||
55 | u_long flag; | ||
56 | int id; | ||
57 | struct mISDNchannel *up; | ||
58 | signed char sapi; | ||
59 | signed char tei; | ||
60 | struct laddr addr; | ||
61 | u_int maxlen; | ||
62 | struct teimgr *tm; | ||
63 | u_int vs, va, vr; | ||
64 | int rc; | ||
65 | u_int window; | ||
66 | u_int sow; | ||
67 | struct FsmInst l2m; | ||
68 | struct FsmTimer t200, t203; | ||
69 | int T200, N200, T203; | ||
70 | u_int next_id; | ||
71 | u_int down_id; | ||
72 | struct sk_buff *windowar[MAX_WINDOW]; | ||
73 | struct sk_buff_head i_queue; | ||
74 | struct sk_buff_head ui_queue; | ||
75 | struct sk_buff_head down_queue; | ||
76 | struct sk_buff_head tmp_queue; | ||
77 | }; | ||
78 | |||
79 | enum { | ||
80 | ST_L2_1, | ||
81 | ST_L2_2, | ||
82 | ST_L2_3, | ||
83 | ST_L2_4, | ||
84 | ST_L2_5, | ||
85 | ST_L2_6, | ||
86 | ST_L2_7, | ||
87 | ST_L2_8, | ||
88 | }; | ||
89 | |||
90 | #define L2_STATE_COUNT (ST_L2_8+1) | ||
91 | |||
92 | extern struct layer2 *create_l2(struct mISDNchannel *, u_int, | ||
93 | u_long, u_long); | ||
94 | extern int tei_l2(struct layer2 *, u_int, u_long arg); | ||
95 | |||
96 | |||
97 | /* from tei.c */ | ||
98 | extern int l2_tei(struct layer2 *, u_int, u_long arg); | ||
99 | extern void release_tei(struct layer2 *); | ||
100 | extern int TEIInit(u_int *); | ||
101 | extern void TEIFree(void); | ||
102 | |||
103 | #define MAX_L2HEADER_LEN 4 | ||
104 | |||
105 | #define RR 0x01 | ||
106 | #define RNR 0x05 | ||
107 | #define REJ 0x09 | ||
108 | #define SABME 0x6f | ||
109 | #define SABM 0x2f | ||
110 | #define DM 0x0f | ||
111 | #define UI 0x03 | ||
112 | #define DISC 0x43 | ||
113 | #define UA 0x63 | ||
114 | #define FRMR 0x87 | ||
115 | #define XID 0xaf | ||
116 | |||
117 | #define CMD 0 | ||
118 | #define RSP 1 | ||
119 | |||
120 | #define LC_FLUSH_WAIT 1 | ||
121 | |||
122 | #define FLG_LAPB 0 | ||
123 | #define FLG_LAPD 1 | ||
124 | #define FLG_ORIG 2 | ||
125 | #define FLG_MOD128 3 | ||
126 | #define FLG_PEND_REL 4 | ||
127 | #define FLG_L3_INIT 5 | ||
128 | #define FLG_T200_RUN 6 | ||
129 | #define FLG_ACK_PEND 7 | ||
130 | #define FLG_REJEXC 8 | ||
131 | #define FLG_OWN_BUSY 9 | ||
132 | #define FLG_PEER_BUSY 10 | ||
133 | #define FLG_DCHAN_BUSY 11 | ||
134 | #define FLG_L1_ACTIV 12 | ||
135 | #define FLG_ESTAB_PEND 13 | ||
136 | #define FLG_PTP 14 | ||
137 | #define FLG_FIXED_TEI 15 | ||
138 | #define FLG_L2BLOCK 16 | ||
139 | #define FLG_L1_NOTREADY 17 | ||
140 | #define FLG_LAPD_NET 18 | ||
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c new file mode 100644 index 000000000000..4ba4cc364c9e --- /dev/null +++ b/drivers/isdn/mISDN/socket.c | |||
@@ -0,0 +1,781 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/mISDNif.h> | ||
19 | #include "core.h" | ||
20 | |||
21 | static int *debug; | ||
22 | |||
23 | static struct proto mISDN_proto = { | ||
24 | .name = "misdn", | ||
25 | .owner = THIS_MODULE, | ||
26 | .obj_size = sizeof(struct mISDN_sock) | ||
27 | }; | ||
28 | |||
29 | #define _pms(sk) ((struct mISDN_sock *)sk) | ||
30 | |||
31 | static struct mISDN_sock_list data_sockets = { | ||
32 | .lock = __RW_LOCK_UNLOCKED(data_sockets.lock) | ||
33 | }; | ||
34 | |||
35 | static struct mISDN_sock_list base_sockets = { | ||
36 | .lock = __RW_LOCK_UNLOCKED(base_sockets.lock) | ||
37 | }; | ||
38 | |||
39 | #define L2_HEADER_LEN 4 | ||
40 | |||
41 | static inline struct sk_buff * | ||
42 | _l2_alloc_skb(unsigned int len, gfp_t gfp_mask) | ||
43 | { | ||
44 | struct sk_buff *skb; | ||
45 | |||
46 | skb = alloc_skb(len + L2_HEADER_LEN, gfp_mask); | ||
47 | if (likely(skb)) | ||
48 | skb_reserve(skb, L2_HEADER_LEN); | ||
49 | return skb; | ||
50 | } | ||
51 | |||
52 | static void | ||
53 | mISDN_sock_link(struct mISDN_sock_list *l, struct sock *sk) | ||
54 | { | ||
55 | write_lock_bh(&l->lock); | ||
56 | sk_add_node(sk, &l->head); | ||
57 | write_unlock_bh(&l->lock); | ||
58 | } | ||
59 | |||
60 | static void mISDN_sock_unlink(struct mISDN_sock_list *l, struct sock *sk) | ||
61 | { | ||
62 | write_lock_bh(&l->lock); | ||
63 | sk_del_node_init(sk); | ||
64 | write_unlock_bh(&l->lock); | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | mISDN_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
69 | { | ||
70 | struct mISDN_sock *msk; | ||
71 | int err; | ||
72 | |||
73 | msk = container_of(ch, struct mISDN_sock, ch); | ||
74 | if (*debug & DEBUG_SOCKET) | ||
75 | printk(KERN_DEBUG "%s len %d %p\n", __func__, skb->len, skb); | ||
76 | if (msk->sk.sk_state == MISDN_CLOSED) | ||
77 | return -EUNATCH; | ||
78 | __net_timestamp(skb); | ||
79 | err = sock_queue_rcv_skb(&msk->sk, skb); | ||
80 | if (err) | ||
81 | printk(KERN_WARNING "%s: error %d\n", __func__, err); | ||
82 | return err; | ||
83 | } | ||
84 | |||
85 | static int | ||
86 | mISDN_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
87 | { | ||
88 | struct mISDN_sock *msk; | ||
89 | |||
90 | msk = container_of(ch, struct mISDN_sock, ch); | ||
91 | if (*debug & DEBUG_SOCKET) | ||
92 | printk(KERN_DEBUG "%s(%p, %x, %p)\n", __func__, ch, cmd, arg); | ||
93 | switch (cmd) { | ||
94 | case CLOSE_CHANNEL: | ||
95 | msk->sk.sk_state = MISDN_CLOSED; | ||
96 | break; | ||
97 | } | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static inline void | ||
102 | mISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | ||
103 | { | ||
104 | struct timeval tv; | ||
105 | |||
106 | if (_pms(sk)->cmask & MISDN_TIME_STAMP) { | ||
107 | skb_get_timestamp(skb, &tv); | ||
108 | put_cmsg(msg, SOL_MISDN, MISDN_TIME_STAMP, sizeof(tv), &tv); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | static int | ||
113 | mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | ||
114 | struct msghdr *msg, size_t len, int flags) | ||
115 | { | ||
116 | struct sk_buff *skb; | ||
117 | struct sock *sk = sock->sk; | ||
118 | struct sockaddr_mISDN *maddr; | ||
119 | |||
120 | int copied, err; | ||
121 | |||
122 | if (*debug & DEBUG_SOCKET) | ||
123 | printk(KERN_DEBUG "%s: len %d, flags %x ch.nr %d, proto %x\n", | ||
124 | __func__, (int)len, flags, _pms(sk)->ch.nr, | ||
125 | sk->sk_protocol); | ||
126 | if (flags & (MSG_OOB)) | ||
127 | return -EOPNOTSUPP; | ||
128 | |||
129 | if (sk->sk_state == MISDN_CLOSED) | ||
130 | return 0; | ||
131 | |||
132 | skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); | ||
133 | if (!skb) | ||
134 | return err; | ||
135 | |||
136 | if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { | ||
137 | msg->msg_namelen = sizeof(struct sockaddr_mISDN); | ||
138 | maddr = (struct sockaddr_mISDN *)msg->msg_name; | ||
139 | maddr->family = AF_ISDN; | ||
140 | maddr->dev = _pms(sk)->dev->id; | ||
141 | if ((sk->sk_protocol == ISDN_P_LAPD_TE) || | ||
142 | (sk->sk_protocol == ISDN_P_LAPD_NT)) { | ||
143 | maddr->channel = (mISDN_HEAD_ID(skb) >> 16) & 0xff; | ||
144 | maddr->tei = (mISDN_HEAD_ID(skb) >> 8) & 0xff; | ||
145 | maddr->sapi = mISDN_HEAD_ID(skb) & 0xff; | ||
146 | } else { | ||
147 | maddr->channel = _pms(sk)->ch.nr; | ||
148 | maddr->sapi = _pms(sk)->ch.addr & 0xFF; | ||
149 | maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF; | ||
150 | } | ||
151 | } else { | ||
152 | if (msg->msg_namelen) | ||
153 | printk(KERN_WARNING "%s: too small namelen %d\n", | ||
154 | __func__, msg->msg_namelen); | ||
155 | msg->msg_namelen = 0; | ||
156 | } | ||
157 | |||
158 | copied = skb->len + MISDN_HEADER_LEN; | ||
159 | if (len < copied) { | ||
160 | if (flags & MSG_PEEK) | ||
161 | atomic_dec(&skb->users); | ||
162 | else | ||
163 | skb_queue_head(&sk->sk_receive_queue, skb); | ||
164 | return -ENOSPC; | ||
165 | } | ||
166 | memcpy(skb_push(skb, MISDN_HEADER_LEN), mISDN_HEAD_P(skb), | ||
167 | MISDN_HEADER_LEN); | ||
168 | |||
169 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | ||
170 | |||
171 | mISDN_sock_cmsg(sk, msg, skb); | ||
172 | |||
173 | skb_free_datagram(sk, skb); | ||
174 | |||
175 | return err ? : copied; | ||
176 | } | ||
177 | |||
178 | static int | ||
179 | mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | ||
180 | struct msghdr *msg, size_t len) | ||
181 | { | ||
182 | struct sock *sk = sock->sk; | ||
183 | struct sk_buff *skb; | ||
184 | int err = -ENOMEM; | ||
185 | struct sockaddr_mISDN *maddr; | ||
186 | |||
187 | if (*debug & DEBUG_SOCKET) | ||
188 | printk(KERN_DEBUG "%s: len %d flags %x ch %d proto %x\n", | ||
189 | __func__, (int)len, msg->msg_flags, _pms(sk)->ch.nr, | ||
190 | sk->sk_protocol); | ||
191 | |||
192 | if (msg->msg_flags & MSG_OOB) | ||
193 | return -EOPNOTSUPP; | ||
194 | |||
195 | if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE)) | ||
196 | return -EINVAL; | ||
197 | |||
198 | if (len < MISDN_HEADER_LEN) | ||
199 | return -EINVAL; | ||
200 | |||
201 | if (sk->sk_state != MISDN_BOUND) | ||
202 | return -EBADFD; | ||
203 | |||
204 | lock_sock(sk); | ||
205 | |||
206 | skb = _l2_alloc_skb(len, GFP_KERNEL); | ||
207 | if (!skb) | ||
208 | goto done; | ||
209 | |||
210 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | ||
211 | err = -EFAULT; | ||
212 | goto drop; | ||
213 | } | ||
214 | |||
215 | memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN); | ||
216 | skb_pull(skb, MISDN_HEADER_LEN); | ||
217 | |||
218 | if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { | ||
219 | /* if we have a address, we use it */ | ||
220 | maddr = (struct sockaddr_mISDN *)msg->msg_name; | ||
221 | mISDN_HEAD_ID(skb) = maddr->channel; | ||
222 | } else { /* use default for L2 messages */ | ||
223 | if ((sk->sk_protocol == ISDN_P_LAPD_TE) || | ||
224 | (sk->sk_protocol == ISDN_P_LAPD_NT)) | ||
225 | mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; | ||
226 | } | ||
227 | |||
228 | if (*debug & DEBUG_SOCKET) | ||
229 | printk(KERN_DEBUG "%s: ID:%x\n", | ||
230 | __func__, mISDN_HEAD_ID(skb)); | ||
231 | |||
232 | err = -ENODEV; | ||
233 | if (!_pms(sk)->ch.peer || | ||
234 | (err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb))) | ||
235 | goto drop; | ||
236 | |||
237 | err = len; | ||
238 | |||
239 | done: | ||
240 | release_sock(sk); | ||
241 | return err; | ||
242 | |||
243 | drop: | ||
244 | kfree_skb(skb); | ||
245 | goto done; | ||
246 | } | ||
247 | |||
248 | static int | ||
249 | data_sock_release(struct socket *sock) | ||
250 | { | ||
251 | struct sock *sk = sock->sk; | ||
252 | |||
253 | if (*debug & DEBUG_SOCKET) | ||
254 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
255 | if (!sk) | ||
256 | return 0; | ||
257 | switch (sk->sk_protocol) { | ||
258 | case ISDN_P_TE_S0: | ||
259 | case ISDN_P_NT_S0: | ||
260 | case ISDN_P_TE_E1: | ||
261 | case ISDN_P_NT_E1: | ||
262 | if (sk->sk_state == MISDN_BOUND) | ||
263 | delete_channel(&_pms(sk)->ch); | ||
264 | else | ||
265 | mISDN_sock_unlink(&data_sockets, sk); | ||
266 | break; | ||
267 | case ISDN_P_LAPD_TE: | ||
268 | case ISDN_P_LAPD_NT: | ||
269 | case ISDN_P_B_RAW: | ||
270 | case ISDN_P_B_HDLC: | ||
271 | case ISDN_P_B_X75SLP: | ||
272 | case ISDN_P_B_L2DTMF: | ||
273 | case ISDN_P_B_L2DSP: | ||
274 | case ISDN_P_B_L2DSPHDLC: | ||
275 | delete_channel(&_pms(sk)->ch); | ||
276 | mISDN_sock_unlink(&data_sockets, sk); | ||
277 | break; | ||
278 | } | ||
279 | |||
280 | lock_sock(sk); | ||
281 | |||
282 | sock_orphan(sk); | ||
283 | skb_queue_purge(&sk->sk_receive_queue); | ||
284 | |||
285 | release_sock(sk); | ||
286 | sock_put(sk); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int | ||
292 | data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) | ||
293 | { | ||
294 | struct mISDN_ctrl_req cq; | ||
295 | int err = -EINVAL, val; | ||
296 | struct mISDNchannel *bchan, *next; | ||
297 | |||
298 | lock_sock(sk); | ||
299 | if (!_pms(sk)->dev) { | ||
300 | err = -ENODEV; | ||
301 | goto done; | ||
302 | } | ||
303 | switch (cmd) { | ||
304 | case IMCTRLREQ: | ||
305 | if (copy_from_user(&cq, p, sizeof(cq))) { | ||
306 | err = -EFAULT; | ||
307 | break; | ||
308 | } | ||
309 | if ((sk->sk_protocol & ~ISDN_P_B_MASK) == ISDN_P_B_START) { | ||
310 | list_for_each_entry_safe(bchan, next, | ||
311 | &_pms(sk)->dev->bchannels, list) { | ||
312 | if (bchan->nr == cq.channel) { | ||
313 | err = bchan->ctrl(bchan, | ||
314 | CONTROL_CHANNEL, &cq); | ||
315 | break; | ||
316 | } | ||
317 | } | ||
318 | } else | ||
319 | err = _pms(sk)->dev->D.ctrl(&_pms(sk)->dev->D, | ||
320 | CONTROL_CHANNEL, &cq); | ||
321 | if (err) | ||
322 | break; | ||
323 | if (copy_to_user(p, &cq, sizeof(cq))) | ||
324 | err = -EFAULT; | ||
325 | break; | ||
326 | case IMCLEAR_L2: | ||
327 | if (sk->sk_protocol != ISDN_P_LAPD_NT) { | ||
328 | err = -EINVAL; | ||
329 | break; | ||
330 | } | ||
331 | if (get_user(val, (int __user *)p)) { | ||
332 | err = -EFAULT; | ||
333 | break; | ||
334 | } | ||
335 | err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, | ||
336 | CONTROL_CHANNEL, &val); | ||
337 | break; | ||
338 | default: | ||
339 | err = -EINVAL; | ||
340 | break; | ||
341 | } | ||
342 | done: | ||
343 | release_sock(sk); | ||
344 | return err; | ||
345 | } | ||
346 | |||
347 | static int | ||
348 | data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
349 | { | ||
350 | int err = 0, id; | ||
351 | struct sock *sk = sock->sk; | ||
352 | struct mISDNdevice *dev; | ||
353 | struct mISDNversion ver; | ||
354 | |||
355 | switch (cmd) { | ||
356 | case IMGETVERSION: | ||
357 | ver.major = MISDN_MAJOR_VERSION; | ||
358 | ver.minor = MISDN_MINOR_VERSION; | ||
359 | ver.release = MISDN_RELEASE; | ||
360 | if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) | ||
361 | err = -EFAULT; | ||
362 | break; | ||
363 | case IMGETCOUNT: | ||
364 | id = get_mdevice_count(); | ||
365 | if (put_user(id, (int __user *)arg)) | ||
366 | err = -EFAULT; | ||
367 | break; | ||
368 | case IMGETDEVINFO: | ||
369 | if (get_user(id, (int __user *)arg)) { | ||
370 | err = -EFAULT; | ||
371 | break; | ||
372 | } | ||
373 | dev = get_mdevice(id); | ||
374 | if (dev) { | ||
375 | struct mISDN_devinfo di; | ||
376 | |||
377 | di.id = dev->id; | ||
378 | di.Dprotocols = dev->Dprotocols; | ||
379 | di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); | ||
380 | di.protocol = dev->D.protocol; | ||
381 | memcpy(di.channelmap, dev->channelmap, | ||
382 | MISDN_CHMAP_SIZE * 4); | ||
383 | di.nrbchan = dev->nrbchan; | ||
384 | strcpy(di.name, dev->name); | ||
385 | if (copy_to_user((void __user *)arg, &di, sizeof(di))) | ||
386 | err = -EFAULT; | ||
387 | } else | ||
388 | err = -ENODEV; | ||
389 | break; | ||
390 | default: | ||
391 | if (sk->sk_state == MISDN_BOUND) | ||
392 | err = data_sock_ioctl_bound(sk, cmd, | ||
393 | (void __user *)arg); | ||
394 | else | ||
395 | err = -ENOTCONN; | ||
396 | } | ||
397 | return err; | ||
398 | } | ||
399 | |||
400 | static int data_sock_setsockopt(struct socket *sock, int level, int optname, | ||
401 | char __user *optval, int len) | ||
402 | { | ||
403 | struct sock *sk = sock->sk; | ||
404 | int err = 0, opt = 0; | ||
405 | |||
406 | if (*debug & DEBUG_SOCKET) | ||
407 | printk(KERN_DEBUG "%s(%p, %d, %x, %p, %d)\n", __func__, sock, | ||
408 | level, optname, optval, len); | ||
409 | |||
410 | lock_sock(sk); | ||
411 | |||
412 | switch (optname) { | ||
413 | case MISDN_TIME_STAMP: | ||
414 | if (get_user(opt, (int __user *)optval)) { | ||
415 | err = -EFAULT; | ||
416 | break; | ||
417 | } | ||
418 | |||
419 | if (opt) | ||
420 | _pms(sk)->cmask |= MISDN_TIME_STAMP; | ||
421 | else | ||
422 | _pms(sk)->cmask &= ~MISDN_TIME_STAMP; | ||
423 | break; | ||
424 | default: | ||
425 | err = -ENOPROTOOPT; | ||
426 | break; | ||
427 | } | ||
428 | release_sock(sk); | ||
429 | return err; | ||
430 | } | ||
431 | |||
432 | static int data_sock_getsockopt(struct socket *sock, int level, int optname, | ||
433 | char __user *optval, int __user *optlen) | ||
434 | { | ||
435 | struct sock *sk = sock->sk; | ||
436 | int len, opt; | ||
437 | |||
438 | if (get_user(len, optlen)) | ||
439 | return -EFAULT; | ||
440 | |||
441 | switch (optname) { | ||
442 | case MISDN_TIME_STAMP: | ||
443 | if (_pms(sk)->cmask & MISDN_TIME_STAMP) | ||
444 | opt = 1; | ||
445 | else | ||
446 | opt = 0; | ||
447 | |||
448 | if (put_user(opt, optval)) | ||
449 | return -EFAULT; | ||
450 | break; | ||
451 | default: | ||
452 | return -ENOPROTOOPT; | ||
453 | } | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | static int | ||
459 | data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | ||
460 | { | ||
461 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
462 | struct sock *sk = sock->sk; | ||
463 | int err = 0; | ||
464 | |||
465 | if (*debug & DEBUG_SOCKET) | ||
466 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
467 | if (addr_len != sizeof(struct sockaddr_mISDN)) | ||
468 | return -EINVAL; | ||
469 | if (!maddr || maddr->family != AF_ISDN) | ||
470 | return -EINVAL; | ||
471 | |||
472 | lock_sock(sk); | ||
473 | |||
474 | if (_pms(sk)->dev) { | ||
475 | err = -EALREADY; | ||
476 | goto done; | ||
477 | } | ||
478 | _pms(sk)->dev = get_mdevice(maddr->dev); | ||
479 | if (!_pms(sk)->dev) { | ||
480 | err = -ENODEV; | ||
481 | goto done; | ||
482 | } | ||
483 | _pms(sk)->ch.send = mISDN_send; | ||
484 | _pms(sk)->ch.ctrl = mISDN_ctrl; | ||
485 | |||
486 | switch (sk->sk_protocol) { | ||
487 | case ISDN_P_TE_S0: | ||
488 | case ISDN_P_NT_S0: | ||
489 | case ISDN_P_TE_E1: | ||
490 | case ISDN_P_NT_E1: | ||
491 | mISDN_sock_unlink(&data_sockets, sk); | ||
492 | err = connect_layer1(_pms(sk)->dev, &_pms(sk)->ch, | ||
493 | sk->sk_protocol, maddr); | ||
494 | if (err) | ||
495 | mISDN_sock_link(&data_sockets, sk); | ||
496 | break; | ||
497 | case ISDN_P_LAPD_TE: | ||
498 | case ISDN_P_LAPD_NT: | ||
499 | err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch, | ||
500 | sk->sk_protocol, maddr); | ||
501 | break; | ||
502 | case ISDN_P_B_RAW: | ||
503 | case ISDN_P_B_HDLC: | ||
504 | case ISDN_P_B_X75SLP: | ||
505 | case ISDN_P_B_L2DTMF: | ||
506 | case ISDN_P_B_L2DSP: | ||
507 | case ISDN_P_B_L2DSPHDLC: | ||
508 | err = connect_Bstack(_pms(sk)->dev, &_pms(sk)->ch, | ||
509 | sk->sk_protocol, maddr); | ||
510 | break; | ||
511 | default: | ||
512 | err = -EPROTONOSUPPORT; | ||
513 | } | ||
514 | if (err) | ||
515 | goto done; | ||
516 | sk->sk_state = MISDN_BOUND; | ||
517 | _pms(sk)->ch.protocol = sk->sk_protocol; | ||
518 | |||
519 | done: | ||
520 | release_sock(sk); | ||
521 | return err; | ||
522 | } | ||
523 | |||
524 | static int | ||
525 | data_sock_getname(struct socket *sock, struct sockaddr *addr, | ||
526 | int *addr_len, int peer) | ||
527 | { | ||
528 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
529 | struct sock *sk = sock->sk; | ||
530 | |||
531 | if (!_pms(sk)->dev) | ||
532 | return -EBADFD; | ||
533 | |||
534 | lock_sock(sk); | ||
535 | |||
536 | *addr_len = sizeof(*maddr); | ||
537 | maddr->dev = _pms(sk)->dev->id; | ||
538 | maddr->channel = _pms(sk)->ch.nr; | ||
539 | maddr->sapi = _pms(sk)->ch.addr & 0xff; | ||
540 | maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xff; | ||
541 | release_sock(sk); | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static const struct proto_ops data_sock_ops = { | ||
546 | .family = PF_ISDN, | ||
547 | .owner = THIS_MODULE, | ||
548 | .release = data_sock_release, | ||
549 | .ioctl = data_sock_ioctl, | ||
550 | .bind = data_sock_bind, | ||
551 | .getname = data_sock_getname, | ||
552 | .sendmsg = mISDN_sock_sendmsg, | ||
553 | .recvmsg = mISDN_sock_recvmsg, | ||
554 | .poll = datagram_poll, | ||
555 | .listen = sock_no_listen, | ||
556 | .shutdown = sock_no_shutdown, | ||
557 | .setsockopt = data_sock_setsockopt, | ||
558 | .getsockopt = data_sock_getsockopt, | ||
559 | .connect = sock_no_connect, | ||
560 | .socketpair = sock_no_socketpair, | ||
561 | .accept = sock_no_accept, | ||
562 | .mmap = sock_no_mmap | ||
563 | }; | ||
564 | |||
565 | static int | ||
566 | data_sock_create(struct net *net, struct socket *sock, int protocol) | ||
567 | { | ||
568 | struct sock *sk; | ||
569 | |||
570 | if (sock->type != SOCK_DGRAM) | ||
571 | return -ESOCKTNOSUPPORT; | ||
572 | |||
573 | sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto); | ||
574 | if (!sk) | ||
575 | return -ENOMEM; | ||
576 | |||
577 | sock_init_data(sock, sk); | ||
578 | |||
579 | sock->ops = &data_sock_ops; | ||
580 | sock->state = SS_UNCONNECTED; | ||
581 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
582 | |||
583 | sk->sk_protocol = protocol; | ||
584 | sk->sk_state = MISDN_OPEN; | ||
585 | mISDN_sock_link(&data_sockets, sk); | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static int | ||
591 | base_sock_release(struct socket *sock) | ||
592 | { | ||
593 | struct sock *sk = sock->sk; | ||
594 | |||
595 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
596 | if (!sk) | ||
597 | return 0; | ||
598 | |||
599 | mISDN_sock_unlink(&base_sockets, sk); | ||
600 | sock_orphan(sk); | ||
601 | sock_put(sk); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static int | ||
607 | base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
608 | { | ||
609 | int err = 0, id; | ||
610 | struct mISDNdevice *dev; | ||
611 | struct mISDNversion ver; | ||
612 | |||
613 | switch (cmd) { | ||
614 | case IMGETVERSION: | ||
615 | ver.major = MISDN_MAJOR_VERSION; | ||
616 | ver.minor = MISDN_MINOR_VERSION; | ||
617 | ver.release = MISDN_RELEASE; | ||
618 | if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) | ||
619 | err = -EFAULT; | ||
620 | break; | ||
621 | case IMGETCOUNT: | ||
622 | id = get_mdevice_count(); | ||
623 | if (put_user(id, (int __user *)arg)) | ||
624 | err = -EFAULT; | ||
625 | break; | ||
626 | case IMGETDEVINFO: | ||
627 | if (get_user(id, (int __user *)arg)) { | ||
628 | err = -EFAULT; | ||
629 | break; | ||
630 | } | ||
631 | dev = get_mdevice(id); | ||
632 | if (dev) { | ||
633 | struct mISDN_devinfo di; | ||
634 | |||
635 | di.id = dev->id; | ||
636 | di.Dprotocols = dev->Dprotocols; | ||
637 | di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); | ||
638 | di.protocol = dev->D.protocol; | ||
639 | memcpy(di.channelmap, dev->channelmap, | ||
640 | MISDN_CHMAP_SIZE * 4); | ||
641 | di.nrbchan = dev->nrbchan; | ||
642 | strcpy(di.name, dev->name); | ||
643 | if (copy_to_user((void __user *)arg, &di, sizeof(di))) | ||
644 | err = -EFAULT; | ||
645 | } else | ||
646 | err = -ENODEV; | ||
647 | break; | ||
648 | default: | ||
649 | err = -EINVAL; | ||
650 | } | ||
651 | return err; | ||
652 | } | ||
653 | |||
654 | static int | ||
655 | base_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | ||
656 | { | ||
657 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
658 | struct sock *sk = sock->sk; | ||
659 | int err = 0; | ||
660 | |||
661 | if (!maddr || maddr->family != AF_ISDN) | ||
662 | return -EINVAL; | ||
663 | |||
664 | lock_sock(sk); | ||
665 | |||
666 | if (_pms(sk)->dev) { | ||
667 | err = -EALREADY; | ||
668 | goto done; | ||
669 | } | ||
670 | |||
671 | _pms(sk)->dev = get_mdevice(maddr->dev); | ||
672 | if (!_pms(sk)->dev) { | ||
673 | err = -ENODEV; | ||
674 | goto done; | ||
675 | } | ||
676 | sk->sk_state = MISDN_BOUND; | ||
677 | |||
678 | done: | ||
679 | release_sock(sk); | ||
680 | return err; | ||
681 | } | ||
682 | |||
683 | static const struct proto_ops base_sock_ops = { | ||
684 | .family = PF_ISDN, | ||
685 | .owner = THIS_MODULE, | ||
686 | .release = base_sock_release, | ||
687 | .ioctl = base_sock_ioctl, | ||
688 | .bind = base_sock_bind, | ||
689 | .getname = sock_no_getname, | ||
690 | .sendmsg = sock_no_sendmsg, | ||
691 | .recvmsg = sock_no_recvmsg, | ||
692 | .poll = sock_no_poll, | ||
693 | .listen = sock_no_listen, | ||
694 | .shutdown = sock_no_shutdown, | ||
695 | .setsockopt = sock_no_setsockopt, | ||
696 | .getsockopt = sock_no_getsockopt, | ||
697 | .connect = sock_no_connect, | ||
698 | .socketpair = sock_no_socketpair, | ||
699 | .accept = sock_no_accept, | ||
700 | .mmap = sock_no_mmap | ||
701 | }; | ||
702 | |||
703 | |||
704 | static int | ||
705 | base_sock_create(struct net *net, struct socket *sock, int protocol) | ||
706 | { | ||
707 | struct sock *sk; | ||
708 | |||
709 | if (sock->type != SOCK_RAW) | ||
710 | return -ESOCKTNOSUPPORT; | ||
711 | |||
712 | sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto); | ||
713 | if (!sk) | ||
714 | return -ENOMEM; | ||
715 | |||
716 | sock_init_data(sock, sk); | ||
717 | sock->ops = &base_sock_ops; | ||
718 | sock->state = SS_UNCONNECTED; | ||
719 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
720 | sk->sk_protocol = protocol; | ||
721 | sk->sk_state = MISDN_OPEN; | ||
722 | mISDN_sock_link(&base_sockets, sk); | ||
723 | |||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | static int | ||
728 | mISDN_sock_create(struct net *net, struct socket *sock, int proto) | ||
729 | { | ||
730 | int err = -EPROTONOSUPPORT; | ||
731 | |||
732 | switch (proto) { | ||
733 | case ISDN_P_BASE: | ||
734 | err = base_sock_create(net, sock, proto); | ||
735 | break; | ||
736 | case ISDN_P_TE_S0: | ||
737 | case ISDN_P_NT_S0: | ||
738 | case ISDN_P_TE_E1: | ||
739 | case ISDN_P_NT_E1: | ||
740 | case ISDN_P_LAPD_TE: | ||
741 | case ISDN_P_LAPD_NT: | ||
742 | case ISDN_P_B_RAW: | ||
743 | case ISDN_P_B_HDLC: | ||
744 | case ISDN_P_B_X75SLP: | ||
745 | case ISDN_P_B_L2DTMF: | ||
746 | case ISDN_P_B_L2DSP: | ||
747 | case ISDN_P_B_L2DSPHDLC: | ||
748 | err = data_sock_create(net, sock, proto); | ||
749 | break; | ||
750 | default: | ||
751 | return err; | ||
752 | } | ||
753 | |||
754 | return err; | ||
755 | } | ||
756 | |||
757 | static struct | ||
758 | net_proto_family mISDN_sock_family_ops = { | ||
759 | .owner = THIS_MODULE, | ||
760 | .family = PF_ISDN, | ||
761 | .create = mISDN_sock_create, | ||
762 | }; | ||
763 | |||
764 | int | ||
765 | misdn_sock_init(u_int *deb) | ||
766 | { | ||
767 | int err; | ||
768 | |||
769 | debug = deb; | ||
770 | err = sock_register(&mISDN_sock_family_ops); | ||
771 | if (err) | ||
772 | printk(KERN_ERR "%s: error(%d)\n", __func__, err); | ||
773 | return err; | ||
774 | } | ||
775 | |||
776 | void | ||
777 | misdn_sock_cleanup(void) | ||
778 | { | ||
779 | sock_unregister(PF_ISDN); | ||
780 | } | ||
781 | |||
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c new file mode 100644 index 000000000000..54cfddcc4784 --- /dev/null +++ b/drivers/isdn/mISDN/stack.c | |||
@@ -0,0 +1,674 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/mISDNif.h> | ||
19 | #include <linux/kthread.h> | ||
20 | #include "core.h" | ||
21 | |||
22 | static u_int *debug; | ||
23 | |||
24 | static inline void | ||
25 | _queue_message(struct mISDNstack *st, struct sk_buff *skb) | ||
26 | { | ||
27 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
28 | |||
29 | if (*debug & DEBUG_QUEUE_FUNC) | ||
30 | printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", | ||
31 | __func__, hh->prim, hh->id, skb); | ||
32 | skb_queue_tail(&st->msgq, skb); | ||
33 | if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) { | ||
34 | test_and_set_bit(mISDN_STACK_WORK, &st->status); | ||
35 | wake_up_interruptible(&st->workq); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | int | ||
40 | mISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb) | ||
41 | { | ||
42 | _queue_message(ch->st, skb); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static struct mISDNchannel * | ||
47 | get_channel4id(struct mISDNstack *st, u_int id) | ||
48 | { | ||
49 | struct mISDNchannel *ch; | ||
50 | |||
51 | mutex_lock(&st->lmutex); | ||
52 | list_for_each_entry(ch, &st->layer2, list) { | ||
53 | if (id == ch->nr) | ||
54 | goto unlock; | ||
55 | } | ||
56 | ch = NULL; | ||
57 | unlock: | ||
58 | mutex_unlock(&st->lmutex); | ||
59 | return ch; | ||
60 | } | ||
61 | |||
62 | static void | ||
63 | send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb) | ||
64 | { | ||
65 | struct hlist_node *node; | ||
66 | struct sock *sk; | ||
67 | struct sk_buff *cskb = NULL; | ||
68 | |||
69 | read_lock(&sl->lock); | ||
70 | sk_for_each(sk, node, &sl->head) { | ||
71 | if (sk->sk_state != MISDN_BOUND) | ||
72 | continue; | ||
73 | if (!cskb) | ||
74 | cskb = skb_copy(skb, GFP_KERNEL); | ||
75 | if (!cskb) { | ||
76 | printk(KERN_WARNING "%s no skb\n", __func__); | ||
77 | break; | ||
78 | } | ||
79 | if (!sock_queue_rcv_skb(sk, cskb)) | ||
80 | cskb = NULL; | ||
81 | } | ||
82 | read_unlock(&sl->lock); | ||
83 | if (cskb) | ||
84 | dev_kfree_skb(cskb); | ||
85 | } | ||
86 | |||
87 | static void | ||
88 | send_layer2(struct mISDNstack *st, struct sk_buff *skb) | ||
89 | { | ||
90 | struct sk_buff *cskb; | ||
91 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
92 | struct mISDNchannel *ch; | ||
93 | int ret; | ||
94 | |||
95 | if (!st) | ||
96 | return; | ||
97 | mutex_lock(&st->lmutex); | ||
98 | if ((hh->id & MISDN_ID_ADDR_MASK) == MISDN_ID_ANY) { /* L2 for all */ | ||
99 | list_for_each_entry(ch, &st->layer2, list) { | ||
100 | if (list_is_last(&ch->list, &st->layer2)) { | ||
101 | cskb = skb; | ||
102 | skb = NULL; | ||
103 | } else { | ||
104 | cskb = skb_copy(skb, GFP_KERNEL); | ||
105 | } | ||
106 | if (cskb) { | ||
107 | ret = ch->send(ch, cskb); | ||
108 | if (ret) { | ||
109 | if (*debug & DEBUG_SEND_ERR) | ||
110 | printk(KERN_DEBUG | ||
111 | "%s ch%d prim(%x) addr(%x)" | ||
112 | " err %d\n", | ||
113 | __func__, ch->nr, | ||
114 | hh->prim, ch->addr, ret); | ||
115 | dev_kfree_skb(cskb); | ||
116 | } | ||
117 | } else { | ||
118 | printk(KERN_WARNING "%s ch%d addr %x no mem\n", | ||
119 | __func__, ch->nr, ch->addr); | ||
120 | goto out; | ||
121 | } | ||
122 | } | ||
123 | } else { | ||
124 | list_for_each_entry(ch, &st->layer2, list) { | ||
125 | if ((hh->id & MISDN_ID_ADDR_MASK) == ch->addr) { | ||
126 | ret = ch->send(ch, skb); | ||
127 | if (!ret) | ||
128 | skb = NULL; | ||
129 | goto out; | ||
130 | } | ||
131 | } | ||
132 | ret = st->dev->teimgr->ctrl(st->dev->teimgr, CHECK_DATA, skb); | ||
133 | if (!ret) | ||
134 | skb = NULL; | ||
135 | else if (*debug & DEBUG_SEND_ERR) | ||
136 | printk(KERN_DEBUG | ||
137 | "%s ch%d mgr prim(%x) addr(%x) err %d\n", | ||
138 | __func__, ch->nr, hh->prim, ch->addr, ret); | ||
139 | } | ||
140 | out: | ||
141 | mutex_unlock(&st->lmutex); | ||
142 | if (skb) | ||
143 | dev_kfree_skb(skb); | ||
144 | } | ||
145 | |||
146 | static inline int | ||
147 | send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) | ||
148 | { | ||
149 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
150 | struct mISDNchannel *ch; | ||
151 | int lm; | ||
152 | |||
153 | lm = hh->prim & MISDN_LAYERMASK; | ||
154 | if (*debug & DEBUG_QUEUE_FUNC) | ||
155 | printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", | ||
156 | __func__, hh->prim, hh->id, skb); | ||
157 | if (lm == 0x1) { | ||
158 | if (!hlist_empty(&st->l1sock.head)) { | ||
159 | __net_timestamp(skb); | ||
160 | send_socklist(&st->l1sock, skb); | ||
161 | } | ||
162 | return st->layer1->send(st->layer1, skb); | ||
163 | } else if (lm == 0x2) { | ||
164 | if (!hlist_empty(&st->l1sock.head)) | ||
165 | send_socklist(&st->l1sock, skb); | ||
166 | send_layer2(st, skb); | ||
167 | return 0; | ||
168 | } else if (lm == 0x4) { | ||
169 | ch = get_channel4id(st, hh->id); | ||
170 | if (ch) | ||
171 | return ch->send(ch, skb); | ||
172 | else | ||
173 | printk(KERN_WARNING | ||
174 | "%s: dev(%s) prim(%x) id(%x) no channel\n", | ||
175 | __func__, st->dev->name, hh->prim, hh->id); | ||
176 | } else if (lm == 0x8) { | ||
177 | WARN_ON(lm == 0x8); | ||
178 | ch = get_channel4id(st, hh->id); | ||
179 | if (ch) | ||
180 | return ch->send(ch, skb); | ||
181 | else | ||
182 | printk(KERN_WARNING | ||
183 | "%s: dev(%s) prim(%x) id(%x) no channel\n", | ||
184 | __func__, st->dev->name, hh->prim, hh->id); | ||
185 | } else { | ||
186 | /* broadcast not handled yet */ | ||
187 | printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n", | ||
188 | __func__, st->dev->name, hh->prim); | ||
189 | } | ||
190 | return -ESRCH; | ||
191 | } | ||
192 | |||
193 | static void | ||
194 | do_clear_stack(struct mISDNstack *st) | ||
195 | { | ||
196 | } | ||
197 | |||
198 | static int | ||
199 | mISDNStackd(void *data) | ||
200 | { | ||
201 | struct mISDNstack *st = data; | ||
202 | int err = 0; | ||
203 | |||
204 | #ifdef CONFIG_SMP | ||
205 | lock_kernel(); | ||
206 | #endif | ||
207 | sigfillset(¤t->blocked); | ||
208 | #ifdef CONFIG_SMP | ||
209 | unlock_kernel(); | ||
210 | #endif | ||
211 | if (*debug & DEBUG_MSG_THREAD) | ||
212 | printk(KERN_DEBUG "mISDNStackd %s started\n", st->dev->name); | ||
213 | |||
214 | if (st->notify != NULL) { | ||
215 | complete(st->notify); | ||
216 | st->notify = NULL; | ||
217 | } | ||
218 | |||
219 | for (;;) { | ||
220 | struct sk_buff *skb; | ||
221 | |||
222 | if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) { | ||
223 | test_and_clear_bit(mISDN_STACK_WORK, &st->status); | ||
224 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
225 | } else | ||
226 | test_and_set_bit(mISDN_STACK_RUNNING, &st->status); | ||
227 | while (test_bit(mISDN_STACK_WORK, &st->status)) { | ||
228 | skb = skb_dequeue(&st->msgq); | ||
229 | if (!skb) { | ||
230 | test_and_clear_bit(mISDN_STACK_WORK, | ||
231 | &st->status); | ||
232 | /* test if a race happens */ | ||
233 | skb = skb_dequeue(&st->msgq); | ||
234 | if (!skb) | ||
235 | continue; | ||
236 | test_and_set_bit(mISDN_STACK_WORK, | ||
237 | &st->status); | ||
238 | } | ||
239 | #ifdef MISDN_MSG_STATS | ||
240 | st->msg_cnt++; | ||
241 | #endif | ||
242 | err = send_msg_to_layer(st, skb); | ||
243 | if (unlikely(err)) { | ||
244 | if (*debug & DEBUG_SEND_ERR) | ||
245 | printk(KERN_DEBUG | ||
246 | "%s: %s prim(%x) id(%x) " | ||
247 | "send call(%d)\n", | ||
248 | __func__, st->dev->name, | ||
249 | mISDN_HEAD_PRIM(skb), | ||
250 | mISDN_HEAD_ID(skb), err); | ||
251 | dev_kfree_skb(skb); | ||
252 | continue; | ||
253 | } | ||
254 | if (unlikely(test_bit(mISDN_STACK_STOPPED, | ||
255 | &st->status))) { | ||
256 | test_and_clear_bit(mISDN_STACK_WORK, | ||
257 | &st->status); | ||
258 | test_and_clear_bit(mISDN_STACK_RUNNING, | ||
259 | &st->status); | ||
260 | break; | ||
261 | } | ||
262 | } | ||
263 | if (test_bit(mISDN_STACK_CLEARING, &st->status)) { | ||
264 | test_and_set_bit(mISDN_STACK_STOPPED, &st->status); | ||
265 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
266 | do_clear_stack(st); | ||
267 | test_and_clear_bit(mISDN_STACK_CLEARING, &st->status); | ||
268 | test_and_set_bit(mISDN_STACK_RESTART, &st->status); | ||
269 | } | ||
270 | if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) { | ||
271 | test_and_clear_bit(mISDN_STACK_STOPPED, &st->status); | ||
272 | test_and_set_bit(mISDN_STACK_RUNNING, &st->status); | ||
273 | if (!skb_queue_empty(&st->msgq)) | ||
274 | test_and_set_bit(mISDN_STACK_WORK, | ||
275 | &st->status); | ||
276 | } | ||
277 | if (test_bit(mISDN_STACK_ABORT, &st->status)) | ||
278 | break; | ||
279 | if (st->notify != NULL) { | ||
280 | complete(st->notify); | ||
281 | st->notify = NULL; | ||
282 | } | ||
283 | #ifdef MISDN_MSG_STATS | ||
284 | st->sleep_cnt++; | ||
285 | #endif | ||
286 | test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); | ||
287 | wait_event_interruptible(st->workq, (st->status & | ||
288 | mISDN_STACK_ACTION_MASK)); | ||
289 | if (*debug & DEBUG_MSG_THREAD) | ||
290 | printk(KERN_DEBUG "%s: %s wake status %08lx\n", | ||
291 | __func__, st->dev->name, st->status); | ||
292 | test_and_set_bit(mISDN_STACK_ACTIVE, &st->status); | ||
293 | |||
294 | test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status); | ||
295 | |||
296 | if (test_bit(mISDN_STACK_STOPPED, &st->status)) { | ||
297 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
298 | #ifdef MISDN_MSG_STATS | ||
299 | st->stopped_cnt++; | ||
300 | #endif | ||
301 | } | ||
302 | } | ||
303 | #ifdef MISDN_MSG_STATS | ||
304 | printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d " | ||
305 | "msg %d sleep %d stopped\n", | ||
306 | st->dev->name, st->msg_cnt, st->sleep_cnt, st->stopped_cnt); | ||
307 | printk(KERN_DEBUG | ||
308 | "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", | ||
309 | st->dev->name, st->thread->utime, st->thread->stime); | ||
310 | printk(KERN_DEBUG | ||
311 | "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", | ||
312 | st->dev->name, st->thread->nvcsw, st->thread->nivcsw); | ||
313 | printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n", | ||
314 | st->dev->name); | ||
315 | #endif | ||
316 | test_and_set_bit(mISDN_STACK_KILLED, &st->status); | ||
317 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
318 | test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); | ||
319 | test_and_clear_bit(mISDN_STACK_ABORT, &st->status); | ||
320 | skb_queue_purge(&st->msgq); | ||
321 | st->thread = NULL; | ||
322 | if (st->notify != NULL) { | ||
323 | complete(st->notify); | ||
324 | st->notify = NULL; | ||
325 | } | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int | ||
330 | l1_receive(struct mISDNchannel *ch, struct sk_buff *skb) | ||
331 | { | ||
332 | if (!ch->st) | ||
333 | return -ENODEV; | ||
334 | __net_timestamp(skb); | ||
335 | _queue_message(ch->st, skb); | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | void | ||
340 | set_channel_address(struct mISDNchannel *ch, u_int sapi, u_int tei) | ||
341 | { | ||
342 | ch->addr = sapi | (tei << 8); | ||
343 | } | ||
344 | |||
345 | void | ||
346 | __add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) | ||
347 | { | ||
348 | list_add_tail(&ch->list, &st->layer2); | ||
349 | } | ||
350 | |||
351 | void | ||
352 | add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) | ||
353 | { | ||
354 | mutex_lock(&st->lmutex); | ||
355 | __add_layer2(ch, st); | ||
356 | mutex_unlock(&st->lmutex); | ||
357 | } | ||
358 | |||
359 | static int | ||
360 | st_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
361 | { | ||
362 | if (!ch->st || ch->st->layer1) | ||
363 | return -EINVAL; | ||
364 | return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg); | ||
365 | } | ||
366 | |||
367 | int | ||
368 | create_stack(struct mISDNdevice *dev) | ||
369 | { | ||
370 | struct mISDNstack *newst; | ||
371 | int err; | ||
372 | DECLARE_COMPLETION_ONSTACK(done); | ||
373 | |||
374 | newst = kzalloc(sizeof(struct mISDNstack), GFP_KERNEL); | ||
375 | if (!newst) { | ||
376 | printk(KERN_ERR "kmalloc mISDN_stack failed\n"); | ||
377 | return -ENOMEM; | ||
378 | } | ||
379 | newst->dev = dev; | ||
380 | INIT_LIST_HEAD(&newst->layer2); | ||
381 | INIT_HLIST_HEAD(&newst->l1sock.head); | ||
382 | rwlock_init(&newst->l1sock.lock); | ||
383 | init_waitqueue_head(&newst->workq); | ||
384 | skb_queue_head_init(&newst->msgq); | ||
385 | mutex_init(&newst->lmutex); | ||
386 | dev->D.st = newst; | ||
387 | err = create_teimanager(dev); | ||
388 | if (err) { | ||
389 | printk(KERN_ERR "kmalloc teimanager failed\n"); | ||
390 | kfree(newst); | ||
391 | return err; | ||
392 | } | ||
393 | dev->teimgr->peer = &newst->own; | ||
394 | dev->teimgr->recv = mISDN_queue_message; | ||
395 | dev->teimgr->st = newst; | ||
396 | newst->layer1 = &dev->D; | ||
397 | dev->D.recv = l1_receive; | ||
398 | dev->D.peer = &newst->own; | ||
399 | newst->own.st = newst; | ||
400 | newst->own.ctrl = st_own_ctrl; | ||
401 | newst->own.send = mISDN_queue_message; | ||
402 | newst->own.recv = mISDN_queue_message; | ||
403 | if (*debug & DEBUG_CORE_FUNC) | ||
404 | printk(KERN_DEBUG "%s: st(%s)\n", __func__, newst->dev->name); | ||
405 | newst->notify = &done; | ||
406 | newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s", | ||
407 | newst->dev->name); | ||
408 | if (IS_ERR(newst->thread)) { | ||
409 | err = PTR_ERR(newst->thread); | ||
410 | printk(KERN_ERR | ||
411 | "mISDN:cannot create kernel thread for %s (%d)\n", | ||
412 | newst->dev->name, err); | ||
413 | delete_teimanager(dev->teimgr); | ||
414 | kfree(newst); | ||
415 | } else | ||
416 | wait_for_completion(&done); | ||
417 | return err; | ||
418 | } | ||
419 | |||
420 | int | ||
421 | connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
422 | u_int protocol, struct sockaddr_mISDN *adr) | ||
423 | { | ||
424 | struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch); | ||
425 | struct channel_req rq; | ||
426 | int err; | ||
427 | |||
428 | |||
429 | if (*debug & DEBUG_CORE_FUNC) | ||
430 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
431 | __func__, dev->name, protocol, adr->dev, adr->channel, | ||
432 | adr->sapi, adr->tei); | ||
433 | switch (protocol) { | ||
434 | case ISDN_P_NT_S0: | ||
435 | case ISDN_P_NT_E1: | ||
436 | case ISDN_P_TE_S0: | ||
437 | case ISDN_P_TE_E1: | ||
438 | #ifdef PROTOCOL_CHECK | ||
439 | /* this should be enhanced */ | ||
440 | if (!list_empty(&dev->D.st->layer2) | ||
441 | && dev->D.protocol != protocol) | ||
442 | return -EBUSY; | ||
443 | if (!hlist_empty(&dev->D.st->l1sock.head) | ||
444 | && dev->D.protocol != protocol) | ||
445 | return -EBUSY; | ||
446 | #endif | ||
447 | ch->recv = mISDN_queue_message; | ||
448 | ch->peer = &dev->D.st->own; | ||
449 | ch->st = dev->D.st; | ||
450 | rq.protocol = protocol; | ||
451 | rq.adr.channel = 0; | ||
452 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
453 | printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); | ||
454 | if (err) | ||
455 | return err; | ||
456 | write_lock_bh(&dev->D.st->l1sock.lock); | ||
457 | sk_add_node(&msk->sk, &dev->D.st->l1sock.head); | ||
458 | write_unlock_bh(&dev->D.st->l1sock.lock); | ||
459 | break; | ||
460 | default: | ||
461 | return -ENOPROTOOPT; | ||
462 | } | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | int | ||
467 | connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
468 | u_int protocol, struct sockaddr_mISDN *adr) | ||
469 | { | ||
470 | struct channel_req rq, rq2; | ||
471 | int pmask, err; | ||
472 | struct Bprotocol *bp; | ||
473 | |||
474 | if (*debug & DEBUG_CORE_FUNC) | ||
475 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
476 | __func__, dev->name, protocol, | ||
477 | adr->dev, adr->channel, adr->sapi, | ||
478 | adr->tei); | ||
479 | ch->st = dev->D.st; | ||
480 | pmask = 1 << (protocol & ISDN_P_B_MASK); | ||
481 | if (pmask & dev->Bprotocols) { | ||
482 | rq.protocol = protocol; | ||
483 | rq.adr = *adr; | ||
484 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
485 | if (err) | ||
486 | return err; | ||
487 | ch->recv = rq.ch->send; | ||
488 | ch->peer = rq.ch; | ||
489 | rq.ch->recv = ch->send; | ||
490 | rq.ch->peer = ch; | ||
491 | rq.ch->st = dev->D.st; | ||
492 | } else { | ||
493 | bp = get_Bprotocol4mask(pmask); | ||
494 | if (!bp) | ||
495 | return -ENOPROTOOPT; | ||
496 | rq2.protocol = protocol; | ||
497 | rq2.adr = *adr; | ||
498 | rq2.ch = ch; | ||
499 | err = bp->create(&rq2); | ||
500 | if (err) | ||
501 | return err; | ||
502 | ch->recv = rq2.ch->send; | ||
503 | ch->peer = rq2.ch; | ||
504 | rq2.ch->st = dev->D.st; | ||
505 | rq.protocol = rq2.protocol; | ||
506 | rq.adr = *adr; | ||
507 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
508 | if (err) { | ||
509 | rq2.ch->ctrl(rq2.ch, CLOSE_CHANNEL, NULL); | ||
510 | return err; | ||
511 | } | ||
512 | rq2.ch->recv = rq.ch->send; | ||
513 | rq2.ch->peer = rq.ch; | ||
514 | rq.ch->recv = rq2.ch->send; | ||
515 | rq.ch->peer = rq2.ch; | ||
516 | rq.ch->st = dev->D.st; | ||
517 | } | ||
518 | ch->protocol = protocol; | ||
519 | ch->nr = rq.ch->nr; | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | int | ||
524 | create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
525 | u_int protocol, struct sockaddr_mISDN *adr) | ||
526 | { | ||
527 | struct channel_req rq; | ||
528 | int err; | ||
529 | |||
530 | if (*debug & DEBUG_CORE_FUNC) | ||
531 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
532 | __func__, dev->name, protocol, | ||
533 | adr->dev, adr->channel, adr->sapi, | ||
534 | adr->tei); | ||
535 | rq.protocol = ISDN_P_TE_S0; | ||
536 | if (dev->Dprotocols & (1 << ISDN_P_TE_E1)) | ||
537 | rq.protocol = ISDN_P_TE_E1; | ||
538 | switch (protocol) { | ||
539 | case ISDN_P_LAPD_NT: | ||
540 | rq.protocol = ISDN_P_NT_S0; | ||
541 | if (dev->Dprotocols & (1 << ISDN_P_NT_E1)) | ||
542 | rq.protocol = ISDN_P_NT_E1; | ||
543 | case ISDN_P_LAPD_TE: | ||
544 | #ifdef PROTOCOL_CHECK | ||
545 | /* this should be enhanced */ | ||
546 | if (!list_empty(&dev->D.st->layer2) | ||
547 | && dev->D.protocol != protocol) | ||
548 | return -EBUSY; | ||
549 | if (!hlist_empty(&dev->D.st->l1sock.head) | ||
550 | && dev->D.protocol != protocol) | ||
551 | return -EBUSY; | ||
552 | #endif | ||
553 | ch->recv = mISDN_queue_message; | ||
554 | ch->peer = &dev->D.st->own; | ||
555 | ch->st = dev->D.st; | ||
556 | rq.adr.channel = 0; | ||
557 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
558 | printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); | ||
559 | if (err) | ||
560 | break; | ||
561 | rq.protocol = protocol; | ||
562 | rq.adr = *adr; | ||
563 | rq.ch = ch; | ||
564 | err = dev->teimgr->ctrl(dev->teimgr, OPEN_CHANNEL, &rq); | ||
565 | printk(KERN_DEBUG "%s: ret 2 %d\n", __func__, err); | ||
566 | if (!err) { | ||
567 | if ((protocol == ISDN_P_LAPD_NT) && !rq.ch) | ||
568 | break; | ||
569 | add_layer2(rq.ch, dev->D.st); | ||
570 | rq.ch->recv = mISDN_queue_message; | ||
571 | rq.ch->peer = &dev->D.st->own; | ||
572 | rq.ch->ctrl(rq.ch, OPEN_CHANNEL, NULL); /* can't fail */ | ||
573 | } | ||
574 | break; | ||
575 | default: | ||
576 | err = -EPROTONOSUPPORT; | ||
577 | } | ||
578 | return err; | ||
579 | } | ||
580 | |||
581 | void | ||
582 | delete_channel(struct mISDNchannel *ch) | ||
583 | { | ||
584 | struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch); | ||
585 | struct mISDNchannel *pch; | ||
586 | |||
587 | if (!ch->st) { | ||
588 | printk(KERN_WARNING "%s: no stack\n", __func__); | ||
589 | return; | ||
590 | } | ||
591 | if (*debug & DEBUG_CORE_FUNC) | ||
592 | printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__, | ||
593 | ch->st->dev->name, ch->protocol); | ||
594 | if (ch->protocol >= ISDN_P_B_START) { | ||
595 | if (ch->peer) { | ||
596 | ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL); | ||
597 | ch->peer = NULL; | ||
598 | } | ||
599 | return; | ||
600 | } | ||
601 | switch (ch->protocol) { | ||
602 | case ISDN_P_NT_S0: | ||
603 | case ISDN_P_TE_S0: | ||
604 | case ISDN_P_NT_E1: | ||
605 | case ISDN_P_TE_E1: | ||
606 | write_lock_bh(&ch->st->l1sock.lock); | ||
607 | sk_del_node_init(&msk->sk); | ||
608 | write_unlock_bh(&ch->st->l1sock.lock); | ||
609 | ch->st->dev->D.ctrl(&ch->st->dev->D, CLOSE_CHANNEL, NULL); | ||
610 | break; | ||
611 | case ISDN_P_LAPD_TE: | ||
612 | pch = get_channel4id(ch->st, ch->nr); | ||
613 | if (pch) { | ||
614 | mutex_lock(&ch->st->lmutex); | ||
615 | list_del(&pch->list); | ||
616 | mutex_unlock(&ch->st->lmutex); | ||
617 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
618 | pch = ch->st->dev->teimgr; | ||
619 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
620 | } else | ||
621 | printk(KERN_WARNING "%s: no l2 channel\n", | ||
622 | __func__); | ||
623 | break; | ||
624 | case ISDN_P_LAPD_NT: | ||
625 | pch = ch->st->dev->teimgr; | ||
626 | if (pch) { | ||
627 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
628 | } else | ||
629 | printk(KERN_WARNING "%s: no l2 channel\n", | ||
630 | __func__); | ||
631 | break; | ||
632 | default: | ||
633 | break; | ||
634 | } | ||
635 | return; | ||
636 | } | ||
637 | |||
638 | void | ||
639 | delete_stack(struct mISDNdevice *dev) | ||
640 | { | ||
641 | struct mISDNstack *st = dev->D.st; | ||
642 | DECLARE_COMPLETION_ONSTACK(done); | ||
643 | |||
644 | if (*debug & DEBUG_CORE_FUNC) | ||
645 | printk(KERN_DEBUG "%s: st(%s)\n", __func__, | ||
646 | st->dev->name); | ||
647 | if (dev->teimgr) | ||
648 | delete_teimanager(dev->teimgr); | ||
649 | if (st->thread) { | ||
650 | if (st->notify) { | ||
651 | printk(KERN_WARNING "%s: notifier in use\n", | ||
652 | __func__); | ||
653 | complete(st->notify); | ||
654 | } | ||
655 | st->notify = &done; | ||
656 | test_and_set_bit(mISDN_STACK_ABORT, &st->status); | ||
657 | test_and_set_bit(mISDN_STACK_WAKEUP, &st->status); | ||
658 | wake_up_interruptible(&st->workq); | ||
659 | wait_for_completion(&done); | ||
660 | } | ||
661 | if (!list_empty(&st->layer2)) | ||
662 | printk(KERN_WARNING "%s: layer2 list not empty\n", | ||
663 | __func__); | ||
664 | if (!hlist_empty(&st->l1sock.head)) | ||
665 | printk(KERN_WARNING "%s: layer1 list not empty\n", | ||
666 | __func__); | ||
667 | kfree(st); | ||
668 | } | ||
669 | |||
670 | void | ||
671 | mISDN_initstack(u_int *dp) | ||
672 | { | ||
673 | debug = dp; | ||
674 | } | ||
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c new file mode 100644 index 000000000000..56a76a0ffddd --- /dev/null +++ b/drivers/isdn/mISDN/tei.c | |||
@@ -0,0 +1,1340 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | #include "layer2.h" | ||
18 | #include <linux/random.h> | ||
19 | #include "core.h" | ||
20 | |||
21 | #define ID_REQUEST 1 | ||
22 | #define ID_ASSIGNED 2 | ||
23 | #define ID_DENIED 3 | ||
24 | #define ID_CHK_REQ 4 | ||
25 | #define ID_CHK_RES 5 | ||
26 | #define ID_REMOVE 6 | ||
27 | #define ID_VERIFY 7 | ||
28 | |||
29 | #define TEI_ENTITY_ID 0xf | ||
30 | |||
31 | #define MGR_PH_ACTIVE 16 | ||
32 | #define MGR_PH_NOTREADY 17 | ||
33 | |||
34 | #define DATIMER_VAL 10000 | ||
35 | |||
36 | static u_int *debug; | ||
37 | |||
38 | static struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL}; | ||
39 | static struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL}; | ||
40 | static struct Fsm teifsmn = {NULL, 0, 0, NULL, NULL}; | ||
41 | |||
42 | enum { | ||
43 | ST_L1_DEACT, | ||
44 | ST_L1_DEACT_PENDING, | ||
45 | ST_L1_ACTIV, | ||
46 | }; | ||
47 | #define DEACT_STATE_COUNT (ST_L1_ACTIV+1) | ||
48 | |||
49 | static char *strDeactState[] = | ||
50 | { | ||
51 | "ST_L1_DEACT", | ||
52 | "ST_L1_DEACT_PENDING", | ||
53 | "ST_L1_ACTIV", | ||
54 | }; | ||
55 | |||
56 | enum { | ||
57 | EV_ACTIVATE, | ||
58 | EV_ACTIVATE_IND, | ||
59 | EV_DEACTIVATE, | ||
60 | EV_DEACTIVATE_IND, | ||
61 | EV_UI, | ||
62 | EV_DATIMER, | ||
63 | }; | ||
64 | |||
65 | #define DEACT_EVENT_COUNT (EV_DATIMER+1) | ||
66 | |||
67 | static char *strDeactEvent[] = | ||
68 | { | ||
69 | "EV_ACTIVATE", | ||
70 | "EV_ACTIVATE_IND", | ||
71 | "EV_DEACTIVATE", | ||
72 | "EV_DEACTIVATE_IND", | ||
73 | "EV_UI", | ||
74 | "EV_DATIMER", | ||
75 | }; | ||
76 | |||
77 | static void | ||
78 | da_debug(struct FsmInst *fi, char *fmt, ...) | ||
79 | { | ||
80 | struct manager *mgr = fi->userdata; | ||
81 | va_list va; | ||
82 | |||
83 | if (!(*debug & DEBUG_L2_TEIFSM)) | ||
84 | return; | ||
85 | va_start(va, fmt); | ||
86 | printk(KERN_DEBUG "mgr(%d): ", mgr->ch.st->dev->id); | ||
87 | vprintk(fmt, va); | ||
88 | printk("\n"); | ||
89 | va_end(va); | ||
90 | } | ||
91 | |||
92 | static void | ||
93 | da_activate(struct FsmInst *fi, int event, void *arg) | ||
94 | { | ||
95 | struct manager *mgr = fi->userdata; | ||
96 | |||
97 | if (fi->state == ST_L1_DEACT_PENDING) | ||
98 | mISDN_FsmDelTimer(&mgr->datimer, 1); | ||
99 | mISDN_FsmChangeState(fi, ST_L1_ACTIV); | ||
100 | } | ||
101 | |||
102 | static void | ||
103 | da_deactivate_ind(struct FsmInst *fi, int event, void *arg) | ||
104 | { | ||
105 | mISDN_FsmChangeState(fi, ST_L1_DEACT); | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | da_deactivate(struct FsmInst *fi, int event, void *arg) | ||
110 | { | ||
111 | struct manager *mgr = fi->userdata; | ||
112 | struct layer2 *l2; | ||
113 | u_long flags; | ||
114 | |||
115 | read_lock_irqsave(&mgr->lock, flags); | ||
116 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
117 | if (l2->l2m.state > ST_L2_4) { | ||
118 | /* have still activ TEI */ | ||
119 | read_unlock_irqrestore(&mgr->lock, flags); | ||
120 | return; | ||
121 | } | ||
122 | } | ||
123 | read_unlock_irqrestore(&mgr->lock, flags); | ||
124 | /* All TEI are inactiv */ | ||
125 | mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 1); | ||
126 | mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); | ||
127 | } | ||
128 | |||
129 | static void | ||
130 | da_ui(struct FsmInst *fi, int event, void *arg) | ||
131 | { | ||
132 | struct manager *mgr = fi->userdata; | ||
133 | |||
134 | /* restart da timer */ | ||
135 | mISDN_FsmDelTimer(&mgr->datimer, 2); | ||
136 | mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 2); | ||
137 | |||
138 | } | ||
139 | |||
140 | static void | ||
141 | da_timer(struct FsmInst *fi, int event, void *arg) | ||
142 | { | ||
143 | struct manager *mgr = fi->userdata; | ||
144 | struct layer2 *l2; | ||
145 | u_long flags; | ||
146 | |||
147 | /* check again */ | ||
148 | read_lock_irqsave(&mgr->lock, flags); | ||
149 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
150 | if (l2->l2m.state > ST_L2_4) { | ||
151 | /* have still activ TEI */ | ||
152 | read_unlock_irqrestore(&mgr->lock, flags); | ||
153 | mISDN_FsmChangeState(fi, ST_L1_ACTIV); | ||
154 | return; | ||
155 | } | ||
156 | } | ||
157 | read_unlock_irqrestore(&mgr->lock, flags); | ||
158 | /* All TEI are inactiv */ | ||
159 | mISDN_FsmChangeState(fi, ST_L1_DEACT); | ||
160 | _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL, | ||
161 | GFP_ATOMIC); | ||
162 | } | ||
163 | |||
164 | static struct FsmNode DeactFnList[] = | ||
165 | { | ||
166 | {ST_L1_DEACT, EV_ACTIVATE_IND, da_activate}, | ||
167 | {ST_L1_ACTIV, EV_DEACTIVATE_IND, da_deactivate_ind}, | ||
168 | {ST_L1_ACTIV, EV_DEACTIVATE, da_deactivate}, | ||
169 | {ST_L1_DEACT_PENDING, EV_ACTIVATE, da_activate}, | ||
170 | {ST_L1_DEACT_PENDING, EV_UI, da_ui}, | ||
171 | {ST_L1_DEACT_PENDING, EV_DATIMER, da_timer}, | ||
172 | }; | ||
173 | |||
174 | enum { | ||
175 | ST_TEI_NOP, | ||
176 | ST_TEI_IDREQ, | ||
177 | ST_TEI_IDVERIFY, | ||
178 | }; | ||
179 | |||
180 | #define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1) | ||
181 | |||
182 | static char *strTeiState[] = | ||
183 | { | ||
184 | "ST_TEI_NOP", | ||
185 | "ST_TEI_IDREQ", | ||
186 | "ST_TEI_IDVERIFY", | ||
187 | }; | ||
188 | |||
189 | enum { | ||
190 | EV_IDREQ, | ||
191 | EV_ASSIGN, | ||
192 | EV_ASSIGN_REQ, | ||
193 | EV_DENIED, | ||
194 | EV_CHKREQ, | ||
195 | EV_CHKRESP, | ||
196 | EV_REMOVE, | ||
197 | EV_VERIFY, | ||
198 | EV_TIMER, | ||
199 | }; | ||
200 | |||
201 | #define TEI_EVENT_COUNT (EV_TIMER+1) | ||
202 | |||
203 | static char *strTeiEvent[] = | ||
204 | { | ||
205 | "EV_IDREQ", | ||
206 | "EV_ASSIGN", | ||
207 | "EV_ASSIGN_REQ", | ||
208 | "EV_DENIED", | ||
209 | "EV_CHKREQ", | ||
210 | "EV_CHKRESP", | ||
211 | "EV_REMOVE", | ||
212 | "EV_VERIFY", | ||
213 | "EV_TIMER", | ||
214 | }; | ||
215 | |||
216 | static void | ||
217 | tei_debug(struct FsmInst *fi, char *fmt, ...) | ||
218 | { | ||
219 | struct teimgr *tm = fi->userdata; | ||
220 | va_list va; | ||
221 | |||
222 | if (!(*debug & DEBUG_L2_TEIFSM)) | ||
223 | return; | ||
224 | va_start(va, fmt); | ||
225 | printk(KERN_DEBUG "tei(%d): ", tm->l2->tei); | ||
226 | vprintk(fmt, va); | ||
227 | printk("\n"); | ||
228 | va_end(va); | ||
229 | } | ||
230 | |||
231 | |||
232 | |||
233 | static int | ||
234 | get_free_id(struct manager *mgr) | ||
235 | { | ||
236 | u64 ids = 0; | ||
237 | int i; | ||
238 | struct layer2 *l2; | ||
239 | |||
240 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
241 | if (l2->ch.nr > 63) { | ||
242 | printk(KERN_WARNING | ||
243 | "%s: more as 63 layer2 for one device\n", | ||
244 | __func__); | ||
245 | return -EBUSY; | ||
246 | } | ||
247 | test_and_set_bit(l2->ch.nr, (u_long *)&ids); | ||
248 | } | ||
249 | for (i = 1; i < 64; i++) | ||
250 | if (!test_bit(i, (u_long *)&ids)) | ||
251 | return i; | ||
252 | printk(KERN_WARNING "%s: more as 63 layer2 for one device\n", | ||
253 | __func__); | ||
254 | return -EBUSY; | ||
255 | } | ||
256 | |||
257 | static int | ||
258 | get_free_tei(struct manager *mgr) | ||
259 | { | ||
260 | u64 ids = 0; | ||
261 | int i; | ||
262 | struct layer2 *l2; | ||
263 | |||
264 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
265 | if (l2->ch.nr == 0) | ||
266 | continue; | ||
267 | if ((l2->ch.addr & 0xff) != 0) | ||
268 | continue; | ||
269 | i = l2->ch.addr >> 8; | ||
270 | if (i < 64) | ||
271 | continue; | ||
272 | i -= 64; | ||
273 | |||
274 | test_and_set_bit(i, (u_long *)&ids); | ||
275 | } | ||
276 | for (i = 0; i < 64; i++) | ||
277 | if (!test_bit(i, (u_long *)&ids)) | ||
278 | return i + 64; | ||
279 | printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n", | ||
280 | __func__); | ||
281 | return -1; | ||
282 | } | ||
283 | |||
284 | static void | ||
285 | teiup_create(struct manager *mgr, u_int prim, int len, void *arg) | ||
286 | { | ||
287 | struct sk_buff *skb; | ||
288 | struct mISDNhead *hh; | ||
289 | int err; | ||
290 | |||
291 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
292 | if (!skb) | ||
293 | return; | ||
294 | hh = mISDN_HEAD_P(skb); | ||
295 | hh->prim = prim; | ||
296 | hh->id = (mgr->ch.nr << 16) | mgr->ch.addr; | ||
297 | if (len) | ||
298 | memcpy(skb_put(skb, len), arg, len); | ||
299 | err = mgr->up->send(mgr->up, skb); | ||
300 | if (err) { | ||
301 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
302 | dev_kfree_skb(skb); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | static u_int | ||
307 | new_id(struct manager *mgr) | ||
308 | { | ||
309 | u_int id; | ||
310 | |||
311 | id = mgr->nextid++; | ||
312 | if (id == 0x7fff) | ||
313 | mgr->nextid = 1; | ||
314 | id <<= 16; | ||
315 | id |= GROUP_TEI << 8; | ||
316 | id |= TEI_SAPI; | ||
317 | return id; | ||
318 | } | ||
319 | |||
320 | static void | ||
321 | do_send(struct manager *mgr) | ||
322 | { | ||
323 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) | ||
324 | return; | ||
325 | |||
326 | if (!test_and_set_bit(MGR_PH_NOTREADY, &mgr->options)) { | ||
327 | struct sk_buff *skb = skb_dequeue(&mgr->sendq); | ||
328 | |||
329 | if (!skb) { | ||
330 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
331 | return; | ||
332 | } | ||
333 | mgr->lastid = mISDN_HEAD_ID(skb); | ||
334 | mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); | ||
335 | if (mgr->ch.recv(mgr->ch.peer, skb)) { | ||
336 | dev_kfree_skb(skb); | ||
337 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
338 | mgr->lastid = MISDN_ID_NONE; | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | |||
343 | static void | ||
344 | do_ack(struct manager *mgr, u_int id) | ||
345 | { | ||
346 | if (test_bit(MGR_PH_NOTREADY, &mgr->options)) { | ||
347 | if (id == mgr->lastid) { | ||
348 | if (test_bit(MGR_PH_ACTIVE, &mgr->options)) { | ||
349 | struct sk_buff *skb; | ||
350 | |||
351 | skb = skb_dequeue(&mgr->sendq); | ||
352 | if (skb) { | ||
353 | mgr->lastid = mISDN_HEAD_ID(skb); | ||
354 | if (!mgr->ch.recv(mgr->ch.peer, skb)) | ||
355 | return; | ||
356 | dev_kfree_skb(skb); | ||
357 | } | ||
358 | } | ||
359 | mgr->lastid = MISDN_ID_NONE; | ||
360 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | |||
365 | static void | ||
366 | mgr_send_down(struct manager *mgr, struct sk_buff *skb) | ||
367 | { | ||
368 | skb_queue_tail(&mgr->sendq, skb); | ||
369 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) { | ||
370 | _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, | ||
371 | NULL, GFP_KERNEL); | ||
372 | } else { | ||
373 | do_send(mgr); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | static int | ||
378 | dl_unit_data(struct manager *mgr, struct sk_buff *skb) | ||
379 | { | ||
380 | if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) /* only net send UI */ | ||
381 | return -EINVAL; | ||
382 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) | ||
383 | _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, | ||
384 | NULL, GFP_KERNEL); | ||
385 | skb_push(skb, 3); | ||
386 | skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */ | ||
387 | skb->data[1] = 0xff; /* TEI 127 */ | ||
388 | skb->data[2] = UI; /* UI frame */ | ||
389 | mISDN_HEAD_PRIM(skb) = PH_DATA_REQ; | ||
390 | mISDN_HEAD_ID(skb) = new_id(mgr); | ||
391 | skb_queue_tail(&mgr->sendq, skb); | ||
392 | do_send(mgr); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | unsigned int | ||
397 | random_ri(void) | ||
398 | { | ||
399 | u16 x; | ||
400 | |||
401 | get_random_bytes(&x, sizeof(x)); | ||
402 | return x; | ||
403 | } | ||
404 | |||
405 | static struct layer2 * | ||
406 | findtei(struct manager *mgr, int tei) | ||
407 | { | ||
408 | struct layer2 *l2; | ||
409 | u_long flags; | ||
410 | |||
411 | read_lock_irqsave(&mgr->lock, flags); | ||
412 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
413 | if ((l2->sapi == 0) && (l2->tei > 0) && | ||
414 | (l2->tei != GROUP_TEI) && (l2->tei == tei)) | ||
415 | goto done; | ||
416 | } | ||
417 | l2 = NULL; | ||
418 | done: | ||
419 | read_unlock_irqrestore(&mgr->lock, flags); | ||
420 | return l2; | ||
421 | } | ||
422 | |||
423 | static void | ||
424 | put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei) | ||
425 | { | ||
426 | struct sk_buff *skb; | ||
427 | u_char bp[8]; | ||
428 | |||
429 | bp[0] = (TEI_SAPI << 2); | ||
430 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
431 | bp[0] |= 2; /* CR:=1 for net command */ | ||
432 | bp[1] = (GROUP_TEI << 1) | 0x1; | ||
433 | bp[2] = UI; | ||
434 | bp[3] = TEI_ENTITY_ID; | ||
435 | bp[4] = ri >> 8; | ||
436 | bp[5] = ri & 0xff; | ||
437 | bp[6] = m_id; | ||
438 | bp[7] = (tei << 1) | 1; | ||
439 | skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), | ||
440 | 8, bp, GFP_ATOMIC); | ||
441 | if (!skb) { | ||
442 | printk(KERN_WARNING "%s: no skb for tei msg\n", __func__); | ||
443 | return; | ||
444 | } | ||
445 | mgr_send_down(mgr, skb); | ||
446 | } | ||
447 | |||
448 | static void | ||
449 | tei_id_request(struct FsmInst *fi, int event, void *arg) | ||
450 | { | ||
451 | struct teimgr *tm = fi->userdata; | ||
452 | |||
453 | if (tm->l2->tei != GROUP_TEI) { | ||
454 | tm->tei_m.printdebug(&tm->tei_m, | ||
455 | "assign request for allready assigned tei %d", | ||
456 | tm->l2->tei); | ||
457 | return; | ||
458 | } | ||
459 | tm->ri = random_ri(); | ||
460 | if (*debug & DEBUG_L2_TEI) | ||
461 | tm->tei_m.printdebug(&tm->tei_m, | ||
462 | "assign request ri %d", tm->ri); | ||
463 | put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); | ||
464 | mISDN_FsmChangeState(fi, ST_TEI_IDREQ); | ||
465 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1); | ||
466 | tm->nval = 3; | ||
467 | } | ||
468 | |||
469 | static void | ||
470 | tei_id_assign(struct FsmInst *fi, int event, void *arg) | ||
471 | { | ||
472 | struct teimgr *tm = fi->userdata; | ||
473 | struct layer2 *l2; | ||
474 | u_char *dp = arg; | ||
475 | int ri, tei; | ||
476 | |||
477 | ri = ((unsigned int) *dp++ << 8); | ||
478 | ri += *dp++; | ||
479 | dp++; | ||
480 | tei = *dp >> 1; | ||
481 | if (*debug & DEBUG_L2_TEI) | ||
482 | tm->tei_m.printdebug(fi, "identity assign ri %d tei %d", | ||
483 | ri, tei); | ||
484 | l2 = findtei(tm->mgr, tei); | ||
485 | if (l2) { /* same tei is in use */ | ||
486 | if (ri != l2->tm->ri) { | ||
487 | tm->tei_m.printdebug(fi, | ||
488 | "possible duplicate assignment tei %d", tei); | ||
489 | tei_l2(l2, MDL_ERROR_RSP, 0); | ||
490 | } | ||
491 | } else if (ri == tm->ri) { | ||
492 | mISDN_FsmDelTimer(&tm->timer, 1); | ||
493 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
494 | tei_l2(tm->l2, MDL_ASSIGN_REQ, tei); | ||
495 | } | ||
496 | } | ||
497 | |||
498 | static void | ||
499 | tei_id_test_dup(struct FsmInst *fi, int event, void *arg) | ||
500 | { | ||
501 | struct teimgr *tm = fi->userdata; | ||
502 | struct layer2 *l2; | ||
503 | u_char *dp = arg; | ||
504 | int tei, ri; | ||
505 | |||
506 | ri = ((unsigned int) *dp++ << 8); | ||
507 | ri += *dp++; | ||
508 | dp++; | ||
509 | tei = *dp >> 1; | ||
510 | if (*debug & DEBUG_L2_TEI) | ||
511 | tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d", | ||
512 | ri, tei); | ||
513 | l2 = findtei(tm->mgr, tei); | ||
514 | if (l2) { /* same tei is in use */ | ||
515 | if (ri != l2->tm->ri) { /* and it wasn't our request */ | ||
516 | tm->tei_m.printdebug(fi, | ||
517 | "possible duplicate assignment tei %d", tei); | ||
518 | mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL); | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | |||
523 | static void | ||
524 | tei_id_denied(struct FsmInst *fi, int event, void *arg) | ||
525 | { | ||
526 | struct teimgr *tm = fi->userdata; | ||
527 | u_char *dp = arg; | ||
528 | int ri, tei; | ||
529 | |||
530 | ri = ((unsigned int) *dp++ << 8); | ||
531 | ri += *dp++; | ||
532 | dp++; | ||
533 | tei = *dp >> 1; | ||
534 | if (*debug & DEBUG_L2_TEI) | ||
535 | tm->tei_m.printdebug(fi, "identity denied ri %d tei %d", | ||
536 | ri, tei); | ||
537 | } | ||
538 | |||
539 | static void | ||
540 | tei_id_chk_req(struct FsmInst *fi, int event, void *arg) | ||
541 | { | ||
542 | struct teimgr *tm = fi->userdata; | ||
543 | u_char *dp = arg; | ||
544 | int tei; | ||
545 | |||
546 | tei = *(dp+3) >> 1; | ||
547 | if (*debug & DEBUG_L2_TEI) | ||
548 | tm->tei_m.printdebug(fi, "identity check req tei %d", tei); | ||
549 | if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) || | ||
550 | (tei == tm->l2->tei))) { | ||
551 | mISDN_FsmDelTimer(&tm->timer, 4); | ||
552 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); | ||
553 | put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei); | ||
554 | } | ||
555 | } | ||
556 | |||
557 | static void | ||
558 | tei_id_remove(struct FsmInst *fi, int event, void *arg) | ||
559 | { | ||
560 | struct teimgr *tm = fi->userdata; | ||
561 | u_char *dp = arg; | ||
562 | int tei; | ||
563 | |||
564 | tei = *(dp+3) >> 1; | ||
565 | if (*debug & DEBUG_L2_TEI) | ||
566 | tm->tei_m.printdebug(fi, "identity remove tei %d", tei); | ||
567 | if ((tm->l2->tei != GROUP_TEI) && | ||
568 | ((tei == GROUP_TEI) || (tei == tm->l2->tei))) { | ||
569 | mISDN_FsmDelTimer(&tm->timer, 5); | ||
570 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); | ||
571 | tei_l2(tm->l2, MDL_REMOVE_REQ, 0); | ||
572 | } | ||
573 | } | ||
574 | |||
575 | static void | ||
576 | tei_id_verify(struct FsmInst *fi, int event, void *arg) | ||
577 | { | ||
578 | struct teimgr *tm = fi->userdata; | ||
579 | |||
580 | if (*debug & DEBUG_L2_TEI) | ||
581 | tm->tei_m.printdebug(fi, "id verify request for tei %d", | ||
582 | tm->l2->tei); | ||
583 | put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); | ||
584 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); | ||
585 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); | ||
586 | tm->nval = 2; | ||
587 | } | ||
588 | |||
589 | static void | ||
590 | tei_id_req_tout(struct FsmInst *fi, int event, void *arg) | ||
591 | { | ||
592 | struct teimgr *tm = fi->userdata; | ||
593 | |||
594 | if (--tm->nval) { | ||
595 | tm->ri = random_ri(); | ||
596 | if (*debug & DEBUG_L2_TEI) | ||
597 | tm->tei_m.printdebug(fi, "assign req(%d) ri %d", | ||
598 | 4 - tm->nval, tm->ri); | ||
599 | put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); | ||
600 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3); | ||
601 | } else { | ||
602 | tm->tei_m.printdebug(fi, "assign req failed"); | ||
603 | tei_l2(tm->l2, MDL_ERROR_RSP, 0); | ||
604 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static void | ||
609 | tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) | ||
610 | { | ||
611 | struct teimgr *tm = fi->userdata; | ||
612 | |||
613 | if (--tm->nval) { | ||
614 | if (*debug & DEBUG_L2_TEI) | ||
615 | tm->tei_m.printdebug(fi, | ||
616 | "id verify req(%d) for tei %d", | ||
617 | 3 - tm->nval, tm->l2->tei); | ||
618 | put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); | ||
619 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); | ||
620 | } else { | ||
621 | tm->tei_m.printdebug(fi, "verify req for tei %d failed", | ||
622 | tm->l2->tei); | ||
623 | tei_l2(tm->l2, MDL_REMOVE_REQ, 0); | ||
624 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
625 | } | ||
626 | } | ||
627 | |||
628 | static struct FsmNode TeiFnListUser[] = | ||
629 | { | ||
630 | {ST_TEI_NOP, EV_IDREQ, tei_id_request}, | ||
631 | {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, | ||
632 | {ST_TEI_NOP, EV_VERIFY, tei_id_verify}, | ||
633 | {ST_TEI_NOP, EV_REMOVE, tei_id_remove}, | ||
634 | {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req}, | ||
635 | {ST_TEI_IDREQ, EV_TIMER, tei_id_req_tout}, | ||
636 | {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign}, | ||
637 | {ST_TEI_IDREQ, EV_DENIED, tei_id_denied}, | ||
638 | {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout}, | ||
639 | {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove}, | ||
640 | {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, | ||
641 | }; | ||
642 | |||
643 | static void | ||
644 | tei_l2remove(struct layer2 *l2) | ||
645 | { | ||
646 | put_tei_msg(l2->tm->mgr, ID_REMOVE, 0, l2->tei); | ||
647 | tei_l2(l2, MDL_REMOVE_REQ, 0); | ||
648 | list_del(&l2->ch.list); | ||
649 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
650 | } | ||
651 | |||
652 | static void | ||
653 | tei_assign_req(struct FsmInst *fi, int event, void *arg) | ||
654 | { | ||
655 | struct teimgr *tm = fi->userdata; | ||
656 | u_char *dp = arg; | ||
657 | |||
658 | if (tm->l2->tei == GROUP_TEI) { | ||
659 | tm->tei_m.printdebug(&tm->tei_m, | ||
660 | "net tei assign request without tei"); | ||
661 | return; | ||
662 | } | ||
663 | tm->ri = ((unsigned int) *dp++ << 8); | ||
664 | tm->ri += *dp++; | ||
665 | if (*debug & DEBUG_L2_TEI) | ||
666 | tm->tei_m.printdebug(&tm->tei_m, | ||
667 | "net assign request ri %d teim %d", tm->ri, *dp); | ||
668 | put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei); | ||
669 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
670 | } | ||
671 | |||
672 | static void | ||
673 | tei_id_chk_req_net(struct FsmInst *fi, int event, void *arg) | ||
674 | { | ||
675 | struct teimgr *tm = fi->userdata; | ||
676 | |||
677 | if (*debug & DEBUG_L2_TEI) | ||
678 | tm->tei_m.printdebug(fi, "id check request for tei %d", | ||
679 | tm->l2->tei); | ||
680 | tm->rcnt = 0; | ||
681 | put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); | ||
682 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); | ||
683 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); | ||
684 | tm->nval = 2; | ||
685 | } | ||
686 | |||
687 | static void | ||
688 | tei_id_chk_resp(struct FsmInst *fi, int event, void *arg) | ||
689 | { | ||
690 | struct teimgr *tm = fi->userdata; | ||
691 | u_char *dp = arg; | ||
692 | int tei; | ||
693 | |||
694 | tei = dp[3] >> 1; | ||
695 | if (*debug & DEBUG_L2_TEI) | ||
696 | tm->tei_m.printdebug(fi, "identity check resp tei %d", tei); | ||
697 | if (tei == tm->l2->tei) | ||
698 | tm->rcnt++; | ||
699 | } | ||
700 | |||
701 | static void | ||
702 | tei_id_verify_net(struct FsmInst *fi, int event, void *arg) | ||
703 | { | ||
704 | struct teimgr *tm = fi->userdata; | ||
705 | u_char *dp = arg; | ||
706 | int tei; | ||
707 | |||
708 | tei = dp[3] >> 1; | ||
709 | if (*debug & DEBUG_L2_TEI) | ||
710 | tm->tei_m.printdebug(fi, "identity verify req tei %d/%d", | ||
711 | tei, tm->l2->tei); | ||
712 | if (tei == tm->l2->tei) | ||
713 | tei_id_chk_req_net(fi, event, arg); | ||
714 | } | ||
715 | |||
716 | static void | ||
717 | tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg) | ||
718 | { | ||
719 | struct teimgr *tm = fi->userdata; | ||
720 | |||
721 | if (tm->rcnt == 1) { | ||
722 | if (*debug & DEBUG_L2_TEI) | ||
723 | tm->tei_m.printdebug(fi, | ||
724 | "check req for tei %d sucessful\n", tm->l2->tei); | ||
725 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
726 | } else if (tm->rcnt > 1) { | ||
727 | /* duplicate assignment; remove */ | ||
728 | tei_l2remove(tm->l2); | ||
729 | } else if (--tm->nval) { | ||
730 | if (*debug & DEBUG_L2_TEI) | ||
731 | tm->tei_m.printdebug(fi, | ||
732 | "id check req(%d) for tei %d", | ||
733 | 3 - tm->nval, tm->l2->tei); | ||
734 | put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); | ||
735 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); | ||
736 | } else { | ||
737 | tm->tei_m.printdebug(fi, "check req for tei %d failed", | ||
738 | tm->l2->tei); | ||
739 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
740 | tei_l2remove(tm->l2); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | static struct FsmNode TeiFnListNet[] = | ||
745 | { | ||
746 | {ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req}, | ||
747 | {ST_TEI_NOP, EV_VERIFY, tei_id_verify_net}, | ||
748 | {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req_net}, | ||
749 | {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout_net}, | ||
750 | {ST_TEI_IDVERIFY, EV_CHKRESP, tei_id_chk_resp}, | ||
751 | }; | ||
752 | |||
753 | static void | ||
754 | tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) | ||
755 | { | ||
756 | if (test_bit(FLG_FIXED_TEI, &tm->l2->flag)) | ||
757 | return; | ||
758 | if (*debug & DEBUG_L2_TEI) | ||
759 | tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt); | ||
760 | if (mt == ID_ASSIGNED) | ||
761 | mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp); | ||
762 | else if (mt == ID_DENIED) | ||
763 | mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp); | ||
764 | else if (mt == ID_CHK_REQ) | ||
765 | mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp); | ||
766 | else if (mt == ID_REMOVE) | ||
767 | mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp); | ||
768 | else if (mt == ID_VERIFY) | ||
769 | mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, dp); | ||
770 | else if (mt == ID_CHK_RES) | ||
771 | mISDN_FsmEvent(&tm->tei_m, EV_CHKRESP, dp); | ||
772 | } | ||
773 | |||
774 | static struct layer2 * | ||
775 | create_new_tei(struct manager *mgr, int tei) | ||
776 | { | ||
777 | u_long opt = 0; | ||
778 | u_long flags; | ||
779 | int id; | ||
780 | struct layer2 *l2; | ||
781 | |||
782 | if (!mgr->up) | ||
783 | return NULL; | ||
784 | if (tei < 64) | ||
785 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); | ||
786 | if (mgr->ch.st->dev->Dprotocols | ||
787 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | ||
788 | test_and_set_bit(OPTION_L2_PMX, &opt); | ||
789 | l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, (u_int)opt, (u_long)tei); | ||
790 | if (!l2) { | ||
791 | printk(KERN_WARNING "%s:no memory for layer2\n", __func__); | ||
792 | return NULL; | ||
793 | } | ||
794 | l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); | ||
795 | if (!l2->tm) { | ||
796 | kfree(l2); | ||
797 | printk(KERN_WARNING "%s:no memory for teimgr\n", __func__); | ||
798 | return NULL; | ||
799 | } | ||
800 | l2->tm->mgr = mgr; | ||
801 | l2->tm->l2 = l2; | ||
802 | l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; | ||
803 | l2->tm->tei_m.userdata = l2->tm; | ||
804 | l2->tm->tei_m.printdebug = tei_debug; | ||
805 | l2->tm->tei_m.fsm = &teifsmn; | ||
806 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
807 | l2->tm->tval = 2000; /* T202 2 sec */ | ||
808 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); | ||
809 | write_lock_irqsave(&mgr->lock, flags); | ||
810 | id = get_free_id(mgr); | ||
811 | list_add_tail(&l2->list, &mgr->layer2); | ||
812 | write_unlock_irqrestore(&mgr->lock, flags); | ||
813 | if (id < 0) { | ||
814 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
815 | printk(KERN_WARNING "%s:no free id\n", __func__); | ||
816 | return NULL; | ||
817 | } else { | ||
818 | l2->ch.nr = id; | ||
819 | __add_layer2(&l2->ch, mgr->ch.st); | ||
820 | l2->ch.recv = mgr->ch.recv; | ||
821 | l2->ch.peer = mgr->ch.peer; | ||
822 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); | ||
823 | } | ||
824 | return l2; | ||
825 | } | ||
826 | |||
827 | static void | ||
828 | new_tei_req(struct manager *mgr, u_char *dp) | ||
829 | { | ||
830 | int tei, ri; | ||
831 | struct layer2 *l2; | ||
832 | |||
833 | ri = dp[0] << 8; | ||
834 | ri += dp[1]; | ||
835 | if (!mgr->up) | ||
836 | goto denied; | ||
837 | tei = get_free_tei(mgr); | ||
838 | if (tei < 0) { | ||
839 | printk(KERN_WARNING "%s:No free tei\n", __func__); | ||
840 | goto denied; | ||
841 | } | ||
842 | l2 = create_new_tei(mgr, tei); | ||
843 | if (!l2) | ||
844 | goto denied; | ||
845 | else | ||
846 | mISDN_FsmEvent(&l2->tm->tei_m, EV_ASSIGN_REQ, dp); | ||
847 | return; | ||
848 | denied: | ||
849 | put_tei_msg(mgr, ID_DENIED, ri, GROUP_TEI); | ||
850 | } | ||
851 | |||
852 | static int | ||
853 | ph_data_ind(struct manager *mgr, struct sk_buff *skb) | ||
854 | { | ||
855 | int ret = -EINVAL; | ||
856 | struct layer2 *l2; | ||
857 | u_long flags; | ||
858 | u_char mt; | ||
859 | |||
860 | if (skb->len < 8) { | ||
861 | if (*debug & DEBUG_L2_TEI) | ||
862 | printk(KERN_DEBUG "%s: short mgr frame %d/8\n", | ||
863 | __func__, skb->len); | ||
864 | goto done; | ||
865 | } | ||
866 | if (*debug & DEBUG_L2_TEI) | ||
867 | |||
868 | if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */ | ||
869 | goto done; | ||
870 | if (skb->data[0] & 1) /* EA0 formal error */ | ||
871 | goto done; | ||
872 | if (!(skb->data[1] & 1)) /* EA1 formal error */ | ||
873 | goto done; | ||
874 | if ((skb->data[1] >> 1) != GROUP_TEI) /* not for us */ | ||
875 | goto done; | ||
876 | if ((skb->data[2] & 0xef) != UI) /* not UI */ | ||
877 | goto done; | ||
878 | if (skb->data[3] != TEI_ENTITY_ID) /* not tei entity */ | ||
879 | goto done; | ||
880 | mt = skb->data[6]; | ||
881 | switch (mt) { | ||
882 | case ID_REQUEST: | ||
883 | case ID_CHK_RES: | ||
884 | case ID_VERIFY: | ||
885 | if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
886 | goto done; | ||
887 | break; | ||
888 | case ID_ASSIGNED: | ||
889 | case ID_DENIED: | ||
890 | case ID_CHK_REQ: | ||
891 | case ID_REMOVE: | ||
892 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
893 | goto done; | ||
894 | break; | ||
895 | default: | ||
896 | goto done; | ||
897 | } | ||
898 | ret = 0; | ||
899 | if (mt == ID_REQUEST) { | ||
900 | new_tei_req(mgr, &skb->data[4]); | ||
901 | goto done; | ||
902 | } | ||
903 | read_lock_irqsave(&mgr->lock, flags); | ||
904 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
905 | tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); | ||
906 | } | ||
907 | read_unlock_irqrestore(&mgr->lock, flags); | ||
908 | done: | ||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | int | ||
913 | l2_tei(struct layer2 *l2, u_int cmd, u_long arg) | ||
914 | { | ||
915 | struct teimgr *tm = l2->tm; | ||
916 | |||
917 | if (test_bit(FLG_FIXED_TEI, &l2->flag)) | ||
918 | return 0; | ||
919 | if (*debug & DEBUG_L2_TEI) | ||
920 | printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); | ||
921 | switch (cmd) { | ||
922 | case MDL_ASSIGN_IND: | ||
923 | mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL); | ||
924 | break; | ||
925 | case MDL_ERROR_IND: | ||
926 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
927 | mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, &l2->tei); | ||
928 | if (test_bit(MGR_OPT_USER, &tm->mgr->options)) | ||
929 | mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL); | ||
930 | break; | ||
931 | case MDL_STATUS_UP_IND: | ||
932 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
933 | mISDN_FsmEvent(&tm->mgr->deact, EV_ACTIVATE, NULL); | ||
934 | break; | ||
935 | case MDL_STATUS_DOWN_IND: | ||
936 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
937 | mISDN_FsmEvent(&tm->mgr->deact, EV_DEACTIVATE, NULL); | ||
938 | break; | ||
939 | case MDL_STATUS_UI_IND: | ||
940 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
941 | mISDN_FsmEvent(&tm->mgr->deact, EV_UI, NULL); | ||
942 | break; | ||
943 | } | ||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | void | ||
948 | release_tei(struct layer2 *l2) | ||
949 | { | ||
950 | struct teimgr *tm = l2->tm; | ||
951 | u_long flags; | ||
952 | |||
953 | mISDN_FsmDelTimer(&tm->timer, 1); | ||
954 | write_lock_irqsave(&tm->mgr->lock, flags); | ||
955 | list_del(&l2->list); | ||
956 | write_unlock_irqrestore(&tm->mgr->lock, flags); | ||
957 | l2->tm = NULL; | ||
958 | kfree(tm); | ||
959 | } | ||
960 | |||
961 | static int | ||
962 | create_teimgr(struct manager *mgr, struct channel_req *crq) | ||
963 | { | ||
964 | struct layer2 *l2; | ||
965 | u_long opt = 0; | ||
966 | u_long flags; | ||
967 | int id; | ||
968 | |||
969 | if (*debug & DEBUG_L2_TEI) | ||
970 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
971 | __func__, mgr->ch.st->dev->name, crq->protocol, | ||
972 | crq->adr.dev, crq->adr.channel, crq->adr.sapi, | ||
973 | crq->adr.tei); | ||
974 | if (crq->adr.sapi != 0) /* not supported yet */ | ||
975 | return -EINVAL; | ||
976 | if (crq->adr.tei > GROUP_TEI) | ||
977 | return -EINVAL; | ||
978 | if (crq->adr.tei < 64) | ||
979 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); | ||
980 | if (crq->adr.tei == 0) | ||
981 | test_and_set_bit(OPTION_L2_PTP, &opt); | ||
982 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { | ||
983 | if (crq->protocol == ISDN_P_LAPD_TE) | ||
984 | return -EPROTONOSUPPORT; | ||
985 | if ((crq->adr.tei != 0) && (crq->adr.tei != 127)) | ||
986 | return -EINVAL; | ||
987 | if (mgr->up) { | ||
988 | printk(KERN_WARNING | ||
989 | "%s: only one network manager is allowed\n", | ||
990 | __func__); | ||
991 | return -EBUSY; | ||
992 | } | ||
993 | } else if (test_bit(MGR_OPT_USER, &mgr->options)) { | ||
994 | if (crq->protocol == ISDN_P_LAPD_NT) | ||
995 | return -EPROTONOSUPPORT; | ||
996 | if ((crq->adr.tei >= 64) && (crq->adr.tei < GROUP_TEI)) | ||
997 | return -EINVAL; /* dyn tei */ | ||
998 | } else { | ||
999 | if (crq->protocol == ISDN_P_LAPD_NT) | ||
1000 | test_and_set_bit(MGR_OPT_NETWORK, &mgr->options); | ||
1001 | if (crq->protocol == ISDN_P_LAPD_TE) | ||
1002 | test_and_set_bit(MGR_OPT_USER, &mgr->options); | ||
1003 | } | ||
1004 | if (mgr->ch.st->dev->Dprotocols | ||
1005 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | ||
1006 | test_and_set_bit(OPTION_L2_PMX, &opt); | ||
1007 | if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) { | ||
1008 | mgr->up = crq->ch; | ||
1009 | id = DL_INFO_L2_CONNECT; | ||
1010 | teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id); | ||
1011 | crq->ch = NULL; | ||
1012 | if (!list_empty(&mgr->layer2)) { | ||
1013 | read_lock_irqsave(&mgr->lock, flags); | ||
1014 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
1015 | l2->up = mgr->up; | ||
1016 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); | ||
1017 | } | ||
1018 | read_unlock_irqrestore(&mgr->lock, flags); | ||
1019 | } | ||
1020 | return 0; | ||
1021 | } | ||
1022 | l2 = create_l2(crq->ch, crq->protocol, (u_int)opt, | ||
1023 | (u_long)crq->adr.tei); | ||
1024 | if (!l2) | ||
1025 | return -ENOMEM; | ||
1026 | l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); | ||
1027 | if (!l2->tm) { | ||
1028 | kfree(l2); | ||
1029 | printk(KERN_ERR "kmalloc teimgr failed\n"); | ||
1030 | return -ENOMEM; | ||
1031 | } | ||
1032 | l2->tm->mgr = mgr; | ||
1033 | l2->tm->l2 = l2; | ||
1034 | l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; | ||
1035 | l2->tm->tei_m.userdata = l2->tm; | ||
1036 | l2->tm->tei_m.printdebug = tei_debug; | ||
1037 | if (crq->protocol == ISDN_P_LAPD_TE) { | ||
1038 | l2->tm->tei_m.fsm = &teifsmu; | ||
1039 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
1040 | l2->tm->tval = 1000; /* T201 1 sec */ | ||
1041 | } else { | ||
1042 | l2->tm->tei_m.fsm = &teifsmn; | ||
1043 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
1044 | l2->tm->tval = 2000; /* T202 2 sec */ | ||
1045 | } | ||
1046 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); | ||
1047 | write_lock_irqsave(&mgr->lock, flags); | ||
1048 | id = get_free_id(mgr); | ||
1049 | list_add_tail(&l2->list, &mgr->layer2); | ||
1050 | write_unlock_irqrestore(&mgr->lock, flags); | ||
1051 | if (id < 0) { | ||
1052 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1053 | } else { | ||
1054 | l2->ch.nr = id; | ||
1055 | l2->up->nr = id; | ||
1056 | crq->ch = &l2->ch; | ||
1057 | id = 0; | ||
1058 | } | ||
1059 | return id; | ||
1060 | } | ||
1061 | |||
1062 | static int | ||
1063 | mgr_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1064 | { | ||
1065 | struct manager *mgr; | ||
1066 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1067 | int ret = -EINVAL; | ||
1068 | |||
1069 | mgr = container_of(ch, struct manager, ch); | ||
1070 | if (*debug & DEBUG_L2_RECV) | ||
1071 | printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", | ||
1072 | __func__, hh->prim, hh->id); | ||
1073 | switch (hh->prim) { | ||
1074 | case PH_DATA_IND: | ||
1075 | mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); | ||
1076 | ret = ph_data_ind(mgr, skb); | ||
1077 | break; | ||
1078 | case PH_DATA_CNF: | ||
1079 | do_ack(mgr, hh->id); | ||
1080 | ret = 0; | ||
1081 | break; | ||
1082 | case PH_ACTIVATE_IND: | ||
1083 | test_and_set_bit(MGR_PH_ACTIVE, &mgr->options); | ||
1084 | mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL); | ||
1085 | do_send(mgr); | ||
1086 | ret = 0; | ||
1087 | break; | ||
1088 | case PH_DEACTIVATE_IND: | ||
1089 | test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options); | ||
1090 | mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL); | ||
1091 | ret = 0; | ||
1092 | break; | ||
1093 | case DL_UNITDATA_REQ: | ||
1094 | return dl_unit_data(mgr, skb); | ||
1095 | } | ||
1096 | if (!ret) | ||
1097 | dev_kfree_skb(skb); | ||
1098 | return ret; | ||
1099 | } | ||
1100 | |||
1101 | static int | ||
1102 | free_teimanager(struct manager *mgr) | ||
1103 | { | ||
1104 | struct layer2 *l2, *nl2; | ||
1105 | |||
1106 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { | ||
1107 | /* not locked lock is taken in release tei */ | ||
1108 | mgr->up = NULL; | ||
1109 | if (test_bit(OPTION_L2_CLEANUP, &mgr->options)) { | ||
1110 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1111 | put_tei_msg(mgr, ID_REMOVE, 0, l2->tei); | ||
1112 | mutex_lock(&mgr->ch.st->lmutex); | ||
1113 | list_del(&l2->ch.list); | ||
1114 | mutex_unlock(&mgr->ch.st->lmutex); | ||
1115 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1116 | } | ||
1117 | test_and_clear_bit(MGR_OPT_NETWORK, &mgr->options); | ||
1118 | } else { | ||
1119 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1120 | l2->up = NULL; | ||
1121 | } | ||
1122 | } | ||
1123 | } | ||
1124 | if (test_bit(MGR_OPT_USER, &mgr->options)) { | ||
1125 | if (list_empty(&mgr->layer2)) | ||
1126 | test_and_clear_bit(MGR_OPT_USER, &mgr->options); | ||
1127 | } | ||
1128 | mgr->ch.st->dev->D.ctrl(&mgr->ch.st->dev->D, CLOSE_CHANNEL, NULL); | ||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | static int | ||
1133 | ctrl_teimanager(struct manager *mgr, void *arg) | ||
1134 | { | ||
1135 | /* currently we only have one option */ | ||
1136 | int clean = *((int *)arg); | ||
1137 | |||
1138 | if (clean) | ||
1139 | test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); | ||
1140 | else | ||
1141 | test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); | ||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | /* This function does create a L2 for fixed TEI in NT Mode */ | ||
1146 | static int | ||
1147 | check_data(struct manager *mgr, struct sk_buff *skb) | ||
1148 | { | ||
1149 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1150 | int ret, tei; | ||
1151 | struct layer2 *l2; | ||
1152 | |||
1153 | if (*debug & DEBUG_L2_CTRL) | ||
1154 | printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", | ||
1155 | __func__, hh->prim, hh->id); | ||
1156 | if (test_bit(MGR_OPT_USER, &mgr->options)) | ||
1157 | return -ENOTCONN; | ||
1158 | if (hh->prim != PH_DATA_IND) | ||
1159 | return -ENOTCONN; | ||
1160 | if (skb->len != 3) | ||
1161 | return -ENOTCONN; | ||
1162 | if (skb->data[0] != 0) | ||
1163 | /* only SAPI 0 command */ | ||
1164 | return -ENOTCONN; | ||
1165 | if (!(skb->data[1] & 1)) /* invalid EA1 */ | ||
1166 | return -EINVAL; | ||
1167 | tei = skb->data[1] >> 0; | ||
1168 | if (tei > 63) /* not a fixed tei */ | ||
1169 | return -ENOTCONN; | ||
1170 | if ((skb->data[2] & ~0x10) != SABME) | ||
1171 | return -ENOTCONN; | ||
1172 | /* We got a SABME for a fixed TEI */ | ||
1173 | l2 = create_new_tei(mgr, tei); | ||
1174 | if (!l2) | ||
1175 | return -ENOMEM; | ||
1176 | ret = l2->ch.send(&l2->ch, skb); | ||
1177 | return ret; | ||
1178 | } | ||
1179 | |||
1180 | void | ||
1181 | delete_teimanager(struct mISDNchannel *ch) | ||
1182 | { | ||
1183 | struct manager *mgr; | ||
1184 | struct layer2 *l2, *nl2; | ||
1185 | |||
1186 | mgr = container_of(ch, struct manager, ch); | ||
1187 | /* not locked lock is taken in release tei */ | ||
1188 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1189 | mutex_lock(&mgr->ch.st->lmutex); | ||
1190 | list_del(&l2->ch.list); | ||
1191 | mutex_unlock(&mgr->ch.st->lmutex); | ||
1192 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1193 | } | ||
1194 | list_del(&mgr->ch.list); | ||
1195 | list_del(&mgr->bcast.list); | ||
1196 | skb_queue_purge(&mgr->sendq); | ||
1197 | kfree(mgr); | ||
1198 | } | ||
1199 | |||
1200 | static int | ||
1201 | mgr_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1202 | { | ||
1203 | struct manager *mgr; | ||
1204 | int ret = -EINVAL; | ||
1205 | |||
1206 | mgr = container_of(ch, struct manager, ch); | ||
1207 | if (*debug & DEBUG_L2_CTRL) | ||
1208 | printk(KERN_DEBUG "%s(%x, %p)\n", __func__, cmd, arg); | ||
1209 | switch (cmd) { | ||
1210 | case OPEN_CHANNEL: | ||
1211 | ret = create_teimgr(mgr, arg); | ||
1212 | break; | ||
1213 | case CLOSE_CHANNEL: | ||
1214 | ret = free_teimanager(mgr); | ||
1215 | break; | ||
1216 | case CONTROL_CHANNEL: | ||
1217 | ret = ctrl_teimanager(mgr, arg); | ||
1218 | break; | ||
1219 | case CHECK_DATA: | ||
1220 | ret = check_data(mgr, arg); | ||
1221 | break; | ||
1222 | } | ||
1223 | return ret; | ||
1224 | } | ||
1225 | |||
1226 | static int | ||
1227 | mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1228 | { | ||
1229 | struct manager *mgr = container_of(ch, struct manager, bcast); | ||
1230 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1231 | struct sk_buff *cskb = NULL; | ||
1232 | struct layer2 *l2; | ||
1233 | u_long flags; | ||
1234 | int ret; | ||
1235 | |||
1236 | read_lock_irqsave(&mgr->lock, flags); | ||
1237 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
1238 | if ((hh->id & MISDN_ID_SAPI_MASK) == | ||
1239 | (l2->ch.addr & MISDN_ID_SAPI_MASK)) { | ||
1240 | if (list_is_last(&l2->list, &mgr->layer2)) { | ||
1241 | cskb = skb; | ||
1242 | skb = NULL; | ||
1243 | } else { | ||
1244 | if (!cskb) | ||
1245 | cskb = skb_copy(skb, GFP_KERNEL); | ||
1246 | } | ||
1247 | if (cskb) { | ||
1248 | ret = l2->ch.send(&l2->ch, cskb); | ||
1249 | if (ret) { | ||
1250 | if (*debug & DEBUG_SEND_ERR) | ||
1251 | printk(KERN_DEBUG | ||
1252 | "%s ch%d prim(%x) addr(%x)" | ||
1253 | " err %d\n", | ||
1254 | __func__, l2->ch.nr, | ||
1255 | hh->prim, l2->ch.addr, ret); | ||
1256 | } else | ||
1257 | cskb = NULL; | ||
1258 | } else { | ||
1259 | printk(KERN_WARNING "%s ch%d addr %x no mem\n", | ||
1260 | __func__, ch->nr, ch->addr); | ||
1261 | goto out; | ||
1262 | } | ||
1263 | } | ||
1264 | } | ||
1265 | out: | ||
1266 | read_unlock_irqrestore(&mgr->lock, flags); | ||
1267 | if (cskb) | ||
1268 | dev_kfree_skb(cskb); | ||
1269 | if (skb) | ||
1270 | dev_kfree_skb(skb); | ||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | static int | ||
1275 | mgr_bcast_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1276 | { | ||
1277 | |||
1278 | return -EINVAL; | ||
1279 | } | ||
1280 | |||
1281 | int | ||
1282 | create_teimanager(struct mISDNdevice *dev) | ||
1283 | { | ||
1284 | struct manager *mgr; | ||
1285 | |||
1286 | mgr = kzalloc(sizeof(struct manager), GFP_KERNEL); | ||
1287 | if (!mgr) | ||
1288 | return -ENOMEM; | ||
1289 | INIT_LIST_HEAD(&mgr->layer2); | ||
1290 | mgr->lock = __RW_LOCK_UNLOCKED(mgr->lock); | ||
1291 | skb_queue_head_init(&mgr->sendq); | ||
1292 | mgr->nextid = 1; | ||
1293 | mgr->lastid = MISDN_ID_NONE; | ||
1294 | mgr->ch.send = mgr_send; | ||
1295 | mgr->ch.ctrl = mgr_ctrl; | ||
1296 | mgr->ch.st = dev->D.st; | ||
1297 | set_channel_address(&mgr->ch, TEI_SAPI, GROUP_TEI); | ||
1298 | add_layer2(&mgr->ch, dev->D.st); | ||
1299 | mgr->bcast.send = mgr_bcast; | ||
1300 | mgr->bcast.ctrl = mgr_bcast_ctrl; | ||
1301 | mgr->bcast.st = dev->D.st; | ||
1302 | set_channel_address(&mgr->bcast, 0, GROUP_TEI); | ||
1303 | add_layer2(&mgr->bcast, dev->D.st); | ||
1304 | mgr->deact.debug = *debug & DEBUG_MANAGER; | ||
1305 | mgr->deact.userdata = mgr; | ||
1306 | mgr->deact.printdebug = da_debug; | ||
1307 | mgr->deact.fsm = &deactfsm; | ||
1308 | mgr->deact.state = ST_L1_DEACT; | ||
1309 | mISDN_FsmInitTimer(&mgr->deact, &mgr->datimer); | ||
1310 | dev->teimgr = &mgr->ch; | ||
1311 | return 0; | ||
1312 | } | ||
1313 | |||
1314 | int TEIInit(u_int *deb) | ||
1315 | { | ||
1316 | debug = deb; | ||
1317 | teifsmu.state_count = TEI_STATE_COUNT; | ||
1318 | teifsmu.event_count = TEI_EVENT_COUNT; | ||
1319 | teifsmu.strEvent = strTeiEvent; | ||
1320 | teifsmu.strState = strTeiState; | ||
1321 | mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser)); | ||
1322 | teifsmn.state_count = TEI_STATE_COUNT; | ||
1323 | teifsmn.event_count = TEI_EVENT_COUNT; | ||
1324 | teifsmn.strEvent = strTeiEvent; | ||
1325 | teifsmn.strState = strTeiState; | ||
1326 | mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet)); | ||
1327 | deactfsm.state_count = DEACT_STATE_COUNT; | ||
1328 | deactfsm.event_count = DEACT_EVENT_COUNT; | ||
1329 | deactfsm.strEvent = strDeactEvent; | ||
1330 | deactfsm.strState = strDeactState; | ||
1331 | mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList)); | ||
1332 | return 0; | ||
1333 | } | ||
1334 | |||
1335 | void TEIFree(void) | ||
1336 | { | ||
1337 | mISDN_FsmFree(&teifsmu); | ||
1338 | mISDN_FsmFree(&teifsmn); | ||
1339 | mISDN_FsmFree(&deactfsm); | ||
1340 | } | ||
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c new file mode 100644 index 000000000000..b5fabc7019d8 --- /dev/null +++ b/drivers/isdn/mISDN/timerdev.c | |||
@@ -0,0 +1,301 @@ | |||
1 | /* | ||
2 | * | ||
3 | * general timer device for using in ISDN stacks | ||
4 | * | ||
5 | * Author Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/poll.h> | ||
21 | #include <linux/vmalloc.h> | ||
22 | #include <linux/timer.h> | ||
23 | #include <linux/miscdevice.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/mISDNif.h> | ||
26 | |||
27 | static int *debug; | ||
28 | |||
29 | |||
30 | struct mISDNtimerdev { | ||
31 | int next_id; | ||
32 | struct list_head pending; | ||
33 | struct list_head expired; | ||
34 | wait_queue_head_t wait; | ||
35 | u_int work; | ||
36 | spinlock_t lock; /* protect lists */ | ||
37 | }; | ||
38 | |||
39 | struct mISDNtimer { | ||
40 | struct list_head list; | ||
41 | struct mISDNtimerdev *dev; | ||
42 | struct timer_list tl; | ||
43 | int id; | ||
44 | }; | ||
45 | |||
46 | static int | ||
47 | mISDN_open(struct inode *ino, struct file *filep) | ||
48 | { | ||
49 | struct mISDNtimerdev *dev; | ||
50 | |||
51 | if (*debug & DEBUG_TIMER) | ||
52 | printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); | ||
53 | dev = kmalloc(sizeof(struct mISDNtimerdev) , GFP_KERNEL); | ||
54 | if (!dev) | ||
55 | return -ENOMEM; | ||
56 | dev->next_id = 1; | ||
57 | INIT_LIST_HEAD(&dev->pending); | ||
58 | INIT_LIST_HEAD(&dev->expired); | ||
59 | spin_lock_init(&dev->lock); | ||
60 | dev->work = 0; | ||
61 | init_waitqueue_head(&dev->wait); | ||
62 | filep->private_data = dev; | ||
63 | __module_get(THIS_MODULE); | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | mISDN_close(struct inode *ino, struct file *filep) | ||
69 | { | ||
70 | struct mISDNtimerdev *dev = filep->private_data; | ||
71 | struct mISDNtimer *timer, *next; | ||
72 | |||
73 | if (*debug & DEBUG_TIMER) | ||
74 | printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); | ||
75 | list_for_each_entry_safe(timer, next, &dev->pending, list) { | ||
76 | del_timer(&timer->tl); | ||
77 | kfree(timer); | ||
78 | } | ||
79 | list_for_each_entry_safe(timer, next, &dev->expired, list) { | ||
80 | kfree(timer); | ||
81 | } | ||
82 | kfree(dev); | ||
83 | module_put(THIS_MODULE); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static ssize_t | ||
88 | mISDN_read(struct file *filep, char *buf, size_t count, loff_t *off) | ||
89 | { | ||
90 | struct mISDNtimerdev *dev = filep->private_data; | ||
91 | struct mISDNtimer *timer; | ||
92 | u_long flags; | ||
93 | int ret = 0; | ||
94 | |||
95 | if (*debug & DEBUG_TIMER) | ||
96 | printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__, | ||
97 | filep, buf, (int)count, off); | ||
98 | if (*off != filep->f_pos) | ||
99 | return -ESPIPE; | ||
100 | |||
101 | if (list_empty(&dev->expired) && (dev->work == 0)) { | ||
102 | if (filep->f_flags & O_NONBLOCK) | ||
103 | return -EAGAIN; | ||
104 | wait_event_interruptible(dev->wait, (dev->work || | ||
105 | !list_empty(&dev->expired))); | ||
106 | if (signal_pending(current)) | ||
107 | return -ERESTARTSYS; | ||
108 | } | ||
109 | if (count < sizeof(int)) | ||
110 | return -ENOSPC; | ||
111 | if (dev->work) | ||
112 | dev->work = 0; | ||
113 | if (!list_empty(&dev->expired)) { | ||
114 | spin_lock_irqsave(&dev->lock, flags); | ||
115 | timer = (struct mISDNtimer *)dev->expired.next; | ||
116 | list_del(&timer->list); | ||
117 | spin_unlock_irqrestore(&dev->lock, flags); | ||
118 | if (put_user(timer->id, (int *)buf)) | ||
119 | ret = -EFAULT; | ||
120 | else | ||
121 | ret = sizeof(int); | ||
122 | kfree(timer); | ||
123 | } | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | static loff_t | ||
128 | mISDN_llseek(struct file *filep, loff_t offset, int orig) | ||
129 | { | ||
130 | return -ESPIPE; | ||
131 | } | ||
132 | |||
133 | static ssize_t | ||
134 | mISDN_write(struct file *filep, const char *buf, size_t count, loff_t *off) | ||
135 | { | ||
136 | return -EOPNOTSUPP; | ||
137 | } | ||
138 | |||
139 | static unsigned int | ||
140 | mISDN_poll(struct file *filep, poll_table *wait) | ||
141 | { | ||
142 | struct mISDNtimerdev *dev = filep->private_data; | ||
143 | unsigned int mask = POLLERR; | ||
144 | |||
145 | if (*debug & DEBUG_TIMER) | ||
146 | printk(KERN_DEBUG "%s(%p, %p)\n", __func__, filep, wait); | ||
147 | if (dev) { | ||
148 | poll_wait(filep, &dev->wait, wait); | ||
149 | mask = 0; | ||
150 | if (dev->work || !list_empty(&dev->expired)) | ||
151 | mask |= (POLLIN | POLLRDNORM); | ||
152 | if (*debug & DEBUG_TIMER) | ||
153 | printk(KERN_DEBUG "%s work(%d) empty(%d)\n", __func__, | ||
154 | dev->work, list_empty(&dev->expired)); | ||
155 | } | ||
156 | return mask; | ||
157 | } | ||
158 | |||
159 | static void | ||
160 | dev_expire_timer(struct mISDNtimer *timer) | ||
161 | { | ||
162 | u_long flags; | ||
163 | |||
164 | spin_lock_irqsave(&timer->dev->lock, flags); | ||
165 | list_del(&timer->list); | ||
166 | list_add_tail(&timer->list, &timer->dev->expired); | ||
167 | spin_unlock_irqrestore(&timer->dev->lock, flags); | ||
168 | wake_up_interruptible(&timer->dev->wait); | ||
169 | } | ||
170 | |||
171 | static int | ||
172 | misdn_add_timer(struct mISDNtimerdev *dev, int timeout) | ||
173 | { | ||
174 | int id; | ||
175 | u_long flags; | ||
176 | struct mISDNtimer *timer; | ||
177 | |||
178 | if (!timeout) { | ||
179 | dev->work = 1; | ||
180 | wake_up_interruptible(&dev->wait); | ||
181 | id = 0; | ||
182 | } else { | ||
183 | timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL); | ||
184 | if (!timer) | ||
185 | return -ENOMEM; | ||
186 | spin_lock_irqsave(&dev->lock, flags); | ||
187 | timer->id = dev->next_id++; | ||
188 | if (dev->next_id < 0) | ||
189 | dev->next_id = 1; | ||
190 | list_add_tail(&timer->list, &dev->pending); | ||
191 | spin_unlock_irqrestore(&dev->lock, flags); | ||
192 | timer->dev = dev; | ||
193 | timer->tl.data = (long)timer; | ||
194 | timer->tl.function = (void *) dev_expire_timer; | ||
195 | init_timer(&timer->tl); | ||
196 | timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000); | ||
197 | add_timer(&timer->tl); | ||
198 | id = timer->id; | ||
199 | } | ||
200 | return id; | ||
201 | } | ||
202 | |||
203 | static int | ||
204 | misdn_del_timer(struct mISDNtimerdev *dev, int id) | ||
205 | { | ||
206 | u_long flags; | ||
207 | struct mISDNtimer *timer; | ||
208 | int ret = 0; | ||
209 | |||
210 | spin_lock_irqsave(&dev->lock, flags); | ||
211 | list_for_each_entry(timer, &dev->pending, list) { | ||
212 | if (timer->id == id) { | ||
213 | list_del_init(&timer->list); | ||
214 | del_timer(&timer->tl); | ||
215 | ret = timer->id; | ||
216 | kfree(timer); | ||
217 | goto unlock; | ||
218 | } | ||
219 | } | ||
220 | unlock: | ||
221 | spin_unlock_irqrestore(&dev->lock, flags); | ||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | static int | ||
226 | mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, | ||
227 | unsigned long arg) | ||
228 | { | ||
229 | struct mISDNtimerdev *dev = filep->private_data; | ||
230 | int id, tout, ret = 0; | ||
231 | |||
232 | |||
233 | if (*debug & DEBUG_TIMER) | ||
234 | printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__, | ||
235 | filep, cmd, arg); | ||
236 | switch (cmd) { | ||
237 | case IMADDTIMER: | ||
238 | if (get_user(tout, (int __user *)arg)) { | ||
239 | ret = -EFAULT; | ||
240 | break; | ||
241 | } | ||
242 | id = misdn_add_timer(dev, tout); | ||
243 | if (*debug & DEBUG_TIMER) | ||
244 | printk(KERN_DEBUG "%s add %d id %d\n", __func__, | ||
245 | tout, id); | ||
246 | if (id < 0) { | ||
247 | ret = id; | ||
248 | break; | ||
249 | } | ||
250 | if (put_user(id, (int __user *)arg)) | ||
251 | ret = -EFAULT; | ||
252 | break; | ||
253 | case IMDELTIMER: | ||
254 | if (get_user(id, (int __user *)arg)) { | ||
255 | ret = -EFAULT; | ||
256 | break; | ||
257 | } | ||
258 | if (*debug & DEBUG_TIMER) | ||
259 | printk(KERN_DEBUG "%s del id %d\n", __func__, id); | ||
260 | id = misdn_del_timer(dev, id); | ||
261 | if (put_user(id, (int __user *)arg)) | ||
262 | ret = -EFAULT; | ||
263 | break; | ||
264 | default: | ||
265 | ret = -EINVAL; | ||
266 | } | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | static struct file_operations mISDN_fops = { | ||
271 | .llseek = mISDN_llseek, | ||
272 | .read = mISDN_read, | ||
273 | .write = mISDN_write, | ||
274 | .poll = mISDN_poll, | ||
275 | .ioctl = mISDN_ioctl, | ||
276 | .open = mISDN_open, | ||
277 | .release = mISDN_close, | ||
278 | }; | ||
279 | |||
280 | static struct miscdevice mISDNtimer = { | ||
281 | .minor = MISC_DYNAMIC_MINOR, | ||
282 | .name = "mISDNtimer", | ||
283 | .fops = &mISDN_fops, | ||
284 | }; | ||
285 | |||
286 | int | ||
287 | mISDN_inittimer(int *deb) | ||
288 | { | ||
289 | int err; | ||
290 | |||
291 | debug = deb; | ||
292 | err = misc_register(&mISDNtimer); | ||
293 | if (err) | ||
294 | printk(KERN_WARNING "mISDN: Could not register timer device\n"); | ||
295 | return err; | ||
296 | } | ||
297 | |||
298 | void mISDN_timer_cleanup(void) | ||
299 | { | ||
300 | misc_deregister(&mISDNtimer); | ||
301 | } | ||