diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/act2000/capi.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/act2000/capi.c')
-rw-r--r-- | drivers/isdn/act2000/capi.c | 1177 |
1 files changed, 1177 insertions, 0 deletions
diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c new file mode 100644 index 000000000000..40395f567231 --- /dev/null +++ b/drivers/isdn/act2000/capi.c | |||
@@ -0,0 +1,1177 @@ | |||
1 | /* $Id: capi.c,v 1.9.6.2 2001/09/23 22:24:32 kai Exp $ | ||
2 | * | ||
3 | * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. | ||
4 | * CAPI encoder/decoder | ||
5 | * | ||
6 | * Author Fritz Elfert | ||
7 | * Copyright by Fritz Elfert <fritz@isdn4linux.de> | ||
8 | * | ||
9 | * This software may be used and distributed according to the terms | ||
10 | * of the GNU General Public License, incorporated herein by reference. | ||
11 | * | ||
12 | * Thanks to Friedemann Baitinger and IBM Germany | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include "act2000.h" | ||
17 | #include "capi.h" | ||
18 | |||
19 | static actcapi_msgdsc valid_msg[] = { | ||
20 | {{ 0x86, 0x02}, "DATA_B3_IND"}, /* DATA_B3_IND/CONF must be first because of speed!!! */ | ||
21 | {{ 0x86, 0x01}, "DATA_B3_CONF"}, | ||
22 | {{ 0x02, 0x01}, "CONNECT_CONF"}, | ||
23 | {{ 0x02, 0x02}, "CONNECT_IND"}, | ||
24 | {{ 0x09, 0x01}, "CONNECT_INFO_CONF"}, | ||
25 | {{ 0x03, 0x02}, "CONNECT_ACTIVE_IND"}, | ||
26 | {{ 0x04, 0x01}, "DISCONNECT_CONF"}, | ||
27 | {{ 0x04, 0x02}, "DISCONNECT_IND"}, | ||
28 | {{ 0x05, 0x01}, "LISTEN_CONF"}, | ||
29 | {{ 0x06, 0x01}, "GET_PARAMS_CONF"}, | ||
30 | {{ 0x07, 0x01}, "INFO_CONF"}, | ||
31 | {{ 0x07, 0x02}, "INFO_IND"}, | ||
32 | {{ 0x08, 0x01}, "DATA_CONF"}, | ||
33 | {{ 0x08, 0x02}, "DATA_IND"}, | ||
34 | {{ 0x40, 0x01}, "SELECT_B2_PROTOCOL_CONF"}, | ||
35 | {{ 0x80, 0x01}, "SELECT_B3_PROTOCOL_CONF"}, | ||
36 | {{ 0x81, 0x01}, "LISTEN_B3_CONF"}, | ||
37 | {{ 0x82, 0x01}, "CONNECT_B3_CONF"}, | ||
38 | {{ 0x82, 0x02}, "CONNECT_B3_IND"}, | ||
39 | {{ 0x83, 0x02}, "CONNECT_B3_ACTIVE_IND"}, | ||
40 | {{ 0x84, 0x01}, "DISCONNECT_B3_CONF"}, | ||
41 | {{ 0x84, 0x02}, "DISCONNECT_B3_IND"}, | ||
42 | {{ 0x85, 0x01}, "GET_B3_PARAMS_CONF"}, | ||
43 | {{ 0x01, 0x01}, "RESET_B3_CONF"}, | ||
44 | {{ 0x01, 0x02}, "RESET_B3_IND"}, | ||
45 | /* {{ 0x87, 0x02, "HANDSET_IND"}, not implemented */ | ||
46 | {{ 0xff, 0x01}, "MANUFACTURER_CONF"}, | ||
47 | {{ 0xff, 0x02}, "MANUFACTURER_IND"}, | ||
48 | #ifdef DEBUG_MSG | ||
49 | /* Requests */ | ||
50 | {{ 0x01, 0x00}, "RESET_B3_REQ"}, | ||
51 | {{ 0x02, 0x00}, "CONNECT_REQ"}, | ||
52 | {{ 0x04, 0x00}, "DISCONNECT_REQ"}, | ||
53 | {{ 0x05, 0x00}, "LISTEN_REQ"}, | ||
54 | {{ 0x06, 0x00}, "GET_PARAMS_REQ"}, | ||
55 | {{ 0x07, 0x00}, "INFO_REQ"}, | ||
56 | {{ 0x08, 0x00}, "DATA_REQ"}, | ||
57 | {{ 0x09, 0x00}, "CONNECT_INFO_REQ"}, | ||
58 | {{ 0x40, 0x00}, "SELECT_B2_PROTOCOL_REQ"}, | ||
59 | {{ 0x80, 0x00}, "SELECT_B3_PROTOCOL_REQ"}, | ||
60 | {{ 0x81, 0x00}, "LISTEN_B3_REQ"}, | ||
61 | {{ 0x82, 0x00}, "CONNECT_B3_REQ"}, | ||
62 | {{ 0x84, 0x00}, "DISCONNECT_B3_REQ"}, | ||
63 | {{ 0x85, 0x00}, "GET_B3_PARAMS_REQ"}, | ||
64 | {{ 0x86, 0x00}, "DATA_B3_REQ"}, | ||
65 | {{ 0xff, 0x00}, "MANUFACTURER_REQ"}, | ||
66 | /* Responses */ | ||
67 | {{ 0x01, 0x03}, "RESET_B3_RESP"}, | ||
68 | {{ 0x02, 0x03}, "CONNECT_RESP"}, | ||
69 | {{ 0x03, 0x03}, "CONNECT_ACTIVE_RESP"}, | ||
70 | {{ 0x04, 0x03}, "DISCONNECT_RESP"}, | ||
71 | {{ 0x07, 0x03}, "INFO_RESP"}, | ||
72 | {{ 0x08, 0x03}, "DATA_RESP"}, | ||
73 | {{ 0x82, 0x03}, "CONNECT_B3_RESP"}, | ||
74 | {{ 0x83, 0x03}, "CONNECT_B3_ACTIVE_RESP"}, | ||
75 | {{ 0x84, 0x03}, "DISCONNECT_B3_RESP"}, | ||
76 | {{ 0x86, 0x03}, "DATA_B3_RESP"}, | ||
77 | {{ 0xff, 0x03}, "MANUFACTURER_RESP"}, | ||
78 | #endif | ||
79 | {{ 0x00, 0x00}, NULL}, | ||
80 | }; | ||
81 | #define num_valid_msg (sizeof(valid_msg)/sizeof(actcapi_msgdsc)) | ||
82 | #define num_valid_imsg 27 /* MANUFACTURER_IND */ | ||
83 | |||
84 | /* | ||
85 | * Check for a valid incoming CAPI message. | ||
86 | * Return: | ||
87 | * 0 = Invalid message | ||
88 | * 1 = Valid message, no B-Channel-data | ||
89 | * 2 = Valid message, B-Channel-data | ||
90 | */ | ||
91 | int | ||
92 | actcapi_chkhdr(act2000_card * card, actcapi_msghdr *hdr) | ||
93 | { | ||
94 | int i; | ||
95 | |||
96 | if (hdr->applicationID != 1) | ||
97 | return 0; | ||
98 | if (hdr->len < 9) | ||
99 | return 0; | ||
100 | for (i = 0; i < num_valid_imsg; i++) | ||
101 | if ((hdr->cmd.cmd == valid_msg[i].cmd.cmd) && | ||
102 | (hdr->cmd.subcmd == valid_msg[i].cmd.subcmd)) { | ||
103 | return (i?1:2); | ||
104 | } | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | #define ACTCAPI_MKHDR(l, c, s) { \ | ||
109 | skb = alloc_skb(l + 8, GFP_ATOMIC); \ | ||
110 | if (skb) { \ | ||
111 | m = (actcapi_msg *)skb_put(skb, l + 8); \ | ||
112 | m->hdr.len = l + 8; \ | ||
113 | m->hdr.applicationID = 1; \ | ||
114 | m->hdr.cmd.cmd = c; \ | ||
115 | m->hdr.cmd.subcmd = s; \ | ||
116 | m->hdr.msgnum = actcapi_nextsmsg(card); \ | ||
117 | } else m = NULL;\ | ||
118 | } | ||
119 | |||
120 | #define ACTCAPI_CHKSKB if (!skb) { \ | ||
121 | printk(KERN_WARNING "actcapi: alloc_skb failed\n"); \ | ||
122 | return; \ | ||
123 | } | ||
124 | |||
125 | #define ACTCAPI_QUEUE_TX { \ | ||
126 | actcapi_debug_msg(skb, 1); \ | ||
127 | skb_queue_tail(&card->sndq, skb); \ | ||
128 | act2000_schedule_tx(card); \ | ||
129 | } | ||
130 | |||
131 | int | ||
132 | actcapi_listen_req(act2000_card *card) | ||
133 | { | ||
134 | __u16 eazmask = 0; | ||
135 | int i; | ||
136 | actcapi_msg *m; | ||
137 | struct sk_buff *skb; | ||
138 | |||
139 | for (i = 0; i < ACT2000_BCH; i++) | ||
140 | eazmask |= card->bch[i].eazmask; | ||
141 | ACTCAPI_MKHDR(9, 0x05, 0x00); | ||
142 | if (!skb) { | ||
143 | printk(KERN_WARNING "actcapi: alloc_skb failed\n"); | ||
144 | return -ENOMEM; | ||
145 | } | ||
146 | m->msg.listen_req.controller = 0; | ||
147 | m->msg.listen_req.infomask = 0x3f; /* All information */ | ||
148 | m->msg.listen_req.eazmask = eazmask; | ||
149 | m->msg.listen_req.simask = (eazmask)?0x86:0; /* All SI's */ | ||
150 | ACTCAPI_QUEUE_TX; | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | int | ||
155 | actcapi_connect_req(act2000_card *card, act2000_chan *chan, char *phone, | ||
156 | char eaz, int si1, int si2) | ||
157 | { | ||
158 | actcapi_msg *m; | ||
159 | struct sk_buff *skb; | ||
160 | |||
161 | ACTCAPI_MKHDR((11 + strlen(phone)), 0x02, 0x00); | ||
162 | if (!skb) { | ||
163 | printk(KERN_WARNING "actcapi: alloc_skb failed\n"); | ||
164 | chan->fsm_state = ACT2000_STATE_NULL; | ||
165 | return -ENOMEM; | ||
166 | } | ||
167 | m->msg.connect_req.controller = 0; | ||
168 | m->msg.connect_req.bchan = 0x83; | ||
169 | m->msg.connect_req.infomask = 0x3f; | ||
170 | m->msg.connect_req.si1 = si1; | ||
171 | m->msg.connect_req.si2 = si2; | ||
172 | m->msg.connect_req.eaz = eaz?eaz:'0'; | ||
173 | m->msg.connect_req.addr.len = strlen(phone) + 1; | ||
174 | m->msg.connect_req.addr.tnp = 0x81; | ||
175 | memcpy(m->msg.connect_req.addr.num, phone, strlen(phone)); | ||
176 | chan->callref = m->hdr.msgnum; | ||
177 | ACTCAPI_QUEUE_TX; | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static void | ||
182 | actcapi_connect_b3_req(act2000_card *card, act2000_chan *chan) | ||
183 | { | ||
184 | actcapi_msg *m; | ||
185 | struct sk_buff *skb; | ||
186 | |||
187 | ACTCAPI_MKHDR(17, 0x82, 0x00); | ||
188 | ACTCAPI_CHKSKB; | ||
189 | m->msg.connect_b3_req.plci = chan->plci; | ||
190 | memset(&m->msg.connect_b3_req.ncpi, 0, | ||
191 | sizeof(m->msg.connect_b3_req.ncpi)); | ||
192 | m->msg.connect_b3_req.ncpi.len = 13; | ||
193 | m->msg.connect_b3_req.ncpi.modulo = 8; | ||
194 | ACTCAPI_QUEUE_TX; | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Set net type (1TR6) or (EDSS1) | ||
199 | */ | ||
200 | int | ||
201 | actcapi_manufacturer_req_net(act2000_card *card) | ||
202 | { | ||
203 | actcapi_msg *m; | ||
204 | struct sk_buff *skb; | ||
205 | |||
206 | ACTCAPI_MKHDR(5, 0xff, 0x00); | ||
207 | if (!skb) { | ||
208 | printk(KERN_WARNING "actcapi: alloc_skb failed\n"); | ||
209 | return -ENOMEM; | ||
210 | } | ||
211 | m->msg.manufacturer_req_net.manuf_msg = 0x11; | ||
212 | m->msg.manufacturer_req_net.controller = 1; | ||
213 | m->msg.manufacturer_req_net.nettype = (card->ptype == ISDN_PTYPE_EURO)?1:0; | ||
214 | ACTCAPI_QUEUE_TX; | ||
215 | printk(KERN_INFO "act2000 %s: D-channel protocol now %s\n", | ||
216 | card->interface.id, (card->ptype == ISDN_PTYPE_EURO)?"euro":"1tr6"); | ||
217 | card->interface.features &= | ||
218 | ~(ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_P_EURO | ISDN_FEATURE_P_1TR6); | ||
219 | card->interface.features |= | ||
220 | ((card->ptype == ISDN_PTYPE_EURO)?ISDN_FEATURE_P_EURO:ISDN_FEATURE_P_1TR6); | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * Switch V.42 on or off | ||
226 | */ | ||
227 | int | ||
228 | actcapi_manufacturer_req_v42(act2000_card *card, ulong arg) | ||
229 | { | ||
230 | actcapi_msg *m; | ||
231 | struct sk_buff *skb; | ||
232 | |||
233 | ACTCAPI_MKHDR(8, 0xff, 0x00); | ||
234 | if (!skb) { | ||
235 | |||
236 | printk(KERN_WARNING "actcapi: alloc_skb failed\n"); | ||
237 | return -ENOMEM; | ||
238 | } | ||
239 | m->msg.manufacturer_req_v42.manuf_msg = 0x10; | ||
240 | m->msg.manufacturer_req_v42.controller = 0; | ||
241 | m->msg.manufacturer_req_v42.v42control = (arg?1:0); | ||
242 | ACTCAPI_QUEUE_TX; | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Set error-handler | ||
248 | */ | ||
249 | int | ||
250 | actcapi_manufacturer_req_errh(act2000_card *card) | ||
251 | { | ||
252 | actcapi_msg *m; | ||
253 | struct sk_buff *skb; | ||
254 | |||
255 | ACTCAPI_MKHDR(4, 0xff, 0x00); | ||
256 | if (!skb) { | ||
257 | |||
258 | printk(KERN_WARNING "actcapi: alloc_skb failed\n"); | ||
259 | return -ENOMEM; | ||
260 | } | ||
261 | m->msg.manufacturer_req_err.manuf_msg = 0x03; | ||
262 | m->msg.manufacturer_req_err.controller = 0; | ||
263 | ACTCAPI_QUEUE_TX; | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * Set MSN-Mapping. | ||
269 | */ | ||
270 | int | ||
271 | actcapi_manufacturer_req_msn(act2000_card *card) | ||
272 | { | ||
273 | msn_entry *p = card->msn_list; | ||
274 | actcapi_msg *m; | ||
275 | struct sk_buff *skb; | ||
276 | int len; | ||
277 | |||
278 | while (p) { | ||
279 | int i; | ||
280 | |||
281 | len = strlen(p->msn); | ||
282 | for (i = 0; i < 2; i++) { | ||
283 | ACTCAPI_MKHDR(6 + len, 0xff, 0x00); | ||
284 | if (!skb) { | ||
285 | printk(KERN_WARNING "actcapi: alloc_skb failed\n"); | ||
286 | return -ENOMEM; | ||
287 | } | ||
288 | m->msg.manufacturer_req_msn.manuf_msg = 0x13 + i; | ||
289 | m->msg.manufacturer_req_msn.controller = 0; | ||
290 | m->msg.manufacturer_req_msn.msnmap.eaz = p->eaz; | ||
291 | m->msg.manufacturer_req_msn.msnmap.len = len; | ||
292 | memcpy(m->msg.manufacturer_req_msn.msnmap.msn, p->msn, len); | ||
293 | ACTCAPI_QUEUE_TX; | ||
294 | } | ||
295 | p = p->next; | ||
296 | } | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | void | ||
301 | actcapi_select_b2_protocol_req(act2000_card *card, act2000_chan *chan) | ||
302 | { | ||
303 | actcapi_msg *m; | ||
304 | struct sk_buff *skb; | ||
305 | |||
306 | ACTCAPI_MKHDR(10, 0x40, 0x00); | ||
307 | ACTCAPI_CHKSKB; | ||
308 | m->msg.select_b2_protocol_req.plci = chan->plci; | ||
309 | memset(&m->msg.select_b2_protocol_req.dlpd, 0, | ||
310 | sizeof(m->msg.select_b2_protocol_req.dlpd)); | ||
311 | m->msg.select_b2_protocol_req.dlpd.len = 6; | ||
312 | switch (chan->l2prot) { | ||
313 | case ISDN_PROTO_L2_TRANS: | ||
314 | m->msg.select_b2_protocol_req.protocol = 0x03; | ||
315 | m->msg.select_b2_protocol_req.dlpd.dlen = 4000; | ||
316 | break; | ||
317 | case ISDN_PROTO_L2_HDLC: | ||
318 | m->msg.select_b2_protocol_req.protocol = 0x02; | ||
319 | m->msg.select_b2_protocol_req.dlpd.dlen = 4000; | ||
320 | break; | ||
321 | case ISDN_PROTO_L2_X75I: | ||
322 | case ISDN_PROTO_L2_X75UI: | ||
323 | case ISDN_PROTO_L2_X75BUI: | ||
324 | m->msg.select_b2_protocol_req.protocol = 0x01; | ||
325 | m->msg.select_b2_protocol_req.dlpd.dlen = 4000; | ||
326 | m->msg.select_b2_protocol_req.dlpd.laa = 3; | ||
327 | m->msg.select_b2_protocol_req.dlpd.lab = 1; | ||
328 | m->msg.select_b2_protocol_req.dlpd.win = 7; | ||
329 | m->msg.select_b2_protocol_req.dlpd.modulo = 8; | ||
330 | break; | ||
331 | } | ||
332 | ACTCAPI_QUEUE_TX; | ||
333 | } | ||
334 | |||
335 | static void | ||
336 | actcapi_select_b3_protocol_req(act2000_card *card, act2000_chan *chan) | ||
337 | { | ||
338 | actcapi_msg *m; | ||
339 | struct sk_buff *skb; | ||
340 | |||
341 | ACTCAPI_MKHDR(17, 0x80, 0x00); | ||
342 | ACTCAPI_CHKSKB; | ||
343 | m->msg.select_b3_protocol_req.plci = chan->plci; | ||
344 | memset(&m->msg.select_b3_protocol_req.ncpd, 0, | ||
345 | sizeof(m->msg.select_b3_protocol_req.ncpd)); | ||
346 | switch (chan->l3prot) { | ||
347 | case ISDN_PROTO_L3_TRANS: | ||
348 | m->msg.select_b3_protocol_req.protocol = 0x04; | ||
349 | m->msg.select_b3_protocol_req.ncpd.len = 13; | ||
350 | m->msg.select_b3_protocol_req.ncpd.modulo = 8; | ||
351 | break; | ||
352 | } | ||
353 | ACTCAPI_QUEUE_TX; | ||
354 | } | ||
355 | |||
356 | static void | ||
357 | actcapi_listen_b3_req(act2000_card *card, act2000_chan *chan) | ||
358 | { | ||
359 | actcapi_msg *m; | ||
360 | struct sk_buff *skb; | ||
361 | |||
362 | ACTCAPI_MKHDR(2, 0x81, 0x00); | ||
363 | ACTCAPI_CHKSKB; | ||
364 | m->msg.listen_b3_req.plci = chan->plci; | ||
365 | ACTCAPI_QUEUE_TX; | ||
366 | } | ||
367 | |||
368 | static void | ||
369 | actcapi_disconnect_req(act2000_card *card, act2000_chan *chan) | ||
370 | { | ||
371 | actcapi_msg *m; | ||
372 | struct sk_buff *skb; | ||
373 | |||
374 | ACTCAPI_MKHDR(3, 0x04, 0x00); | ||
375 | ACTCAPI_CHKSKB; | ||
376 | m->msg.disconnect_req.plci = chan->plci; | ||
377 | m->msg.disconnect_req.cause = 0; | ||
378 | ACTCAPI_QUEUE_TX; | ||
379 | } | ||
380 | |||
381 | void | ||
382 | actcapi_disconnect_b3_req(act2000_card *card, act2000_chan *chan) | ||
383 | { | ||
384 | actcapi_msg *m; | ||
385 | struct sk_buff *skb; | ||
386 | |||
387 | ACTCAPI_MKHDR(17, 0x84, 0x00); | ||
388 | ACTCAPI_CHKSKB; | ||
389 | m->msg.disconnect_b3_req.ncci = chan->ncci; | ||
390 | memset(&m->msg.disconnect_b3_req.ncpi, 0, | ||
391 | sizeof(m->msg.disconnect_b3_req.ncpi)); | ||
392 | m->msg.disconnect_b3_req.ncpi.len = 13; | ||
393 | m->msg.disconnect_b3_req.ncpi.modulo = 8; | ||
394 | chan->fsm_state = ACT2000_STATE_BHWAIT; | ||
395 | ACTCAPI_QUEUE_TX; | ||
396 | } | ||
397 | |||
398 | void | ||
399 | actcapi_connect_resp(act2000_card *card, act2000_chan *chan, __u8 cause) | ||
400 | { | ||
401 | actcapi_msg *m; | ||
402 | struct sk_buff *skb; | ||
403 | |||
404 | ACTCAPI_MKHDR(3, 0x02, 0x03); | ||
405 | ACTCAPI_CHKSKB; | ||
406 | m->msg.connect_resp.plci = chan->plci; | ||
407 | m->msg.connect_resp.rejectcause = cause; | ||
408 | if (cause) { | ||
409 | chan->fsm_state = ACT2000_STATE_NULL; | ||
410 | chan->plci = 0x8000; | ||
411 | } else | ||
412 | chan->fsm_state = ACT2000_STATE_IWAIT; | ||
413 | ACTCAPI_QUEUE_TX; | ||
414 | } | ||
415 | |||
416 | static void | ||
417 | actcapi_connect_active_resp(act2000_card *card, act2000_chan *chan) | ||
418 | { | ||
419 | actcapi_msg *m; | ||
420 | struct sk_buff *skb; | ||
421 | |||
422 | ACTCAPI_MKHDR(2, 0x03, 0x03); | ||
423 | ACTCAPI_CHKSKB; | ||
424 | m->msg.connect_resp.plci = chan->plci; | ||
425 | if (chan->fsm_state == ACT2000_STATE_IWAIT) | ||
426 | chan->fsm_state = ACT2000_STATE_IBWAIT; | ||
427 | ACTCAPI_QUEUE_TX; | ||
428 | } | ||
429 | |||
430 | static void | ||
431 | actcapi_connect_b3_resp(act2000_card *card, act2000_chan *chan, __u8 rejectcause) | ||
432 | { | ||
433 | actcapi_msg *m; | ||
434 | struct sk_buff *skb; | ||
435 | |||
436 | ACTCAPI_MKHDR((rejectcause?3:17), 0x82, 0x03); | ||
437 | ACTCAPI_CHKSKB; | ||
438 | m->msg.connect_b3_resp.ncci = chan->ncci; | ||
439 | m->msg.connect_b3_resp.rejectcause = rejectcause; | ||
440 | if (!rejectcause) { | ||
441 | memset(&m->msg.connect_b3_resp.ncpi, 0, | ||
442 | sizeof(m->msg.connect_b3_resp.ncpi)); | ||
443 | m->msg.connect_b3_resp.ncpi.len = 13; | ||
444 | m->msg.connect_b3_resp.ncpi.modulo = 8; | ||
445 | chan->fsm_state = ACT2000_STATE_BWAIT; | ||
446 | } | ||
447 | ACTCAPI_QUEUE_TX; | ||
448 | } | ||
449 | |||
450 | static void | ||
451 | actcapi_connect_b3_active_resp(act2000_card *card, act2000_chan *chan) | ||
452 | { | ||
453 | actcapi_msg *m; | ||
454 | struct sk_buff *skb; | ||
455 | |||
456 | ACTCAPI_MKHDR(2, 0x83, 0x03); | ||
457 | ACTCAPI_CHKSKB; | ||
458 | m->msg.connect_b3_active_resp.ncci = chan->ncci; | ||
459 | chan->fsm_state = ACT2000_STATE_ACTIVE; | ||
460 | ACTCAPI_QUEUE_TX; | ||
461 | } | ||
462 | |||
463 | static void | ||
464 | actcapi_info_resp(act2000_card *card, act2000_chan *chan) | ||
465 | { | ||
466 | actcapi_msg *m; | ||
467 | struct sk_buff *skb; | ||
468 | |||
469 | ACTCAPI_MKHDR(2, 0x07, 0x03); | ||
470 | ACTCAPI_CHKSKB; | ||
471 | m->msg.info_resp.plci = chan->plci; | ||
472 | ACTCAPI_QUEUE_TX; | ||
473 | } | ||
474 | |||
475 | static void | ||
476 | actcapi_disconnect_b3_resp(act2000_card *card, act2000_chan *chan) | ||
477 | { | ||
478 | actcapi_msg *m; | ||
479 | struct sk_buff *skb; | ||
480 | |||
481 | ACTCAPI_MKHDR(2, 0x84, 0x03); | ||
482 | ACTCAPI_CHKSKB; | ||
483 | m->msg.disconnect_b3_resp.ncci = chan->ncci; | ||
484 | chan->ncci = 0x8000; | ||
485 | chan->queued = 0; | ||
486 | ACTCAPI_QUEUE_TX; | ||
487 | } | ||
488 | |||
489 | static void | ||
490 | actcapi_disconnect_resp(act2000_card *card, act2000_chan *chan) | ||
491 | { | ||
492 | actcapi_msg *m; | ||
493 | struct sk_buff *skb; | ||
494 | |||
495 | ACTCAPI_MKHDR(2, 0x04, 0x03); | ||
496 | ACTCAPI_CHKSKB; | ||
497 | m->msg.disconnect_resp.plci = chan->plci; | ||
498 | chan->plci = 0x8000; | ||
499 | ACTCAPI_QUEUE_TX; | ||
500 | } | ||
501 | |||
502 | static int | ||
503 | new_plci(act2000_card *card, __u16 plci) | ||
504 | { | ||
505 | int i; | ||
506 | for (i = 0; i < ACT2000_BCH; i++) | ||
507 | if (card->bch[i].plci == 0x8000) { | ||
508 | card->bch[i].plci = plci; | ||
509 | return i; | ||
510 | } | ||
511 | return -1; | ||
512 | } | ||
513 | |||
514 | static int | ||
515 | find_plci(act2000_card *card, __u16 plci) | ||
516 | { | ||
517 | int i; | ||
518 | for (i = 0; i < ACT2000_BCH; i++) | ||
519 | if (card->bch[i].plci == plci) | ||
520 | return i; | ||
521 | return -1; | ||
522 | } | ||
523 | |||
524 | static int | ||
525 | find_ncci(act2000_card *card, __u16 ncci) | ||
526 | { | ||
527 | int i; | ||
528 | for (i = 0; i < ACT2000_BCH; i++) | ||
529 | if (card->bch[i].ncci == ncci) | ||
530 | return i; | ||
531 | return -1; | ||
532 | } | ||
533 | |||
534 | static int | ||
535 | find_dialing(act2000_card *card, __u16 callref) | ||
536 | { | ||
537 | int i; | ||
538 | for (i = 0; i < ACT2000_BCH; i++) | ||
539 | if ((card->bch[i].callref == callref) && | ||
540 | (card->bch[i].fsm_state == ACT2000_STATE_OCALL)) | ||
541 | return i; | ||
542 | return -1; | ||
543 | } | ||
544 | |||
545 | static int | ||
546 | actcapi_data_b3_ind(act2000_card *card, struct sk_buff *skb) { | ||
547 | __u16 plci; | ||
548 | __u16 ncci; | ||
549 | __u16 controller; | ||
550 | __u8 blocknr; | ||
551 | int chan; | ||
552 | actcapi_msg *msg = (actcapi_msg *)skb->data; | ||
553 | |||
554 | EVAL_NCCI(msg->msg.data_b3_ind.fakencci, plci, controller, ncci); | ||
555 | chan = find_ncci(card, ncci); | ||
556 | if (chan < 0) | ||
557 | return 0; | ||
558 | if (card->bch[chan].fsm_state != ACT2000_STATE_ACTIVE) | ||
559 | return 0; | ||
560 | if (card->bch[chan].plci != plci) | ||
561 | return 0; | ||
562 | blocknr = msg->msg.data_b3_ind.blocknr; | ||
563 | skb_pull(skb, 19); | ||
564 | card->interface.rcvcallb_skb(card->myid, chan, skb); | ||
565 | if (!(skb = alloc_skb(11, GFP_ATOMIC))) { | ||
566 | printk(KERN_WARNING "actcapi: alloc_skb failed\n"); | ||
567 | return 1; | ||
568 | } | ||
569 | msg = (actcapi_msg *)skb_put(skb, 11); | ||
570 | msg->hdr.len = 11; | ||
571 | msg->hdr.applicationID = 1; | ||
572 | msg->hdr.cmd.cmd = 0x86; | ||
573 | msg->hdr.cmd.subcmd = 0x03; | ||
574 | msg->hdr.msgnum = actcapi_nextsmsg(card); | ||
575 | msg->msg.data_b3_resp.ncci = ncci; | ||
576 | msg->msg.data_b3_resp.blocknr = blocknr; | ||
577 | ACTCAPI_QUEUE_TX; | ||
578 | return 1; | ||
579 | } | ||
580 | |||
581 | /* | ||
582 | * Walk over ackq, unlink DATA_B3_REQ from it, if | ||
583 | * ncci and blocknr are matching. | ||
584 | * Decrement queued-bytes counter. | ||
585 | */ | ||
586 | static int | ||
587 | handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) { | ||
588 | unsigned long flags; | ||
589 | struct sk_buff *skb; | ||
590 | struct sk_buff *tmp; | ||
591 | struct actcapi_msg *m; | ||
592 | int ret = 0; | ||
593 | |||
594 | spin_lock_irqsave(&card->lock, flags); | ||
595 | skb = skb_peek(&card->ackq); | ||
596 | spin_unlock_irqrestore(&card->lock, flags); | ||
597 | if (!skb) { | ||
598 | printk(KERN_WARNING "act2000: handle_ack nothing found!\n"); | ||
599 | return 0; | ||
600 | } | ||
601 | tmp = skb; | ||
602 | while (1) { | ||
603 | m = (actcapi_msg *)tmp->data; | ||
604 | if ((((m->msg.data_b3_req.fakencci >> 8) & 0xff) == chan->ncci) && | ||
605 | (m->msg.data_b3_req.blocknr == blocknr)) { | ||
606 | /* found corresponding DATA_B3_REQ */ | ||
607 | skb_unlink(tmp); | ||
608 | chan->queued -= m->msg.data_b3_req.datalen; | ||
609 | if (m->msg.data_b3_req.flags) | ||
610 | ret = m->msg.data_b3_req.datalen; | ||
611 | dev_kfree_skb(tmp); | ||
612 | if (chan->queued < 0) | ||
613 | chan->queued = 0; | ||
614 | return ret; | ||
615 | } | ||
616 | spin_lock_irqsave(&card->lock, flags); | ||
617 | tmp = skb_peek((struct sk_buff_head *)tmp); | ||
618 | spin_unlock_irqrestore(&card->lock, flags); | ||
619 | if ((tmp == skb) || (tmp == NULL)) { | ||
620 | /* reached end of queue */ | ||
621 | printk(KERN_WARNING "act2000: handle_ack nothing found!\n"); | ||
622 | return 0; | ||
623 | } | ||
624 | } | ||
625 | } | ||
626 | |||
627 | void | ||
628 | actcapi_dispatch(act2000_card *card) | ||
629 | { | ||
630 | struct sk_buff *skb; | ||
631 | actcapi_msg *msg; | ||
632 | __u16 ccmd; | ||
633 | int chan; | ||
634 | int len; | ||
635 | act2000_chan *ctmp; | ||
636 | isdn_ctrl cmd; | ||
637 | char tmp[170]; | ||
638 | |||
639 | while ((skb = skb_dequeue(&card->rcvq))) { | ||
640 | actcapi_debug_msg(skb, 0); | ||
641 | msg = (actcapi_msg *)skb->data; | ||
642 | ccmd = ((msg->hdr.cmd.cmd << 8) | msg->hdr.cmd.subcmd); | ||
643 | switch (ccmd) { | ||
644 | case 0x8602: | ||
645 | /* DATA_B3_IND */ | ||
646 | if (actcapi_data_b3_ind(card, skb)) | ||
647 | return; | ||
648 | break; | ||
649 | case 0x8601: | ||
650 | /* DATA_B3_CONF */ | ||
651 | chan = find_ncci(card, msg->msg.data_b3_conf.ncci); | ||
652 | if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_ACTIVE)) { | ||
653 | if (msg->msg.data_b3_conf.info != 0) | ||
654 | printk(KERN_WARNING "act2000: DATA_B3_CONF: %04x\n", | ||
655 | msg->msg.data_b3_conf.info); | ||
656 | len = handle_ack(card, &card->bch[chan], | ||
657 | msg->msg.data_b3_conf.blocknr); | ||
658 | if (len) { | ||
659 | cmd.driver = card->myid; | ||
660 | cmd.command = ISDN_STAT_BSENT; | ||
661 | cmd.arg = chan; | ||
662 | cmd.parm.length = len; | ||
663 | card->interface.statcallb(&cmd); | ||
664 | } | ||
665 | } | ||
666 | break; | ||
667 | case 0x0201: | ||
668 | /* CONNECT_CONF */ | ||
669 | chan = find_dialing(card, msg->hdr.msgnum); | ||
670 | if (chan >= 0) { | ||
671 | if (msg->msg.connect_conf.info) { | ||
672 | card->bch[chan].fsm_state = ACT2000_STATE_NULL; | ||
673 | cmd.driver = card->myid; | ||
674 | cmd.command = ISDN_STAT_DHUP; | ||
675 | cmd.arg = chan; | ||
676 | card->interface.statcallb(&cmd); | ||
677 | } else { | ||
678 | card->bch[chan].fsm_state = ACT2000_STATE_OWAIT; | ||
679 | card->bch[chan].plci = msg->msg.connect_conf.plci; | ||
680 | } | ||
681 | } | ||
682 | break; | ||
683 | case 0x0202: | ||
684 | /* CONNECT_IND */ | ||
685 | chan = new_plci(card, msg->msg.connect_ind.plci); | ||
686 | if (chan < 0) { | ||
687 | ctmp = (act2000_chan *)tmp; | ||
688 | ctmp->plci = msg->msg.connect_ind.plci; | ||
689 | actcapi_connect_resp(card, ctmp, 0x11); /* All Card-Cannels busy */ | ||
690 | } else { | ||
691 | card->bch[chan].fsm_state = ACT2000_STATE_ICALL; | ||
692 | cmd.driver = card->myid; | ||
693 | cmd.command = ISDN_STAT_ICALL; | ||
694 | cmd.arg = chan; | ||
695 | cmd.parm.setup.si1 = msg->msg.connect_ind.si1; | ||
696 | cmd.parm.setup.si2 = msg->msg.connect_ind.si2; | ||
697 | if (card->ptype == ISDN_PTYPE_EURO) | ||
698 | strcpy(cmd.parm.setup.eazmsn, | ||
699 | act2000_find_eaz(card, msg->msg.connect_ind.eaz)); | ||
700 | else { | ||
701 | cmd.parm.setup.eazmsn[0] = msg->msg.connect_ind.eaz; | ||
702 | cmd.parm.setup.eazmsn[1] = 0; | ||
703 | } | ||
704 | memset(cmd.parm.setup.phone, 0, sizeof(cmd.parm.setup.phone)); | ||
705 | memcpy(cmd.parm.setup.phone, msg->msg.connect_ind.addr.num, | ||
706 | msg->msg.connect_ind.addr.len - 1); | ||
707 | cmd.parm.setup.plan = msg->msg.connect_ind.addr.tnp; | ||
708 | cmd.parm.setup.screen = 0; | ||
709 | if (card->interface.statcallb(&cmd) == 2) | ||
710 | actcapi_connect_resp(card, &card->bch[chan], 0x15); /* Reject Call */ | ||
711 | } | ||
712 | break; | ||
713 | case 0x0302: | ||
714 | /* CONNECT_ACTIVE_IND */ | ||
715 | chan = find_plci(card, msg->msg.connect_active_ind.plci); | ||
716 | if (chan >= 0) | ||
717 | switch (card->bch[chan].fsm_state) { | ||
718 | case ACT2000_STATE_IWAIT: | ||
719 | actcapi_connect_active_resp(card, &card->bch[chan]); | ||
720 | break; | ||
721 | case ACT2000_STATE_OWAIT: | ||
722 | actcapi_connect_active_resp(card, &card->bch[chan]); | ||
723 | actcapi_select_b2_protocol_req(card, &card->bch[chan]); | ||
724 | break; | ||
725 | } | ||
726 | break; | ||
727 | case 0x8202: | ||
728 | /* CONNECT_B3_IND */ | ||
729 | chan = find_plci(card, msg->msg.connect_b3_ind.plci); | ||
730 | if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_IBWAIT)) { | ||
731 | card->bch[chan].ncci = msg->msg.connect_b3_ind.ncci; | ||
732 | actcapi_connect_b3_resp(card, &card->bch[chan], 0); | ||
733 | } else { | ||
734 | ctmp = (act2000_chan *)tmp; | ||
735 | ctmp->ncci = msg->msg.connect_b3_ind.ncci; | ||
736 | actcapi_connect_b3_resp(card, ctmp, 0x11); /* All Card-Cannels busy */ | ||
737 | } | ||
738 | break; | ||
739 | case 0x8302: | ||
740 | /* CONNECT_B3_ACTIVE_IND */ | ||
741 | chan = find_ncci(card, msg->msg.connect_b3_active_ind.ncci); | ||
742 | if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BWAIT)) { | ||
743 | actcapi_connect_b3_active_resp(card, &card->bch[chan]); | ||
744 | cmd.driver = card->myid; | ||
745 | cmd.command = ISDN_STAT_BCONN; | ||
746 | cmd.arg = chan; | ||
747 | card->interface.statcallb(&cmd); | ||
748 | } | ||
749 | break; | ||
750 | case 0x8402: | ||
751 | /* DISCONNECT_B3_IND */ | ||
752 | chan = find_ncci(card, msg->msg.disconnect_b3_ind.ncci); | ||
753 | if (chan >= 0) { | ||
754 | ctmp = &card->bch[chan]; | ||
755 | actcapi_disconnect_b3_resp(card, ctmp); | ||
756 | switch (ctmp->fsm_state) { | ||
757 | case ACT2000_STATE_ACTIVE: | ||
758 | ctmp->fsm_state = ACT2000_STATE_DHWAIT2; | ||
759 | cmd.driver = card->myid; | ||
760 | cmd.command = ISDN_STAT_BHUP; | ||
761 | cmd.arg = chan; | ||
762 | card->interface.statcallb(&cmd); | ||
763 | break; | ||
764 | case ACT2000_STATE_BHWAIT2: | ||
765 | actcapi_disconnect_req(card, ctmp); | ||
766 | ctmp->fsm_state = ACT2000_STATE_DHWAIT; | ||
767 | cmd.driver = card->myid; | ||
768 | cmd.command = ISDN_STAT_BHUP; | ||
769 | cmd.arg = chan; | ||
770 | card->interface.statcallb(&cmd); | ||
771 | break; | ||
772 | } | ||
773 | } | ||
774 | break; | ||
775 | case 0x0402: | ||
776 | /* DISCONNECT_IND */ | ||
777 | chan = find_plci(card, msg->msg.disconnect_ind.plci); | ||
778 | if (chan >= 0) { | ||
779 | ctmp = &card->bch[chan]; | ||
780 | actcapi_disconnect_resp(card, ctmp); | ||
781 | ctmp->fsm_state = ACT2000_STATE_NULL; | ||
782 | cmd.driver = card->myid; | ||
783 | cmd.command = ISDN_STAT_DHUP; | ||
784 | cmd.arg = chan; | ||
785 | card->interface.statcallb(&cmd); | ||
786 | } else { | ||
787 | ctmp = (act2000_chan *)tmp; | ||
788 | ctmp->plci = msg->msg.disconnect_ind.plci; | ||
789 | actcapi_disconnect_resp(card, ctmp); | ||
790 | } | ||
791 | break; | ||
792 | case 0x4001: | ||
793 | /* SELECT_B2_PROTOCOL_CONF */ | ||
794 | chan = find_plci(card, msg->msg.select_b2_protocol_conf.plci); | ||
795 | if (chan >= 0) | ||
796 | switch (card->bch[chan].fsm_state) { | ||
797 | case ACT2000_STATE_ICALL: | ||
798 | case ACT2000_STATE_OWAIT: | ||
799 | ctmp = &card->bch[chan]; | ||
800 | if (msg->msg.select_b2_protocol_conf.info == 0) | ||
801 | actcapi_select_b3_protocol_req(card, ctmp); | ||
802 | else { | ||
803 | ctmp->fsm_state = ACT2000_STATE_NULL; | ||
804 | cmd.driver = card->myid; | ||
805 | cmd.command = ISDN_STAT_DHUP; | ||
806 | cmd.arg = chan; | ||
807 | card->interface.statcallb(&cmd); | ||
808 | } | ||
809 | break; | ||
810 | } | ||
811 | break; | ||
812 | case 0x8001: | ||
813 | /* SELECT_B3_PROTOCOL_CONF */ | ||
814 | chan = find_plci(card, msg->msg.select_b3_protocol_conf.plci); | ||
815 | if (chan >= 0) | ||
816 | switch (card->bch[chan].fsm_state) { | ||
817 | case ACT2000_STATE_ICALL: | ||
818 | case ACT2000_STATE_OWAIT: | ||
819 | ctmp = &card->bch[chan]; | ||
820 | if (msg->msg.select_b3_protocol_conf.info == 0) | ||
821 | actcapi_listen_b3_req(card, ctmp); | ||
822 | else { | ||
823 | ctmp->fsm_state = ACT2000_STATE_NULL; | ||
824 | cmd.driver = card->myid; | ||
825 | cmd.command = ISDN_STAT_DHUP; | ||
826 | cmd.arg = chan; | ||
827 | card->interface.statcallb(&cmd); | ||
828 | } | ||
829 | } | ||
830 | break; | ||
831 | case 0x8101: | ||
832 | /* LISTEN_B3_CONF */ | ||
833 | chan = find_plci(card, msg->msg.listen_b3_conf.plci); | ||
834 | if (chan >= 0) | ||
835 | switch (card->bch[chan].fsm_state) { | ||
836 | case ACT2000_STATE_ICALL: | ||
837 | ctmp = &card->bch[chan]; | ||
838 | if (msg->msg.listen_b3_conf.info == 0) | ||
839 | actcapi_connect_resp(card, ctmp, 0); | ||
840 | else { | ||
841 | ctmp->fsm_state = ACT2000_STATE_NULL; | ||
842 | cmd.driver = card->myid; | ||
843 | cmd.command = ISDN_STAT_DHUP; | ||
844 | cmd.arg = chan; | ||
845 | card->interface.statcallb(&cmd); | ||
846 | } | ||
847 | break; | ||
848 | case ACT2000_STATE_OWAIT: | ||
849 | ctmp = &card->bch[chan]; | ||
850 | if (msg->msg.listen_b3_conf.info == 0) { | ||
851 | actcapi_connect_b3_req(card, ctmp); | ||
852 | ctmp->fsm_state = ACT2000_STATE_OBWAIT; | ||
853 | cmd.driver = card->myid; | ||
854 | cmd.command = ISDN_STAT_DCONN; | ||
855 | cmd.arg = chan; | ||
856 | card->interface.statcallb(&cmd); | ||
857 | } else { | ||
858 | ctmp->fsm_state = ACT2000_STATE_NULL; | ||
859 | cmd.driver = card->myid; | ||
860 | cmd.command = ISDN_STAT_DHUP; | ||
861 | cmd.arg = chan; | ||
862 | card->interface.statcallb(&cmd); | ||
863 | } | ||
864 | break; | ||
865 | } | ||
866 | break; | ||
867 | case 0x8201: | ||
868 | /* CONNECT_B3_CONF */ | ||
869 | chan = find_plci(card, msg->msg.connect_b3_conf.plci); | ||
870 | if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_OBWAIT)) { | ||
871 | ctmp = &card->bch[chan]; | ||
872 | if (msg->msg.connect_b3_conf.info) { | ||
873 | ctmp->fsm_state = ACT2000_STATE_NULL; | ||
874 | cmd.driver = card->myid; | ||
875 | cmd.command = ISDN_STAT_DHUP; | ||
876 | cmd.arg = chan; | ||
877 | card->interface.statcallb(&cmd); | ||
878 | } else { | ||
879 | ctmp->ncci = msg->msg.connect_b3_conf.ncci; | ||
880 | ctmp->fsm_state = ACT2000_STATE_BWAIT; | ||
881 | } | ||
882 | } | ||
883 | break; | ||
884 | case 0x8401: | ||
885 | /* DISCONNECT_B3_CONF */ | ||
886 | chan = find_ncci(card, msg->msg.disconnect_b3_conf.ncci); | ||
887 | if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BHWAIT)) | ||
888 | card->bch[chan].fsm_state = ACT2000_STATE_BHWAIT2; | ||
889 | break; | ||
890 | case 0x0702: | ||
891 | /* INFO_IND */ | ||
892 | chan = find_plci(card, msg->msg.info_ind.plci); | ||
893 | if (chan >= 0) | ||
894 | /* TODO: Eval Charging info / cause */ | ||
895 | actcapi_info_resp(card, &card->bch[chan]); | ||
896 | break; | ||
897 | case 0x0401: | ||
898 | /* LISTEN_CONF */ | ||
899 | case 0x0501: | ||
900 | /* LISTEN_CONF */ | ||
901 | case 0xff01: | ||
902 | /* MANUFACTURER_CONF */ | ||
903 | break; | ||
904 | case 0xff02: | ||
905 | /* MANUFACTURER_IND */ | ||
906 | if (msg->msg.manuf_msg == 3) { | ||
907 | memset(tmp, 0, sizeof(tmp)); | ||
908 | strncpy(tmp, | ||
909 | &msg->msg.manufacturer_ind_err.errstring, | ||
910 | msg->hdr.len - 16); | ||
911 | if (msg->msg.manufacturer_ind_err.errcode) | ||
912 | printk(KERN_WARNING "act2000: %s\n", tmp); | ||
913 | else { | ||
914 | printk(KERN_DEBUG "act2000: %s\n", tmp); | ||
915 | if ((!strncmp(tmp, "INFO: Trace buffer con", 22)) || | ||
916 | (!strncmp(tmp, "INFO: Compile Date/Tim", 22))) { | ||
917 | card->flags |= ACT2000_FLAGS_RUNNING; | ||
918 | cmd.command = ISDN_STAT_RUN; | ||
919 | cmd.driver = card->myid; | ||
920 | cmd.arg = 0; | ||
921 | actcapi_manufacturer_req_net(card); | ||
922 | actcapi_manufacturer_req_msn(card); | ||
923 | actcapi_listen_req(card); | ||
924 | card->interface.statcallb(&cmd); | ||
925 | } | ||
926 | } | ||
927 | } | ||
928 | break; | ||
929 | default: | ||
930 | printk(KERN_WARNING "act2000: UNHANDLED Message %04x\n", ccmd); | ||
931 | break; | ||
932 | } | ||
933 | dev_kfree_skb(skb); | ||
934 | } | ||
935 | } | ||
936 | |||
937 | #ifdef DEBUG_MSG | ||
938 | static void | ||
939 | actcapi_debug_caddr(actcapi_addr *addr) | ||
940 | { | ||
941 | char tmp[30]; | ||
942 | |||
943 | printk(KERN_DEBUG " Alen = %d\n", addr->len); | ||
944 | if (addr->len > 0) | ||
945 | printk(KERN_DEBUG " Atnp = 0x%02x\n", addr->tnp); | ||
946 | if (addr->len > 1) { | ||
947 | memset(tmp, 0, 30); | ||
948 | memcpy(tmp, addr->num, addr->len - 1); | ||
949 | printk(KERN_DEBUG " Anum = '%s'\n", tmp); | ||
950 | } | ||
951 | } | ||
952 | |||
953 | static void | ||
954 | actcapi_debug_ncpi(actcapi_ncpi *ncpi) | ||
955 | { | ||
956 | printk(KERN_DEBUG " ncpi.len = %d\n", ncpi->len); | ||
957 | if (ncpi->len >= 2) | ||
958 | printk(KERN_DEBUG " ncpi.lic = 0x%04x\n", ncpi->lic); | ||
959 | if (ncpi->len >= 4) | ||
960 | printk(KERN_DEBUG " ncpi.hic = 0x%04x\n", ncpi->hic); | ||
961 | if (ncpi->len >= 6) | ||
962 | printk(KERN_DEBUG " ncpi.ltc = 0x%04x\n", ncpi->ltc); | ||
963 | if (ncpi->len >= 8) | ||
964 | printk(KERN_DEBUG " ncpi.htc = 0x%04x\n", ncpi->htc); | ||
965 | if (ncpi->len >= 10) | ||
966 | printk(KERN_DEBUG " ncpi.loc = 0x%04x\n", ncpi->loc); | ||
967 | if (ncpi->len >= 12) | ||
968 | printk(KERN_DEBUG " ncpi.hoc = 0x%04x\n", ncpi->hoc); | ||
969 | if (ncpi->len >= 13) | ||
970 | printk(KERN_DEBUG " ncpi.mod = %d\n", ncpi->modulo); | ||
971 | } | ||
972 | |||
973 | static void | ||
974 | actcapi_debug_dlpd(actcapi_dlpd *dlpd) | ||
975 | { | ||
976 | printk(KERN_DEBUG " dlpd.len = %d\n", dlpd->len); | ||
977 | if (dlpd->len >= 2) | ||
978 | printk(KERN_DEBUG " dlpd.dlen = 0x%04x\n", dlpd->dlen); | ||
979 | if (dlpd->len >= 3) | ||
980 | printk(KERN_DEBUG " dlpd.laa = 0x%02x\n", dlpd->laa); | ||
981 | if (dlpd->len >= 4) | ||
982 | printk(KERN_DEBUG " dlpd.lab = 0x%02x\n", dlpd->lab); | ||
983 | if (dlpd->len >= 5) | ||
984 | printk(KERN_DEBUG " dlpd.modulo = %d\n", dlpd->modulo); | ||
985 | if (dlpd->len >= 6) | ||
986 | printk(KERN_DEBUG " dlpd.win = %d\n", dlpd->win); | ||
987 | } | ||
988 | |||
989 | #ifdef DEBUG_DUMP_SKB | ||
990 | static void dump_skb(struct sk_buff *skb) { | ||
991 | char tmp[80]; | ||
992 | char *p = skb->data; | ||
993 | char *t = tmp; | ||
994 | int i; | ||
995 | |||
996 | for (i = 0; i < skb->len; i++) { | ||
997 | t += sprintf(t, "%02x ", *p++ & 0xff); | ||
998 | if ((i & 0x0f) == 8) { | ||
999 | printk(KERN_DEBUG "dump: %s\n", tmp); | ||
1000 | t = tmp; | ||
1001 | } | ||
1002 | } | ||
1003 | if (i & 0x07) | ||
1004 | printk(KERN_DEBUG "dump: %s\n", tmp); | ||
1005 | } | ||
1006 | #endif | ||
1007 | |||
1008 | void | ||
1009 | actcapi_debug_msg(struct sk_buff *skb, int direction) | ||
1010 | { | ||
1011 | actcapi_msg *msg = (actcapi_msg *)skb->data; | ||
1012 | char *descr; | ||
1013 | int i; | ||
1014 | char tmp[170]; | ||
1015 | |||
1016 | #ifndef DEBUG_DATA_MSG | ||
1017 | if (msg->hdr.cmd.cmd == 0x86) | ||
1018 | return; | ||
1019 | #endif | ||
1020 | descr = "INVALID"; | ||
1021 | #ifdef DEBUG_DUMP_SKB | ||
1022 | dump_skb(skb); | ||
1023 | #endif | ||
1024 | for (i = 0; i < num_valid_msg; i++) | ||
1025 | if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) && | ||
1026 | (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) { | ||
1027 | descr = valid_msg[i].description; | ||
1028 | break; | ||
1029 | } | ||
1030 | printk(KERN_DEBUG "%s %s msg\n", direction?"Outgoing":"Incoming", descr); | ||
1031 | printk(KERN_DEBUG " ApplID = %d\n", msg->hdr.applicationID); | ||
1032 | printk(KERN_DEBUG " Len = %d\n", msg->hdr.len); | ||
1033 | printk(KERN_DEBUG " MsgNum = 0x%04x\n", msg->hdr.msgnum); | ||
1034 | printk(KERN_DEBUG " Cmd = 0x%02x\n", msg->hdr.cmd.cmd); | ||
1035 | printk(KERN_DEBUG " SubCmd = 0x%02x\n", msg->hdr.cmd.subcmd); | ||
1036 | switch (i) { | ||
1037 | case 0: | ||
1038 | /* DATA B3 IND */ | ||
1039 | printk(KERN_DEBUG " BLOCK = 0x%02x\n", | ||
1040 | msg->msg.data_b3_ind.blocknr); | ||
1041 | break; | ||
1042 | case 2: | ||
1043 | /* CONNECT CONF */ | ||
1044 | printk(KERN_DEBUG " PLCI = 0x%04x\n", | ||
1045 | msg->msg.connect_conf.plci); | ||
1046 | printk(KERN_DEBUG " Info = 0x%04x\n", | ||
1047 | msg->msg.connect_conf.info); | ||
1048 | break; | ||
1049 | case 3: | ||
1050 | /* CONNECT IND */ | ||
1051 | printk(KERN_DEBUG " PLCI = 0x%04x\n", | ||
1052 | msg->msg.connect_ind.plci); | ||
1053 | printk(KERN_DEBUG " Contr = %d\n", | ||
1054 | msg->msg.connect_ind.controller); | ||
1055 | printk(KERN_DEBUG " SI1 = %d\n", | ||
1056 | msg->msg.connect_ind.si1); | ||
1057 | printk(KERN_DEBUG " SI2 = %d\n", | ||
1058 | msg->msg.connect_ind.si2); | ||
1059 | printk(KERN_DEBUG " EAZ = '%c'\n", | ||
1060 | msg->msg.connect_ind.eaz); | ||
1061 | actcapi_debug_caddr(&msg->msg.connect_ind.addr); | ||
1062 | break; | ||
1063 | case 5: | ||
1064 | /* CONNECT ACTIVE IND */ | ||
1065 | printk(KERN_DEBUG " PLCI = 0x%04x\n", | ||
1066 | msg->msg.connect_active_ind.plci); | ||
1067 | actcapi_debug_caddr(&msg->msg.connect_active_ind.addr); | ||
1068 | break; | ||
1069 | case 8: | ||
1070 | /* LISTEN CONF */ | ||
1071 | printk(KERN_DEBUG " Contr = %d\n", | ||
1072 | msg->msg.listen_conf.controller); | ||
1073 | printk(KERN_DEBUG " Info = 0x%04x\n", | ||
1074 | msg->msg.listen_conf.info); | ||
1075 | break; | ||
1076 | case 11: | ||
1077 | /* INFO IND */ | ||
1078 | printk(KERN_DEBUG " PLCI = 0x%04x\n", | ||
1079 | msg->msg.info_ind.plci); | ||
1080 | printk(KERN_DEBUG " Imsk = 0x%04x\n", | ||
1081 | msg->msg.info_ind.nr.mask); | ||
1082 | if (msg->hdr.len > 12) { | ||
1083 | int l = msg->hdr.len - 12; | ||
1084 | int j; | ||
1085 | char *p = tmp; | ||
1086 | for (j = 0; j < l ; j++) | ||
1087 | p += sprintf(p, "%02x ", msg->msg.info_ind.el.display[j]); | ||
1088 | printk(KERN_DEBUG " D = '%s'\n", tmp); | ||
1089 | } | ||
1090 | break; | ||
1091 | case 14: | ||
1092 | /* SELECT B2 PROTOCOL CONF */ | ||
1093 | printk(KERN_DEBUG " PLCI = 0x%04x\n", | ||
1094 | msg->msg.select_b2_protocol_conf.plci); | ||
1095 | printk(KERN_DEBUG " Info = 0x%04x\n", | ||
1096 | msg->msg.select_b2_protocol_conf.info); | ||
1097 | break; | ||
1098 | case 15: | ||
1099 | /* SELECT B3 PROTOCOL CONF */ | ||
1100 | printk(KERN_DEBUG " PLCI = 0x%04x\n", | ||
1101 | msg->msg.select_b3_protocol_conf.plci); | ||
1102 | printk(KERN_DEBUG " Info = 0x%04x\n", | ||
1103 | msg->msg.select_b3_protocol_conf.info); | ||
1104 | break; | ||
1105 | case 16: | ||
1106 | /* LISTEN B3 CONF */ | ||
1107 | printk(KERN_DEBUG " PLCI = 0x%04x\n", | ||
1108 | msg->msg.listen_b3_conf.plci); | ||
1109 | printk(KERN_DEBUG " Info = 0x%04x\n", | ||
1110 | msg->msg.listen_b3_conf.info); | ||
1111 | break; | ||
1112 | case 18: | ||
1113 | /* CONNECT B3 IND */ | ||
1114 | printk(KERN_DEBUG " NCCI = 0x%04x\n", | ||
1115 | msg->msg.connect_b3_ind.ncci); | ||
1116 | printk(KERN_DEBUG " PLCI = 0x%04x\n", | ||
1117 | msg->msg.connect_b3_ind.plci); | ||
1118 | actcapi_debug_ncpi(&msg->msg.connect_b3_ind.ncpi); | ||
1119 | break; | ||
1120 | case 19: | ||
1121 | /* CONNECT B3 ACTIVE IND */ | ||
1122 | printk(KERN_DEBUG " NCCI = 0x%04x\n", | ||
1123 | msg->msg.connect_b3_active_ind.ncci); | ||
1124 | actcapi_debug_ncpi(&msg->msg.connect_b3_active_ind.ncpi); | ||
1125 | break; | ||
1126 | case 26: | ||
1127 | /* MANUFACTURER IND */ | ||
1128 | printk(KERN_DEBUG " Mmsg = 0x%02x\n", | ||
1129 | msg->msg.manufacturer_ind_err.manuf_msg); | ||
1130 | switch (msg->msg.manufacturer_ind_err.manuf_msg) { | ||
1131 | case 3: | ||
1132 | printk(KERN_DEBUG " Contr = %d\n", | ||
1133 | msg->msg.manufacturer_ind_err.controller); | ||
1134 | printk(KERN_DEBUG " Code = 0x%08x\n", | ||
1135 | msg->msg.manufacturer_ind_err.errcode); | ||
1136 | memset(tmp, 0, sizeof(tmp)); | ||
1137 | strncpy(tmp, &msg->msg.manufacturer_ind_err.errstring, | ||
1138 | msg->hdr.len - 16); | ||
1139 | printk(KERN_DEBUG " Emsg = '%s'\n", tmp); | ||
1140 | break; | ||
1141 | } | ||
1142 | break; | ||
1143 | case 30: | ||
1144 | /* LISTEN REQ */ | ||
1145 | printk(KERN_DEBUG " Imsk = 0x%08x\n", | ||
1146 | msg->msg.listen_req.infomask); | ||
1147 | printk(KERN_DEBUG " Emsk = 0x%04x\n", | ||
1148 | msg->msg.listen_req.eazmask); | ||
1149 | printk(KERN_DEBUG " Smsk = 0x%04x\n", | ||
1150 | msg->msg.listen_req.simask); | ||
1151 | break; | ||
1152 | case 35: | ||
1153 | /* SELECT_B2_PROTOCOL_REQ */ | ||
1154 | printk(KERN_DEBUG " PLCI = 0x%04x\n", | ||
1155 | msg->msg.select_b2_protocol_req.plci); | ||
1156 | printk(KERN_DEBUG " prot = 0x%02x\n", | ||
1157 | msg->msg.select_b2_protocol_req.protocol); | ||
1158 | if (msg->hdr.len >= 11) | ||
1159 | printk(KERN_DEBUG "No dlpd\n"); | ||
1160 | else | ||
1161 | actcapi_debug_dlpd(&msg->msg.select_b2_protocol_req.dlpd); | ||
1162 | break; | ||
1163 | case 44: | ||
1164 | /* CONNECT RESP */ | ||
1165 | printk(KERN_DEBUG " PLCI = 0x%04x\n", | ||
1166 | msg->msg.connect_resp.plci); | ||
1167 | printk(KERN_DEBUG " CAUSE = 0x%02x\n", | ||
1168 | msg->msg.connect_resp.rejectcause); | ||
1169 | break; | ||
1170 | case 45: | ||
1171 | /* CONNECT ACTIVE RESP */ | ||
1172 | printk(KERN_DEBUG " PLCI = 0x%04x\n", | ||
1173 | msg->msg.connect_active_resp.plci); | ||
1174 | break; | ||
1175 | } | ||
1176 | } | ||
1177 | #endif | ||