Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / isdn / act2000 / capi.c
blob40395f567231570a10afa5040e09643b108016c0
1 /* $Id: capi.c,v 1.9.6.2 2001/09/23 22:24:32 kai Exp $
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
4 * CAPI encoder/decoder
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.
12 * Thanks to Friedemann Baitinger and IBM Germany
16 #include "act2000.h"
17 #include "capi.h"
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},
81 #define num_valid_msg (sizeof(valid_msg)/sizeof(actcapi_msgdsc))
82 #define num_valid_imsg 27 /* MANUFACTURER_IND */
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
91 int
92 actcapi_chkhdr(act2000_card * card, actcapi_msghdr *hdr)
94 int i;
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);
105 return 0;
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;\
120 #define ACTCAPI_CHKSKB if (!skb) { \
121 printk(KERN_WARNING "actcapi: alloc_skb failed\n"); \
122 return; \
125 #define ACTCAPI_QUEUE_TX { \
126 actcapi_debug_msg(skb, 1); \
127 skb_queue_tail(&card->sndq, skb); \
128 act2000_schedule_tx(card); \
132 actcapi_listen_req(act2000_card *card)
134 __u16 eazmask = 0;
135 int i;
136 actcapi_msg *m;
137 struct sk_buff *skb;
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;
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;
155 actcapi_connect_req(act2000_card *card, act2000_chan *chan, char *phone,
156 char eaz, int si1, int si2)
158 actcapi_msg *m;
159 struct sk_buff *skb;
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;
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;
181 static void
182 actcapi_connect_b3_req(act2000_card *card, act2000_chan *chan)
184 actcapi_msg *m;
185 struct sk_buff *skb;
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;
198 * Set net type (1TR6) or (EDSS1)
201 actcapi_manufacturer_req_net(act2000_card *card)
203 actcapi_msg *m;
204 struct sk_buff *skb;
206 ACTCAPI_MKHDR(5, 0xff, 0x00);
207 if (!skb) {
208 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
209 return -ENOMEM;
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;
225 * Switch V.42 on or off
228 actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
230 actcapi_msg *m;
231 struct sk_buff *skb;
233 ACTCAPI_MKHDR(8, 0xff, 0x00);
234 if (!skb) {
236 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
237 return -ENOMEM;
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;
247 * Set error-handler
250 actcapi_manufacturer_req_errh(act2000_card *card)
252 actcapi_msg *m;
253 struct sk_buff *skb;
255 ACTCAPI_MKHDR(4, 0xff, 0x00);
256 if (!skb) {
258 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
259 return -ENOMEM;
261 m->msg.manufacturer_req_err.manuf_msg = 0x03;
262 m->msg.manufacturer_req_err.controller = 0;
263 ACTCAPI_QUEUE_TX;
264 return 0;
268 * Set MSN-Mapping.
271 actcapi_manufacturer_req_msn(act2000_card *card)
273 msn_entry *p = card->msn_list;
274 actcapi_msg *m;
275 struct sk_buff *skb;
276 int len;
278 while (p) {
279 int i;
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;
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;
295 p = p->next;
297 return 0;
300 void
301 actcapi_select_b2_protocol_req(act2000_card *card, act2000_chan *chan)
303 actcapi_msg *m;
304 struct sk_buff *skb;
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;
332 ACTCAPI_QUEUE_TX;
335 static void
336 actcapi_select_b3_protocol_req(act2000_card *card, act2000_chan *chan)
338 actcapi_msg *m;
339 struct sk_buff *skb;
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;
353 ACTCAPI_QUEUE_TX;
356 static void
357 actcapi_listen_b3_req(act2000_card *card, act2000_chan *chan)
359 actcapi_msg *m;
360 struct sk_buff *skb;
362 ACTCAPI_MKHDR(2, 0x81, 0x00);
363 ACTCAPI_CHKSKB;
364 m->msg.listen_b3_req.plci = chan->plci;
365 ACTCAPI_QUEUE_TX;
368 static void
369 actcapi_disconnect_req(act2000_card *card, act2000_chan *chan)
371 actcapi_msg *m;
372 struct sk_buff *skb;
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;
381 void
382 actcapi_disconnect_b3_req(act2000_card *card, act2000_chan *chan)
384 actcapi_msg *m;
385 struct sk_buff *skb;
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;
398 void
399 actcapi_connect_resp(act2000_card *card, act2000_chan *chan, __u8 cause)
401 actcapi_msg *m;
402 struct sk_buff *skb;
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;
416 static void
417 actcapi_connect_active_resp(act2000_card *card, act2000_chan *chan)
419 actcapi_msg *m;
420 struct sk_buff *skb;
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;
430 static void
431 actcapi_connect_b3_resp(act2000_card *card, act2000_chan *chan, __u8 rejectcause)
433 actcapi_msg *m;
434 struct sk_buff *skb;
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;
447 ACTCAPI_QUEUE_TX;
450 static void
451 actcapi_connect_b3_active_resp(act2000_card *card, act2000_chan *chan)
453 actcapi_msg *m;
454 struct sk_buff *skb;
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;
463 static void
464 actcapi_info_resp(act2000_card *card, act2000_chan *chan)
466 actcapi_msg *m;
467 struct sk_buff *skb;
469 ACTCAPI_MKHDR(2, 0x07, 0x03);
470 ACTCAPI_CHKSKB;
471 m->msg.info_resp.plci = chan->plci;
472 ACTCAPI_QUEUE_TX;
475 static void
476 actcapi_disconnect_b3_resp(act2000_card *card, act2000_chan *chan)
478 actcapi_msg *m;
479 struct sk_buff *skb;
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;
489 static void
490 actcapi_disconnect_resp(act2000_card *card, act2000_chan *chan)
492 actcapi_msg *m;
493 struct sk_buff *skb;
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;
502 static int
503 new_plci(act2000_card *card, __u16 plci)
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;
511 return -1;
514 static int
515 find_plci(act2000_card *card, __u16 plci)
517 int i;
518 for (i = 0; i < ACT2000_BCH; i++)
519 if (card->bch[i].plci == plci)
520 return i;
521 return -1;
524 static int
525 find_ncci(act2000_card *card, __u16 ncci)
527 int i;
528 for (i = 0; i < ACT2000_BCH; i++)
529 if (card->bch[i].ncci == ncci)
530 return i;
531 return -1;
534 static int
535 find_dialing(act2000_card *card, __u16 callref)
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;
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;
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;
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;
582 * Walk over ackq, unlink DATA_B3_REQ from it, if
583 * ncci and blocknr are matching.
584 * Decrement queued-bytes counter.
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;
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;
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;
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;
627 void
628 actcapi_dispatch(act2000_card *card)
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];
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);
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;
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;
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 */
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;
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 */
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);
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;
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);
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);
809 break;
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);
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);
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);
864 break;
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;
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);
928 break;
929 default:
930 printk(KERN_WARNING "act2000: UNHANDLED Message %04x\n", ccmd);
931 break;
933 dev_kfree_skb(skb);
937 #ifdef DEBUG_MSG
938 static void
939 actcapi_debug_caddr(actcapi_addr *addr)
941 char tmp[30];
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);
953 static void
954 actcapi_debug_ncpi(actcapi_ncpi *ncpi)
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);
973 static void
974 actcapi_debug_dlpd(actcapi_dlpd *dlpd)
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);
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;
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;
1003 if (i & 0x07)
1004 printk(KERN_DEBUG "dump: %s\n", tmp);
1006 #endif
1008 void
1009 actcapi_debug_msg(struct sk_buff *skb, int direction)
1011 actcapi_msg *msg = (actcapi_msg *)skb->data;
1012 char *descr;
1013 int i;
1014 char tmp[170];
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;
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);
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;
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;
1177 #endif