diff options
Diffstat (limited to 'drivers/isdn/pcbit')
-rw-r--r-- | drivers/isdn/pcbit/Kconfig | 14 | ||||
-rw-r--r-- | drivers/isdn/pcbit/Makefile | 9 | ||||
-rw-r--r-- | drivers/isdn/pcbit/callbacks.c | 367 | ||||
-rw-r--r-- | drivers/isdn/pcbit/callbacks.h | 49 | ||||
-rw-r--r-- | drivers/isdn/pcbit/capi.c | 663 | ||||
-rw-r--r-- | drivers/isdn/pcbit/capi.h | 88 | ||||
-rw-r--r-- | drivers/isdn/pcbit/drv.c | 1088 | ||||
-rw-r--r-- | drivers/isdn/pcbit/edss1.c | 325 | ||||
-rw-r--r-- | drivers/isdn/pcbit/edss1.h | 99 | ||||
-rw-r--r-- | drivers/isdn/pcbit/layer2.c | 732 | ||||
-rw-r--r-- | drivers/isdn/pcbit/layer2.h | 288 | ||||
-rw-r--r-- | drivers/isdn/pcbit/module.c | 130 | ||||
-rw-r--r-- | drivers/isdn/pcbit/pcbit.h | 169 |
13 files changed, 4021 insertions, 0 deletions
diff --git a/drivers/isdn/pcbit/Kconfig b/drivers/isdn/pcbit/Kconfig new file mode 100644 index 000000000000..f06997faef16 --- /dev/null +++ b/drivers/isdn/pcbit/Kconfig | |||
@@ -0,0 +1,14 @@ | |||
1 | # | ||
2 | # Config.in for PCBIT ISDN driver | ||
3 | # | ||
4 | config ISDN_DRV_PCBIT | ||
5 | tristate "PCBIT-D support" | ||
6 | depends on ISDN_I4L && ISA && (BROKEN || !PPC) | ||
7 | help | ||
8 | This enables support for the PCBIT ISDN-card. This card is | ||
9 | manufactured in Portugal by Octal. For running this card, | ||
10 | additional firmware is necessary, which has to be downloaded into | ||
11 | the card using a utility which is distributed separately. See | ||
12 | <file:Documentation/isdn/README> and | ||
13 | <file:Documentation/isdn/README.pcbit> for more information. | ||
14 | |||
diff --git a/drivers/isdn/pcbit/Makefile b/drivers/isdn/pcbit/Makefile new file mode 100644 index 000000000000..2d026c3242e8 --- /dev/null +++ b/drivers/isdn/pcbit/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # Makefile for the pcbit ISDN device driver | ||
2 | |||
3 | # Each configuration option enables a list of files. | ||
4 | |||
5 | obj-$(CONFIG_ISDN_DRV_PCBIT) += pcbit.o | ||
6 | |||
7 | # Multipart objects. | ||
8 | |||
9 | pcbit-y := module.o edss1.o drv.o layer2.o capi.o callbacks.o | ||
diff --git a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c new file mode 100644 index 000000000000..692ec72d1ee8 --- /dev/null +++ b/drivers/isdn/pcbit/callbacks.c | |||
@@ -0,0 +1,367 @@ | |||
1 | /* | ||
2 | * Callbacks for the FSM | ||
3 | * | ||
4 | * Copyright (C) 1996 Universidade de Lisboa | ||
5 | * | ||
6 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms of | ||
9 | * the GNU General Public License, incorporated herein by reference. | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * Fix: 19981230 - Carlos Morgado <chbm@techie.com> | ||
14 | * Port of Nelson Escravana's <nelson.escravana@usa.net> fix to CalledPN | ||
15 | * NULL pointer dereference in cb_in_1 (originally fixed in 2.0) | ||
16 | */ | ||
17 | |||
18 | #include <linux/sched.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/kernel.h> | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/skbuff.h> | ||
26 | |||
27 | #include <asm/io.h> | ||
28 | |||
29 | #include <linux/isdnif.h> | ||
30 | |||
31 | #include "pcbit.h" | ||
32 | #include "layer2.h" | ||
33 | #include "edss1.h" | ||
34 | #include "callbacks.h" | ||
35 | #include "capi.h" | ||
36 | |||
37 | ushort last_ref_num = 1; | ||
38 | |||
39 | /* | ||
40 | * send_conn_req | ||
41 | * | ||
42 | */ | ||
43 | |||
44 | void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
45 | struct callb_data *cbdata) | ||
46 | { | ||
47 | struct sk_buff *skb; | ||
48 | int len; | ||
49 | ushort refnum; | ||
50 | |||
51 | |||
52 | #ifdef DEBUG | ||
53 | printk(KERN_DEBUG "Called Party Number: %s\n", | ||
54 | cbdata->data.setup.CalledPN); | ||
55 | #endif | ||
56 | /* | ||
57 | * hdr - kmalloc in capi_conn_req | ||
58 | * - kfree when msg has been sent | ||
59 | */ | ||
60 | |||
61 | if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb, | ||
62 | chan->proto)) < 0) | ||
63 | { | ||
64 | printk("capi_conn_req failed\n"); | ||
65 | return; | ||
66 | } | ||
67 | |||
68 | |||
69 | refnum = last_ref_num++ & 0x7fffU; | ||
70 | |||
71 | chan->callref = 0; | ||
72 | chan->layer2link = 0; | ||
73 | chan->snum = 0; | ||
74 | chan->s_refnum = refnum; | ||
75 | |||
76 | pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len); | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * rcv CONNECT | ||
81 | * will go into ACTIVE state | ||
82 | * send CONN_ACTIVE_RESP | ||
83 | * send Select protocol request | ||
84 | */ | ||
85 | |||
86 | void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
87 | struct callb_data *data) | ||
88 | { | ||
89 | isdn_ctrl ictl; | ||
90 | struct sk_buff *skb; | ||
91 | int len; | ||
92 | ushort refnum; | ||
93 | |||
94 | if ((len=capi_conn_active_resp(chan, &skb)) < 0) | ||
95 | { | ||
96 | printk("capi_conn_active_req failed\n"); | ||
97 | return; | ||
98 | } | ||
99 | |||
100 | refnum = last_ref_num++ & 0x7fffU; | ||
101 | chan->s_refnum = refnum; | ||
102 | |||
103 | pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len); | ||
104 | |||
105 | |||
106 | ictl.command = ISDN_STAT_DCONN; | ||
107 | ictl.driver=dev->id; | ||
108 | ictl.arg=chan->id; | ||
109 | dev->dev_if->statcallb(&ictl); | ||
110 | |||
111 | /* ACTIVE D-channel */ | ||
112 | |||
113 | /* Select protocol */ | ||
114 | |||
115 | if ((len=capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) { | ||
116 | printk("capi_select_proto_req failed\n"); | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | refnum = last_ref_num++ & 0x7fffU; | ||
121 | chan->s_refnum = refnum; | ||
122 | |||
123 | pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len); | ||
124 | } | ||
125 | |||
126 | |||
127 | /* | ||
128 | * Disconnect received (actually RELEASE COMPLETE) | ||
129 | * This means we were not able to establish connection with remote | ||
130 | * Inform the big boss above | ||
131 | */ | ||
132 | void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
133 | struct callb_data *data) | ||
134 | { | ||
135 | isdn_ctrl ictl; | ||
136 | |||
137 | ictl.command = ISDN_STAT_DHUP; | ||
138 | ictl.driver=dev->id; | ||
139 | ictl.arg=chan->id; | ||
140 | dev->dev_if->statcallb(&ictl); | ||
141 | } | ||
142 | |||
143 | |||
144 | /* | ||
145 | * Incoming call received | ||
146 | * inform user | ||
147 | */ | ||
148 | |||
149 | void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
150 | struct callb_data *cbdata) | ||
151 | { | ||
152 | isdn_ctrl ictl; | ||
153 | unsigned short refnum; | ||
154 | struct sk_buff *skb; | ||
155 | int len; | ||
156 | |||
157 | |||
158 | ictl.command = ISDN_STAT_ICALL; | ||
159 | ictl.driver=dev->id; | ||
160 | ictl.arg=chan->id; | ||
161 | |||
162 | /* | ||
163 | * ictl.num >= strlen() + strlen() + 5 | ||
164 | */ | ||
165 | |||
166 | if (cbdata->data.setup.CallingPN == NULL) { | ||
167 | printk(KERN_DEBUG "NULL CallingPN to phone; using 0\n"); | ||
168 | strcpy(ictl.parm.setup.phone, "0"); | ||
169 | } | ||
170 | else { | ||
171 | strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN); | ||
172 | } | ||
173 | if (cbdata->data.setup.CalledPN == NULL) { | ||
174 | printk(KERN_DEBUG "NULL CalledPN to eazmsn; using 0\n"); | ||
175 | strcpy(ictl.parm.setup.eazmsn, "0"); | ||
176 | } | ||
177 | else { | ||
178 | strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN); | ||
179 | } | ||
180 | ictl.parm.setup.si1 = 7; | ||
181 | ictl.parm.setup.si2 = 0; | ||
182 | ictl.parm.setup.plan = 0; | ||
183 | ictl.parm.setup.screen = 0; | ||
184 | |||
185 | #ifdef DEBUG | ||
186 | printk(KERN_DEBUG "statstr: %s\n", ictl.num); | ||
187 | #endif | ||
188 | |||
189 | dev->dev_if->statcallb(&ictl); | ||
190 | |||
191 | |||
192 | if ((len=capi_conn_resp(chan, &skb)) < 0) { | ||
193 | printk(KERN_DEBUG "capi_conn_resp failed\n"); | ||
194 | return; | ||
195 | } | ||
196 | |||
197 | refnum = last_ref_num++ & 0x7fffU; | ||
198 | chan->s_refnum = refnum; | ||
199 | |||
200 | pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len); | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * user has replied | ||
205 | * open the channel | ||
206 | * send CONNECT message CONNECT_ACTIVE_REQ in CAPI | ||
207 | */ | ||
208 | |||
209 | void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
210 | struct callb_data *data) | ||
211 | { | ||
212 | unsigned short refnum; | ||
213 | struct sk_buff *skb; | ||
214 | int len; | ||
215 | |||
216 | if ((len = capi_conn_active_req(chan, &skb)) < 0) { | ||
217 | printk(KERN_DEBUG "capi_conn_active_req failed\n"); | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | |||
222 | refnum = last_ref_num++ & 0x7fffU; | ||
223 | chan->s_refnum = refnum; | ||
224 | |||
225 | printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n"); | ||
226 | pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len); | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * CONN_ACK arrived | ||
231 | * start b-proto selection | ||
232 | * | ||
233 | */ | ||
234 | |||
235 | void cb_in_3(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
236 | struct callb_data *data) | ||
237 | { | ||
238 | unsigned short refnum; | ||
239 | struct sk_buff *skb; | ||
240 | int len; | ||
241 | |||
242 | if ((len = capi_select_proto_req(chan, &skb, 0 /*incoming*/)) < 0) | ||
243 | { | ||
244 | printk("capi_select_proto_req failed\n"); | ||
245 | return; | ||
246 | } | ||
247 | |||
248 | refnum = last_ref_num++ & 0x7fffU; | ||
249 | chan->s_refnum = refnum; | ||
250 | |||
251 | pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len); | ||
252 | |||
253 | } | ||
254 | |||
255 | |||
256 | /* | ||
257 | * Received disconnect ind on active state | ||
258 | * send disconnect resp | ||
259 | * send msg to user | ||
260 | */ | ||
261 | void cb_disc_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
262 | struct callb_data *data) | ||
263 | { | ||
264 | struct sk_buff *skb; | ||
265 | int len; | ||
266 | ushort refnum; | ||
267 | isdn_ctrl ictl; | ||
268 | |||
269 | if ((len = capi_disc_resp(chan, &skb)) < 0) { | ||
270 | printk("capi_disc_resp failed\n"); | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | refnum = last_ref_num++ & 0x7fffU; | ||
275 | chan->s_refnum = refnum; | ||
276 | |||
277 | pcbit_l2_write(dev, MSG_DISC_RESP, refnum, skb, len); | ||
278 | |||
279 | ictl.command = ISDN_STAT_BHUP; | ||
280 | ictl.driver=dev->id; | ||
281 | ictl.arg=chan->id; | ||
282 | dev->dev_if->statcallb(&ictl); | ||
283 | } | ||
284 | |||
285 | |||
286 | /* | ||
287 | * User HANGUP on active/call proceeding state | ||
288 | * send disc.req | ||
289 | */ | ||
290 | void cb_disc_2(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
291 | struct callb_data *data) | ||
292 | { | ||
293 | struct sk_buff *skb; | ||
294 | int len; | ||
295 | ushort refnum; | ||
296 | |||
297 | if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0) | ||
298 | { | ||
299 | printk("capi_disc_req failed\n"); | ||
300 | return; | ||
301 | } | ||
302 | |||
303 | refnum = last_ref_num++ & 0x7fffU; | ||
304 | chan->s_refnum = refnum; | ||
305 | |||
306 | pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len); | ||
307 | } | ||
308 | |||
309 | /* | ||
310 | * Disc confirm received send BHUP | ||
311 | * Problem: when the HL driver sends the disc req itself | ||
312 | * LL receives BHUP | ||
313 | */ | ||
314 | void cb_disc_3(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
315 | struct callb_data *data) | ||
316 | { | ||
317 | isdn_ctrl ictl; | ||
318 | |||
319 | ictl.command = ISDN_STAT_BHUP; | ||
320 | ictl.driver=dev->id; | ||
321 | ictl.arg=chan->id; | ||
322 | dev->dev_if->statcallb(&ictl); | ||
323 | } | ||
324 | |||
325 | void cb_notdone(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
326 | struct callb_data *data) | ||
327 | { | ||
328 | } | ||
329 | |||
330 | /* | ||
331 | * send activate b-chan protocol | ||
332 | */ | ||
333 | void cb_selp_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
334 | struct callb_data *data) | ||
335 | { | ||
336 | struct sk_buff *skb; | ||
337 | int len; | ||
338 | ushort refnum; | ||
339 | |||
340 | if ((len = capi_activate_transp_req(chan, &skb)) < 0) | ||
341 | { | ||
342 | printk("capi_conn_activate_transp_req failed\n"); | ||
343 | return; | ||
344 | } | ||
345 | |||
346 | refnum = last_ref_num++ & 0x7fffU; | ||
347 | chan->s_refnum = refnum; | ||
348 | |||
349 | pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len); | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Inform User that the B-channel is available | ||
354 | */ | ||
355 | void cb_open(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
356 | struct callb_data *data) | ||
357 | { | ||
358 | isdn_ctrl ictl; | ||
359 | |||
360 | ictl.command = ISDN_STAT_BCONN; | ||
361 | ictl.driver=dev->id; | ||
362 | ictl.arg=chan->id; | ||
363 | dev->dev_if->statcallb(&ictl); | ||
364 | } | ||
365 | |||
366 | |||
367 | |||
diff --git a/drivers/isdn/pcbit/callbacks.h b/drivers/isdn/pcbit/callbacks.h new file mode 100644 index 000000000000..f510dc56b57e --- /dev/null +++ b/drivers/isdn/pcbit/callbacks.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * Callbacks prototypes for FSM | ||
3 | * | ||
4 | * Copyright (C) 1996 Universidade de Lisboa | ||
5 | * | ||
6 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms of | ||
9 | * the GNU General Public License, incorporated herein by reference. | ||
10 | */ | ||
11 | |||
12 | #ifndef CALLBACKS_H | ||
13 | #define CALLBACKS_H | ||
14 | |||
15 | |||
16 | extern void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
17 | struct callb_data *data); | ||
18 | |||
19 | extern void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
20 | struct callb_data *data); | ||
21 | |||
22 | extern void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
23 | struct callb_data *data); | ||
24 | |||
25 | extern void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
26 | struct callb_data *data); | ||
27 | extern void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
28 | struct callb_data *data); | ||
29 | extern void cb_in_3(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
30 | struct callb_data *data); | ||
31 | |||
32 | extern void cb_disc_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
33 | struct callb_data *data); | ||
34 | extern void cb_disc_2(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
35 | struct callb_data *data); | ||
36 | extern void cb_disc_3(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
37 | struct callb_data *data); | ||
38 | |||
39 | extern void cb_notdone(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
40 | struct callb_data *data); | ||
41 | |||
42 | extern void cb_selp_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
43 | struct callb_data *data); | ||
44 | extern void cb_open(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
45 | struct callb_data *data); | ||
46 | |||
47 | #endif | ||
48 | |||
49 | |||
diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c new file mode 100644 index 000000000000..29eb03a8c29d --- /dev/null +++ b/drivers/isdn/pcbit/capi.c | |||
@@ -0,0 +1,663 @@ | |||
1 | /* | ||
2 | * CAPI encoder/decoder for | ||
3 | * Portugal Telecom CAPI 2.0 | ||
4 | * | ||
5 | * Copyright (C) 1996 Universidade de Lisboa | ||
6 | * | ||
7 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
8 | * | ||
9 | * This software may be used and distributed according to the terms of | ||
10 | * the GNU General Public License, incorporated herein by reference. | ||
11 | * | ||
12 | * Not compatible with the AVM Gmbh. CAPI 2.0 | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * Documentation: | ||
18 | * - "Common ISDN API - Perfil Português - Versão 2.1", | ||
19 | * Telecom Portugal, Fev 1992. | ||
20 | * - "Common ISDN API - Especificação de protocolos para | ||
21 | * acesso aos canais B", Inesc, Jan 1994. | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * TODO: better decoding of Information Elements | ||
26 | * for debug purposes mainly | ||
27 | * encode our number in CallerPN and ConnectedPN | ||
28 | */ | ||
29 | |||
30 | #include <linux/sched.h> | ||
31 | #include <linux/string.h> | ||
32 | #include <linux/kernel.h> | ||
33 | |||
34 | #include <linux/types.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/mm.h> | ||
37 | |||
38 | #include <linux/skbuff.h> | ||
39 | |||
40 | #include <asm/io.h> | ||
41 | #include <asm/string.h> | ||
42 | |||
43 | #include <linux/isdnif.h> | ||
44 | |||
45 | #include "pcbit.h" | ||
46 | #include "edss1.h" | ||
47 | #include "capi.h" | ||
48 | |||
49 | |||
50 | /* | ||
51 | * Encoding of CAPI messages | ||
52 | * | ||
53 | */ | ||
54 | |||
55 | int capi_conn_req(const char * calledPN, struct sk_buff **skb, int proto) | ||
56 | { | ||
57 | ushort len; | ||
58 | |||
59 | /* | ||
60 | * length | ||
61 | * AppInfoMask - 2 | ||
62 | * BC0 - 3 | ||
63 | * BC1 - 1 | ||
64 | * Chan - 2 | ||
65 | * Keypad - 1 | ||
66 | * CPN - 1 | ||
67 | * CPSA - 1 | ||
68 | * CalledPN - 2 + strlen | ||
69 | * CalledPSA - 1 | ||
70 | * rest... - 4 | ||
71 | * ---------------- | ||
72 | * Total 18 + strlen | ||
73 | */ | ||
74 | |||
75 | len = 18 + strlen(calledPN); | ||
76 | |||
77 | if (proto == ISDN_PROTO_L2_TRANS) | ||
78 | len++; | ||
79 | |||
80 | if ((*skb = dev_alloc_skb(len)) == NULL) { | ||
81 | |||
82 | printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n"); | ||
83 | return -1; | ||
84 | } | ||
85 | |||
86 | /* InfoElmMask */ | ||
87 | *((ushort*) skb_put(*skb, 2)) = AppInfoMask; | ||
88 | |||
89 | if (proto == ISDN_PROTO_L2_TRANS) | ||
90 | { | ||
91 | /* Bearer Capability - Mandatory*/ | ||
92 | *(skb_put(*skb, 1)) = 3; /* BC0.Length */ | ||
93 | *(skb_put(*skb, 1)) = 0x80; /* Speech */ | ||
94 | *(skb_put(*skb, 1)) = 0x10; /* Circuit Mode */ | ||
95 | *(skb_put(*skb, 1)) = 0x23; /* A-law */ | ||
96 | } | ||
97 | else | ||
98 | { | ||
99 | /* Bearer Capability - Mandatory*/ | ||
100 | *(skb_put(*skb, 1)) = 2; /* BC0.Length */ | ||
101 | *(skb_put(*skb, 1)) = 0x88; /* Digital Information */ | ||
102 | *(skb_put(*skb, 1)) = 0x90; /* BC0.Octect4 */ | ||
103 | } | ||
104 | |||
105 | /* Bearer Capability - Optional*/ | ||
106 | *(skb_put(*skb, 1)) = 0; /* BC1.Length = 0 */ | ||
107 | |||
108 | *(skb_put(*skb, 1)) = 1; /* ChannelID.Length = 1 */ | ||
109 | *(skb_put(*skb, 1)) = 0x83; /* Basic Interface - Any Channel */ | ||
110 | |||
111 | *(skb_put(*skb, 1)) = 0; /* Keypad.Length = 0 */ | ||
112 | |||
113 | |||
114 | *(skb_put(*skb, 1)) = 0; /* CallingPN.Length = 0 */ | ||
115 | *(skb_put(*skb, 1)) = 0; /* CallingPSA.Length = 0 */ | ||
116 | |||
117 | /* Called Party Number */ | ||
118 | *(skb_put(*skb, 1)) = strlen(calledPN) + 1; | ||
119 | *(skb_put(*skb, 1)) = 0x81; | ||
120 | memcpy(skb_put(*skb, strlen(calledPN)), calledPN, strlen(calledPN)); | ||
121 | |||
122 | /* '#' */ | ||
123 | |||
124 | *(skb_put(*skb, 1)) = 0; /* CalledPSA.Length = 0 */ | ||
125 | |||
126 | /* LLC.Length = 0; */ | ||
127 | /* HLC0.Length = 0; */ | ||
128 | /* HLC1.Length = 0; */ | ||
129 | /* UTUS.Length = 0; */ | ||
130 | memset(skb_put(*skb, 4), 0, 4); | ||
131 | |||
132 | return len; | ||
133 | } | ||
134 | |||
135 | int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb) | ||
136 | { | ||
137 | |||
138 | if ((*skb = dev_alloc_skb(5)) == NULL) { | ||
139 | |||
140 | printk(KERN_WARNING "capi_conn_resp: alloc_skb failed\n"); | ||
141 | return -1; | ||
142 | } | ||
143 | |||
144 | *((ushort*) skb_put(*skb, 2) ) = chan->callref; | ||
145 | *(skb_put(*skb, 1)) = 0x01; /* ACCEPT_CALL */ | ||
146 | *(skb_put(*skb, 1)) = 0; | ||
147 | *(skb_put(*skb, 1)) = 0; | ||
148 | |||
149 | return 5; | ||
150 | } | ||
151 | |||
152 | int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb) | ||
153 | { | ||
154 | /* | ||
155 | * 8 bytes | ||
156 | */ | ||
157 | |||
158 | if ((*skb = dev_alloc_skb(8)) == NULL) { | ||
159 | |||
160 | printk(KERN_WARNING "capi_conn_active_req: alloc_skb failed\n"); | ||
161 | return -1; | ||
162 | } | ||
163 | |||
164 | *((ushort*) skb_put(*skb, 2) ) = chan->callref; | ||
165 | |||
166 | #ifdef DEBUG | ||
167 | printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref); | ||
168 | #endif | ||
169 | |||
170 | *(skb_put(*skb, 1)) = 0; /* BC.Length = 0; */ | ||
171 | *(skb_put(*skb, 1)) = 0; /* ConnectedPN.Length = 0 */ | ||
172 | *(skb_put(*skb, 1)) = 0; /* PSA.Length */ | ||
173 | *(skb_put(*skb, 1)) = 0; /* LLC.Length = 0; */ | ||
174 | *(skb_put(*skb, 1)) = 0; /* HLC.Length = 0; */ | ||
175 | *(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */ | ||
176 | |||
177 | return 8; | ||
178 | } | ||
179 | |||
180 | int capi_conn_active_resp(struct pcbit_chan* chan, struct sk_buff **skb) | ||
181 | { | ||
182 | /* | ||
183 | * 2 bytes | ||
184 | */ | ||
185 | |||
186 | if ((*skb = dev_alloc_skb(2)) == NULL) { | ||
187 | |||
188 | printk(KERN_WARNING "capi_conn_active_resp: alloc_skb failed\n"); | ||
189 | return -1; | ||
190 | } | ||
191 | |||
192 | *((ushort*) skb_put(*skb, 2) ) = chan->callref; | ||
193 | |||
194 | return 2; | ||
195 | } | ||
196 | |||
197 | |||
198 | int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb, | ||
199 | int outgoing) | ||
200 | { | ||
201 | |||
202 | /* | ||
203 | * 18 bytes | ||
204 | */ | ||
205 | |||
206 | if ((*skb = dev_alloc_skb(18)) == NULL) { | ||
207 | |||
208 | printk(KERN_WARNING "capi_select_proto_req: alloc_skb failed\n"); | ||
209 | return -1; | ||
210 | } | ||
211 | |||
212 | *((ushort*) skb_put(*skb, 2) ) = chan->callref; | ||
213 | |||
214 | /* Layer2 protocol */ | ||
215 | |||
216 | switch (chan->proto) { | ||
217 | case ISDN_PROTO_L2_X75I: | ||
218 | *(skb_put(*skb, 1)) = 0x05; /* LAPB */ | ||
219 | break; | ||
220 | case ISDN_PROTO_L2_HDLC: | ||
221 | *(skb_put(*skb, 1)) = 0x02; | ||
222 | break; | ||
223 | case ISDN_PROTO_L2_TRANS: | ||
224 | /* | ||
225 | * Voice (a-law) | ||
226 | */ | ||
227 | *(skb_put(*skb, 1)) = 0x06; | ||
228 | break; | ||
229 | default: | ||
230 | #ifdef DEBUG | ||
231 | printk(KERN_DEBUG "Transparent\n"); | ||
232 | #endif | ||
233 | *(skb_put(*skb, 1)) = 0x03; | ||
234 | break; | ||
235 | } | ||
236 | |||
237 | *(skb_put(*skb, 1)) = (outgoing ? 0x02 : 0x42); /* Don't ask */ | ||
238 | *(skb_put(*skb, 1)) = 0x00; | ||
239 | |||
240 | *((ushort *) skb_put(*skb, 2)) = MRU; | ||
241 | |||
242 | |||
243 | *(skb_put(*skb, 1)) = 0x08; /* Modulo */ | ||
244 | *(skb_put(*skb, 1)) = 0x07; /* Max Window */ | ||
245 | |||
246 | *(skb_put(*skb, 1)) = 0x01; /* No Layer3 Protocol */ | ||
247 | |||
248 | /* | ||
249 | * 2 - layer3 MTU [10] | ||
250 | * - Modulo [12] | ||
251 | * - Window | ||
252 | * - layer1 proto [14] | ||
253 | * - bitrate | ||
254 | * - sub-channel [16] | ||
255 | * - layer1dataformat [17] | ||
256 | */ | ||
257 | |||
258 | memset(skb_put(*skb, 8), 0, 8); | ||
259 | |||
260 | return 18; | ||
261 | } | ||
262 | |||
263 | |||
264 | int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb) | ||
265 | { | ||
266 | |||
267 | if ((*skb = dev_alloc_skb(7)) == NULL) { | ||
268 | |||
269 | printk(KERN_WARNING "capi_activate_transp_req: alloc_skb failed\n"); | ||
270 | return -1; | ||
271 | } | ||
272 | |||
273 | *((ushort*) skb_put(*skb, 2) ) = chan->callref; | ||
274 | |||
275 | |||
276 | *(skb_put(*skb, 1)) = chan->layer2link; /* Layer2 id */ | ||
277 | *(skb_put(*skb, 1)) = 0x00; /* Transmit by default */ | ||
278 | |||
279 | *((ushort *) skb_put(*skb, 2)) = MRU; | ||
280 | |||
281 | *(skb_put(*skb, 1)) = 0x01; /* Enables reception*/ | ||
282 | |||
283 | return 7; | ||
284 | } | ||
285 | |||
286 | int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb) | ||
287 | { | ||
288 | ushort data_len; | ||
289 | |||
290 | |||
291 | /* | ||
292 | * callref - 2 | ||
293 | * layer2link - 1 | ||
294 | * wBlockLength - 2 | ||
295 | * data - 4 | ||
296 | * sernum - 1 | ||
297 | */ | ||
298 | |||
299 | data_len = skb->len; | ||
300 | |||
301 | if(skb_headroom(skb) < 10) | ||
302 | { | ||
303 | printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb); | ||
304 | } | ||
305 | else | ||
306 | { | ||
307 | skb_push(skb, 10); | ||
308 | } | ||
309 | |||
310 | *((u16 *) (skb->data)) = chan->callref; | ||
311 | skb->data[2] = chan->layer2link; | ||
312 | *((u16 *) (skb->data + 3)) = data_len; | ||
313 | |||
314 | chan->s_refnum = (chan->s_refnum + 1) % 8; | ||
315 | *((u32 *) (skb->data + 5)) = chan->s_refnum; | ||
316 | |||
317 | skb->data[9] = 0; /* HDLC frame number */ | ||
318 | |||
319 | return 10; | ||
320 | } | ||
321 | |||
322 | int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb) | ||
323 | |||
324 | { | ||
325 | if ((*skb = dev_alloc_skb(4)) == NULL) { | ||
326 | |||
327 | printk(KERN_WARNING "capi_tdata_resp: alloc_skb failed\n"); | ||
328 | return -1; | ||
329 | } | ||
330 | |||
331 | *((ushort*) skb_put(*skb, 2) ) = chan->callref; | ||
332 | |||
333 | *(skb_put(*skb, 1)) = chan->layer2link; | ||
334 | *(skb_put(*skb, 1)) = chan->r_refnum; | ||
335 | |||
336 | return (*skb)->len; | ||
337 | } | ||
338 | |||
339 | int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause) | ||
340 | { | ||
341 | |||
342 | if ((*skb = dev_alloc_skb(6)) == NULL) { | ||
343 | |||
344 | printk(KERN_WARNING "capi_disc_req: alloc_skb failed\n"); | ||
345 | return -1; | ||
346 | } | ||
347 | |||
348 | *((ushort*) skb_put(*skb, 2) ) = callref; | ||
349 | |||
350 | *(skb_put(*skb, 1)) = 2; /* Cause.Length = 2; */ | ||
351 | *(skb_put(*skb, 1)) = 0x80; | ||
352 | *(skb_put(*skb, 1)) = 0x80 | cause; | ||
353 | |||
354 | /* | ||
355 | * Change it: we should send 'Sic transit gloria Mundi' here ;-) | ||
356 | */ | ||
357 | |||
358 | *(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */ | ||
359 | |||
360 | return 6; | ||
361 | } | ||
362 | |||
363 | int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb) | ||
364 | { | ||
365 | if ((*skb = dev_alloc_skb(2)) == NULL) { | ||
366 | |||
367 | printk(KERN_WARNING "capi_disc_resp: alloc_skb failed\n"); | ||
368 | return -1; | ||
369 | } | ||
370 | |||
371 | *((ushort*) skb_put(*skb, 2)) = chan->callref; | ||
372 | |||
373 | return 2; | ||
374 | } | ||
375 | |||
376 | |||
377 | /* | ||
378 | * Decoding of CAPI messages | ||
379 | * | ||
380 | */ | ||
381 | |||
382 | int capi_decode_conn_ind(struct pcbit_chan * chan, | ||
383 | struct sk_buff *skb, | ||
384 | struct callb_data *info) | ||
385 | { | ||
386 | int CIlen, len; | ||
387 | |||
388 | /* Call Reference [CAPI] */ | ||
389 | chan->callref = *((ushort*) skb->data); | ||
390 | skb_pull(skb, 2); | ||
391 | |||
392 | #ifdef DEBUG | ||
393 | printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref); | ||
394 | #endif | ||
395 | |||
396 | /* Channel Identification */ | ||
397 | |||
398 | /* Expect | ||
399 | Len = 1 | ||
400 | Octect 3 = 0100 10CC - [ 7 Basic, 4 , 2-1 chan ] | ||
401 | */ | ||
402 | |||
403 | CIlen = skb->data[0]; | ||
404 | #ifdef DEBUG | ||
405 | if (CIlen == 1) { | ||
406 | |||
407 | if ( ((skb->data[1]) & 0xFC) == 0x48 ) | ||
408 | printk(KERN_DEBUG "decode_conn_ind: chan ok\n"); | ||
409 | printk(KERN_DEBUG "phyChan = %d\n", skb->data[1] & 0x03); | ||
410 | } | ||
411 | else | ||
412 | printk(KERN_DEBUG "conn_ind: CIlen = %d\n", CIlen); | ||
413 | #endif | ||
414 | skb_pull(skb, CIlen + 1); | ||
415 | |||
416 | /* Calling Party Number */ | ||
417 | /* An "additional service" as far as Portugal Telecom is concerned */ | ||
418 | |||
419 | len = skb->data[0]; | ||
420 | |||
421 | if (len > 0) { | ||
422 | int count = 1; | ||
423 | |||
424 | #ifdef DEBUG | ||
425 | printk(KERN_DEBUG "CPN: Octect 3 %02x\n", skb->data[1]); | ||
426 | #endif | ||
427 | if ((skb->data[1] & 0x80) == 0) | ||
428 | count = 2; | ||
429 | |||
430 | if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC))) | ||
431 | return -1; | ||
432 | |||
433 | memcpy(info->data.setup.CallingPN, skb->data + count + 1, | ||
434 | len - count); | ||
435 | info->data.setup.CallingPN[len - count] = 0; | ||
436 | |||
437 | } | ||
438 | else { | ||
439 | info->data.setup.CallingPN = NULL; | ||
440 | printk(KERN_DEBUG "NULL CallingPN\n"); | ||
441 | } | ||
442 | |||
443 | skb_pull(skb, len + 1); | ||
444 | |||
445 | /* Calling Party Subaddress */ | ||
446 | skb_pull(skb, skb->data[0] + 1); | ||
447 | |||
448 | /* Called Party Number */ | ||
449 | |||
450 | len = skb->data[0]; | ||
451 | |||
452 | if (len > 0) { | ||
453 | int count = 1; | ||
454 | |||
455 | if ((skb->data[1] & 0x80) == 0) | ||
456 | count = 2; | ||
457 | |||
458 | if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC))) | ||
459 | return -1; | ||
460 | |||
461 | memcpy(info->data.setup.CalledPN, skb->data + count + 1, | ||
462 | len - count); | ||
463 | info->data.setup.CalledPN[len - count] = 0; | ||
464 | |||
465 | } | ||
466 | else { | ||
467 | info->data.setup.CalledPN = NULL; | ||
468 | printk(KERN_DEBUG "NULL CalledPN\n"); | ||
469 | } | ||
470 | |||
471 | skb_pull(skb, len + 1); | ||
472 | |||
473 | /* Called Party Subaddress */ | ||
474 | skb_pull(skb, skb->data[0] + 1); | ||
475 | |||
476 | /* LLC */ | ||
477 | skb_pull(skb, skb->data[0] + 1); | ||
478 | |||
479 | /* HLC */ | ||
480 | skb_pull(skb, skb->data[0] + 1); | ||
481 | |||
482 | /* U2U */ | ||
483 | skb_pull(skb, skb->data[0] + 1); | ||
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * returns errcode | ||
490 | */ | ||
491 | |||
492 | int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb, | ||
493 | int *complete) | ||
494 | { | ||
495 | int errcode; | ||
496 | |||
497 | chan->callref = *((ushort *) skb->data); /* Update CallReference */ | ||
498 | skb_pull(skb, 2); | ||
499 | |||
500 | errcode = *((ushort *) skb->data); /* read errcode */ | ||
501 | skb_pull(skb, 2); | ||
502 | |||
503 | *complete = *(skb->data); | ||
504 | skb_pull(skb, 1); | ||
505 | |||
506 | /* FIX ME */ | ||
507 | /* This is actually a firmware bug */ | ||
508 | if (!*complete) | ||
509 | { | ||
510 | printk(KERN_DEBUG "complete=%02x\n", *complete); | ||
511 | *complete = 1; | ||
512 | } | ||
513 | |||
514 | |||
515 | /* Optional Bearer Capability */ | ||
516 | skb_pull(skb, *(skb->data) + 1); | ||
517 | |||
518 | /* Channel Identification */ | ||
519 | skb_pull(skb, *(skb->data) + 1); | ||
520 | |||
521 | /* High Layer Compatibility follows */ | ||
522 | skb_pull(skb, *(skb->data) + 1); | ||
523 | |||
524 | return errcode; | ||
525 | } | ||
526 | |||
527 | int capi_decode_conn_actv_ind(struct pcbit_chan * chan, struct sk_buff *skb) | ||
528 | { | ||
529 | ushort len; | ||
530 | #ifdef DEBUG | ||
531 | char str[32]; | ||
532 | #endif | ||
533 | |||
534 | /* Yet Another Bearer Capability */ | ||
535 | skb_pull(skb, *(skb->data) + 1); | ||
536 | |||
537 | |||
538 | /* Connected Party Number */ | ||
539 | len=*(skb->data); | ||
540 | |||
541 | #ifdef DEBUG | ||
542 | if (len > 1 && len < 31) { | ||
543 | memcpy(str, skb->data + 2, len - 1); | ||
544 | str[len] = 0; | ||
545 | printk(KERN_DEBUG "Connected Party Number: %s\n", str); | ||
546 | } | ||
547 | else | ||
548 | printk(KERN_DEBUG "actv_ind CPN len = %d\n", len); | ||
549 | #endif | ||
550 | |||
551 | skb_pull(skb, len + 1); | ||
552 | |||
553 | /* Connected Subaddress */ | ||
554 | skb_pull(skb, *(skb->data) + 1); | ||
555 | |||
556 | /* Low Layer Capability */ | ||
557 | skb_pull(skb, *(skb->data) + 1); | ||
558 | |||
559 | /* High Layer Capability */ | ||
560 | skb_pull(skb, *(skb->data) + 1); | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | int capi_decode_conn_actv_conf(struct pcbit_chan * chan, struct sk_buff *skb) | ||
566 | { | ||
567 | ushort errcode; | ||
568 | |||
569 | errcode = *((ushort*) skb->data); | ||
570 | skb_pull(skb, 2); | ||
571 | |||
572 | /* Channel Identification | ||
573 | skb_pull(skb, skb->data[0] + 1); | ||
574 | */ | ||
575 | return errcode; | ||
576 | } | ||
577 | |||
578 | |||
579 | int capi_decode_sel_proto_conf(struct pcbit_chan *chan, struct sk_buff *skb) | ||
580 | { | ||
581 | ushort errcode; | ||
582 | |||
583 | chan->layer2link = *(skb->data); | ||
584 | skb_pull(skb, 1); | ||
585 | |||
586 | errcode = *((ushort*) skb->data); | ||
587 | skb_pull(skb, 2); | ||
588 | |||
589 | return errcode; | ||
590 | } | ||
591 | |||
592 | int capi_decode_actv_trans_conf(struct pcbit_chan *chan, struct sk_buff *skb) | ||
593 | { | ||
594 | ushort errcode; | ||
595 | |||
596 | if (chan->layer2link != *(skb->data) ) | ||
597 | printk("capi_decode_actv_trans_conf: layer2link doesn't match\n"); | ||
598 | |||
599 | skb_pull(skb, 1); | ||
600 | |||
601 | errcode = *((ushort*) skb->data); | ||
602 | skb_pull(skb, 2); | ||
603 | |||
604 | return errcode; | ||
605 | } | ||
606 | |||
607 | int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb) | ||
608 | { | ||
609 | ushort len; | ||
610 | #ifdef DEBUG | ||
611 | int i; | ||
612 | #endif | ||
613 | /* Cause */ | ||
614 | |||
615 | len = *(skb->data); | ||
616 | skb_pull(skb, 1); | ||
617 | |||
618 | #ifdef DEBUG | ||
619 | |||
620 | for (i=0; i<len; i++) | ||
621 | printk(KERN_DEBUG "Cause Octect %d: %02x\n", i+3, | ||
622 | *(skb->data + i)); | ||
623 | #endif | ||
624 | |||
625 | skb_pull(skb, len); | ||
626 | |||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb) | ||
631 | { | ||
632 | ushort errcode; | ||
633 | |||
634 | errcode = *((ushort*) skb->data); | ||
635 | skb_pull(skb, 2); | ||
636 | |||
637 | return errcode; | ||
638 | } | ||
639 | |||
640 | #ifdef DEBUG | ||
641 | int capi_decode_debug_188(u_char *hdr, ushort hdrlen) | ||
642 | { | ||
643 | char str[64]; | ||
644 | int len; | ||
645 | |||
646 | len = hdr[0]; | ||
647 | |||
648 | if (len < 64 && len == hdrlen - 1) { | ||
649 | memcpy(str, hdr + 1, hdrlen - 1); | ||
650 | str[hdrlen - 1] = 0; | ||
651 | printk("%s\n", str); | ||
652 | } | ||
653 | else | ||
654 | printk("debug message incorrect\n"); | ||
655 | |||
656 | return 0; | ||
657 | } | ||
658 | #endif | ||
659 | |||
660 | |||
661 | |||
662 | |||
663 | |||
diff --git a/drivers/isdn/pcbit/capi.h b/drivers/isdn/pcbit/capi.h new file mode 100644 index 000000000000..18e6aa360a8f --- /dev/null +++ b/drivers/isdn/pcbit/capi.h | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * CAPI encode/decode prototypes and defines | ||
3 | * | ||
4 | * Copyright (C) 1996 Universidade de Lisboa | ||
5 | * | ||
6 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms of | ||
9 | * the GNU General Public License, incorporated herein by reference. | ||
10 | */ | ||
11 | |||
12 | #ifndef CAPI_H | ||
13 | #define CAPI_H | ||
14 | |||
15 | |||
16 | #define REQ_CAUSE 0x01 | ||
17 | #define REQ_DISPLAY 0x04 | ||
18 | #define REQ_USER_TO_USER 0x08 | ||
19 | |||
20 | #define AppInfoMask REQ_CAUSE|REQ_DISPLAY|REQ_USER_TO_USER | ||
21 | |||
22 | /* Connection Setup */ | ||
23 | extern int capi_conn_req(const char * calledPN, struct sk_buff **buf, | ||
24 | int proto); | ||
25 | extern int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb, | ||
26 | int *complete); | ||
27 | |||
28 | extern int capi_decode_conn_ind(struct pcbit_chan * chan, struct sk_buff *skb, | ||
29 | struct callb_data *info); | ||
30 | extern int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb); | ||
31 | |||
32 | extern int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb); | ||
33 | extern int capi_decode_conn_actv_conf(struct pcbit_chan * chan, | ||
34 | struct sk_buff *skb); | ||
35 | |||
36 | extern int capi_decode_conn_actv_ind(struct pcbit_chan * chan, | ||
37 | struct sk_buff *skb); | ||
38 | extern int capi_conn_active_resp(struct pcbit_chan* chan, | ||
39 | struct sk_buff **skb); | ||
40 | |||
41 | /* Data */ | ||
42 | extern int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb, | ||
43 | int outgoing); | ||
44 | extern int capi_decode_sel_proto_conf(struct pcbit_chan *chan, | ||
45 | struct sk_buff *skb); | ||
46 | |||
47 | extern int capi_activate_transp_req(struct pcbit_chan *chan, | ||
48 | struct sk_buff **skb); | ||
49 | extern int capi_decode_actv_trans_conf(struct pcbit_chan *chan, | ||
50 | struct sk_buff *skb); | ||
51 | |||
52 | extern int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb); | ||
53 | extern int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb); | ||
54 | |||
55 | /* Connection Termination */ | ||
56 | extern int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause); | ||
57 | extern int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb); | ||
58 | |||
59 | extern int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb); | ||
60 | extern int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb); | ||
61 | |||
62 | #ifdef DEBUG | ||
63 | extern int capi_decode_debug_188(u_char *hdr, ushort hdrlen); | ||
64 | #endif | ||
65 | |||
66 | static inline struct pcbit_chan * | ||
67 | capi_channel(struct pcbit_dev *dev, struct sk_buff *skb) | ||
68 | { | ||
69 | ushort callref; | ||
70 | |||
71 | callref = *((ushort*) skb->data); | ||
72 | skb_pull(skb, 2); | ||
73 | |||
74 | if (dev->b1->callref == callref) | ||
75 | return dev->b1; | ||
76 | else if (dev->b2->callref == callref) | ||
77 | return dev->b2; | ||
78 | |||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | #endif | ||
83 | |||
84 | |||
85 | |||
86 | |||
87 | |||
88 | |||
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c new file mode 100644 index 000000000000..e98f9c48c184 --- /dev/null +++ b/drivers/isdn/pcbit/drv.c | |||
@@ -0,0 +1,1088 @@ | |||
1 | /* | ||
2 | * PCBIT-D interface with isdn4linux | ||
3 | * | ||
4 | * Copyright (C) 1996 Universidade de Lisboa | ||
5 | * | ||
6 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms of | ||
9 | * the GNU General Public License, incorporated herein by reference. | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * Fixes: | ||
14 | * | ||
15 | * Nuno Grilo <l38486@alfa.ist.utl.pt> | ||
16 | * fixed msn_list NULL pointer dereference. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | |||
22 | #include <linux/sched.h> | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | |||
26 | #include <linux/types.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/string.h> | ||
31 | #include <linux/skbuff.h> | ||
32 | |||
33 | #include <linux/isdnif.h> | ||
34 | #include <asm/string.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <linux/ioport.h> | ||
37 | |||
38 | #include "pcbit.h" | ||
39 | #include "edss1.h" | ||
40 | #include "layer2.h" | ||
41 | #include "capi.h" | ||
42 | |||
43 | |||
44 | extern ushort last_ref_num; | ||
45 | |||
46 | static int pcbit_ioctl(isdn_ctrl* ctl); | ||
47 | |||
48 | static char* pcbit_devname[MAX_PCBIT_CARDS] = { | ||
49 | "pcbit0", | ||
50 | "pcbit1", | ||
51 | "pcbit2", | ||
52 | "pcbit3" | ||
53 | }; | ||
54 | |||
55 | /* | ||
56 | * prototypes | ||
57 | */ | ||
58 | |||
59 | int pcbit_command(isdn_ctrl* ctl); | ||
60 | int pcbit_stat(u_char __user * buf, int len, int, int); | ||
61 | int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb); | ||
62 | int pcbit_writecmd(const u_char __user *, int, int, int); | ||
63 | |||
64 | static int set_protocol_running(struct pcbit_dev * dev); | ||
65 | |||
66 | static void pcbit_clear_msn(struct pcbit_dev *dev); | ||
67 | static void pcbit_set_msn(struct pcbit_dev *dev, char *list); | ||
68 | static int pcbit_check_msn(struct pcbit_dev *dev, char *msn); | ||
69 | |||
70 | |||
71 | extern void pcbit_deliver(void * data); | ||
72 | |||
73 | int pcbit_init_dev(int board, int mem_base, int irq) | ||
74 | { | ||
75 | struct pcbit_dev *dev; | ||
76 | isdn_if *dev_if; | ||
77 | |||
78 | if ((dev=kmalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL) | ||
79 | { | ||
80 | printk("pcbit_init: couldn't malloc pcbit_dev struct\n"); | ||
81 | return -ENOMEM; | ||
82 | } | ||
83 | |||
84 | dev_pcbit[board] = dev; | ||
85 | memset(dev, 0, sizeof(struct pcbit_dev)); | ||
86 | init_waitqueue_head(&dev->set_running_wq); | ||
87 | spin_lock_init(&dev->lock); | ||
88 | |||
89 | if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) { | ||
90 | dev->ph_mem = mem_base; | ||
91 | if (!request_mem_region(dev->ph_mem, 4096, "PCBIT mem")) { | ||
92 | printk(KERN_WARNING | ||
93 | "PCBIT: memory region %lx-%lx already in use\n", | ||
94 | dev->ph_mem, dev->ph_mem + 4096); | ||
95 | kfree(dev); | ||
96 | dev_pcbit[board] = NULL; | ||
97 | return -EACCES; | ||
98 | } | ||
99 | dev->sh_mem = ioremap(dev->ph_mem, 4096); | ||
100 | } | ||
101 | else | ||
102 | { | ||
103 | printk("memory address invalid"); | ||
104 | kfree(dev); | ||
105 | dev_pcbit[board] = NULL; | ||
106 | return -EACCES; | ||
107 | } | ||
108 | |||
109 | dev->b1 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL); | ||
110 | if (!dev->b1) { | ||
111 | printk("pcbit_init: couldn't malloc pcbit_chan struct\n"); | ||
112 | iounmap(dev->sh_mem); | ||
113 | release_mem_region(dev->ph_mem, 4096); | ||
114 | kfree(dev); | ||
115 | return -ENOMEM; | ||
116 | } | ||
117 | |||
118 | dev->b2 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL); | ||
119 | if (!dev->b2) { | ||
120 | printk("pcbit_init: couldn't malloc pcbit_chan struct\n"); | ||
121 | kfree(dev->b1); | ||
122 | iounmap(dev->sh_mem); | ||
123 | release_mem_region(dev->ph_mem, 4096); | ||
124 | kfree(dev); | ||
125 | return -ENOMEM; | ||
126 | } | ||
127 | |||
128 | memset(dev->b1, 0, sizeof(struct pcbit_chan)); | ||
129 | memset(dev->b2, 0, sizeof(struct pcbit_chan)); | ||
130 | dev->b2->id = 1; | ||
131 | |||
132 | INIT_WORK(&dev->qdelivery, pcbit_deliver, dev); | ||
133 | |||
134 | /* | ||
135 | * interrupts | ||
136 | */ | ||
137 | |||
138 | if (request_irq(irq, &pcbit_irq_handler, 0, pcbit_devname[board], dev) != 0) | ||
139 | { | ||
140 | kfree(dev->b1); | ||
141 | kfree(dev->b2); | ||
142 | iounmap(dev->sh_mem); | ||
143 | release_mem_region(dev->ph_mem, 4096); | ||
144 | kfree(dev); | ||
145 | dev_pcbit[board] = NULL; | ||
146 | return -EIO; | ||
147 | } | ||
148 | |||
149 | dev->irq = irq; | ||
150 | |||
151 | /* next frame to be received */ | ||
152 | dev->rcv_seq = 0; | ||
153 | dev->send_seq = 0; | ||
154 | dev->unack_seq = 0; | ||
155 | |||
156 | dev->hl_hdrlen = 16; | ||
157 | |||
158 | dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL); | ||
159 | |||
160 | if (!dev_if) { | ||
161 | free_irq(irq, dev); | ||
162 | kfree(dev->b1); | ||
163 | kfree(dev->b2); | ||
164 | iounmap(dev->sh_mem); | ||
165 | release_mem_region(dev->ph_mem, 4096); | ||
166 | kfree(dev); | ||
167 | dev_pcbit[board] = NULL; | ||
168 | return -EIO; | ||
169 | } | ||
170 | |||
171 | dev->dev_if = dev_if; | ||
172 | |||
173 | dev_if->owner = THIS_MODULE; | ||
174 | |||
175 | dev_if->channels = 2; | ||
176 | |||
177 | dev_if->features = (ISDN_FEATURE_P_EURO | ISDN_FEATURE_L3_TRANS | | ||
178 | ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS ); | ||
179 | |||
180 | dev_if->writebuf_skb = pcbit_xmit; | ||
181 | dev_if->hl_hdrlen = 16; | ||
182 | |||
183 | dev_if->maxbufsize = MAXBUFSIZE; | ||
184 | dev_if->command = pcbit_command; | ||
185 | |||
186 | dev_if->writecmd = pcbit_writecmd; | ||
187 | dev_if->readstat = pcbit_stat; | ||
188 | |||
189 | |||
190 | strcpy(dev_if->id, pcbit_devname[board]); | ||
191 | |||
192 | if (!register_isdn(dev_if)) { | ||
193 | free_irq(irq, dev); | ||
194 | kfree(dev->b1); | ||
195 | kfree(dev->b2); | ||
196 | iounmap(dev->sh_mem); | ||
197 | release_mem_region(dev->ph_mem, 4096); | ||
198 | kfree(dev); | ||
199 | dev_pcbit[board] = NULL; | ||
200 | return -EIO; | ||
201 | } | ||
202 | |||
203 | dev->id = dev_if->channels; | ||
204 | |||
205 | |||
206 | dev->l2_state = L2_DOWN; | ||
207 | dev->free = 511; | ||
208 | |||
209 | /* | ||
210 | * set_protocol_running(dev); | ||
211 | */ | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | #ifdef MODULE | ||
217 | void pcbit_terminate(int board) | ||
218 | { | ||
219 | struct pcbit_dev * dev; | ||
220 | |||
221 | dev = dev_pcbit[board]; | ||
222 | |||
223 | if (dev) { | ||
224 | /* unregister_isdn(dev->dev_if); */ | ||
225 | free_irq(dev->irq, dev); | ||
226 | pcbit_clear_msn(dev); | ||
227 | kfree(dev->dev_if); | ||
228 | if (dev->b1->fsm_timer.function) | ||
229 | del_timer(&dev->b1->fsm_timer); | ||
230 | if (dev->b2->fsm_timer.function) | ||
231 | del_timer(&dev->b2->fsm_timer); | ||
232 | kfree(dev->b1); | ||
233 | kfree(dev->b2); | ||
234 | iounmap(dev->sh_mem); | ||
235 | release_mem_region(dev->ph_mem, 4096); | ||
236 | kfree(dev); | ||
237 | } | ||
238 | } | ||
239 | #endif | ||
240 | |||
241 | int pcbit_command(isdn_ctrl* ctl) | ||
242 | { | ||
243 | struct pcbit_dev *dev; | ||
244 | struct pcbit_chan *chan; | ||
245 | struct callb_data info; | ||
246 | |||
247 | dev = finddev(ctl->driver); | ||
248 | |||
249 | if (!dev) | ||
250 | { | ||
251 | printk("pcbit_command: unknown device\n"); | ||
252 | return -1; | ||
253 | } | ||
254 | |||
255 | chan = (ctl->arg & 0x0F) ? dev->b2 : dev->b1; | ||
256 | |||
257 | |||
258 | switch(ctl->command) { | ||
259 | case ISDN_CMD_IOCTL: | ||
260 | return pcbit_ioctl(ctl); | ||
261 | break; | ||
262 | case ISDN_CMD_DIAL: | ||
263 | info.type = EV_USR_SETUP_REQ; | ||
264 | info.data.setup.CalledPN = (char *) &ctl->parm.setup.phone; | ||
265 | pcbit_fsm_event(dev, chan, EV_USR_SETUP_REQ, &info); | ||
266 | break; | ||
267 | case ISDN_CMD_ACCEPTD: | ||
268 | pcbit_fsm_event(dev, chan, EV_USR_SETUP_RESP, NULL); | ||
269 | break; | ||
270 | case ISDN_CMD_ACCEPTB: | ||
271 | printk("ISDN_CMD_ACCEPTB - not really needed\n"); | ||
272 | break; | ||
273 | case ISDN_CMD_HANGUP: | ||
274 | pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL); | ||
275 | break; | ||
276 | case ISDN_CMD_SETL2: | ||
277 | chan->proto = (ctl->arg >> 8); | ||
278 | break; | ||
279 | case ISDN_CMD_CLREAZ: | ||
280 | pcbit_clear_msn(dev); | ||
281 | break; | ||
282 | case ISDN_CMD_SETEAZ: | ||
283 | pcbit_set_msn(dev, ctl->parm.num); | ||
284 | break; | ||
285 | case ISDN_CMD_SETL3: | ||
286 | if ((ctl->arg >> 8) != ISDN_PROTO_L3_TRANS) | ||
287 | printk(KERN_DEBUG "L3 protocol unknown\n"); | ||
288 | break; | ||
289 | default: | ||
290 | printk(KERN_DEBUG "pcbit_command: unknown command\n"); | ||
291 | break; | ||
292 | }; | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | * Another Hack :-( | ||
299 | * on some conditions the board stops sending TDATA_CONFs | ||
300 | * let's see if we can turn around the problem | ||
301 | */ | ||
302 | |||
303 | #ifdef BLOCK_TIMER | ||
304 | static void pcbit_block_timer(unsigned long data) | ||
305 | { | ||
306 | struct pcbit_chan *chan; | ||
307 | struct pcbit_dev * dev; | ||
308 | isdn_ctrl ictl; | ||
309 | |||
310 | chan = (struct pcbit_chan *) data; | ||
311 | |||
312 | dev = chan2dev(chan); | ||
313 | |||
314 | if (dev == NULL) { | ||
315 | printk(KERN_DEBUG "pcbit: chan2dev failed\n"); | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | del_timer(&chan->block_timer); | ||
320 | chan->block_timer.function = NULL; | ||
321 | |||
322 | #ifdef DEBUG | ||
323 | printk(KERN_DEBUG "pcbit_block_timer\n"); | ||
324 | #endif | ||
325 | chan->queued = 0; | ||
326 | ictl.driver = dev->id; | ||
327 | ictl.command = ISDN_STAT_BSENT; | ||
328 | ictl.arg = chan->id; | ||
329 | dev->dev_if->statcallb(&ictl); | ||
330 | } | ||
331 | #endif | ||
332 | |||
333 | int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb) | ||
334 | { | ||
335 | ushort hdrlen; | ||
336 | int refnum, len; | ||
337 | struct pcbit_chan * chan; | ||
338 | struct pcbit_dev *dev; | ||
339 | |||
340 | dev = finddev(driver); | ||
341 | if (dev == NULL) | ||
342 | { | ||
343 | printk("finddev returned NULL"); | ||
344 | return -1; | ||
345 | } | ||
346 | |||
347 | chan = chnum ? dev->b2 : dev->b1; | ||
348 | |||
349 | |||
350 | if (chan->fsm_state != ST_ACTIVE) | ||
351 | return -1; | ||
352 | |||
353 | if (chan->queued >= MAX_QUEUED ) | ||
354 | { | ||
355 | #ifdef DEBUG_QUEUE | ||
356 | printk(KERN_DEBUG | ||
357 | "pcbit: %d packets already in queue - write fails\n", | ||
358 | chan->queued); | ||
359 | #endif | ||
360 | /* | ||
361 | * packet stays on the head of the device queue | ||
362 | * since dev_start_xmit will fail | ||
363 | * see net/core/dev.c | ||
364 | */ | ||
365 | #ifdef BLOCK_TIMER | ||
366 | if (chan->block_timer.function == NULL) { | ||
367 | init_timer(&chan->block_timer); | ||
368 | chan->block_timer.function = &pcbit_block_timer; | ||
369 | chan->block_timer.data = (long) chan; | ||
370 | chan->block_timer.expires = jiffies + 1 * HZ; | ||
371 | add_timer(&chan->block_timer); | ||
372 | } | ||
373 | #endif | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | |||
378 | chan->queued++; | ||
379 | |||
380 | len = skb->len; | ||
381 | |||
382 | hdrlen = capi_tdata_req(chan, skb); | ||
383 | |||
384 | refnum = last_ref_num++ & 0x7fffU; | ||
385 | chan->s_refnum = refnum; | ||
386 | |||
387 | pcbit_l2_write(dev, MSG_TDATA_REQ, refnum, skb, hdrlen); | ||
388 | |||
389 | return len; | ||
390 | } | ||
391 | |||
392 | int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel) | ||
393 | { | ||
394 | struct pcbit_dev * dev; | ||
395 | int i, j; | ||
396 | const u_char * loadbuf; | ||
397 | u_char * ptr = NULL; | ||
398 | u_char *cbuf; | ||
399 | |||
400 | int errstat; | ||
401 | |||
402 | dev = finddev(driver); | ||
403 | |||
404 | if (!dev) | ||
405 | { | ||
406 | printk("pcbit_writecmd: couldn't find device"); | ||
407 | return -ENODEV; | ||
408 | } | ||
409 | |||
410 | switch(dev->l2_state) { | ||
411 | case L2_LWMODE: | ||
412 | /* check (size <= rdp_size); write buf into board */ | ||
413 | if (len < 0 || len > BANK4 + 1 || len > 1024) | ||
414 | { | ||
415 | printk("pcbit_writecmd: invalid length %d\n", len); | ||
416 | return -EINVAL; | ||
417 | } | ||
418 | |||
419 | cbuf = kmalloc(len, GFP_KERNEL); | ||
420 | if (!cbuf) | ||
421 | return -ENOMEM; | ||
422 | |||
423 | if (copy_from_user(cbuf, buf, len)) { | ||
424 | kfree(cbuf); | ||
425 | return -EFAULT; | ||
426 | } | ||
427 | memcpy_toio(dev->sh_mem, cbuf, len); | ||
428 | kfree(cbuf); | ||
429 | return len; | ||
430 | case L2_FWMODE: | ||
431 | /* this is the hard part */ | ||
432 | /* dumb board */ | ||
433 | /* get it into kernel space */ | ||
434 | if ((ptr = kmalloc(len, GFP_KERNEL))==NULL) | ||
435 | return -ENOMEM; | ||
436 | if (copy_from_user(ptr, buf, len)) { | ||
437 | kfree(ptr); | ||
438 | return -EFAULT; | ||
439 | } | ||
440 | loadbuf = ptr; | ||
441 | |||
442 | errstat = 0; | ||
443 | |||
444 | for (i=0; i < len; i++) | ||
445 | { | ||
446 | for(j=0; j < LOAD_RETRY; j++) | ||
447 | if (!(readb(dev->sh_mem + dev->loadptr))) | ||
448 | break; | ||
449 | |||
450 | if (j == LOAD_RETRY) | ||
451 | { | ||
452 | errstat = -ETIME; | ||
453 | printk("TIMEOUT i=%d\n", i); | ||
454 | break; | ||
455 | } | ||
456 | writeb(loadbuf[i], dev->sh_mem + dev->loadptr + 1); | ||
457 | writeb(0x01, dev->sh_mem + dev->loadptr); | ||
458 | |||
459 | dev->loadptr += 2; | ||
460 | if (dev->loadptr > LOAD_ZONE_END) | ||
461 | dev->loadptr = LOAD_ZONE_START; | ||
462 | } | ||
463 | kfree(ptr); | ||
464 | |||
465 | return errstat ? errstat : len; | ||
466 | default: | ||
467 | return -EBUSY; | ||
468 | } | ||
469 | } | ||
470 | |||
471 | /* | ||
472 | * demultiplexing of messages | ||
473 | * | ||
474 | */ | ||
475 | |||
476 | void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, | ||
477 | struct sk_buff * skb, | ||
478 | ushort hdr_len, ushort refnum) | ||
479 | { | ||
480 | struct pcbit_chan *chan; | ||
481 | struct sk_buff *skb2; | ||
482 | unsigned short len; | ||
483 | struct callb_data cbdata; | ||
484 | int complete, err; | ||
485 | isdn_ctrl ictl; | ||
486 | |||
487 | switch(msg) { | ||
488 | |||
489 | case MSG_TDATA_IND: | ||
490 | if (!(chan = capi_channel(dev, skb))) { | ||
491 | printk(KERN_WARNING | ||
492 | "CAPI header: unknown channel id\n"); | ||
493 | break; | ||
494 | } | ||
495 | chan->r_refnum = skb->data[7]; | ||
496 | skb_pull(skb, 8); | ||
497 | |||
498 | dev->dev_if->rcvcallb_skb(dev->id, chan->id, skb); | ||
499 | |||
500 | if (capi_tdata_resp(chan, &skb2) > 0) | ||
501 | pcbit_l2_write(dev, MSG_TDATA_RESP, refnum, | ||
502 | skb2, skb2->len); | ||
503 | return; | ||
504 | break; | ||
505 | case MSG_TDATA_CONF: | ||
506 | if (!(chan = capi_channel(dev, skb))) { | ||
507 | printk(KERN_WARNING | ||
508 | "CAPI header: unknown channel id\n"); | ||
509 | break; | ||
510 | } | ||
511 | |||
512 | #ifdef DEBUG | ||
513 | if ( (*((ushort *) (skb->data + 2) )) != 0) { | ||
514 | printk(KERN_DEBUG "TDATA_CONF error\n"); | ||
515 | } | ||
516 | #endif | ||
517 | #ifdef BLOCK_TIMER | ||
518 | if (chan->queued == MAX_QUEUED) { | ||
519 | del_timer(&chan->block_timer); | ||
520 | chan->block_timer.function = NULL; | ||
521 | } | ||
522 | |||
523 | #endif | ||
524 | chan->queued--; | ||
525 | |||
526 | ictl.driver = dev->id; | ||
527 | ictl.command = ISDN_STAT_BSENT; | ||
528 | ictl.arg = chan->id; | ||
529 | dev->dev_if->statcallb(&ictl); | ||
530 | break; | ||
531 | |||
532 | case MSG_CONN_IND: | ||
533 | /* | ||
534 | * channel: 1st not used will do | ||
535 | * if both are used we're in trouble | ||
536 | */ | ||
537 | |||
538 | if (!dev->b1->fsm_state) | ||
539 | chan = dev->b1; | ||
540 | else if (!dev->b2->fsm_state) | ||
541 | chan = dev->b2; | ||
542 | else { | ||
543 | printk(KERN_INFO | ||
544 | "Incoming connection: no channels available"); | ||
545 | |||
546 | if ((len = capi_disc_req(*(ushort*)(skb->data), &skb2, CAUSE_NOCHAN)) > 0) | ||
547 | pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb2, len); | ||
548 | break; | ||
549 | } | ||
550 | |||
551 | cbdata.data.setup.CalledPN = NULL; | ||
552 | cbdata.data.setup.CallingPN = NULL; | ||
553 | |||
554 | capi_decode_conn_ind(chan, skb, &cbdata); | ||
555 | cbdata.type = EV_NET_SETUP; | ||
556 | |||
557 | pcbit_fsm_event(dev, chan, EV_NET_SETUP, NULL); | ||
558 | |||
559 | if (pcbit_check_msn(dev, cbdata.data.setup.CallingPN)) | ||
560 | pcbit_fsm_event(dev, chan, EV_USR_PROCED_REQ, &cbdata); | ||
561 | else | ||
562 | pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL); | ||
563 | |||
564 | if (cbdata.data.setup.CalledPN) | ||
565 | kfree(cbdata.data.setup.CalledPN); | ||
566 | if (cbdata.data.setup.CallingPN) | ||
567 | kfree(cbdata.data.setup.CallingPN); | ||
568 | break; | ||
569 | |||
570 | case MSG_CONN_CONF: | ||
571 | /* | ||
572 | * We should be able to find the channel by the message | ||
573 | * reference number. The current version of the firmware | ||
574 | * doesn't sent the ref number correctly. | ||
575 | */ | ||
576 | #ifdef DEBUG | ||
577 | printk(KERN_DEBUG "refnum=%04x b1=%04x b2=%04x\n", refnum, | ||
578 | dev->b1->s_refnum, | ||
579 | dev->b2->s_refnum); | ||
580 | #endif | ||
581 | /* We just try to find a channel in the right state */ | ||
582 | |||
583 | if (dev->b1->fsm_state == ST_CALL_INIT) | ||
584 | chan = dev->b1; | ||
585 | else { | ||
586 | if (dev->b2->s_refnum == ST_CALL_INIT) | ||
587 | chan = dev->b2; | ||
588 | else { | ||
589 | chan = NULL; | ||
590 | printk(KERN_WARNING "Connection Confirm - no channel in Call Init state\n"); | ||
591 | break; | ||
592 | } | ||
593 | } | ||
594 | if (capi_decode_conn_conf(chan, skb, &complete)) { | ||
595 | printk(KERN_DEBUG "conn_conf indicates error\n"); | ||
596 | pcbit_fsm_event(dev, chan, EV_ERROR, NULL); | ||
597 | } | ||
598 | else | ||
599 | if (complete) | ||
600 | pcbit_fsm_event(dev, chan, EV_NET_CALL_PROC, NULL); | ||
601 | else | ||
602 | pcbit_fsm_event(dev, chan, EV_NET_SETUP_ACK, NULL); | ||
603 | break; | ||
604 | case MSG_CONN_ACTV_IND: | ||
605 | |||
606 | if (!(chan = capi_channel(dev, skb))) { | ||
607 | printk(KERN_WARNING | ||
608 | "CAPI header: unknown channel id\n"); | ||
609 | break; | ||
610 | } | ||
611 | |||
612 | if (capi_decode_conn_actv_ind(chan, skb)) { | ||
613 | printk("error in capi_decode_conn_actv_ind\n"); | ||
614 | /* pcbit_fsm_event(dev, chan, EV_ERROR, NULL); */ | ||
615 | break; | ||
616 | } | ||
617 | chan->r_refnum = refnum; | ||
618 | pcbit_fsm_event(dev, chan, EV_NET_CONN, NULL); | ||
619 | break; | ||
620 | case MSG_CONN_ACTV_CONF: | ||
621 | |||
622 | if (!(chan = capi_channel(dev, skb))) { | ||
623 | printk(KERN_WARNING | ||
624 | "CAPI header: unknown channel id\n"); | ||
625 | break; | ||
626 | } | ||
627 | |||
628 | if (capi_decode_conn_actv_conf(chan, skb) == 0) | ||
629 | pcbit_fsm_event(dev, chan, EV_NET_CONN_ACK, NULL); | ||
630 | |||
631 | else | ||
632 | printk(KERN_DEBUG "decode_conn_actv_conf failed\n"); | ||
633 | break; | ||
634 | |||
635 | case MSG_SELP_CONF: | ||
636 | |||
637 | if (!(chan = capi_channel(dev, skb))) { | ||
638 | printk(KERN_WARNING | ||
639 | "CAPI header: unknown channel id\n"); | ||
640 | break; | ||
641 | } | ||
642 | |||
643 | if (!(err = capi_decode_sel_proto_conf(chan, skb))) | ||
644 | pcbit_fsm_event(dev, chan, EV_NET_SELP_RESP, NULL); | ||
645 | else { | ||
646 | /* Error */ | ||
647 | printk("error %d - capi_decode_sel_proto_conf\n", err); | ||
648 | } | ||
649 | break; | ||
650 | case MSG_ACT_TRANSP_CONF: | ||
651 | if (!(chan = capi_channel(dev, skb))) { | ||
652 | printk(KERN_WARNING | ||
653 | "CAPI header: unknown channel id\n"); | ||
654 | break; | ||
655 | } | ||
656 | |||
657 | if (!capi_decode_actv_trans_conf(chan, skb)) | ||
658 | pcbit_fsm_event(dev, chan, EV_NET_ACTV_RESP, NULL); | ||
659 | break; | ||
660 | |||
661 | case MSG_DISC_IND: | ||
662 | |||
663 | if (!(chan = capi_channel(dev, skb))) { | ||
664 | printk(KERN_WARNING | ||
665 | "CAPI header: unknown channel id\n"); | ||
666 | break; | ||
667 | } | ||
668 | |||
669 | if (!capi_decode_disc_ind(chan, skb)) | ||
670 | pcbit_fsm_event(dev, chan, EV_NET_DISC, NULL); | ||
671 | else | ||
672 | printk(KERN_WARNING "capi_decode_disc_ind - error\n"); | ||
673 | break; | ||
674 | case MSG_DISC_CONF: | ||
675 | if (!(chan = capi_channel(dev, skb))) { | ||
676 | printk(KERN_WARNING | ||
677 | "CAPI header: unknown channel id\n"); | ||
678 | break; | ||
679 | } | ||
680 | |||
681 | if (!capi_decode_disc_ind(chan, skb)) | ||
682 | pcbit_fsm_event(dev, chan, EV_NET_RELEASE, NULL); | ||
683 | else | ||
684 | printk(KERN_WARNING "capi_decode_disc_conf - error\n"); | ||
685 | break; | ||
686 | case MSG_INFO_IND: | ||
687 | #ifdef DEBUG | ||
688 | printk(KERN_DEBUG "received Info Indication - discarded\n"); | ||
689 | #endif | ||
690 | break; | ||
691 | #ifdef DEBUG | ||
692 | case MSG_DEBUG_188: | ||
693 | capi_decode_debug_188(skb->data, skb->len); | ||
694 | break; | ||
695 | |||
696 | default: | ||
697 | printk(KERN_DEBUG "pcbit_l3_receive: unknown message %08lx\n", | ||
698 | msg); | ||
699 | break; | ||
700 | #endif | ||
701 | } | ||
702 | |||
703 | kfree_skb(skb); | ||
704 | |||
705 | } | ||
706 | |||
707 | /* | ||
708 | * Single statbuf | ||
709 | * should be a statbuf per device | ||
710 | */ | ||
711 | |||
712 | static char statbuf[STATBUF_LEN]; | ||
713 | static int stat_st = 0; | ||
714 | static int stat_end = 0; | ||
715 | |||
716 | int pcbit_stat(u_char __user *buf, int len, int driver, int channel) | ||
717 | { | ||
718 | int stat_count; | ||
719 | stat_count = stat_end - stat_st; | ||
720 | |||
721 | if (stat_count < 0) | ||
722 | stat_count = STATBUF_LEN - stat_st + stat_end; | ||
723 | |||
724 | /* FIXME: should we sleep and wait for more cookies ? */ | ||
725 | if (len > stat_count) | ||
726 | len = stat_count; | ||
727 | |||
728 | if (stat_st < stat_end) | ||
729 | { | ||
730 | copy_to_user(buf, statbuf + stat_st, len); | ||
731 | stat_st += len; | ||
732 | } | ||
733 | else | ||
734 | { | ||
735 | if (len > STATBUF_LEN - stat_st) | ||
736 | { | ||
737 | copy_to_user(buf, statbuf + stat_st, | ||
738 | STATBUF_LEN - stat_st); | ||
739 | copy_to_user(buf, statbuf, | ||
740 | len - (STATBUF_LEN - stat_st)); | ||
741 | |||
742 | stat_st = len - (STATBUF_LEN - stat_st); | ||
743 | } | ||
744 | else | ||
745 | { | ||
746 | copy_to_user(buf, statbuf + stat_st, len); | ||
747 | |||
748 | stat_st += len; | ||
749 | |||
750 | if (stat_st == STATBUF_LEN) | ||
751 | stat_st = 0; | ||
752 | } | ||
753 | } | ||
754 | |||
755 | if (stat_st == stat_end) | ||
756 | stat_st = stat_end = 0; | ||
757 | |||
758 | return len; | ||
759 | } | ||
760 | |||
761 | static void pcbit_logstat(struct pcbit_dev *dev, char *str) | ||
762 | { | ||
763 | int i; | ||
764 | isdn_ctrl ictl; | ||
765 | |||
766 | for (i=stat_end; i<strlen(str); i++) | ||
767 | { | ||
768 | statbuf[i]=str[i]; | ||
769 | stat_end = (stat_end + 1) % STATBUF_LEN; | ||
770 | if (stat_end == stat_st) | ||
771 | stat_st = (stat_st + 1) % STATBUF_LEN; | ||
772 | } | ||
773 | |||
774 | ictl.command=ISDN_STAT_STAVAIL; | ||
775 | ictl.driver=dev->id; | ||
776 | ictl.arg=strlen(str); | ||
777 | dev->dev_if->statcallb(&ictl); | ||
778 | } | ||
779 | |||
780 | extern char * isdn_state_table[]; | ||
781 | extern char * strisdnevent(unsigned short); | ||
782 | |||
783 | |||
784 | void pcbit_state_change(struct pcbit_dev * dev, struct pcbit_chan * chan, | ||
785 | unsigned short i, unsigned short ev, unsigned short f) | ||
786 | { | ||
787 | char buf[256]; | ||
788 | |||
789 | sprintf(buf, "change on device: %d channel:%d\n%s -> %s -> %s\n", | ||
790 | dev->id, chan->id, | ||
791 | isdn_state_table[i], strisdnevent(ev), isdn_state_table[f] | ||
792 | ); | ||
793 | |||
794 | #ifdef DEBUG | ||
795 | printk("%s", buf); | ||
796 | #endif | ||
797 | |||
798 | pcbit_logstat(dev, buf); | ||
799 | } | ||
800 | |||
801 | static void set_running_timeout(unsigned long ptr) | ||
802 | { | ||
803 | struct pcbit_dev * dev; | ||
804 | |||
805 | #ifdef DEBUG | ||
806 | printk(KERN_DEBUG "set_running_timeout\n"); | ||
807 | #endif | ||
808 | dev = (struct pcbit_dev *) ptr; | ||
809 | |||
810 | wake_up_interruptible(&dev->set_running_wq); | ||
811 | } | ||
812 | |||
813 | static int set_protocol_running(struct pcbit_dev * dev) | ||
814 | { | ||
815 | isdn_ctrl ctl; | ||
816 | |||
817 | init_timer(&dev->set_running_timer); | ||
818 | |||
819 | dev->set_running_timer.function = &set_running_timeout; | ||
820 | dev->set_running_timer.data = (ulong) dev; | ||
821 | dev->set_running_timer.expires = jiffies + SET_RUN_TIMEOUT; | ||
822 | |||
823 | /* kick it */ | ||
824 | |||
825 | dev->l2_state = L2_STARTING; | ||
826 | |||
827 | writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)), | ||
828 | dev->sh_mem + BANK4); | ||
829 | |||
830 | add_timer(&dev->set_running_timer); | ||
831 | |||
832 | interruptible_sleep_on(&dev->set_running_wq); | ||
833 | |||
834 | del_timer(&dev->set_running_timer); | ||
835 | |||
836 | if (dev->l2_state == L2_RUNNING) | ||
837 | { | ||
838 | printk(KERN_DEBUG "pcbit: running\n"); | ||
839 | |||
840 | dev->unack_seq = dev->send_seq; | ||
841 | |||
842 | dev->writeptr = dev->sh_mem; | ||
843 | dev->readptr = dev->sh_mem + BANK2; | ||
844 | |||
845 | /* tell the good news to the upper layer */ | ||
846 | ctl.driver = dev->id; | ||
847 | ctl.command = ISDN_STAT_RUN; | ||
848 | |||
849 | dev->dev_if->statcallb(&ctl); | ||
850 | } | ||
851 | else | ||
852 | { | ||
853 | printk(KERN_DEBUG "pcbit: initialization failed\n"); | ||
854 | printk(KERN_DEBUG "pcbit: firmware not loaded\n"); | ||
855 | |||
856 | dev->l2_state = L2_DOWN; | ||
857 | |||
858 | #ifdef DEBUG | ||
859 | printk(KERN_DEBUG "Bank3 = %02x\n", | ||
860 | readb(dev->sh_mem + BANK3)); | ||
861 | #endif | ||
862 | writeb(0x40, dev->sh_mem + BANK4); | ||
863 | |||
864 | /* warn the upper layer */ | ||
865 | ctl.driver = dev->id; | ||
866 | ctl.command = ISDN_STAT_STOP; | ||
867 | |||
868 | dev->dev_if->statcallb(&ctl); | ||
869 | |||
870 | return -EL2HLT; /* Level 2 halted */ | ||
871 | } | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int pcbit_ioctl(isdn_ctrl* ctl) | ||
877 | { | ||
878 | struct pcbit_dev * dev; | ||
879 | struct pcbit_ioctl *cmd; | ||
880 | |||
881 | dev = finddev(ctl->driver); | ||
882 | |||
883 | if (!dev) | ||
884 | { | ||
885 | printk(KERN_DEBUG "pcbit_ioctl: unknown device\n"); | ||
886 | return -ENODEV; | ||
887 | } | ||
888 | |||
889 | cmd = (struct pcbit_ioctl *) ctl->parm.num; | ||
890 | |||
891 | switch(ctl->arg) { | ||
892 | case PCBIT_IOCTL_GETSTAT: | ||
893 | cmd->info.l2_status = dev->l2_state; | ||
894 | break; | ||
895 | |||
896 | case PCBIT_IOCTL_STRLOAD: | ||
897 | if (dev->l2_state == L2_RUNNING) | ||
898 | return -EBUSY; | ||
899 | |||
900 | dev->unack_seq = dev->send_seq = dev->rcv_seq = 0; | ||
901 | |||
902 | dev->writeptr = dev->sh_mem; | ||
903 | dev->readptr = dev->sh_mem + BANK2; | ||
904 | |||
905 | dev->l2_state = L2_LOADING; | ||
906 | break; | ||
907 | |||
908 | case PCBIT_IOCTL_LWMODE: | ||
909 | if (dev->l2_state != L2_LOADING) | ||
910 | return -EINVAL; | ||
911 | |||
912 | dev->l2_state = L2_LWMODE; | ||
913 | break; | ||
914 | |||
915 | case PCBIT_IOCTL_FWMODE: | ||
916 | if (dev->l2_state == L2_RUNNING) | ||
917 | return -EBUSY; | ||
918 | dev->loadptr = LOAD_ZONE_START; | ||
919 | dev->l2_state = L2_FWMODE; | ||
920 | |||
921 | break; | ||
922 | case PCBIT_IOCTL_ENDLOAD: | ||
923 | if (dev->l2_state == L2_RUNNING) | ||
924 | return -EBUSY; | ||
925 | dev->l2_state = L2_DOWN; | ||
926 | break; | ||
927 | |||
928 | case PCBIT_IOCTL_SETBYTE: | ||
929 | if (dev->l2_state == L2_RUNNING) | ||
930 | return -EBUSY; | ||
931 | |||
932 | /* check addr */ | ||
933 | if (cmd->info.rdp_byte.addr > BANK4) | ||
934 | return -EFAULT; | ||
935 | |||
936 | writeb(cmd->info.rdp_byte.value, dev->sh_mem + cmd->info.rdp_byte.addr); | ||
937 | break; | ||
938 | case PCBIT_IOCTL_GETBYTE: | ||
939 | if (dev->l2_state == L2_RUNNING) | ||
940 | return -EBUSY; | ||
941 | |||
942 | /* check addr */ | ||
943 | |||
944 | if (cmd->info.rdp_byte.addr > BANK4) | ||
945 | { | ||
946 | printk("getbyte: invalid addr %04x\n", cmd->info.rdp_byte.addr); | ||
947 | return -EFAULT; | ||
948 | } | ||
949 | |||
950 | cmd->info.rdp_byte.value = readb(dev->sh_mem + cmd->info.rdp_byte.addr); | ||
951 | break; | ||
952 | case PCBIT_IOCTL_RUNNING: | ||
953 | if (dev->l2_state == L2_RUNNING) | ||
954 | return -EBUSY; | ||
955 | return set_protocol_running(dev); | ||
956 | break; | ||
957 | case PCBIT_IOCTL_WATCH188: | ||
958 | if (dev->l2_state != L2_LOADING) | ||
959 | return -EINVAL; | ||
960 | pcbit_l2_write(dev, MSG_WATCH188, 0x0001, NULL, 0); | ||
961 | break; | ||
962 | case PCBIT_IOCTL_PING188: | ||
963 | if (dev->l2_state != L2_LOADING) | ||
964 | return -EINVAL; | ||
965 | pcbit_l2_write(dev, MSG_PING188_REQ, 0x0001, NULL, 0); | ||
966 | break; | ||
967 | case PCBIT_IOCTL_APION: | ||
968 | if (dev->l2_state != L2_LOADING) | ||
969 | return -EINVAL; | ||
970 | pcbit_l2_write(dev, MSG_API_ON, 0x0001, NULL, 0); | ||
971 | break; | ||
972 | case PCBIT_IOCTL_STOP: | ||
973 | dev->l2_state = L2_DOWN; | ||
974 | writeb(0x40, dev->sh_mem + BANK4); | ||
975 | dev->rcv_seq = 0; | ||
976 | dev->send_seq = 0; | ||
977 | dev->unack_seq = 0; | ||
978 | break; | ||
979 | default: | ||
980 | printk("error: unknown ioctl\n"); | ||
981 | break; | ||
982 | }; | ||
983 | return 0; | ||
984 | } | ||
985 | |||
986 | /* | ||
987 | * MSN list handling | ||
988 | * | ||
989 | * if null reject all calls | ||
990 | * if first entry has null MSN accept all calls | ||
991 | */ | ||
992 | |||
993 | static void pcbit_clear_msn(struct pcbit_dev *dev) | ||
994 | { | ||
995 | struct msn_entry *ptr, *back; | ||
996 | |||
997 | for (ptr=dev->msn_list; ptr; ) | ||
998 | { | ||
999 | back = ptr->next; | ||
1000 | kfree(ptr); | ||
1001 | ptr = back; | ||
1002 | } | ||
1003 | |||
1004 | dev->msn_list = NULL; | ||
1005 | } | ||
1006 | |||
1007 | static void pcbit_set_msn(struct pcbit_dev *dev, char *list) | ||
1008 | { | ||
1009 | struct msn_entry *ptr; | ||
1010 | struct msn_entry *back = NULL; | ||
1011 | char *cp, *sp; | ||
1012 | int len; | ||
1013 | |||
1014 | if (strlen(list) == 0) { | ||
1015 | ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC); | ||
1016 | if (!ptr) { | ||
1017 | printk(KERN_WARNING "kmalloc failed\n"); | ||
1018 | return; | ||
1019 | } | ||
1020 | |||
1021 | ptr->msn = NULL; | ||
1022 | |||
1023 | ptr->next = dev->msn_list; | ||
1024 | dev->msn_list = ptr; | ||
1025 | |||
1026 | return; | ||
1027 | } | ||
1028 | |||
1029 | if (dev->msn_list) | ||
1030 | for (back=dev->msn_list; back->next; back=back->next); | ||
1031 | |||
1032 | sp = list; | ||
1033 | |||
1034 | do { | ||
1035 | cp=strchr(sp, ','); | ||
1036 | if (cp) | ||
1037 | len = cp - sp; | ||
1038 | else | ||
1039 | len = strlen(sp); | ||
1040 | |||
1041 | ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC); | ||
1042 | |||
1043 | if (!ptr) { | ||
1044 | printk(KERN_WARNING "kmalloc failed\n"); | ||
1045 | return; | ||
1046 | } | ||
1047 | ptr->next = NULL; | ||
1048 | |||
1049 | ptr->msn = kmalloc(len, GFP_ATOMIC); | ||
1050 | if (!ptr->msn) { | ||
1051 | printk(KERN_WARNING "kmalloc failed\n"); | ||
1052 | kfree(ptr); | ||
1053 | return; | ||
1054 | } | ||
1055 | |||
1056 | memcpy(ptr->msn, sp, len - 1); | ||
1057 | ptr->msn[len] = 0; | ||
1058 | |||
1059 | #ifdef DEBUG | ||
1060 | printk(KERN_DEBUG "msn: %s\n", ptr->msn); | ||
1061 | #endif | ||
1062 | if (dev->msn_list == NULL) | ||
1063 | dev->msn_list = ptr; | ||
1064 | else | ||
1065 | back->next = ptr; | ||
1066 | back = ptr; | ||
1067 | sp += len; | ||
1068 | } while(cp); | ||
1069 | } | ||
1070 | |||
1071 | /* | ||
1072 | * check if we do signal or reject an incoming call | ||
1073 | */ | ||
1074 | static int pcbit_check_msn(struct pcbit_dev *dev, char *msn) | ||
1075 | { | ||
1076 | struct msn_entry *ptr; | ||
1077 | |||
1078 | for (ptr=dev->msn_list; ptr; ptr=ptr->next) { | ||
1079 | |||
1080 | if (ptr->msn == NULL) | ||
1081 | return 1; | ||
1082 | |||
1083 | if (strcmp(ptr->msn, msn) == 0) | ||
1084 | return 1; | ||
1085 | } | ||
1086 | |||
1087 | return 0; | ||
1088 | } | ||
diff --git a/drivers/isdn/pcbit/edss1.c b/drivers/isdn/pcbit/edss1.c new file mode 100644 index 000000000000..93ca7de5670b --- /dev/null +++ b/drivers/isdn/pcbit/edss1.c | |||
@@ -0,0 +1,325 @@ | |||
1 | /* | ||
2 | * DSS.1 Finite State Machine | ||
3 | * base: ITU-T Rec Q.931 | ||
4 | * | ||
5 | * Copyright (C) 1996 Universidade de Lisboa | ||
6 | * | ||
7 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
8 | * | ||
9 | * This software may be used and distributed according to the terms of | ||
10 | * the GNU General Public License, incorporated herein by reference. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * TODO: complete the FSM | ||
15 | * move state/event descriptions to a user space logger | ||
16 | */ | ||
17 | |||
18 | #include <linux/sched.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/kernel.h> | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/skbuff.h> | ||
26 | |||
27 | #include <linux/timer.h> | ||
28 | #include <asm/io.h> | ||
29 | |||
30 | #include <linux/isdnif.h> | ||
31 | |||
32 | #include "pcbit.h" | ||
33 | #include "edss1.h" | ||
34 | #include "layer2.h" | ||
35 | #include "callbacks.h" | ||
36 | |||
37 | |||
38 | extern void pcbit_state_change(struct pcbit_dev *, struct pcbit_chan *, | ||
39 | unsigned short i, unsigned short ev, | ||
40 | unsigned short f); | ||
41 | |||
42 | extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS]; | ||
43 | |||
44 | char * isdn_state_table[] = { | ||
45 | "Closed", | ||
46 | "Call initiated", | ||
47 | "Overlap sending", | ||
48 | "Outgoing call proceeding", | ||
49 | "NOT DEFINED", | ||
50 | "Call delivered", | ||
51 | "Call present", | ||
52 | "Call received", | ||
53 | "Connect request", | ||
54 | "Incoming call proceeding", | ||
55 | "Active", | ||
56 | "Disconnect request", | ||
57 | "Disconnect indication", | ||
58 | "NOT DEFINED", | ||
59 | "NOT DEFINED", | ||
60 | "Suspend request", | ||
61 | "NOT DEFINED", | ||
62 | "Resume request", | ||
63 | "NOT DEFINED", | ||
64 | "Release Request", | ||
65 | "NOT DEFINED", | ||
66 | "NOT DEFINED", | ||
67 | "NOT DEFINED", | ||
68 | "NOT DEFINED", | ||
69 | "NOT DEFINED", | ||
70 | "Overlap receiving", | ||
71 | "Select protocol on B-Channel", | ||
72 | "Activate B-channel protocol" | ||
73 | }; | ||
74 | |||
75 | #ifdef DEBUG_ERRS | ||
76 | static | ||
77 | struct CauseValue { | ||
78 | byte nr; | ||
79 | char *descr; | ||
80 | } cvlist[]={ | ||
81 | {0x01,"Unallocated (unassigned) number"}, | ||
82 | {0x02,"No route to specified transit network"}, | ||
83 | {0x03,"No route to destination"}, | ||
84 | {0x04,"Send special information tone"}, | ||
85 | {0x05,"Misdialled trunk prefix"}, | ||
86 | {0x06,"Channel unacceptable"}, | ||
87 | {0x07,"Channel awarded and being delivered in an established channel"}, | ||
88 | {0x08,"Preemption"}, | ||
89 | {0x09,"Preemption - circuit reserved for reuse"}, | ||
90 | {0x10,"Normal call clearing"}, | ||
91 | {0x11,"User busy"}, | ||
92 | {0x12,"No user responding"}, | ||
93 | {0x13,"No answer from user (user alerted)"}, | ||
94 | {0x14,"Subscriber absent"}, | ||
95 | {0x15,"Call rejected"}, | ||
96 | {0x16,"Number changed"}, | ||
97 | {0x1a,"non-selected user clearing"}, | ||
98 | {0x1b,"Destination out of order"}, | ||
99 | {0x1c,"Invalid number format (address incomplete)"}, | ||
100 | {0x1d,"Facility rejected"}, | ||
101 | {0x1e,"Response to Status enquiry"}, | ||
102 | {0x1f,"Normal, unspecified"}, | ||
103 | {0x22,"No circuit/channel available"}, | ||
104 | {0x26,"Network out of order"}, | ||
105 | {0x27,"Permanent frame mode connection out-of-service"}, | ||
106 | {0x28,"Permanent frame mode connection operational"}, | ||
107 | {0x29,"Temporary failure"}, | ||
108 | {0x2a,"Switching equipment congestion"}, | ||
109 | {0x2b,"Access information discarded"}, | ||
110 | {0x2c,"Requested circuit/channel not available"}, | ||
111 | {0x2e,"Precedence call blocked"}, | ||
112 | {0x2f,"Resource unavailable, unspecified"}, | ||
113 | {0x31,"Quality of service unavailable"}, | ||
114 | {0x32,"Requested facility not subscribed"}, | ||
115 | {0x35,"Outgoing calls barred within CUG"}, | ||
116 | {0x37,"Incoming calls barred within CUG"}, | ||
117 | {0x39,"Bearer capability not authorized"}, | ||
118 | {0x3a,"Bearer capability not presently available"}, | ||
119 | {0x3e,"Inconsistency in designated outgoing access information and subscriber class"}, | ||
120 | {0x3f,"Service or option not available, unspecified"}, | ||
121 | {0x41,"Bearer capability not implemented"}, | ||
122 | {0x42,"Channel type not implemented"}, | ||
123 | {0x43,"Requested facility not implemented"}, | ||
124 | {0x44,"Only restricted digital information bearer capability is available"}, | ||
125 | {0x4f,"Service or option not implemented"}, | ||
126 | {0x51,"Invalid call reference value"}, | ||
127 | {0x52,"Identified channel does not exist"}, | ||
128 | {0x53,"A suspended call exists, but this call identity does not"}, | ||
129 | {0x54,"Call identity in use"}, | ||
130 | {0x55,"No call suspended"}, | ||
131 | {0x56,"Call having the requested call identity has been cleared"}, | ||
132 | {0x57,"User not member of CUG"}, | ||
133 | {0x58,"Incompatible destination"}, | ||
134 | {0x5a,"Non-existent CUG"}, | ||
135 | {0x5b,"Invalid transit network selection"}, | ||
136 | {0x5f,"Invalid message, unspecified"}, | ||
137 | {0x60,"Mandatory information element is missing"}, | ||
138 | {0x61,"Message type non-existent or not implemented"}, | ||
139 | {0x62,"Message not compatible with call state or message type non-existent or not implemented"}, | ||
140 | {0x63,"Information element/parameter non-existent or not implemented"}, | ||
141 | {0x64,"Invalid information element contents"}, | ||
142 | {0x65,"Message not compatible with call state"}, | ||
143 | {0x66,"Recovery on timer expiry"}, | ||
144 | {0x67,"Parameter non-existent or not implemented - passed on"}, | ||
145 | {0x6e,"Message with unrecognized parameter discarded"}, | ||
146 | {0x6f,"Protocol error, unspecified"}, | ||
147 | {0x7f,"Interworking, unspecified"} | ||
148 | }; | ||
149 | |||
150 | #endif | ||
151 | |||
152 | static struct isdn_event_desc { | ||
153 | unsigned short ev; | ||
154 | char * desc; | ||
155 | } isdn_event_table [] = { | ||
156 | {EV_USR_SETUP_REQ, "CC->L3: Setup Request"}, | ||
157 | {EV_USR_SETUP_RESP, "CC->L3: Setup Response"}, | ||
158 | {EV_USR_PROCED_REQ, "CC->L3: Proceeding Request"}, | ||
159 | {EV_USR_RELEASE_REQ, "CC->L3: Release Request"}, | ||
160 | |||
161 | {EV_NET_SETUP, "NET->TE: setup "}, | ||
162 | {EV_NET_CALL_PROC, "NET->TE: call proceeding"}, | ||
163 | {EV_NET_SETUP_ACK, "NET->TE: setup acknowledge (more info needed)"}, | ||
164 | {EV_NET_CONN, "NET->TE: connect"}, | ||
165 | {EV_NET_CONN_ACK, "NET->TE: connect acknowledge"}, | ||
166 | {EV_NET_DISC, "NET->TE: disconnect indication"}, | ||
167 | {EV_NET_RELEASE, "NET->TE: release"}, | ||
168 | {EV_NET_RELEASE_COMP, "NET->TE: release complete"}, | ||
169 | {EV_NET_SELP_RESP, "Board: Select B-channel protocol ack"}, | ||
170 | {EV_NET_ACTV_RESP, "Board: Activate B-channel protocol ack"}, | ||
171 | {EV_TIMER, "Timeout"}, | ||
172 | {0, "NULL"} | ||
173 | }; | ||
174 | |||
175 | char * strisdnevent(ushort ev) | ||
176 | { | ||
177 | struct isdn_event_desc * entry; | ||
178 | |||
179 | for (entry = isdn_event_table; entry->ev; entry++) | ||
180 | if (entry->ev == ev) | ||
181 | break; | ||
182 | |||
183 | return entry->desc; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Euro ISDN finite state machine | ||
188 | */ | ||
189 | |||
190 | static struct fsm_timer_entry fsm_timers[] = { | ||
191 | {ST_CALL_PROC, 10}, | ||
192 | {ST_DISC_REQ, 2}, | ||
193 | {ST_ACTIVE_SELP, 5}, | ||
194 | {ST_ACTIVE_ACTV, 5}, | ||
195 | {ST_INCM_PROC, 10}, | ||
196 | {ST_CONN_REQ, 2}, | ||
197 | {0xff, 0} | ||
198 | }; | ||
199 | |||
200 | static struct fsm_entry fsm_table[] = { | ||
201 | /* Connect Phase */ | ||
202 | /* Outgoing */ | ||
203 | {ST_NULL, ST_CALL_INIT, EV_USR_SETUP_REQ, cb_out_1}, | ||
204 | |||
205 | {ST_CALL_INIT, ST_OVER_SEND, EV_NET_SETUP_ACK, cb_notdone}, | ||
206 | {ST_CALL_INIT, ST_CALL_PROC, EV_NET_CALL_PROC, NULL}, | ||
207 | {ST_CALL_INIT, ST_NULL, EV_NET_DISC, cb_out_2}, | ||
208 | |||
209 | {ST_CALL_PROC, ST_ACTIVE_SELP, EV_NET_CONN, cb_out_2}, | ||
210 | {ST_CALL_PROC, ST_NULL, EV_NET_DISC, cb_disc_1}, | ||
211 | {ST_CALL_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, | ||
212 | |||
213 | /* Incoming */ | ||
214 | {ST_NULL, ST_CALL_PRES, EV_NET_SETUP, NULL}, | ||
215 | |||
216 | {ST_CALL_PRES, ST_INCM_PROC, EV_USR_PROCED_REQ, cb_in_1}, | ||
217 | {ST_CALL_PRES, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, | ||
218 | |||
219 | {ST_INCM_PROC, ST_CONN_REQ, EV_USR_SETUP_RESP, cb_in_2}, | ||
220 | {ST_INCM_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, | ||
221 | |||
222 | {ST_CONN_REQ, ST_ACTIVE_SELP, EV_NET_CONN_ACK, cb_in_3}, | ||
223 | |||
224 | /* Active */ | ||
225 | {ST_ACTIVE, ST_NULL, EV_NET_DISC, cb_disc_1}, | ||
226 | {ST_ACTIVE, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, | ||
227 | {ST_ACTIVE, ST_NULL, EV_NET_RELEASE, cb_disc_3}, | ||
228 | |||
229 | /* Disconnect */ | ||
230 | |||
231 | {ST_DISC_REQ, ST_NULL, EV_NET_DISC, cb_disc_1}, | ||
232 | {ST_DISC_REQ, ST_NULL, EV_NET_RELEASE, cb_disc_3}, | ||
233 | |||
234 | /* protocol selection */ | ||
235 | {ST_ACTIVE_SELP, ST_ACTIVE_ACTV, EV_NET_SELP_RESP, cb_selp_1}, | ||
236 | {ST_ACTIVE_SELP, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, | ||
237 | |||
238 | {ST_ACTIVE_ACTV, ST_ACTIVE, EV_NET_ACTV_RESP, cb_open}, | ||
239 | {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, | ||
240 | |||
241 | /* Timers */ | ||
242 | {ST_CALL_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2}, | ||
243 | {ST_DISC_REQ, ST_NULL, EV_TIMER, cb_disc_3}, | ||
244 | {ST_ACTIVE_SELP, ST_DISC_REQ, EV_TIMER, cb_disc_2}, | ||
245 | {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_TIMER, cb_disc_2}, | ||
246 | {ST_INCM_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2}, | ||
247 | {ST_CONN_REQ, ST_CONN_REQ, EV_TIMER, cb_in_2}, | ||
248 | |||
249 | {0xff, 0, 0, NULL} | ||
250 | }; | ||
251 | |||
252 | |||
253 | static void pcbit_fsm_timer(unsigned long data) | ||
254 | { | ||
255 | struct pcbit_dev *dev; | ||
256 | struct pcbit_chan *chan; | ||
257 | |||
258 | chan = (struct pcbit_chan *) data; | ||
259 | |||
260 | del_timer(&chan->fsm_timer); | ||
261 | chan->fsm_timer.function = NULL; | ||
262 | |||
263 | dev = chan2dev(chan); | ||
264 | |||
265 | if (dev == NULL) { | ||
266 | printk(KERN_WARNING "pcbit: timer for unknown device\n"); | ||
267 | return; | ||
268 | } | ||
269 | |||
270 | pcbit_fsm_event(dev, chan, EV_TIMER, NULL); | ||
271 | } | ||
272 | |||
273 | |||
274 | void pcbit_fsm_event(struct pcbit_dev *dev, struct pcbit_chan *chan, | ||
275 | unsigned short event, struct callb_data *data) | ||
276 | { | ||
277 | struct fsm_entry * action; | ||
278 | struct fsm_timer_entry *tentry; | ||
279 | unsigned long flags; | ||
280 | |||
281 | spin_lock_irqsave(&dev->lock, flags); | ||
282 | |||
283 | for (action = fsm_table; action->init != 0xff; action++) | ||
284 | if (action->init == chan->fsm_state && action->event == event) | ||
285 | break; | ||
286 | |||
287 | if (action->init == 0xff) { | ||
288 | |||
289 | spin_unlock_irqrestore(&dev->lock, flags); | ||
290 | printk(KERN_DEBUG "fsm error: event %x on state %x\n", | ||
291 | event, chan->fsm_state); | ||
292 | return; | ||
293 | } | ||
294 | |||
295 | if (chan->fsm_timer.function) { | ||
296 | del_timer(&chan->fsm_timer); | ||
297 | chan->fsm_timer.function = NULL; | ||
298 | } | ||
299 | |||
300 | chan->fsm_state = action->final; | ||
301 | |||
302 | pcbit_state_change(dev, chan, action->init, event, action->final); | ||
303 | |||
304 | for (tentry = fsm_timers; tentry->init != 0xff; tentry++) | ||
305 | if (tentry->init == chan->fsm_state) | ||
306 | break; | ||
307 | |||
308 | if (tentry->init != 0xff) { | ||
309 | init_timer(&chan->fsm_timer); | ||
310 | chan->fsm_timer.function = &pcbit_fsm_timer; | ||
311 | chan->fsm_timer.data = (ulong) chan; | ||
312 | chan->fsm_timer.expires = jiffies + tentry->timeout * HZ; | ||
313 | add_timer(&chan->fsm_timer); | ||
314 | } | ||
315 | |||
316 | spin_unlock_irqrestore(&dev->lock, flags); | ||
317 | |||
318 | if (action->callb) | ||
319 | action->callb(dev, chan, data); | ||
320 | |||
321 | } | ||
322 | |||
323 | |||
324 | |||
325 | |||
diff --git a/drivers/isdn/pcbit/edss1.h b/drivers/isdn/pcbit/edss1.h new file mode 100644 index 000000000000..6bb587005b86 --- /dev/null +++ b/drivers/isdn/pcbit/edss1.h | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * DSS.1 module definitions | ||
3 | * | ||
4 | * Copyright (C) 1996 Universidade de Lisboa | ||
5 | * | ||
6 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms of | ||
9 | * the GNU General Public License, incorporated herein by reference. | ||
10 | */ | ||
11 | |||
12 | #ifndef EDSS1_H | ||
13 | #define EDSS1_H | ||
14 | |||
15 | /* ISDN states */ | ||
16 | |||
17 | #define ST_NULL 0 | ||
18 | #define ST_CALL_INIT 1 /* Call initiated */ | ||
19 | #define ST_OVER_SEND 2 /* Overlap sending - Requests More Info 4 call */ | ||
20 | #define ST_CALL_PROC 3 /* Call Proceeding */ | ||
21 | #define ST_CALL_DELV 4 | ||
22 | #define ST_CALL_PRES 6 /* Call Present - Received CONN.IND */ | ||
23 | #define ST_CALL_RECV 7 /* Alerting sent */ | ||
24 | #define ST_CONN_REQ 8 /* Answered - waiting 4 CONN.CONF */ | ||
25 | #define ST_INCM_PROC 9 | ||
26 | #define ST_ACTIVE 10 | ||
27 | #define ST_DISC_REQ 11 | ||
28 | #define ST_DISC_IND 12 | ||
29 | #define ST_SUSP_REQ 15 | ||
30 | #define ST_RESM_REQ 17 | ||
31 | #define ST_RELS_REQ 19 | ||
32 | #define ST_OVER_RECV 25 | ||
33 | |||
34 | #define ST_ACTIVE_SELP 26 /* Select protocol on B-Channel */ | ||
35 | #define ST_ACTIVE_ACTV 27 /* Activate B-channel protocol */ | ||
36 | |||
37 | #define MAX_STATE ST_ACTIVE_ACTV | ||
38 | |||
39 | #define EV_NULL 0 | ||
40 | #define EV_USR_SETUP_REQ 1 | ||
41 | #define EV_USR_SETUP_RESP 2 | ||
42 | #define EV_USR_PROCED_REQ 3 | ||
43 | #define EV_USR_RELEASE_REQ 4 | ||
44 | #define EV_USR_REJECT_REQ 4 | ||
45 | |||
46 | #define EV_NET_SETUP 16 | ||
47 | #define EV_NET_CALL_PROC 17 | ||
48 | #define EV_NET_SETUP_ACK 18 | ||
49 | #define EV_NET_CONN 19 | ||
50 | #define EV_NET_CONN_ACK 20 | ||
51 | |||
52 | #define EV_NET_SELP_RESP 21 | ||
53 | #define EV_NET_ACTV_RESP 22 | ||
54 | |||
55 | #define EV_NET_DISC 23 | ||
56 | #define EV_NET_RELEASE 24 | ||
57 | #define EV_NET_RELEASE_COMP 25 | ||
58 | |||
59 | #define EV_TIMER 26 | ||
60 | #define EV_ERROR 32 | ||
61 | |||
62 | /* | ||
63 | * Cause values | ||
64 | * only the ones we use | ||
65 | */ | ||
66 | |||
67 | #define CAUSE_NORMAL 0x10U | ||
68 | #define CAUSE_NOCHAN 0x22U | ||
69 | |||
70 | struct callb_data { | ||
71 | unsigned short type; | ||
72 | union { | ||
73 | struct ConnInfo { | ||
74 | char *CalledPN; | ||
75 | char *CallingPN; | ||
76 | } setup; | ||
77 | unsigned short cause; | ||
78 | } data; | ||
79 | }; | ||
80 | |||
81 | struct fsm_entry { | ||
82 | unsigned short init; | ||
83 | unsigned short final; | ||
84 | unsigned short event; | ||
85 | void (*callb)(struct pcbit_dev *, struct pcbit_chan *, struct callb_data*); | ||
86 | }; | ||
87 | |||
88 | struct fsm_timer_entry { | ||
89 | unsigned short init; | ||
90 | unsigned long timeout; /* in seconds */ | ||
91 | }; | ||
92 | |||
93 | |||
94 | extern void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *, | ||
95 | unsigned short event, struct callb_data *); | ||
96 | #endif | ||
97 | |||
98 | |||
99 | |||
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c new file mode 100644 index 000000000000..ba766930f088 --- /dev/null +++ b/drivers/isdn/pcbit/layer2.c | |||
@@ -0,0 +1,732 @@ | |||
1 | /* | ||
2 | * PCBIT-D low-layer interface | ||
3 | * | ||
4 | * Copyright (C) 1996 Universidade de Lisboa | ||
5 | * | ||
6 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms of | ||
9 | * the GNU General Public License, incorporated herein by reference. | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * 19991203 - Fernando Carvalho - takion@superbofh.org | ||
14 | * Hacked to compile with egcs and run with current version of isdn modules | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * Based on documentation provided by Inesc: | ||
19 | * - "Interface com bus do PC para o PCBIT e PCBIT-D", Inesc, Jan 93 | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | * TODO: better handling of errors | ||
24 | * re-write/remove debug printks | ||
25 | */ | ||
26 | |||
27 | #include <linux/sched.h> | ||
28 | #include <linux/string.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/types.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/workqueue.h> | ||
34 | #include <linux/mm.h> | ||
35 | #include <linux/skbuff.h> | ||
36 | |||
37 | #include <linux/isdnif.h> | ||
38 | |||
39 | #include <asm/system.h> | ||
40 | #include <asm/io.h> | ||
41 | |||
42 | |||
43 | #include "pcbit.h" | ||
44 | #include "layer2.h" | ||
45 | #include "edss1.h" | ||
46 | |||
47 | #undef DEBUG_FRAG | ||
48 | |||
49 | |||
50 | |||
51 | /* | ||
52 | * task queue struct | ||
53 | */ | ||
54 | |||
55 | |||
56 | |||
57 | /* | ||
58 | * Layer 3 packet demultiplexer | ||
59 | * drv.c | ||
60 | */ | ||
61 | |||
62 | extern void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg, | ||
63 | struct sk_buff *skb, | ||
64 | ushort hdr_len, ushort refnum); | ||
65 | |||
66 | /* | ||
67 | * Prototypes | ||
68 | */ | ||
69 | |||
70 | void pcbit_deliver(void *data); | ||
71 | static void pcbit_transmit(struct pcbit_dev *dev); | ||
72 | |||
73 | static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack); | ||
74 | |||
75 | static void pcbit_l2_error(struct pcbit_dev *dev); | ||
76 | static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info); | ||
77 | static void pcbit_l2_err_recover(unsigned long data); | ||
78 | |||
79 | static void pcbit_firmware_bug(struct pcbit_dev *dev); | ||
80 | |||
81 | static __inline__ void | ||
82 | pcbit_sched_delivery(struct pcbit_dev *dev) | ||
83 | { | ||
84 | schedule_work(&dev->qdelivery); | ||
85 | } | ||
86 | |||
87 | |||
88 | /* | ||
89 | * Called from layer3 | ||
90 | */ | ||
91 | |||
92 | int | ||
93 | pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum, | ||
94 | struct sk_buff *skb, unsigned short hdr_len) | ||
95 | { | ||
96 | struct frame_buf *frame, | ||
97 | *ptr; | ||
98 | unsigned long flags; | ||
99 | |||
100 | if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) { | ||
101 | dev_kfree_skb(skb); | ||
102 | return -1; | ||
103 | } | ||
104 | if ((frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf), | ||
105 | GFP_ATOMIC)) == NULL) { | ||
106 | printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n"); | ||
107 | dev_kfree_skb(skb); | ||
108 | return -1; | ||
109 | } | ||
110 | frame->msg = msg; | ||
111 | frame->refnum = refnum; | ||
112 | frame->copied = 0; | ||
113 | frame->hdr_len = hdr_len; | ||
114 | |||
115 | if (skb) | ||
116 | frame->dt_len = skb->len - hdr_len; | ||
117 | else | ||
118 | frame->dt_len = 0; | ||
119 | |||
120 | frame->skb = skb; | ||
121 | |||
122 | frame->next = NULL; | ||
123 | |||
124 | spin_lock_irqsave(&dev->lock, flags); | ||
125 | |||
126 | if (dev->write_queue == NULL) { | ||
127 | dev->write_queue = frame; | ||
128 | spin_unlock_irqrestore(&dev->lock, flags); | ||
129 | pcbit_transmit(dev); | ||
130 | } else { | ||
131 | for (ptr = dev->write_queue; ptr->next; ptr = ptr->next); | ||
132 | ptr->next = frame; | ||
133 | |||
134 | spin_unlock_irqrestore(&dev->lock, flags); | ||
135 | } | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static __inline__ void | ||
140 | pcbit_tx_update(struct pcbit_dev *dev, ushort len) | ||
141 | { | ||
142 | u_char info; | ||
143 | |||
144 | dev->send_seq = (dev->send_seq + 1) % 8; | ||
145 | |||
146 | dev->fsize[dev->send_seq] = len; | ||
147 | info = 0; | ||
148 | info |= dev->rcv_seq << 3; | ||
149 | info |= dev->send_seq; | ||
150 | |||
151 | writeb(info, dev->sh_mem + BANK4); | ||
152 | |||
153 | } | ||
154 | |||
155 | /* | ||
156 | * called by interrupt service routine or by write_2 | ||
157 | */ | ||
158 | |||
159 | static void | ||
160 | pcbit_transmit(struct pcbit_dev *dev) | ||
161 | { | ||
162 | struct frame_buf *frame = NULL; | ||
163 | unsigned char unacked; | ||
164 | int flen; /* fragment frame length including all headers */ | ||
165 | int free; | ||
166 | int count, | ||
167 | cp_len; | ||
168 | unsigned long flags; | ||
169 | unsigned short tt; | ||
170 | |||
171 | if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) | ||
172 | return; | ||
173 | |||
174 | unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07; | ||
175 | |||
176 | spin_lock_irqsave(&dev->lock, flags); | ||
177 | |||
178 | if (dev->free > 16 && dev->write_queue && unacked < 7) { | ||
179 | |||
180 | if (!dev->w_busy) | ||
181 | dev->w_busy = 1; | ||
182 | else { | ||
183 | spin_unlock_irqrestore(&dev->lock, flags); | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | |||
188 | frame = dev->write_queue; | ||
189 | free = dev->free; | ||
190 | |||
191 | spin_unlock_irqrestore(&dev->lock, flags); | ||
192 | |||
193 | if (frame->copied == 0) { | ||
194 | |||
195 | /* Type 0 frame */ | ||
196 | |||
197 | ulong msg; | ||
198 | |||
199 | if (frame->skb) | ||
200 | flen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len; | ||
201 | else | ||
202 | flen = FRAME_HDR_LEN + PREHDR_LEN; | ||
203 | |||
204 | if (flen > free) | ||
205 | flen = free; | ||
206 | |||
207 | msg = frame->msg; | ||
208 | |||
209 | /* | ||
210 | * Board level 2 header | ||
211 | */ | ||
212 | |||
213 | pcbit_writew(dev, flen - FRAME_HDR_LEN); | ||
214 | |||
215 | pcbit_writeb(dev, GET_MSG_CPU(msg)); | ||
216 | |||
217 | pcbit_writeb(dev, GET_MSG_PROC(msg)); | ||
218 | |||
219 | /* TH */ | ||
220 | pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); | ||
221 | |||
222 | /* TD */ | ||
223 | pcbit_writew(dev, frame->dt_len); | ||
224 | |||
225 | |||
226 | /* | ||
227 | * Board level 3 fixed-header | ||
228 | */ | ||
229 | |||
230 | /* LEN = TH */ | ||
231 | pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); | ||
232 | |||
233 | /* XX */ | ||
234 | pcbit_writew(dev, 0); | ||
235 | |||
236 | /* C + S */ | ||
237 | pcbit_writeb(dev, GET_MSG_CMD(msg)); | ||
238 | pcbit_writeb(dev, GET_MSG_SCMD(msg)); | ||
239 | |||
240 | /* NUM */ | ||
241 | pcbit_writew(dev, frame->refnum); | ||
242 | |||
243 | count = FRAME_HDR_LEN + PREHDR_LEN; | ||
244 | } else { | ||
245 | /* Type 1 frame */ | ||
246 | |||
247 | flen = 2 + (frame->skb->len - frame->copied); | ||
248 | |||
249 | if (flen > free) | ||
250 | flen = free; | ||
251 | |||
252 | /* TT */ | ||
253 | tt = ((ushort) (flen - 2)) | 0x8000U; /* Type 1 */ | ||
254 | pcbit_writew(dev, tt); | ||
255 | |||
256 | count = 2; | ||
257 | } | ||
258 | |||
259 | if (frame->skb) { | ||
260 | cp_len = frame->skb->len - frame->copied; | ||
261 | if (cp_len > flen - count) | ||
262 | cp_len = flen - count; | ||
263 | |||
264 | memcpy_topcbit(dev, frame->skb->data + frame->copied, | ||
265 | cp_len); | ||
266 | frame->copied += cp_len; | ||
267 | } | ||
268 | /* bookkeeping */ | ||
269 | dev->free -= flen; | ||
270 | pcbit_tx_update(dev, flen); | ||
271 | |||
272 | spin_lock_irqsave(&dev->lock, flags); | ||
273 | |||
274 | if (frame->skb == NULL || frame->copied == frame->skb->len) { | ||
275 | |||
276 | dev->write_queue = frame->next; | ||
277 | |||
278 | if (frame->skb != NULL) { | ||
279 | /* free frame */ | ||
280 | dev_kfree_skb(frame->skb); | ||
281 | } | ||
282 | kfree(frame); | ||
283 | } | ||
284 | dev->w_busy = 0; | ||
285 | spin_unlock_irqrestore(&dev->lock, flags); | ||
286 | } else { | ||
287 | spin_unlock_irqrestore(&dev->lock, flags); | ||
288 | #ifdef DEBUG | ||
289 | printk(KERN_DEBUG "unacked %d free %d write_queue %s\n", | ||
290 | unacked, dev->free, dev->write_queue ? "not empty" : | ||
291 | "empty"); | ||
292 | #endif | ||
293 | } | ||
294 | } | ||
295 | |||
296 | |||
297 | /* | ||
298 | * deliver a queued frame to the upper layer | ||
299 | */ | ||
300 | |||
301 | void | ||
302 | pcbit_deliver(void *data) | ||
303 | { | ||
304 | struct frame_buf *frame; | ||
305 | unsigned long flags, msg; | ||
306 | struct pcbit_dev *dev = (struct pcbit_dev *) data; | ||
307 | |||
308 | spin_lock_irqsave(&dev->lock, flags); | ||
309 | |||
310 | while ((frame = dev->read_queue)) { | ||
311 | dev->read_queue = frame->next; | ||
312 | spin_unlock_irqrestore(&dev->lock, flags); | ||
313 | |||
314 | SET_MSG_CPU(msg, 0); | ||
315 | SET_MSG_PROC(msg, 0); | ||
316 | SET_MSG_CMD(msg, frame->skb->data[2]); | ||
317 | SET_MSG_SCMD(msg, frame->skb->data[3]); | ||
318 | |||
319 | frame->refnum = *((ushort *) frame->skb->data + 4); | ||
320 | frame->msg = *((ulong *) & msg); | ||
321 | |||
322 | skb_pull(frame->skb, 6); | ||
323 | |||
324 | pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, | ||
325 | frame->refnum); | ||
326 | |||
327 | kfree(frame); | ||
328 | |||
329 | spin_lock_irqsave(&dev->lock, flags); | ||
330 | } | ||
331 | |||
332 | spin_unlock_irqrestore(&dev->lock, flags); | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | * Reads BANK 2 & Reassembles | ||
337 | */ | ||
338 | |||
339 | static void | ||
340 | pcbit_receive(struct pcbit_dev *dev) | ||
341 | { | ||
342 | unsigned short tt; | ||
343 | u_char cpu, | ||
344 | proc; | ||
345 | struct frame_buf *frame = NULL; | ||
346 | unsigned long flags; | ||
347 | u_char type1; | ||
348 | |||
349 | if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) | ||
350 | return; | ||
351 | |||
352 | tt = pcbit_readw(dev); | ||
353 | |||
354 | if ((tt & 0x7fffU) > 511) { | ||
355 | printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n", | ||
356 | tt); | ||
357 | pcbit_l2_error(dev); | ||
358 | return; | ||
359 | } | ||
360 | if (!(tt & 0x8000U)) { /* Type 0 */ | ||
361 | type1 = 0; | ||
362 | |||
363 | if (dev->read_frame) { | ||
364 | printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n"); | ||
365 | /* discard previous queued frame */ | ||
366 | if (dev->read_frame->skb) | ||
367 | kfree_skb(dev->read_frame->skb); | ||
368 | kfree(dev->read_frame); | ||
369 | dev->read_frame = NULL; | ||
370 | } | ||
371 | frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC); | ||
372 | |||
373 | if (frame == NULL) { | ||
374 | printk(KERN_WARNING "kmalloc failed\n"); | ||
375 | return; | ||
376 | } | ||
377 | memset(frame, 0, sizeof(struct frame_buf)); | ||
378 | |||
379 | cpu = pcbit_readb(dev); | ||
380 | proc = pcbit_readb(dev); | ||
381 | |||
382 | |||
383 | if (cpu != 0x06 && cpu != 0x02) { | ||
384 | printk(KERN_DEBUG "pcbit: invalid cpu value\n"); | ||
385 | kfree(frame); | ||
386 | pcbit_l2_error(dev); | ||
387 | return; | ||
388 | } | ||
389 | /* | ||
390 | * we discard cpu & proc on receiving | ||
391 | * but we read it to update the pointer | ||
392 | */ | ||
393 | |||
394 | frame->hdr_len = pcbit_readw(dev); | ||
395 | frame->dt_len = pcbit_readw(dev); | ||
396 | |||
397 | /* | ||
398 | * 0 sized packet | ||
399 | * I don't know if they are an error or not... | ||
400 | * But they are very frequent | ||
401 | * Not documented | ||
402 | */ | ||
403 | |||
404 | if (frame->hdr_len == 0) { | ||
405 | kfree(frame); | ||
406 | #ifdef DEBUG | ||
407 | printk(KERN_DEBUG "0 sized frame\n"); | ||
408 | #endif | ||
409 | pcbit_firmware_bug(dev); | ||
410 | return; | ||
411 | } | ||
412 | /* sanity check the length values */ | ||
413 | if (frame->hdr_len > 1024 || frame->dt_len > 2048) { | ||
414 | #ifdef DEBUG | ||
415 | printk(KERN_DEBUG "length problem: "); | ||
416 | printk(KERN_DEBUG "TH=%04x TD=%04x\n", | ||
417 | frame->hdr_len, | ||
418 | frame->dt_len); | ||
419 | #endif | ||
420 | pcbit_l2_error(dev); | ||
421 | kfree(frame); | ||
422 | return; | ||
423 | } | ||
424 | /* minimum frame read */ | ||
425 | |||
426 | frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len + | ||
427 | ((frame->hdr_len + 15) & ~15)); | ||
428 | |||
429 | if (!frame->skb) { | ||
430 | printk(KERN_DEBUG "pcbit_receive: out of memory\n"); | ||
431 | kfree(frame); | ||
432 | return; | ||
433 | } | ||
434 | /* 16 byte alignment for IP */ | ||
435 | if (frame->dt_len) | ||
436 | skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15); | ||
437 | |||
438 | } else { | ||
439 | /* Type 1 */ | ||
440 | type1 = 1; | ||
441 | tt &= 0x7fffU; | ||
442 | |||
443 | if (!(frame = dev->read_frame)) { | ||
444 | printk("Type 1 frame and no frame queued\n"); | ||
445 | /* usually after an error: toss frame */ | ||
446 | dev->readptr += tt; | ||
447 | if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN) | ||
448 | dev->readptr -= BANKLEN; | ||
449 | return; | ||
450 | |||
451 | } | ||
452 | } | ||
453 | |||
454 | memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt); | ||
455 | |||
456 | frame->copied += tt; | ||
457 | spin_lock_irqsave(&dev->lock, flags); | ||
458 | if (frame->copied == frame->hdr_len + frame->dt_len) { | ||
459 | |||
460 | if (type1) { | ||
461 | dev->read_frame = NULL; | ||
462 | } | ||
463 | if (dev->read_queue) { | ||
464 | struct frame_buf *ptr; | ||
465 | for (ptr = dev->read_queue; ptr->next; ptr = ptr->next); | ||
466 | ptr->next = frame; | ||
467 | } else | ||
468 | dev->read_queue = frame; | ||
469 | |||
470 | } else { | ||
471 | dev->read_frame = frame; | ||
472 | } | ||
473 | spin_unlock_irqrestore(&dev->lock, flags); | ||
474 | } | ||
475 | |||
476 | /* | ||
477 | * The board sends 0 sized frames | ||
478 | * They are TDATA_CONFs that get messed up somehow | ||
479 | * gotta send a fake acknowledgment to the upper layer somehow | ||
480 | */ | ||
481 | |||
482 | static __inline__ void | ||
483 | pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan *chan) | ||
484 | { | ||
485 | isdn_ctrl ictl; | ||
486 | |||
487 | if (chan->queued) { | ||
488 | chan->queued--; | ||
489 | |||
490 | ictl.driver = dev->id; | ||
491 | ictl.command = ISDN_STAT_BSENT; | ||
492 | ictl.arg = chan->id; | ||
493 | dev->dev_if->statcallb(&ictl); | ||
494 | } | ||
495 | } | ||
496 | |||
497 | static void | ||
498 | pcbit_firmware_bug(struct pcbit_dev *dev) | ||
499 | { | ||
500 | struct pcbit_chan *chan; | ||
501 | |||
502 | chan = dev->b1; | ||
503 | |||
504 | if (chan->fsm_state == ST_ACTIVE) { | ||
505 | pcbit_fake_conf(dev, chan); | ||
506 | } | ||
507 | chan = dev->b2; | ||
508 | |||
509 | if (chan->fsm_state == ST_ACTIVE) { | ||
510 | pcbit_fake_conf(dev, chan); | ||
511 | } | ||
512 | } | ||
513 | |||
514 | irqreturn_t | ||
515 | pcbit_irq_handler(int interrupt, void *devptr, struct pt_regs *regs) | ||
516 | { | ||
517 | struct pcbit_dev *dev; | ||
518 | u_char info, | ||
519 | ack_seq, | ||
520 | read_seq; | ||
521 | |||
522 | dev = (struct pcbit_dev *) devptr; | ||
523 | |||
524 | if (!dev) { | ||
525 | printk(KERN_WARNING "pcbit_irq_handler: wrong device\n"); | ||
526 | return IRQ_NONE; | ||
527 | } | ||
528 | if (dev->interrupt) { | ||
529 | printk(KERN_DEBUG "pcbit: reentering interrupt hander\n"); | ||
530 | return IRQ_HANDLED; | ||
531 | } | ||
532 | dev->interrupt = 1; | ||
533 | |||
534 | info = readb(dev->sh_mem + BANK3); | ||
535 | |||
536 | if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) { | ||
537 | pcbit_l2_active_conf(dev, info); | ||
538 | dev->interrupt = 0; | ||
539 | return IRQ_HANDLED; | ||
540 | } | ||
541 | if (info & 0x40U) { /* E bit set */ | ||
542 | #ifdef DEBUG | ||
543 | printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n"); | ||
544 | #endif | ||
545 | pcbit_l2_error(dev); | ||
546 | dev->interrupt = 0; | ||
547 | return IRQ_HANDLED; | ||
548 | } | ||
549 | if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) { | ||
550 | dev->interrupt = 0; | ||
551 | return IRQ_HANDLED; | ||
552 | } | ||
553 | ack_seq = (info >> 3) & 0x07U; | ||
554 | read_seq = (info & 0x07U); | ||
555 | |||
556 | dev->interrupt = 0; | ||
557 | |||
558 | if (read_seq != dev->rcv_seq) { | ||
559 | while (read_seq != dev->rcv_seq) { | ||
560 | pcbit_receive(dev); | ||
561 | dev->rcv_seq = (dev->rcv_seq + 1) % 8; | ||
562 | } | ||
563 | pcbit_sched_delivery(dev); | ||
564 | } | ||
565 | if (ack_seq != dev->unack_seq) { | ||
566 | pcbit_recv_ack(dev, ack_seq); | ||
567 | } | ||
568 | info = dev->rcv_seq << 3; | ||
569 | info |= dev->send_seq; | ||
570 | |||
571 | writeb(info, dev->sh_mem + BANK4); | ||
572 | return IRQ_HANDLED; | ||
573 | } | ||
574 | |||
575 | |||
576 | static void | ||
577 | pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info) | ||
578 | { | ||
579 | u_char state; | ||
580 | |||
581 | state = dev->l2_state; | ||
582 | |||
583 | #ifdef DEBUG | ||
584 | printk(KERN_DEBUG "layer2_active_confirm\n"); | ||
585 | #endif | ||
586 | |||
587 | |||
588 | if (info & 0x80U) { | ||
589 | dev->rcv_seq = info & 0x07U; | ||
590 | dev->l2_state = L2_RUNNING; | ||
591 | } else | ||
592 | dev->l2_state = L2_DOWN; | ||
593 | |||
594 | if (state == L2_STARTING) | ||
595 | wake_up_interruptible(&dev->set_running_wq); | ||
596 | |||
597 | if (state == L2_ERROR && dev->l2_state == L2_RUNNING) { | ||
598 | pcbit_transmit(dev); | ||
599 | } | ||
600 | } | ||
601 | |||
602 | static void | ||
603 | pcbit_l2_err_recover(unsigned long data) | ||
604 | { | ||
605 | |||
606 | struct pcbit_dev *dev; | ||
607 | struct frame_buf *frame; | ||
608 | |||
609 | dev = (struct pcbit_dev *) data; | ||
610 | |||
611 | del_timer(&dev->error_recover_timer); | ||
612 | if (dev->w_busy || dev->r_busy) { | ||
613 | init_timer(&dev->error_recover_timer); | ||
614 | dev->error_recover_timer.expires = jiffies + ERRTIME; | ||
615 | add_timer(&dev->error_recover_timer); | ||
616 | return; | ||
617 | } | ||
618 | dev->w_busy = dev->r_busy = 1; | ||
619 | |||
620 | if (dev->read_frame) { | ||
621 | if (dev->read_frame->skb) | ||
622 | kfree_skb(dev->read_frame->skb); | ||
623 | kfree(dev->read_frame); | ||
624 | dev->read_frame = NULL; | ||
625 | } | ||
626 | if (dev->write_queue) { | ||
627 | frame = dev->write_queue; | ||
628 | #ifdef FREE_ON_ERROR | ||
629 | dev->write_queue = dev->write_queue->next; | ||
630 | |||
631 | if (frame->skb) { | ||
632 | dev_kfree_skb(frame->skb); | ||
633 | } | ||
634 | kfree(frame); | ||
635 | #else | ||
636 | frame->copied = 0; | ||
637 | #endif | ||
638 | } | ||
639 | dev->rcv_seq = dev->send_seq = dev->unack_seq = 0; | ||
640 | dev->free = 511; | ||
641 | dev->l2_state = L2_ERROR; | ||
642 | |||
643 | /* this is an hack... */ | ||
644 | pcbit_firmware_bug(dev); | ||
645 | |||
646 | dev->writeptr = dev->sh_mem; | ||
647 | dev->readptr = dev->sh_mem + BANK2; | ||
648 | |||
649 | writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)), | ||
650 | dev->sh_mem + BANK4); | ||
651 | dev->w_busy = dev->r_busy = 0; | ||
652 | |||
653 | } | ||
654 | |||
655 | static void | ||
656 | pcbit_l2_error(struct pcbit_dev *dev) | ||
657 | { | ||
658 | if (dev->l2_state == L2_RUNNING) { | ||
659 | |||
660 | printk(KERN_INFO "pcbit: layer 2 error\n"); | ||
661 | |||
662 | #ifdef DEBUG | ||
663 | log_state(dev); | ||
664 | #endif | ||
665 | |||
666 | dev->l2_state = L2_DOWN; | ||
667 | |||
668 | init_timer(&dev->error_recover_timer); | ||
669 | dev->error_recover_timer.function = &pcbit_l2_err_recover; | ||
670 | dev->error_recover_timer.data = (ulong) dev; | ||
671 | dev->error_recover_timer.expires = jiffies + ERRTIME; | ||
672 | add_timer(&dev->error_recover_timer); | ||
673 | } | ||
674 | } | ||
675 | |||
676 | /* | ||
677 | * Description: | ||
678 | * if board acks frames | ||
679 | * update dev->free | ||
680 | * call pcbit_transmit to write possible queued frames | ||
681 | */ | ||
682 | |||
683 | static void | ||
684 | pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack) | ||
685 | { | ||
686 | int i, | ||
687 | count; | ||
688 | int unacked; | ||
689 | |||
690 | unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07; | ||
691 | |||
692 | /* dev->unack_seq < ack <= dev->send_seq; */ | ||
693 | |||
694 | if (unacked) { | ||
695 | |||
696 | if (dev->send_seq > dev->unack_seq) { | ||
697 | if (ack <= dev->unack_seq || ack > dev->send_seq) { | ||
698 | printk(KERN_DEBUG | ||
699 | "layer 2 ack unacceptable - dev %d", | ||
700 | dev->id); | ||
701 | |||
702 | pcbit_l2_error(dev); | ||
703 | } else if (ack > dev->send_seq && ack <= dev->unack_seq) { | ||
704 | printk(KERN_DEBUG | ||
705 | "layer 2 ack unacceptable - dev %d", | ||
706 | dev->id); | ||
707 | pcbit_l2_error(dev); | ||
708 | } | ||
709 | } | ||
710 | /* ack is acceptable */ | ||
711 | |||
712 | |||
713 | i = dev->unack_seq; | ||
714 | |||
715 | do { | ||
716 | dev->unack_seq = i = (i + 1) % 8; | ||
717 | dev->free += dev->fsize[i]; | ||
718 | } while (i != ack); | ||
719 | |||
720 | count = 0; | ||
721 | while (count < 7 && dev->write_queue) { | ||
722 | u8 lsend_seq = dev->send_seq; | ||
723 | |||
724 | pcbit_transmit(dev); | ||
725 | |||
726 | if (dev->send_seq == lsend_seq) | ||
727 | break; | ||
728 | count++; | ||
729 | } | ||
730 | } else | ||
731 | printk(KERN_DEBUG "recv_ack: unacked = 0\n"); | ||
732 | } | ||
diff --git a/drivers/isdn/pcbit/layer2.h b/drivers/isdn/pcbit/layer2.h new file mode 100644 index 000000000000..0d99da3a3e2b --- /dev/null +++ b/drivers/isdn/pcbit/layer2.h | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * PCBIT-D low-layer interface definitions | ||
3 | * | ||
4 | * Copyright (C) 1996 Universidade de Lisboa | ||
5 | * | ||
6 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms of | ||
9 | * the GNU General Public License, incorporated herein by reference. | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * 19991203 - Fernando Carvalho - takion@superbofh.org | ||
14 | * Hacked to compile with egcs and run with current version of isdn modules | ||
15 | */ | ||
16 | |||
17 | #ifndef LAYER2_H | ||
18 | #define LAYER2_H | ||
19 | |||
20 | #include <linux/interrupt.h> | ||
21 | |||
22 | #include <asm/byteorder.h> | ||
23 | |||
24 | #define BANK1 0x0000U /* PC -> Board */ | ||
25 | #define BANK2 0x01ffU /* Board -> PC */ | ||
26 | #define BANK3 0x03feU /* Att Board */ | ||
27 | #define BANK4 0x03ffU /* Att PC */ | ||
28 | |||
29 | #define BANKLEN 0x01FFU | ||
30 | |||
31 | #define LOAD_ZONE_START 0x03f8U | ||
32 | #define LOAD_ZONE_END 0x03fdU | ||
33 | |||
34 | #define LOAD_RETRY 18000000 | ||
35 | |||
36 | |||
37 | |||
38 | /* TAM - XX - C - S - NUM */ | ||
39 | #define PREHDR_LEN 8 | ||
40 | /* TT - M - I - TH - TD */ | ||
41 | #define FRAME_HDR_LEN 8 | ||
42 | |||
43 | #define MSG_CONN_REQ 0x08000100 | ||
44 | #define MSG_CONN_CONF 0x00000101 | ||
45 | #define MSG_CONN_IND 0x00000102 | ||
46 | #define MSG_CONN_RESP 0x08000103 | ||
47 | |||
48 | #define MSG_CONN_ACTV_REQ 0x08000300 | ||
49 | #define MSG_CONN_ACTV_CONF 0x00000301 | ||
50 | #define MSG_CONN_ACTV_IND 0x00000302 | ||
51 | #define MSG_CONN_ACTV_RESP 0x08000303 | ||
52 | |||
53 | #define MSG_DISC_REQ 0x08000400 | ||
54 | #define MSG_DISC_CONF 0x00000401 | ||
55 | #define MSG_DISC_IND 0x00000402 | ||
56 | #define MSG_DISC_RESP 0x08000403 | ||
57 | |||
58 | #define MSG_TDATA_REQ 0x0908E200 | ||
59 | #define MSG_TDATA_CONF 0x0000E201 | ||
60 | #define MSG_TDATA_IND 0x0000E202 | ||
61 | #define MSG_TDATA_RESP 0x0908E203 | ||
62 | |||
63 | #define MSG_SELP_REQ 0x09004000 | ||
64 | #define MSG_SELP_CONF 0x00004001 | ||
65 | |||
66 | #define MSG_ACT_TRANSP_REQ 0x0908E000 | ||
67 | #define MSG_ACT_TRANSP_CONF 0x0000E001 | ||
68 | |||
69 | #define MSG_STPROT_REQ 0x09004100 | ||
70 | #define MSG_STPROT_CONF 0x00004101 | ||
71 | |||
72 | #define MSG_PING188_REQ 0x09030500 | ||
73 | #define MSG_PING188_CONF 0x000005bc | ||
74 | |||
75 | #define MSG_WATCH188 0x09030400 | ||
76 | |||
77 | #define MSG_API_ON 0x08020102 | ||
78 | #define MSG_POOL_PCBIT 0x08020400 | ||
79 | #define MSG_POOL_PCBIT_CONF 0x00000401 | ||
80 | |||
81 | #define MSG_INFO_IND 0x00002602 | ||
82 | #define MSG_INFO_RESP 0x08002603 | ||
83 | |||
84 | #define MSG_DEBUG_188 0x0000ff00 | ||
85 | |||
86 | /* | ||
87 | |||
88 | long 4 3 2 1 | ||
89 | Intel 1 2 3 4 | ||
90 | */ | ||
91 | |||
92 | #ifdef __LITTLE_ENDIAN | ||
93 | #define SET_MSG_SCMD(msg, ch) (msg = (msg & 0xffffff00) | (((ch) & 0xff))) | ||
94 | #define SET_MSG_CMD(msg, ch) (msg = (msg & 0xffff00ff) | (((ch) & 0xff) << 8)) | ||
95 | #define SET_MSG_PROC(msg, ch) (msg = (msg & 0xff00ffff) | (((ch) & 0xff) << 16)) | ||
96 | #define SET_MSG_CPU(msg, ch) (msg = (msg & 0x00ffffff) | (((ch) & 0xff) << 24)) | ||
97 | |||
98 | #define GET_MSG_SCMD(msg) ((msg) & 0xFF) | ||
99 | #define GET_MSG_CMD(msg) ((msg) >> 8 & 0xFF) | ||
100 | #define GET_MSG_PROC(msg) ((msg) >> 16 & 0xFF) | ||
101 | #define GET_MSG_CPU(msg) ((msg) >> 24) | ||
102 | |||
103 | #else | ||
104 | #error "Non-Intel CPU" | ||
105 | #endif | ||
106 | |||
107 | #define MAX_QUEUED 7 | ||
108 | |||
109 | #define SCHED_READ 0x01 | ||
110 | #define SCHED_WRITE 0x02 | ||
111 | |||
112 | #define SET_RUN_TIMEOUT 2*HZ /* 2 seconds */ | ||
113 | |||
114 | struct frame_buf { | ||
115 | ulong msg; | ||
116 | unsigned int refnum; | ||
117 | unsigned int dt_len; | ||
118 | unsigned int hdr_len; | ||
119 | struct sk_buff *skb; | ||
120 | unsigned int copied; | ||
121 | struct frame_buf * next; | ||
122 | }; | ||
123 | |||
124 | extern int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum, | ||
125 | struct sk_buff *skb, unsigned short hdr_len); | ||
126 | |||
127 | extern irqreturn_t pcbit_irq_handler(int interrupt, void *, struct pt_regs *regs); | ||
128 | |||
129 | extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS]; | ||
130 | |||
131 | #ifdef DEBUG | ||
132 | static __inline__ void log_state(struct pcbit_dev *dev) { | ||
133 | printk(KERN_DEBUG "writeptr = %ld\n", | ||
134 | (ulong) (dev->writeptr - dev->sh_mem)); | ||
135 | printk(KERN_DEBUG "readptr = %ld\n", | ||
136 | (ulong) (dev->readptr - (dev->sh_mem + BANK2))); | ||
137 | printk(KERN_DEBUG "{rcv_seq=%01x, send_seq=%01x, unack_seq=%01x}\n", | ||
138 | dev->rcv_seq, dev->send_seq, dev->unack_seq); | ||
139 | } | ||
140 | #endif | ||
141 | |||
142 | static __inline__ struct pcbit_dev * chan2dev(struct pcbit_chan * chan) | ||
143 | { | ||
144 | struct pcbit_dev * dev; | ||
145 | int i; | ||
146 | |||
147 | |||
148 | for (i=0; i<MAX_PCBIT_CARDS; i++) | ||
149 | if ((dev=dev_pcbit[i])) | ||
150 | if (dev->b1 == chan || dev->b2 == chan) | ||
151 | return dev; | ||
152 | return NULL; | ||
153 | |||
154 | } | ||
155 | |||
156 | static __inline__ struct pcbit_dev * finddev(int id) | ||
157 | { | ||
158 | struct pcbit_dev * dev; | ||
159 | int i; | ||
160 | |||
161 | for (i=0; i<MAX_PCBIT_CARDS; i++) | ||
162 | if ((dev=dev_pcbit[i])) | ||
163 | if (dev->id == id) | ||
164 | return dev; | ||
165 | return NULL; | ||
166 | } | ||
167 | |||
168 | |||
169 | /* | ||
170 | * Support routines for reading and writing in the board | ||
171 | */ | ||
172 | |||
173 | static __inline__ void pcbit_writeb(struct pcbit_dev *dev, unsigned char dt) | ||
174 | { | ||
175 | writeb(dt, dev->writeptr++); | ||
176 | if (dev->writeptr == dev->sh_mem + BANKLEN) | ||
177 | dev->writeptr = dev->sh_mem; | ||
178 | } | ||
179 | |||
180 | static __inline__ void pcbit_writew(struct pcbit_dev *dev, unsigned short dt) | ||
181 | { | ||
182 | int dist; | ||
183 | |||
184 | dist = BANKLEN - (dev->writeptr - dev->sh_mem); | ||
185 | switch (dist) { | ||
186 | case 2: | ||
187 | writew(dt, dev->writeptr); | ||
188 | dev->writeptr = dev->sh_mem; | ||
189 | break; | ||
190 | case 1: | ||
191 | writeb((u_char) (dt & 0x00ffU), dev->writeptr); | ||
192 | dev->writeptr = dev->sh_mem; | ||
193 | writeb((u_char) (dt >> 8), dev->writeptr++); | ||
194 | break; | ||
195 | default: | ||
196 | writew(dt, dev->writeptr); | ||
197 | dev->writeptr += 2; | ||
198 | break; | ||
199 | }; | ||
200 | } | ||
201 | |||
202 | static __inline__ void memcpy_topcbit(struct pcbit_dev * dev, u_char * data, | ||
203 | int len) | ||
204 | { | ||
205 | int diff; | ||
206 | |||
207 | diff = len - (BANKLEN - (dev->writeptr - dev->sh_mem) ); | ||
208 | |||
209 | if (diff > 0) | ||
210 | { | ||
211 | memcpy_toio(dev->writeptr, data, len - diff); | ||
212 | memcpy_toio(dev->sh_mem, data + (len - diff), diff); | ||
213 | dev->writeptr = dev->sh_mem + diff; | ||
214 | } | ||
215 | else | ||
216 | { | ||
217 | memcpy_toio(dev->writeptr, data, len); | ||
218 | |||
219 | dev->writeptr += len; | ||
220 | if (diff == 0) | ||
221 | dev->writeptr = dev->sh_mem; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static __inline__ unsigned char pcbit_readb(struct pcbit_dev *dev) | ||
226 | { | ||
227 | unsigned char val; | ||
228 | |||
229 | val = readb(dev->readptr++); | ||
230 | if (dev->readptr == dev->sh_mem + BANK2 + BANKLEN) | ||
231 | dev->readptr = dev->sh_mem + BANK2; | ||
232 | |||
233 | return val; | ||
234 | } | ||
235 | |||
236 | static __inline__ unsigned short pcbit_readw(struct pcbit_dev *dev) | ||
237 | { | ||
238 | int dist; | ||
239 | unsigned short val; | ||
240 | |||
241 | dist = BANKLEN - ( dev->readptr - (dev->sh_mem + BANK2 ) ); | ||
242 | switch (dist) { | ||
243 | case 2: | ||
244 | val = readw(dev->readptr); | ||
245 | dev->readptr = dev->sh_mem + BANK2; | ||
246 | break; | ||
247 | case 1: | ||
248 | val = readb(dev->readptr); | ||
249 | dev->readptr = dev->sh_mem + BANK2; | ||
250 | val = (readb(dev->readptr++) << 8) | val; | ||
251 | break; | ||
252 | default: | ||
253 | val = readw(dev->readptr); | ||
254 | dev->readptr += 2; | ||
255 | break; | ||
256 | }; | ||
257 | return val; | ||
258 | } | ||
259 | |||
260 | static __inline__ void memcpy_frompcbit(struct pcbit_dev * dev, u_char * data, int len) | ||
261 | { | ||
262 | int diff; | ||
263 | |||
264 | diff = len - (BANKLEN - (dev->readptr - (dev->sh_mem + BANK2) ) ); | ||
265 | if (diff > 0) | ||
266 | { | ||
267 | memcpy_fromio(data, dev->readptr, len - diff); | ||
268 | memcpy_fromio(data + (len - diff), dev->sh_mem + BANK2 , diff); | ||
269 | dev->readptr = dev->sh_mem + BANK2 + diff; | ||
270 | } | ||
271 | else | ||
272 | { | ||
273 | memcpy_fromio(data, dev->readptr, len); | ||
274 | dev->readptr += len; | ||
275 | if (diff == 0) | ||
276 | dev->readptr = dev->sh_mem + BANK2; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | |||
281 | #endif | ||
282 | |||
283 | |||
284 | |||
285 | |||
286 | |||
287 | |||
288 | |||
diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c new file mode 100644 index 000000000000..282073a35d6a --- /dev/null +++ b/drivers/isdn/pcbit/module.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * PCBIT-D module support | ||
3 | * | ||
4 | * Copyright (C) 1996 Universidade de Lisboa | ||
5 | * | ||
6 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms of | ||
9 | * the GNU General Public License, incorporated herein by reference. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/skbuff.h> | ||
18 | |||
19 | #include <linux/isdnif.h> | ||
20 | #include "pcbit.h" | ||
21 | |||
22 | MODULE_DESCRIPTION("ISDN4Linux: Driver for PCBIT-T card"); | ||
23 | MODULE_AUTHOR("Pedro Roque Marques"); | ||
24 | MODULE_LICENSE("GPL"); | ||
25 | |||
26 | static int mem[MAX_PCBIT_CARDS]; | ||
27 | static int irq[MAX_PCBIT_CARDS]; | ||
28 | |||
29 | module_param_array(mem, int, NULL, 0); | ||
30 | module_param_array(irq, int, NULL, 0); | ||
31 | |||
32 | static int num_boards; | ||
33 | struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS]; | ||
34 | |||
35 | extern void pcbit_terminate(int board); | ||
36 | extern int pcbit_init_dev(int board, int mem_base, int irq); | ||
37 | |||
38 | static int __init pcbit_init(void) | ||
39 | { | ||
40 | int board; | ||
41 | |||
42 | num_boards = 0; | ||
43 | |||
44 | printk(KERN_NOTICE | ||
45 | "PCBIT-D device driver v 0.5-fjpc0 19991204 - " | ||
46 | "Copyright (C) 1996 Universidade de Lisboa\n"); | ||
47 | |||
48 | if (mem[0] || irq[0]) | ||
49 | { | ||
50 | for (board=0; board < MAX_PCBIT_CARDS && mem[board] && irq[board]; board++) | ||
51 | { | ||
52 | if (!mem[board]) | ||
53 | mem[board] = 0xD0000; | ||
54 | if (!irq[board]) | ||
55 | irq[board] = 5; | ||
56 | |||
57 | if (pcbit_init_dev(board, mem[board], irq[board]) == 0) | ||
58 | num_boards++; | ||
59 | |||
60 | else | ||
61 | { | ||
62 | printk(KERN_WARNING | ||
63 | "pcbit_init failed for dev %d", | ||
64 | board + 1); | ||
65 | return -EIO; | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | /* Hardcoded default settings detection */ | ||
71 | |||
72 | if (!num_boards) | ||
73 | { | ||
74 | printk(KERN_INFO | ||
75 | "Trying to detect board using default settings\n"); | ||
76 | if (pcbit_init_dev(0, 0xD0000, 5) == 0) | ||
77 | num_boards++; | ||
78 | else | ||
79 | return -EIO; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static void __exit pcbit_exit(void) | ||
85 | { | ||
86 | #ifdef MODULE | ||
87 | int board; | ||
88 | |||
89 | for (board = 0; board < num_boards; board++) | ||
90 | pcbit_terminate(board); | ||
91 | printk(KERN_NOTICE | ||
92 | "PCBIT-D module unloaded\n"); | ||
93 | #endif | ||
94 | } | ||
95 | |||
96 | #ifndef MODULE | ||
97 | #define MAX_PARA (MAX_PCBIT_CARDS * 2) | ||
98 | static int __init pcbit_setup(char *line) | ||
99 | { | ||
100 | int i, j, argc; | ||
101 | char *str; | ||
102 | int ints[MAX_PARA+1]; | ||
103 | |||
104 | str = get_options(line, MAX_PARA, ints); | ||
105 | argc = ints[0]; | ||
106 | i = 0; | ||
107 | j = 1; | ||
108 | |||
109 | while (argc && (i<MAX_PCBIT_CARDS)) { | ||
110 | |||
111 | if (argc) { | ||
112 | mem[i] = ints[j]; | ||
113 | j++; argc--; | ||
114 | } | ||
115 | |||
116 | if (argc) { | ||
117 | irq[i] = ints[j]; | ||
118 | j++; argc--; | ||
119 | } | ||
120 | |||
121 | i++; | ||
122 | } | ||
123 | return(1); | ||
124 | } | ||
125 | __setup("pcbit=", pcbit_setup); | ||
126 | #endif | ||
127 | |||
128 | module_init(pcbit_init); | ||
129 | module_exit(pcbit_exit); | ||
130 | |||
diff --git a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h new file mode 100644 index 000000000000..388bacefd23a --- /dev/null +++ b/drivers/isdn/pcbit/pcbit.h | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * PCBIT-D device driver definitions | ||
3 | * | ||
4 | * Copyright (C) 1996 Universidade de Lisboa | ||
5 | * | ||
6 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms of | ||
9 | * the GNU General Public License, incorporated herein by reference. | ||
10 | */ | ||
11 | |||
12 | #ifndef PCBIT_H | ||
13 | #define PCBIT_H | ||
14 | |||
15 | #include <linux/workqueue.h> | ||
16 | |||
17 | #define MAX_PCBIT_CARDS 4 | ||
18 | |||
19 | |||
20 | #define BLOCK_TIMER | ||
21 | |||
22 | #ifdef __KERNEL__ | ||
23 | |||
24 | struct pcbit_chan { | ||
25 | unsigned short id; | ||
26 | unsigned short callref; /* Call Reference */ | ||
27 | unsigned char proto; /* layer2protocol */ | ||
28 | unsigned char queued; /* unacked data messages */ | ||
29 | unsigned char layer2link; /* used in TData */ | ||
30 | unsigned char snum; /* used in TData */ | ||
31 | unsigned short s_refnum; | ||
32 | unsigned short r_refnum; | ||
33 | unsigned short fsm_state; | ||
34 | struct timer_list fsm_timer; | ||
35 | #ifdef BLOCK_TIMER | ||
36 | struct timer_list block_timer; | ||
37 | #endif | ||
38 | }; | ||
39 | |||
40 | struct msn_entry { | ||
41 | char *msn; | ||
42 | struct msn_entry * next; | ||
43 | }; | ||
44 | |||
45 | struct pcbit_dev { | ||
46 | /* board */ | ||
47 | |||
48 | volatile unsigned char __iomem *sh_mem; /* RDP address */ | ||
49 | unsigned long ph_mem; | ||
50 | unsigned int irq; | ||
51 | unsigned int id; | ||
52 | unsigned int interrupt; /* set during interrupt | ||
53 | processing */ | ||
54 | spinlock_t lock; | ||
55 | /* isdn4linux */ | ||
56 | |||
57 | struct msn_entry * msn_list; /* ISDN address list */ | ||
58 | |||
59 | isdn_if * dev_if; | ||
60 | |||
61 | ushort ll_hdrlen; | ||
62 | ushort hl_hdrlen; | ||
63 | |||
64 | /* link layer */ | ||
65 | unsigned char l2_state; | ||
66 | |||
67 | struct frame_buf *read_queue; | ||
68 | struct frame_buf *read_frame; | ||
69 | struct frame_buf *write_queue; | ||
70 | |||
71 | /* Protocol start */ | ||
72 | wait_queue_head_t set_running_wq; | ||
73 | struct timer_list set_running_timer; | ||
74 | |||
75 | struct timer_list error_recover_timer; | ||
76 | |||
77 | struct work_struct qdelivery; | ||
78 | |||
79 | u_char w_busy; | ||
80 | u_char r_busy; | ||
81 | |||
82 | volatile unsigned char __iomem *readptr; | ||
83 | volatile unsigned char __iomem *writeptr; | ||
84 | |||
85 | ushort loadptr; | ||
86 | |||
87 | unsigned short fsize[8]; /* sent layer2 frames size */ | ||
88 | |||
89 | unsigned char send_seq; | ||
90 | unsigned char rcv_seq; | ||
91 | unsigned char unack_seq; | ||
92 | |||
93 | unsigned short free; | ||
94 | |||
95 | /* channels */ | ||
96 | |||
97 | struct pcbit_chan *b1; | ||
98 | struct pcbit_chan *b2; | ||
99 | }; | ||
100 | |||
101 | #define STATS_TIMER (10*HZ) | ||
102 | #define ERRTIME (HZ/10) | ||
103 | |||
104 | /* MRU */ | ||
105 | #define MAXBUFSIZE 1534 | ||
106 | #define MRU MAXBUFSIZE | ||
107 | |||
108 | #define STATBUF_LEN 2048 | ||
109 | /* | ||
110 | * | ||
111 | */ | ||
112 | |||
113 | #endif /* __KERNEL__ */ | ||
114 | |||
115 | /* isdn_ctrl only allows a long sized argument */ | ||
116 | |||
117 | struct pcbit_ioctl { | ||
118 | union { | ||
119 | struct byte_op { | ||
120 | ushort addr; | ||
121 | ushort value; | ||
122 | } rdp_byte; | ||
123 | unsigned long l2_status; | ||
124 | } info; | ||
125 | }; | ||
126 | |||
127 | |||
128 | |||
129 | #define PCBIT_IOCTL_GETSTAT 0x01 /* layer2 status */ | ||
130 | #define PCBIT_IOCTL_LWMODE 0x02 /* linear write mode */ | ||
131 | #define PCBIT_IOCTL_STRLOAD 0x03 /* start load mode */ | ||
132 | #define PCBIT_IOCTL_ENDLOAD 0x04 /* end load mode */ | ||
133 | #define PCBIT_IOCTL_SETBYTE 0x05 /* set byte */ | ||
134 | #define PCBIT_IOCTL_GETBYTE 0x06 /* get byte */ | ||
135 | #define PCBIT_IOCTL_RUNNING 0x07 /* set protocol running */ | ||
136 | #define PCBIT_IOCTL_WATCH188 0x08 /* set watch 188 */ | ||
137 | #define PCBIT_IOCTL_PING188 0x09 /* ping 188 */ | ||
138 | #define PCBIT_IOCTL_FWMODE 0x0A /* firmware write mode */ | ||
139 | #define PCBIT_IOCTL_STOP 0x0B /* stop protocol */ | ||
140 | #define PCBIT_IOCTL_APION 0x0C /* issue API_ON */ | ||
141 | |||
142 | #ifndef __KERNEL__ | ||
143 | |||
144 | #define PCBIT_GETSTAT (PCBIT_IOCTL_GETSTAT + IIOCDRVCTL) | ||
145 | #define PCBIT_LWMODE (PCBIT_IOCTL_LWMODE + IIOCDRVCTL) | ||
146 | #define PCBIT_STRLOAD (PCBIT_IOCTL_STRLOAD + IIOCDRVCTL) | ||
147 | #define PCBIT_ENDLOAD (PCBIT_IOCTL_ENDLOAD + IIOCDRVCTL) | ||
148 | #define PCBIT_SETBYTE (PCBIT_IOCTL_SETBYTE + IIOCDRVCTL) | ||
149 | #define PCBIT_GETBYTE (PCBIT_IOCTL_GETBYTE + IIOCDRVCTL) | ||
150 | #define PCBIT_RUNNING (PCBIT_IOCTL_RUNNING + IIOCDRVCTL) | ||
151 | #define PCBIT_WATCH188 (PCBIT_IOCTL_WATCH188 + IIOCDRVCTL) | ||
152 | #define PCBIT_PING188 (PCBIT_IOCTL_PING188 + IIOCDRVCTL) | ||
153 | #define PCBIT_FWMODE (PCBIT_IOCTL_FWMODE + IIOCDRVCTL) | ||
154 | #define PCBIT_STOP (PCBIT_IOCTL_STOP + IIOCDRVCTL) | ||
155 | #define PCBIT_APION (PCBIT_IOCTL_APION + IIOCDRVCTL) | ||
156 | |||
157 | #define MAXSUPERLINE 3000 | ||
158 | |||
159 | #endif | ||
160 | |||
161 | #define L2_DOWN 0 | ||
162 | #define L2_LOADING 1 | ||
163 | #define L2_LWMODE 2 | ||
164 | #define L2_FWMODE 3 | ||
165 | #define L2_STARTING 4 | ||
166 | #define L2_RUNNING 5 | ||
167 | #define L2_ERROR 6 | ||
168 | |||
169 | #endif | ||