diff options
Diffstat (limited to 'drivers/isdn/hisax/isdnl1.c')
-rw-r--r-- | drivers/isdn/hisax/isdnl1.c | 932 |
1 files changed, 932 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c new file mode 100644 index 000000000000..4d08d27f1499 --- /dev/null +++ b/drivers/isdn/hisax/isdnl1.c | |||
@@ -0,0 +1,932 @@ | |||
1 | /* $Id: isdnl1.c,v 2.46.2.5 2004/02/11 13:21:34 keil Exp $ | ||
2 | * | ||
3 | * common low level stuff for Siemens Chipsetbased isdn cards | ||
4 | * | ||
5 | * Author Karsten Keil | ||
6 | * based on the teles driver from Jan den Ouden | ||
7 | * Copyright by Karsten Keil <keil@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 | * For changes and modifications please read | ||
13 | * Documentation/isdn/HiSax.cert | ||
14 | * | ||
15 | * Thanks to Jan den Ouden | ||
16 | * Fritz Elfert | ||
17 | * Beat Doebeli | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | const char *l1_revision = "$Revision: 2.46.2.5 $"; | ||
22 | |||
23 | #include <linux/init.h> | ||
24 | #include "hisax.h" | ||
25 | #include "isdnl1.h" | ||
26 | |||
27 | #define TIMER3_VALUE 7000 | ||
28 | |||
29 | static struct Fsm l1fsm_b; | ||
30 | static struct Fsm l1fsm_s; | ||
31 | |||
32 | enum { | ||
33 | ST_L1_F2, | ||
34 | ST_L1_F3, | ||
35 | ST_L1_F4, | ||
36 | ST_L1_F5, | ||
37 | ST_L1_F6, | ||
38 | ST_L1_F7, | ||
39 | ST_L1_F8, | ||
40 | }; | ||
41 | |||
42 | #define L1S_STATE_COUNT (ST_L1_F8+1) | ||
43 | |||
44 | static char *strL1SState[] = | ||
45 | { | ||
46 | "ST_L1_F2", | ||
47 | "ST_L1_F3", | ||
48 | "ST_L1_F4", | ||
49 | "ST_L1_F5", | ||
50 | "ST_L1_F6", | ||
51 | "ST_L1_F7", | ||
52 | "ST_L1_F8", | ||
53 | }; | ||
54 | |||
55 | #ifdef HISAX_UINTERFACE | ||
56 | static | ||
57 | struct Fsm l1fsm_u = | ||
58 | {NULL, 0, 0, NULL, NULL}; | ||
59 | |||
60 | enum { | ||
61 | ST_L1_RESET, | ||
62 | ST_L1_DEACT, | ||
63 | ST_L1_SYNC2, | ||
64 | ST_L1_TRANS, | ||
65 | }; | ||
66 | |||
67 | #define L1U_STATE_COUNT (ST_L1_TRANS+1) | ||
68 | |||
69 | static char *strL1UState[] = | ||
70 | { | ||
71 | "ST_L1_RESET", | ||
72 | "ST_L1_DEACT", | ||
73 | "ST_L1_SYNC2", | ||
74 | "ST_L1_TRANS", | ||
75 | }; | ||
76 | #endif | ||
77 | |||
78 | enum { | ||
79 | ST_L1_NULL, | ||
80 | ST_L1_WAIT_ACT, | ||
81 | ST_L1_WAIT_DEACT, | ||
82 | ST_L1_ACTIV, | ||
83 | }; | ||
84 | |||
85 | #define L1B_STATE_COUNT (ST_L1_ACTIV+1) | ||
86 | |||
87 | static char *strL1BState[] = | ||
88 | { | ||
89 | "ST_L1_NULL", | ||
90 | "ST_L1_WAIT_ACT", | ||
91 | "ST_L1_WAIT_DEACT", | ||
92 | "ST_L1_ACTIV", | ||
93 | }; | ||
94 | |||
95 | enum { | ||
96 | EV_PH_ACTIVATE, | ||
97 | EV_PH_DEACTIVATE, | ||
98 | EV_RESET_IND, | ||
99 | EV_DEACT_CNF, | ||
100 | EV_DEACT_IND, | ||
101 | EV_POWER_UP, | ||
102 | EV_RSYNC_IND, | ||
103 | EV_INFO2_IND, | ||
104 | EV_INFO4_IND, | ||
105 | EV_TIMER_DEACT, | ||
106 | EV_TIMER_ACT, | ||
107 | EV_TIMER3, | ||
108 | }; | ||
109 | |||
110 | #define L1_EVENT_COUNT (EV_TIMER3 + 1) | ||
111 | |||
112 | static char *strL1Event[] = | ||
113 | { | ||
114 | "EV_PH_ACTIVATE", | ||
115 | "EV_PH_DEACTIVATE", | ||
116 | "EV_RESET_IND", | ||
117 | "EV_DEACT_CNF", | ||
118 | "EV_DEACT_IND", | ||
119 | "EV_POWER_UP", | ||
120 | "EV_RSYNC_IND", | ||
121 | "EV_INFO2_IND", | ||
122 | "EV_INFO4_IND", | ||
123 | "EV_TIMER_DEACT", | ||
124 | "EV_TIMER_ACT", | ||
125 | "EV_TIMER3", | ||
126 | }; | ||
127 | |||
128 | void | ||
129 | debugl1(struct IsdnCardState *cs, char *fmt, ...) | ||
130 | { | ||
131 | va_list args; | ||
132 | char tmp[8]; | ||
133 | |||
134 | va_start(args, fmt); | ||
135 | sprintf(tmp, "Card%d ", cs->cardnr + 1); | ||
136 | VHiSax_putstatus(cs, tmp, fmt, args); | ||
137 | va_end(args); | ||
138 | } | ||
139 | |||
140 | static void | ||
141 | l1m_debug(struct FsmInst *fi, char *fmt, ...) | ||
142 | { | ||
143 | va_list args; | ||
144 | struct PStack *st = fi->userdata; | ||
145 | struct IsdnCardState *cs = st->l1.hardware; | ||
146 | char tmp[8]; | ||
147 | |||
148 | va_start(args, fmt); | ||
149 | sprintf(tmp, "Card%d ", cs->cardnr + 1); | ||
150 | VHiSax_putstatus(cs, tmp, fmt, args); | ||
151 | va_end(args); | ||
152 | } | ||
153 | |||
154 | void | ||
155 | L1activated(struct IsdnCardState *cs) | ||
156 | { | ||
157 | struct PStack *st; | ||
158 | |||
159 | st = cs->stlist; | ||
160 | while (st) { | ||
161 | if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) | ||
162 | st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); | ||
163 | else | ||
164 | st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL); | ||
165 | st = st->next; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | void | ||
170 | L1deactivated(struct IsdnCardState *cs) | ||
171 | { | ||
172 | struct PStack *st; | ||
173 | |||
174 | st = cs->stlist; | ||
175 | while (st) { | ||
176 | if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags)) | ||
177 | st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL); | ||
178 | st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL); | ||
179 | st = st->next; | ||
180 | } | ||
181 | test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags); | ||
182 | } | ||
183 | |||
184 | void | ||
185 | DChannel_proc_xmt(struct IsdnCardState *cs) | ||
186 | { | ||
187 | struct PStack *stptr; | ||
188 | |||
189 | if (cs->tx_skb) | ||
190 | return; | ||
191 | |||
192 | stptr = cs->stlist; | ||
193 | while (stptr != NULL) { | ||
194 | if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) { | ||
195 | stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL); | ||
196 | break; | ||
197 | } else | ||
198 | stptr = stptr->next; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | void | ||
203 | DChannel_proc_rcv(struct IsdnCardState *cs) | ||
204 | { | ||
205 | struct sk_buff *skb, *nskb; | ||
206 | struct PStack *stptr = cs->stlist; | ||
207 | int found, tei, sapi; | ||
208 | |||
209 | if (stptr) | ||
210 | if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags)) | ||
211 | FsmEvent(&stptr->l1.l1m, EV_TIMER_ACT, NULL); | ||
212 | while ((skb = skb_dequeue(&cs->rq))) { | ||
213 | #ifdef L2FRAME_DEBUG /* psa */ | ||
214 | if (cs->debug & L1_DEB_LAPD) | ||
215 | Logl2Frame(cs, skb, "PH_DATA", 1); | ||
216 | #endif | ||
217 | stptr = cs->stlist; | ||
218 | if (skb->len<3) { | ||
219 | debugl1(cs, "D-channel frame too short(%d)",skb->len); | ||
220 | dev_kfree_skb(skb); | ||
221 | return; | ||
222 | } | ||
223 | if ((skb->data[0] & 1) || !(skb->data[1] &1)) { | ||
224 | debugl1(cs, "D-channel frame wrong EA0/EA1"); | ||
225 | dev_kfree_skb(skb); | ||
226 | return; | ||
227 | } | ||
228 | sapi = skb->data[0] >> 2; | ||
229 | tei = skb->data[1] >> 1; | ||
230 | if (cs->debug & DEB_DLOG_HEX) | ||
231 | LogFrame(cs, skb->data, skb->len); | ||
232 | if (cs->debug & DEB_DLOG_VERBOSE) | ||
233 | dlogframe(cs, skb, 1); | ||
234 | if (tei == GROUP_TEI) { | ||
235 | if (sapi == CTRL_SAPI) { /* sapi 0 */ | ||
236 | while (stptr != NULL) { | ||
237 | if ((nskb = skb_clone(skb, GFP_ATOMIC))) | ||
238 | stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb); | ||
239 | else | ||
240 | printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n"); | ||
241 | stptr = stptr->next; | ||
242 | } | ||
243 | } else if (sapi == TEI_SAPI) { | ||
244 | while (stptr != NULL) { | ||
245 | if ((nskb = skb_clone(skb, GFP_ATOMIC))) | ||
246 | stptr->l1.l1tei(stptr, PH_DATA | INDICATION, nskb); | ||
247 | else | ||
248 | printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n"); | ||
249 | stptr = stptr->next; | ||
250 | } | ||
251 | } | ||
252 | dev_kfree_skb(skb); | ||
253 | } else if (sapi == CTRL_SAPI) { /* sapi 0 */ | ||
254 | found = 0; | ||
255 | while (stptr != NULL) | ||
256 | if (tei == stptr->l2.tei) { | ||
257 | stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb); | ||
258 | found = !0; | ||
259 | break; | ||
260 | } else | ||
261 | stptr = stptr->next; | ||
262 | if (!found) | ||
263 | dev_kfree_skb(skb); | ||
264 | } else | ||
265 | dev_kfree_skb(skb); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | static void | ||
270 | BChannel_proc_xmt(struct BCState *bcs) | ||
271 | { | ||
272 | struct PStack *st = bcs->st; | ||
273 | |||
274 | if (test_bit(BC_FLG_BUSY, &bcs->Flag)) { | ||
275 | debugl1(bcs->cs, "BC_BUSY Error"); | ||
276 | return; | ||
277 | } | ||
278 | |||
279 | if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) | ||
280 | st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); | ||
281 | if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) { | ||
282 | if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) { | ||
283 | st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); | ||
284 | } | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static void | ||
289 | BChannel_proc_rcv(struct BCState *bcs) | ||
290 | { | ||
291 | struct sk_buff *skb; | ||
292 | |||
293 | if (bcs->st->l1.l1m.state == ST_L1_WAIT_ACT) { | ||
294 | FsmDelTimer(&bcs->st->l1.timer, 4); | ||
295 | FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL); | ||
296 | } | ||
297 | while ((skb = skb_dequeue(&bcs->rqueue))) { | ||
298 | bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | static void | ||
303 | BChannel_proc_ack(struct BCState *bcs) | ||
304 | { | ||
305 | u_long flags; | ||
306 | int ack; | ||
307 | |||
308 | spin_lock_irqsave(&bcs->aclock, flags); | ||
309 | ack = bcs->ackcnt; | ||
310 | bcs->ackcnt = 0; | ||
311 | spin_unlock_irqrestore(&bcs->aclock, flags); | ||
312 | if (ack) | ||
313 | lli_writewakeup(bcs->st, ack); | ||
314 | } | ||
315 | |||
316 | void | ||
317 | BChannel_bh(struct BCState *bcs) | ||
318 | { | ||
319 | if (!bcs) | ||
320 | return; | ||
321 | if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event)) | ||
322 | BChannel_proc_rcv(bcs); | ||
323 | if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event)) | ||
324 | BChannel_proc_xmt(bcs); | ||
325 | if (test_and_clear_bit(B_ACKPENDING, &bcs->event)) | ||
326 | BChannel_proc_ack(bcs); | ||
327 | } | ||
328 | |||
329 | void | ||
330 | HiSax_addlist(struct IsdnCardState *cs, | ||
331 | struct PStack *st) | ||
332 | { | ||
333 | st->next = cs->stlist; | ||
334 | cs->stlist = st; | ||
335 | } | ||
336 | |||
337 | void | ||
338 | HiSax_rmlist(struct IsdnCardState *cs, | ||
339 | struct PStack *st) | ||
340 | { | ||
341 | struct PStack *p; | ||
342 | |||
343 | FsmDelTimer(&st->l1.timer, 0); | ||
344 | if (cs->stlist == st) | ||
345 | cs->stlist = st->next; | ||
346 | else { | ||
347 | p = cs->stlist; | ||
348 | while (p) | ||
349 | if (p->next == st) { | ||
350 | p->next = st->next; | ||
351 | return; | ||
352 | } else | ||
353 | p = p->next; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | void | ||
358 | init_bcstate(struct IsdnCardState *cs, int bc) | ||
359 | { | ||
360 | struct BCState *bcs = cs->bcs + bc; | ||
361 | |||
362 | bcs->cs = cs; | ||
363 | bcs->channel = bc; | ||
364 | INIT_WORK(&bcs->tqueue, (void *)(void *) BChannel_bh, bcs); | ||
365 | spin_lock_init(&bcs->aclock); | ||
366 | bcs->BC_SetStack = NULL; | ||
367 | bcs->BC_Close = NULL; | ||
368 | bcs->Flag = 0; | ||
369 | } | ||
370 | |||
371 | #ifdef L2FRAME_DEBUG /* psa */ | ||
372 | |||
373 | char * | ||
374 | l2cmd(u_char cmd) | ||
375 | { | ||
376 | switch (cmd & ~0x10) { | ||
377 | case 1: | ||
378 | return "RR"; | ||
379 | case 5: | ||
380 | return "RNR"; | ||
381 | case 9: | ||
382 | return "REJ"; | ||
383 | case 0x6f: | ||
384 | return "SABME"; | ||
385 | case 0x0f: | ||
386 | return "DM"; | ||
387 | case 3: | ||
388 | return "UI"; | ||
389 | case 0x43: | ||
390 | return "DISC"; | ||
391 | case 0x63: | ||
392 | return "UA"; | ||
393 | case 0x87: | ||
394 | return "FRMR"; | ||
395 | case 0xaf: | ||
396 | return "XID"; | ||
397 | default: | ||
398 | if (!(cmd & 1)) | ||
399 | return "I"; | ||
400 | else | ||
401 | return "invalid command"; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | static char tmpdeb[32]; | ||
406 | |||
407 | char * | ||
408 | l2frames(u_char * ptr) | ||
409 | { | ||
410 | switch (ptr[2] & ~0x10) { | ||
411 | case 1: | ||
412 | case 5: | ||
413 | case 9: | ||
414 | sprintf(tmpdeb, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1); | ||
415 | break; | ||
416 | case 0x6f: | ||
417 | case 0x0f: | ||
418 | case 3: | ||
419 | case 0x43: | ||
420 | case 0x63: | ||
421 | case 0x87: | ||
422 | case 0xaf: | ||
423 | sprintf(tmpdeb, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4); | ||
424 | break; | ||
425 | default: | ||
426 | if (!(ptr[2] & 1)) { | ||
427 | sprintf(tmpdeb, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1); | ||
428 | break; | ||
429 | } else | ||
430 | return "invalid command"; | ||
431 | } | ||
432 | |||
433 | |||
434 | return tmpdeb; | ||
435 | } | ||
436 | |||
437 | void | ||
438 | Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir) | ||
439 | { | ||
440 | u_char *ptr; | ||
441 | |||
442 | ptr = skb->data; | ||
443 | |||
444 | if (ptr[0] & 1 || !(ptr[1] & 1)) | ||
445 | debugl1(cs, "Address not LAPD"); | ||
446 | else | ||
447 | debugl1(cs, "%s %s: %s%c (sapi %d, tei %d)", | ||
448 | (dir ? "<-" : "->"), buf, l2frames(ptr), | ||
449 | ((ptr[0] & 2) >> 1) == dir ? 'C' : 'R', ptr[0] >> 2, ptr[1] >> 1); | ||
450 | } | ||
451 | #endif | ||
452 | |||
453 | static void | ||
454 | l1_reset(struct FsmInst *fi, int event, void *arg) | ||
455 | { | ||
456 | FsmChangeState(fi, ST_L1_F3); | ||
457 | } | ||
458 | |||
459 | static void | ||
460 | l1_deact_cnf(struct FsmInst *fi, int event, void *arg) | ||
461 | { | ||
462 | struct PStack *st = fi->userdata; | ||
463 | |||
464 | FsmChangeState(fi, ST_L1_F3); | ||
465 | if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) | ||
466 | st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); | ||
467 | } | ||
468 | |||
469 | static void | ||
470 | l1_deact_req_s(struct FsmInst *fi, int event, void *arg) | ||
471 | { | ||
472 | struct PStack *st = fi->userdata; | ||
473 | |||
474 | FsmChangeState(fi, ST_L1_F3); | ||
475 | FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); | ||
476 | test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); | ||
477 | } | ||
478 | |||
479 | static void | ||
480 | l1_power_up_s(struct FsmInst *fi, int event, void *arg) | ||
481 | { | ||
482 | struct PStack *st = fi->userdata; | ||
483 | |||
484 | if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) { | ||
485 | FsmChangeState(fi, ST_L1_F4); | ||
486 | st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); | ||
487 | FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); | ||
488 | test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); | ||
489 | } else | ||
490 | FsmChangeState(fi, ST_L1_F3); | ||
491 | } | ||
492 | |||
493 | static void | ||
494 | l1_go_F5(struct FsmInst *fi, int event, void *arg) | ||
495 | { | ||
496 | FsmChangeState(fi, ST_L1_F5); | ||
497 | } | ||
498 | |||
499 | static void | ||
500 | l1_go_F8(struct FsmInst *fi, int event, void *arg) | ||
501 | { | ||
502 | FsmChangeState(fi, ST_L1_F8); | ||
503 | } | ||
504 | |||
505 | static void | ||
506 | l1_info2_ind(struct FsmInst *fi, int event, void *arg) | ||
507 | { | ||
508 | struct PStack *st = fi->userdata; | ||
509 | |||
510 | #ifdef HISAX_UINTERFACE | ||
511 | if (test_bit(FLG_L1_UINT, &st->l1.Flags)) | ||
512 | FsmChangeState(fi, ST_L1_SYNC2); | ||
513 | else | ||
514 | #endif | ||
515 | FsmChangeState(fi, ST_L1_F6); | ||
516 | st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); | ||
517 | } | ||
518 | |||
519 | static void | ||
520 | l1_info4_ind(struct FsmInst *fi, int event, void *arg) | ||
521 | { | ||
522 | struct PStack *st = fi->userdata; | ||
523 | |||
524 | #ifdef HISAX_UINTERFACE | ||
525 | if (test_bit(FLG_L1_UINT, &st->l1.Flags)) | ||
526 | FsmChangeState(fi, ST_L1_TRANS); | ||
527 | else | ||
528 | #endif | ||
529 | FsmChangeState(fi, ST_L1_F7); | ||
530 | st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); | ||
531 | if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) | ||
532 | FsmDelTimer(&st->l1.timer, 4); | ||
533 | if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) { | ||
534 | if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags)) | ||
535 | FsmDelTimer(&st->l1.timer, 3); | ||
536 | FsmRestartTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2); | ||
537 | test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | static void | ||
542 | l1_timer3(struct FsmInst *fi, int event, void *arg) | ||
543 | { | ||
544 | struct PStack *st = fi->userdata; | ||
545 | |||
546 | test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags); | ||
547 | if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) | ||
548 | L1deactivated(st->l1.hardware); | ||
549 | |||
550 | #ifdef HISAX_UINTERFACE | ||
551 | if (!test_bit(FLG_L1_UINT, &st->l1.Flags)) | ||
552 | #endif | ||
553 | if (st->l1.l1m.state != ST_L1_F6) { | ||
554 | FsmChangeState(fi, ST_L1_F3); | ||
555 | st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); | ||
556 | } | ||
557 | } | ||
558 | |||
559 | static void | ||
560 | l1_timer_act(struct FsmInst *fi, int event, void *arg) | ||
561 | { | ||
562 | struct PStack *st = fi->userdata; | ||
563 | |||
564 | test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags); | ||
565 | test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags); | ||
566 | L1activated(st->l1.hardware); | ||
567 | } | ||
568 | |||
569 | static void | ||
570 | l1_timer_deact(struct FsmInst *fi, int event, void *arg) | ||
571 | { | ||
572 | struct PStack *st = fi->userdata; | ||
573 | |||
574 | test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); | ||
575 | test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags); | ||
576 | L1deactivated(st->l1.hardware); | ||
577 | st->l1.l1hw(st, HW_DEACTIVATE | RESPONSE, NULL); | ||
578 | } | ||
579 | |||
580 | static void | ||
581 | l1_activate_s(struct FsmInst *fi, int event, void *arg) | ||
582 | { | ||
583 | struct PStack *st = fi->userdata; | ||
584 | |||
585 | st->l1.l1hw(st, HW_RESET | REQUEST, NULL); | ||
586 | } | ||
587 | |||
588 | static void | ||
589 | l1_activate_no(struct FsmInst *fi, int event, void *arg) | ||
590 | { | ||
591 | struct PStack *st = fi->userdata; | ||
592 | |||
593 | if ((!test_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) && (!test_bit(FLG_L1_T3RUN, &st->l1.Flags))) { | ||
594 | test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags); | ||
595 | L1deactivated(st->l1.hardware); | ||
596 | } | ||
597 | } | ||
598 | |||
599 | static struct FsmNode L1SFnList[] __initdata = | ||
600 | { | ||
601 | {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, | ||
602 | {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, | ||
603 | {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, | ||
604 | {ST_L1_F3, EV_RESET_IND, l1_reset}, | ||
605 | {ST_L1_F4, EV_RESET_IND, l1_reset}, | ||
606 | {ST_L1_F5, EV_RESET_IND, l1_reset}, | ||
607 | {ST_L1_F6, EV_RESET_IND, l1_reset}, | ||
608 | {ST_L1_F7, EV_RESET_IND, l1_reset}, | ||
609 | {ST_L1_F8, EV_RESET_IND, l1_reset}, | ||
610 | {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf}, | ||
611 | {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf}, | ||
612 | {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf}, | ||
613 | {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, | ||
614 | {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, | ||
615 | {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, | ||
616 | {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, | ||
617 | {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, | ||
618 | {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, | ||
619 | {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, | ||
620 | {ST_L1_F4, EV_RSYNC_IND, l1_go_F5}, | ||
621 | {ST_L1_F6, EV_RSYNC_IND, l1_go_F8}, | ||
622 | {ST_L1_F7, EV_RSYNC_IND, l1_go_F8}, | ||
623 | {ST_L1_F3, EV_INFO2_IND, l1_info2_ind}, | ||
624 | {ST_L1_F4, EV_INFO2_IND, l1_info2_ind}, | ||
625 | {ST_L1_F5, EV_INFO2_IND, l1_info2_ind}, | ||
626 | {ST_L1_F7, EV_INFO2_IND, l1_info2_ind}, | ||
627 | {ST_L1_F8, EV_INFO2_IND, l1_info2_ind}, | ||
628 | {ST_L1_F3, EV_INFO4_IND, l1_info4_ind}, | ||
629 | {ST_L1_F4, EV_INFO4_IND, l1_info4_ind}, | ||
630 | {ST_L1_F5, EV_INFO4_IND, l1_info4_ind}, | ||
631 | {ST_L1_F6, EV_INFO4_IND, l1_info4_ind}, | ||
632 | {ST_L1_F8, EV_INFO4_IND, l1_info4_ind}, | ||
633 | {ST_L1_F3, EV_TIMER3, l1_timer3}, | ||
634 | {ST_L1_F4, EV_TIMER3, l1_timer3}, | ||
635 | {ST_L1_F5, EV_TIMER3, l1_timer3}, | ||
636 | {ST_L1_F6, EV_TIMER3, l1_timer3}, | ||
637 | {ST_L1_F8, EV_TIMER3, l1_timer3}, | ||
638 | {ST_L1_F7, EV_TIMER_ACT, l1_timer_act}, | ||
639 | {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact}, | ||
640 | {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact}, | ||
641 | {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact}, | ||
642 | {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact}, | ||
643 | {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact}, | ||
644 | {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, | ||
645 | }; | ||
646 | |||
647 | #define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode)) | ||
648 | |||
649 | #ifdef HISAX_UINTERFACE | ||
650 | static void | ||
651 | l1_deact_req_u(struct FsmInst *fi, int event, void *arg) | ||
652 | { | ||
653 | struct PStack *st = fi->userdata; | ||
654 | |||
655 | FsmChangeState(fi, ST_L1_RESET); | ||
656 | FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); | ||
657 | test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); | ||
658 | st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); | ||
659 | } | ||
660 | |||
661 | static void | ||
662 | l1_power_up_u(struct FsmInst *fi, int event, void *arg) | ||
663 | { | ||
664 | struct PStack *st = fi->userdata; | ||
665 | |||
666 | FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); | ||
667 | test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); | ||
668 | } | ||
669 | |||
670 | static void | ||
671 | l1_info0_ind(struct FsmInst *fi, int event, void *arg) | ||
672 | { | ||
673 | FsmChangeState(fi, ST_L1_DEACT); | ||
674 | } | ||
675 | |||
676 | static void | ||
677 | l1_activate_u(struct FsmInst *fi, int event, void *arg) | ||
678 | { | ||
679 | struct PStack *st = fi->userdata; | ||
680 | |||
681 | st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL); | ||
682 | } | ||
683 | |||
684 | static struct FsmNode L1UFnList[] __initdata = | ||
685 | { | ||
686 | {ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u}, | ||
687 | {ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u}, | ||
688 | {ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u}, | ||
689 | {ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u}, | ||
690 | {ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u}, | ||
691 | {ST_L1_DEACT, EV_POWER_UP, l1_power_up_u}, | ||
692 | {ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind}, | ||
693 | {ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind}, | ||
694 | {ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind}, | ||
695 | {ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind}, | ||
696 | {ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind}, | ||
697 | {ST_L1_RESET, EV_INFO4_IND, l1_info4_ind}, | ||
698 | {ST_L1_DEACT, EV_TIMER3, l1_timer3}, | ||
699 | {ST_L1_SYNC2, EV_TIMER3, l1_timer3}, | ||
700 | {ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act}, | ||
701 | {ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact}, | ||
702 | {ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact}, | ||
703 | {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact}, | ||
704 | }; | ||
705 | |||
706 | #define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode)) | ||
707 | |||
708 | #endif | ||
709 | |||
710 | static void | ||
711 | l1b_activate(struct FsmInst *fi, int event, void *arg) | ||
712 | { | ||
713 | struct PStack *st = fi->userdata; | ||
714 | |||
715 | FsmChangeState(fi, ST_L1_WAIT_ACT); | ||
716 | FsmRestartTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2); | ||
717 | } | ||
718 | |||
719 | static void | ||
720 | l1b_deactivate(struct FsmInst *fi, int event, void *arg) | ||
721 | { | ||
722 | struct PStack *st = fi->userdata; | ||
723 | |||
724 | FsmChangeState(fi, ST_L1_WAIT_DEACT); | ||
725 | FsmRestartTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2); | ||
726 | } | ||
727 | |||
728 | static void | ||
729 | l1b_timer_act(struct FsmInst *fi, int event, void *arg) | ||
730 | { | ||
731 | struct PStack *st = fi->userdata; | ||
732 | |||
733 | FsmChangeState(fi, ST_L1_ACTIV); | ||
734 | st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); | ||
735 | } | ||
736 | |||
737 | static void | ||
738 | l1b_timer_deact(struct FsmInst *fi, int event, void *arg) | ||
739 | { | ||
740 | struct PStack *st = fi->userdata; | ||
741 | |||
742 | FsmChangeState(fi, ST_L1_NULL); | ||
743 | st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); | ||
744 | } | ||
745 | |||
746 | static struct FsmNode L1BFnList[] __initdata = | ||
747 | { | ||
748 | {ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate}, | ||
749 | {ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act}, | ||
750 | {ST_L1_ACTIV, EV_PH_DEACTIVATE, l1b_deactivate}, | ||
751 | {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact}, | ||
752 | }; | ||
753 | |||
754 | #define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode)) | ||
755 | |||
756 | int __init | ||
757 | Isdnl1New(void) | ||
758 | { | ||
759 | int retval; | ||
760 | |||
761 | l1fsm_s.state_count = L1S_STATE_COUNT; | ||
762 | l1fsm_s.event_count = L1_EVENT_COUNT; | ||
763 | l1fsm_s.strEvent = strL1Event; | ||
764 | l1fsm_s.strState = strL1SState; | ||
765 | retval = FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT); | ||
766 | if (retval) | ||
767 | return retval; | ||
768 | |||
769 | l1fsm_b.state_count = L1B_STATE_COUNT; | ||
770 | l1fsm_b.event_count = L1_EVENT_COUNT; | ||
771 | l1fsm_b.strEvent = strL1Event; | ||
772 | l1fsm_b.strState = strL1BState; | ||
773 | retval = FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT); | ||
774 | if (retval) { | ||
775 | FsmFree(&l1fsm_s); | ||
776 | return retval; | ||
777 | } | ||
778 | #ifdef HISAX_UINTERFACE | ||
779 | l1fsm_u.state_count = L1U_STATE_COUNT; | ||
780 | l1fsm_u.event_count = L1_EVENT_COUNT; | ||
781 | l1fsm_u.strEvent = strL1Event; | ||
782 | l1fsm_u.strState = strL1UState; | ||
783 | retval = FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT); | ||
784 | if (retval) { | ||
785 | FsmFree(&l1fsm_s); | ||
786 | FsmFree(&l1fsm_b); | ||
787 | return retval; | ||
788 | } | ||
789 | #endif | ||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | void Isdnl1Free(void) | ||
794 | { | ||
795 | #ifdef HISAX_UINTERFACE | ||
796 | FsmFree(&l1fsm_u); | ||
797 | #endif | ||
798 | FsmFree(&l1fsm_s); | ||
799 | FsmFree(&l1fsm_b); | ||
800 | } | ||
801 | |||
802 | static void | ||
803 | dch_l2l1(struct PStack *st, int pr, void *arg) | ||
804 | { | ||
805 | struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; | ||
806 | |||
807 | switch (pr) { | ||
808 | case (PH_DATA | REQUEST): | ||
809 | case (PH_PULL | REQUEST): | ||
810 | case (PH_PULL |INDICATION): | ||
811 | st->l1.l1hw(st, pr, arg); | ||
812 | break; | ||
813 | case (PH_ACTIVATE | REQUEST): | ||
814 | if (cs->debug) | ||
815 | debugl1(cs, "PH_ACTIVATE_REQ %s", | ||
816 | st->l1.l1m.fsm->strState[st->l1.l1m.state]); | ||
817 | if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) | ||
818 | st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); | ||
819 | else { | ||
820 | test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags); | ||
821 | FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg); | ||
822 | } | ||
823 | break; | ||
824 | case (PH_TESTLOOP | REQUEST): | ||
825 | if (1 & (long) arg) | ||
826 | debugl1(cs, "PH_TEST_LOOP B1"); | ||
827 | if (2 & (long) arg) | ||
828 | debugl1(cs, "PH_TEST_LOOP B2"); | ||
829 | if (!(3 & (long) arg)) | ||
830 | debugl1(cs, "PH_TEST_LOOP DISABLED"); | ||
831 | st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); | ||
832 | break; | ||
833 | default: | ||
834 | if (cs->debug) | ||
835 | debugl1(cs, "dch_l2l1 msg %04X unhandled", pr); | ||
836 | break; | ||
837 | } | ||
838 | } | ||
839 | |||
840 | void | ||
841 | l1_msg(struct IsdnCardState *cs, int pr, void *arg) { | ||
842 | struct PStack *st; | ||
843 | |||
844 | st = cs->stlist; | ||
845 | |||
846 | while (st) { | ||
847 | switch(pr) { | ||
848 | case (HW_RESET | INDICATION): | ||
849 | FsmEvent(&st->l1.l1m, EV_RESET_IND, arg); | ||
850 | break; | ||
851 | case (HW_DEACTIVATE | CONFIRM): | ||
852 | FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg); | ||
853 | break; | ||
854 | case (HW_DEACTIVATE | INDICATION): | ||
855 | FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg); | ||
856 | break; | ||
857 | case (HW_POWERUP | CONFIRM): | ||
858 | FsmEvent(&st->l1.l1m, EV_POWER_UP, arg); | ||
859 | break; | ||
860 | case (HW_RSYNC | INDICATION): | ||
861 | FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg); | ||
862 | break; | ||
863 | case (HW_INFO2 | INDICATION): | ||
864 | FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg); | ||
865 | break; | ||
866 | case (HW_INFO4_P8 | INDICATION): | ||
867 | case (HW_INFO4_P10 | INDICATION): | ||
868 | FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg); | ||
869 | break; | ||
870 | default: | ||
871 | if (cs->debug) | ||
872 | debugl1(cs, "l1msg %04X unhandled", pr); | ||
873 | break; | ||
874 | } | ||
875 | st = st->next; | ||
876 | } | ||
877 | } | ||
878 | |||
879 | void | ||
880 | l1_msg_b(struct PStack *st, int pr, void *arg) { | ||
881 | switch(pr) { | ||
882 | case (PH_ACTIVATE | REQUEST): | ||
883 | FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, NULL); | ||
884 | break; | ||
885 | case (PH_DEACTIVATE | REQUEST): | ||
886 | FsmEvent(&st->l1.l1m, EV_PH_DEACTIVATE, NULL); | ||
887 | break; | ||
888 | } | ||
889 | } | ||
890 | |||
891 | void | ||
892 | setstack_HiSax(struct PStack *st, struct IsdnCardState *cs) | ||
893 | { | ||
894 | st->l1.hardware = cs; | ||
895 | st->protocol = cs->protocol; | ||
896 | st->l1.l1m.fsm = &l1fsm_s; | ||
897 | st->l1.l1m.state = ST_L1_F3; | ||
898 | st->l1.Flags = 0; | ||
899 | #ifdef HISAX_UINTERFACE | ||
900 | if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) { | ||
901 | st->l1.l1m.fsm = &l1fsm_u; | ||
902 | st->l1.l1m.state = ST_L1_RESET; | ||
903 | st->l1.Flags = FLG_L1_UINT; | ||
904 | } | ||
905 | #endif | ||
906 | st->l1.l1m.debug = cs->debug; | ||
907 | st->l1.l1m.userdata = st; | ||
908 | st->l1.l1m.userint = 0; | ||
909 | st->l1.l1m.printdebug = l1m_debug; | ||
910 | FsmInitTimer(&st->l1.l1m, &st->l1.timer); | ||
911 | setstack_tei(st); | ||
912 | setstack_manager(st); | ||
913 | st->l1.stlistp = &(cs->stlist); | ||
914 | st->l2.l2l1 = dch_l2l1; | ||
915 | if (cs->setstack_d) | ||
916 | cs->setstack_d(st, cs); | ||
917 | } | ||
918 | |||
919 | void | ||
920 | setstack_l1_B(struct PStack *st) | ||
921 | { | ||
922 | struct IsdnCardState *cs = st->l1.hardware; | ||
923 | |||
924 | st->l1.l1m.fsm = &l1fsm_b; | ||
925 | st->l1.l1m.state = ST_L1_NULL; | ||
926 | st->l1.l1m.debug = cs->debug; | ||
927 | st->l1.l1m.userdata = st; | ||
928 | st->l1.l1m.userint = 0; | ||
929 | st->l1.l1m.printdebug = l1m_debug; | ||
930 | st->l1.Flags = 0; | ||
931 | FsmInitTimer(&st->l1.l1m, &st->l1.timer); | ||
932 | } | ||