PM / sleep: Asynchronous threads for suspend_noirq
[linux/fpc-iii.git] / drivers / isdn / hisax / hisax_isac.c
blob5154c252a25fe73e8d4af8de96955f2a2f245a69
1 /*
2 * Driver for ISAC-S and ISAC-SX
3 * ISDN Subscriber Access Controller for Terminals
5 * Author Kai Germaschewski
6 * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
7 * 2001 by Karsten Keil <keil@isdn4linux.de>
9 * based upon Karsten Keil's original isac.c driver
11 * This software may be used and distributed according to the terms
12 * of the GNU General Public License, incorporated herein by reference.
14 * Thanks to Wizard Computersysteme GmbH, Bremervoerde and
15 * SoHaNet Technology GmbH, Berlin
16 * for supporting the development of this driver
19 /* TODO:
20 * specifically handle level vs edge triggered?
23 #include <linux/module.h>
24 #include <linux/gfp.h>
25 #include <linux/init.h>
26 #include <linux/netdevice.h>
27 #include "hisax_isac.h"
29 // debugging cruft
31 #define __debug_variable debug
32 #include "hisax_debug.h"
34 #ifdef CONFIG_HISAX_DEBUG
35 static int debug = 1;
36 module_param(debug, int, 0);
38 static char *ISACVer[] = {
39 "2086/2186 V1.1",
40 "2085 B1",
41 "2085 B2",
42 "2085 V2.3"
44 #endif
46 MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
47 MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
48 MODULE_LICENSE("GPL");
50 #define DBG_WARN 0x0001
51 #define DBG_IRQ 0x0002
52 #define DBG_L1M 0x0004
53 #define DBG_PR 0x0008
54 #define DBG_RFIFO 0x0100
55 #define DBG_RPACKET 0x0200
56 #define DBG_XFIFO 0x1000
57 #define DBG_XPACKET 0x2000
59 // we need to distinguish ISAC-S and ISAC-SX
60 #define TYPE_ISAC 0x00
61 #define TYPE_ISACSX 0x01
63 // registers etc.
64 #define ISAC_MASK 0x20
65 #define ISAC_ISTA 0x20
66 #define ISAC_ISTA_EXI 0x01
67 #define ISAC_ISTA_SIN 0x02
68 #define ISAC_ISTA_CISQ 0x04
69 #define ISAC_ISTA_XPR 0x10
70 #define ISAC_ISTA_RSC 0x20
71 #define ISAC_ISTA_RPF 0x40
72 #define ISAC_ISTA_RME 0x80
74 #define ISAC_STAR 0x21
75 #define ISAC_CMDR 0x21
76 #define ISAC_CMDR_XRES 0x01
77 #define ISAC_CMDR_XME 0x02
78 #define ISAC_CMDR_XTF 0x08
79 #define ISAC_CMDR_RRES 0x40
80 #define ISAC_CMDR_RMC 0x80
82 #define ISAC_EXIR 0x24
83 #define ISAC_EXIR_MOS 0x04
84 #define ISAC_EXIR_XDU 0x40
85 #define ISAC_EXIR_XMR 0x80
87 #define ISAC_ADF2 0x39
88 #define ISAC_SPCR 0x30
89 #define ISAC_ADF1 0x38
91 #define ISAC_CIR0 0x31
92 #define ISAC_CIX0 0x31
93 #define ISAC_CIR0_CIC0 0x02
94 #define ISAC_CIR0_CIC1 0x01
96 #define ISAC_CIR1 0x33
97 #define ISAC_CIX1 0x33
98 #define ISAC_STCR 0x37
99 #define ISAC_MODE 0x22
101 #define ISAC_RSTA 0x27
102 #define ISAC_RSTA_RDO 0x40
103 #define ISAC_RSTA_CRC 0x20
104 #define ISAC_RSTA_RAB 0x10
106 #define ISAC_RBCL 0x25
107 #define ISAC_RBCH 0x2A
108 #define ISAC_TIMR 0x23
109 #define ISAC_SQXR 0x3b
110 #define ISAC_MOSR 0x3a
111 #define ISAC_MOCR 0x3a
112 #define ISAC_MOR0 0x32
113 #define ISAC_MOX0 0x32
114 #define ISAC_MOR1 0x34
115 #define ISAC_MOX1 0x34
117 #define ISAC_RBCH_XAC 0x80
119 #define ISAC_CMD_TIM 0x0
120 #define ISAC_CMD_RES 0x1
121 #define ISAC_CMD_SSP 0x2
122 #define ISAC_CMD_SCP 0x3
123 #define ISAC_CMD_AR8 0x8
124 #define ISAC_CMD_AR10 0x9
125 #define ISAC_CMD_ARL 0xa
126 #define ISAC_CMD_DI 0xf
128 #define ISACSX_MASK 0x60
129 #define ISACSX_ISTA 0x60
130 #define ISACSX_ISTA_ICD 0x01
131 #define ISACSX_ISTA_CIC 0x10
133 #define ISACSX_MASKD 0x20
134 #define ISACSX_ISTAD 0x20
135 #define ISACSX_ISTAD_XDU 0x04
136 #define ISACSX_ISTAD_XMR 0x08
137 #define ISACSX_ISTAD_XPR 0x10
138 #define ISACSX_ISTAD_RFO 0x20
139 #define ISACSX_ISTAD_RPF 0x40
140 #define ISACSX_ISTAD_RME 0x80
142 #define ISACSX_CMDRD 0x21
143 #define ISACSX_CMDRD_XRES 0x01
144 #define ISACSX_CMDRD_XME 0x02
145 #define ISACSX_CMDRD_XTF 0x08
146 #define ISACSX_CMDRD_RRES 0x40
147 #define ISACSX_CMDRD_RMC 0x80
149 #define ISACSX_MODED 0x22
151 #define ISACSX_RBCLD 0x26
153 #define ISACSX_RSTAD 0x28
154 #define ISACSX_RSTAD_RAB 0x10
155 #define ISACSX_RSTAD_CRC 0x20
156 #define ISACSX_RSTAD_RDO 0x40
157 #define ISACSX_RSTAD_VFR 0x80
159 #define ISACSX_CIR0 0x2e
160 #define ISACSX_CIR0_CIC0 0x08
161 #define ISACSX_CIX0 0x2e
163 #define ISACSX_TR_CONF0 0x30
165 #define ISACSX_TR_CONF2 0x32
167 static struct Fsm l1fsm;
169 enum {
170 ST_L1_RESET,
171 ST_L1_F3_PDOWN,
172 ST_L1_F3_PUP,
173 ST_L1_F3_PEND_DEACT,
174 ST_L1_F4,
175 ST_L1_F5,
176 ST_L1_F6,
177 ST_L1_F7,
178 ST_L1_F8,
181 #define L1_STATE_COUNT (ST_L1_F8 + 1)
183 static char *strL1State[] =
185 "ST_L1_RESET",
186 "ST_L1_F3_PDOWN",
187 "ST_L1_F3_PUP",
188 "ST_L1_F3_PEND_DEACT",
189 "ST_L1_F4",
190 "ST_L1_F5",
191 "ST_L1_F6",
192 "ST_L1_F7",
193 "ST_L1_F8",
196 enum {
197 EV_PH_DR, // 0000
198 EV_PH_RES, // 0001
199 EV_PH_TMA, // 0010
200 EV_PH_SLD, // 0011
201 EV_PH_RSY, // 0100
202 EV_PH_DR6, // 0101
203 EV_PH_EI, // 0110
204 EV_PH_PU, // 0111
205 EV_PH_AR, // 1000
206 EV_PH_9, // 1001
207 EV_PH_ARL, // 1010
208 EV_PH_CVR, // 1011
209 EV_PH_AI8, // 1100
210 EV_PH_AI10, // 1101
211 EV_PH_AIL, // 1110
212 EV_PH_DC, // 1111
213 EV_PH_ACTIVATE_REQ,
214 EV_PH_DEACTIVATE_REQ,
215 EV_TIMER3,
218 #define L1_EVENT_COUNT (EV_TIMER3 + 1)
220 static char *strL1Event[] =
222 "EV_PH_DR", // 0000
223 "EV_PH_RES", // 0001
224 "EV_PH_TMA", // 0010
225 "EV_PH_SLD", // 0011
226 "EV_PH_RSY", // 0100
227 "EV_PH_DR6", // 0101
228 "EV_PH_EI", // 0110
229 "EV_PH_PU", // 0111
230 "EV_PH_AR", // 1000
231 "EV_PH_9", // 1001
232 "EV_PH_ARL", // 1010
233 "EV_PH_CVR", // 1011
234 "EV_PH_AI8", // 1100
235 "EV_PH_AI10", // 1101
236 "EV_PH_AIL", // 1110
237 "EV_PH_DC", // 1111
238 "EV_PH_ACTIVATE_REQ",
239 "EV_PH_DEACTIVATE_REQ",
240 "EV_TIMER3",
243 static inline void D_L1L2(struct isac *isac, int pr, void *arg)
245 struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if;
247 DBG(DBG_PR, "pr %#x", pr);
248 ifc->l1l2(ifc, pr, arg);
251 static void ph_command(struct isac *isac, unsigned int command)
253 DBG(DBG_L1M, "ph_command %#x", command);
254 switch (isac->type) {
255 case TYPE_ISAC:
256 isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3);
257 break;
258 case TYPE_ISACSX:
259 isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1));
260 break;
264 // ----------------------------------------------------------------------
266 static void l1_di(struct FsmInst *fi, int event, void *arg)
268 struct isac *isac = fi->userdata;
270 FsmChangeState(fi, ST_L1_RESET);
271 ph_command(isac, ISAC_CMD_DI);
274 static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg)
276 struct isac *isac = fi->userdata;
278 FsmChangeState(fi, ST_L1_RESET);
279 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
280 ph_command(isac, ISAC_CMD_DI);
283 static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
285 FsmChangeState(fi, ST_L1_F3_PDOWN);
288 static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg)
290 struct isac *isac = fi->userdata;
292 FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
293 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
294 ph_command(isac, ISAC_CMD_DI);
297 static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg)
299 struct isac *isac = fi->userdata;
301 FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
302 ph_command(isac, ISAC_CMD_DI);
305 static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
307 FsmChangeState(fi, ST_L1_F4);
310 static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
312 FsmChangeState(fi, ST_L1_F5);
315 static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
317 FsmChangeState(fi, ST_L1_F6);
320 static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
322 struct isac *isac = fi->userdata;
324 FsmChangeState(fi, ST_L1_F6);
325 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
328 static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
330 struct isac *isac = fi->userdata;
332 FsmDelTimer(&isac->timer, 0);
333 FsmChangeState(fi, ST_L1_F7);
334 ph_command(isac, ISAC_CMD_AR8);
335 D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL);
338 static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
340 FsmChangeState(fi, ST_L1_F8);
343 static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
345 struct isac *isac = fi->userdata;
347 FsmChangeState(fi, ST_L1_F8);
348 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
351 static void l1_ar8(struct FsmInst *fi, int event, void *arg)
353 struct isac *isac = fi->userdata;
355 FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
356 ph_command(isac, ISAC_CMD_AR8);
359 static void l1_timer3(struct FsmInst *fi, int event, void *arg)
361 struct isac *isac = fi->userdata;
363 ph_command(isac, ISAC_CMD_DI);
364 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
367 // state machines according to data sheet PSB 2186 / 3186
369 static struct FsmNode L1FnList[] __initdata =
371 {ST_L1_RESET, EV_PH_RES, l1_di},
372 {ST_L1_RESET, EV_PH_EI, l1_di},
373 {ST_L1_RESET, EV_PH_DC, l1_go_f3pdown},
374 {ST_L1_RESET, EV_PH_AR, l1_go_f6},
375 {ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind},
377 {ST_L1_F3_PDOWN, EV_PH_RES, l1_di},
378 {ST_L1_F3_PDOWN, EV_PH_EI, l1_di},
379 {ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6},
380 {ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5},
381 {ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4},
382 {ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind},
383 {ST_L1_F3_PDOWN, EV_PH_ACTIVATE_REQ, l1_ar8},
384 {ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3},
386 {ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di},
387 {ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di},
388 {ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown},
389 {ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5},
390 {ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6},
391 {ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind},
393 {ST_L1_F4, EV_PH_RES, l1_di},
394 {ST_L1_F4, EV_PH_EI, l1_di},
395 {ST_L1_F4, EV_PH_RSY, l1_go_f5},
396 {ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind},
397 {ST_L1_F4, EV_TIMER3, l1_timer3},
398 {ST_L1_F4, EV_PH_DC, l1_go_f3pdown},
400 {ST_L1_F5, EV_PH_RES, l1_di},
401 {ST_L1_F5, EV_PH_EI, l1_di},
402 {ST_L1_F5, EV_PH_AR, l1_go_f6},
403 {ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind},
404 {ST_L1_F5, EV_TIMER3, l1_timer3},
405 {ST_L1_F5, EV_PH_DR, l1_go_f3pend},
406 {ST_L1_F5, EV_PH_DC, l1_go_f3pdown},
408 {ST_L1_F6, EV_PH_RES, l1_di},
409 {ST_L1_F6, EV_PH_EI, l1_di},
410 {ST_L1_F6, EV_PH_RSY, l1_go_f8},
411 {ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind},
412 {ST_L1_F6, EV_PH_DR6, l1_go_f3pend},
413 {ST_L1_F6, EV_TIMER3, l1_timer3},
414 {ST_L1_F6, EV_PH_DC, l1_go_f3pdown},
416 {ST_L1_F7, EV_PH_RES, l1_di_deact_ind},
417 {ST_L1_F7, EV_PH_EI, l1_di_deact_ind},
418 {ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind},
419 {ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind},
420 {ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind},
422 {ST_L1_F8, EV_PH_RES, l1_di},
423 {ST_L1_F8, EV_PH_EI, l1_di},
424 {ST_L1_F8, EV_PH_AR, l1_go_f6},
425 {ST_L1_F8, EV_PH_DR, l1_go_f3pend},
426 {ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind},
427 {ST_L1_F8, EV_TIMER3, l1_timer3},
428 {ST_L1_F8, EV_PH_DC, l1_go_f3pdown},
431 static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
433 va_list args;
434 char buf[256];
436 va_start(args, fmt);
437 vsnprintf(buf, sizeof(buf), fmt, args);
438 DBG(DBG_L1M, "%s", buf);
439 va_end(args);
442 static void isac_version(struct isac *cs)
444 int val;
446 val = cs->read_isac(cs, ISAC_RBCH);
447 DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);
450 static void isac_empty_fifo(struct isac *isac, int count)
452 // this also works for isacsx, since
453 // CMDR(D) register works the same
454 u_char *ptr;
456 DBG(DBG_IRQ, "count %d", count);
458 if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
459 DBG(DBG_WARN, "overrun %d", isac->rcvidx + count);
460 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
461 isac->rcvidx = 0;
462 return;
464 ptr = isac->rcvbuf + isac->rcvidx;
465 isac->rcvidx += count;
466 isac->read_isac_fifo(isac, ptr, count);
467 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
468 DBG_PACKET(DBG_RFIFO, ptr, count);
471 static void isac_fill_fifo(struct isac *isac)
473 // this also works for isacsx, since
474 // CMDR(D) register works the same
476 int count;
477 unsigned char cmd;
478 u_char *ptr;
480 BUG_ON(!isac->tx_skb);
482 count = isac->tx_skb->len;
483 BUG_ON(count <= 0);
485 DBG(DBG_IRQ, "count %d", count);
487 if (count > 0x20) {
488 count = 0x20;
489 cmd = ISAC_CMDR_XTF;
490 } else {
491 cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
494 ptr = isac->tx_skb->data;
495 skb_pull(isac->tx_skb, count);
496 isac->tx_cnt += count;
497 DBG_PACKET(DBG_XFIFO, ptr, count);
498 isac->write_isac_fifo(isac, ptr, count);
499 isac->write_isac(isac, ISAC_CMDR, cmd);
502 static void isac_retransmit(struct isac *isac)
504 if (!isac->tx_skb) {
505 DBG(DBG_WARN, "no skb");
506 return;
508 skb_push(isac->tx_skb, isac->tx_cnt);
509 isac->tx_cnt = 0;
513 static inline void isac_cisq_interrupt(struct isac *isac)
515 unsigned char val;
517 val = isac->read_isac(isac, ISAC_CIR0);
518 DBG(DBG_IRQ, "CIR0 %#x", val);
519 if (val & ISAC_CIR0_CIC0) {
520 DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf);
521 FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
523 if (val & ISAC_CIR0_CIC1) {
524 val = isac->read_isac(isac, ISAC_CIR1);
525 DBG(DBG_WARN, "ISAC CIR1 %#x", val);
529 static inline void isac_rme_interrupt(struct isac *isac)
531 unsigned char val;
532 int count;
533 struct sk_buff *skb;
535 val = isac->read_isac(isac, ISAC_RSTA);
536 if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB))
537 != ISAC_RSTA_CRC) {
538 DBG(DBG_WARN, "RSTA %#x, dropped", val);
539 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
540 goto out;
543 count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
544 DBG(DBG_IRQ, "RBCL %#x", count);
545 if (count == 0)
546 count = 0x20;
548 isac_empty_fifo(isac, count);
549 count = isac->rcvidx;
550 if (count < 1) {
551 DBG(DBG_WARN, "count %d < 1", count);
552 goto out;
555 skb = alloc_skb(count, GFP_ATOMIC);
556 if (!skb) {
557 DBG(DBG_WARN, "no memory, dropping\n");
558 goto out;
560 memcpy(skb_put(skb, count), isac->rcvbuf, count);
561 DBG_SKB(DBG_RPACKET, skb);
562 D_L1L2(isac, PH_DATA | INDICATION, skb);
563 out:
564 isac->rcvidx = 0;
567 static inline void isac_xpr_interrupt(struct isac *isac)
569 if (!isac->tx_skb)
570 return;
572 if (isac->tx_skb->len > 0) {
573 isac_fill_fifo(isac);
574 return;
576 dev_kfree_skb_irq(isac->tx_skb);
577 isac->tx_cnt = 0;
578 isac->tx_skb = NULL;
579 D_L1L2(isac, PH_DATA | CONFIRM, NULL);
582 static inline void isac_exi_interrupt(struct isac *isac)
584 unsigned char val;
586 val = isac->read_isac(isac, ISAC_EXIR);
587 DBG(2, "EXIR %#x", val);
589 if (val & ISAC_EXIR_XMR) {
590 DBG(DBG_WARN, "ISAC XMR");
591 isac_retransmit(isac);
593 if (val & ISAC_EXIR_XDU) {
594 DBG(DBG_WARN, "ISAC XDU");
595 isac_retransmit(isac);
597 if (val & ISAC_EXIR_MOS) { /* MOS */
598 DBG(DBG_WARN, "MOS");
599 val = isac->read_isac(isac, ISAC_MOSR);
600 DBG(2, "ISAC MOSR %#x", val);
604 void isac_irq(struct isac *isac)
606 unsigned char val;
608 val = isac->read_isac(isac, ISAC_ISTA);
609 DBG(DBG_IRQ, "ISTA %#x", val);
611 if (val & ISAC_ISTA_EXI) {
612 DBG(DBG_IRQ, "EXI");
613 isac_exi_interrupt(isac);
615 if (val & ISAC_ISTA_XPR) {
616 DBG(DBG_IRQ, "XPR");
617 isac_xpr_interrupt(isac);
619 if (val & ISAC_ISTA_RME) {
620 DBG(DBG_IRQ, "RME");
621 isac_rme_interrupt(isac);
623 if (val & ISAC_ISTA_RPF) {
624 DBG(DBG_IRQ, "RPF");
625 isac_empty_fifo(isac, 0x20);
627 if (val & ISAC_ISTA_CISQ) {
628 DBG(DBG_IRQ, "CISQ");
629 isac_cisq_interrupt(isac);
631 if (val & ISAC_ISTA_RSC) {
632 DBG(DBG_WARN, "RSC");
634 if (val & ISAC_ISTA_SIN) {
635 DBG(DBG_WARN, "SIN");
637 isac->write_isac(isac, ISAC_MASK, 0xff);
638 isac->write_isac(isac, ISAC_MASK, 0x00);
641 // ======================================================================
643 static inline void isacsx_cic_interrupt(struct isac *isac)
645 unsigned char val;
647 val = isac->read_isac(isac, ISACSX_CIR0);
648 DBG(DBG_IRQ, "CIR0 %#x", val);
649 if (val & ISACSX_CIR0_CIC0) {
650 DBG(DBG_IRQ, "CODR0 %#x", val >> 4);
651 FsmEvent(&isac->l1m, val >> 4, NULL);
655 static inline void isacsx_rme_interrupt(struct isac *isac)
657 int count;
658 struct sk_buff *skb;
659 unsigned char val;
661 val = isac->read_isac(isac, ISACSX_RSTAD);
662 if ((val & (ISACSX_RSTAD_VFR |
663 ISACSX_RSTAD_RDO |
664 ISACSX_RSTAD_CRC |
665 ISACSX_RSTAD_RAB))
666 != (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) {
667 DBG(DBG_WARN, "RSTAD %#x, dropped", val);
668 isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
669 goto out;
672 count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
673 DBG(DBG_IRQ, "RBCLD %#x", count);
674 if (count == 0)
675 count = 0x20;
677 isac_empty_fifo(isac, count);
678 // strip trailing status byte
679 count = isac->rcvidx - 1;
680 if (count < 1) {
681 DBG(DBG_WARN, "count %d < 1", count);
682 goto out;
685 skb = dev_alloc_skb(count);
686 if (!skb) {
687 DBG(DBG_WARN, "no memory, dropping");
688 goto out;
690 memcpy(skb_put(skb, count), isac->rcvbuf, count);
691 DBG_SKB(DBG_RPACKET, skb);
692 D_L1L2(isac, PH_DATA | INDICATION, skb);
693 out:
694 isac->rcvidx = 0;
697 static inline void isacsx_xpr_interrupt(struct isac *isac)
699 if (!isac->tx_skb)
700 return;
702 if (isac->tx_skb->len > 0) {
703 isac_fill_fifo(isac);
704 return;
706 dev_kfree_skb_irq(isac->tx_skb);
707 isac->tx_skb = NULL;
708 isac->tx_cnt = 0;
709 D_L1L2(isac, PH_DATA | CONFIRM, NULL);
712 static inline void isacsx_icd_interrupt(struct isac *isac)
714 unsigned char val;
716 val = isac->read_isac(isac, ISACSX_ISTAD);
717 DBG(DBG_IRQ, "ISTAD %#x", val);
718 if (val & ISACSX_ISTAD_XDU) {
719 DBG(DBG_WARN, "ISTAD XDU");
720 isac_retransmit(isac);
722 if (val & ISACSX_ISTAD_XMR) {
723 DBG(DBG_WARN, "ISTAD XMR");
724 isac_retransmit(isac);
726 if (val & ISACSX_ISTAD_XPR) {
727 DBG(DBG_IRQ, "ISTAD XPR");
728 isacsx_xpr_interrupt(isac);
730 if (val & ISACSX_ISTAD_RFO) {
731 DBG(DBG_WARN, "ISTAD RFO");
732 isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
734 if (val & ISACSX_ISTAD_RME) {
735 DBG(DBG_IRQ, "ISTAD RME");
736 isacsx_rme_interrupt(isac);
738 if (val & ISACSX_ISTAD_RPF) {
739 DBG(DBG_IRQ, "ISTAD RPF");
740 isac_empty_fifo(isac, 0x20);
744 void isacsx_irq(struct isac *isac)
746 unsigned char val;
748 val = isac->read_isac(isac, ISACSX_ISTA);
749 DBG(DBG_IRQ, "ISTA %#x", val);
751 if (val & ISACSX_ISTA_ICD)
752 isacsx_icd_interrupt(isac);
753 if (val & ISACSX_ISTA_CIC)
754 isacsx_cic_interrupt(isac);
757 void isac_init(struct isac *isac)
759 isac->tx_skb = NULL;
760 isac->l1m.fsm = &l1fsm;
761 isac->l1m.state = ST_L1_RESET;
762 #ifdef CONFIG_HISAX_DEBUG
763 isac->l1m.debug = 1;
764 #else
765 isac->l1m.debug = 0;
766 #endif
767 isac->l1m.userdata = isac;
768 isac->l1m.printdebug = l1m_debug;
769 FsmInitTimer(&isac->l1m, &isac->timer);
772 void isac_setup(struct isac *isac)
774 int val, eval;
776 isac->type = TYPE_ISAC;
777 isac_version(isac);
779 ph_command(isac, ISAC_CMD_RES);
781 isac->write_isac(isac, ISAC_MASK, 0xff);
782 isac->mocr = 0xaa;
783 if (test_bit(ISAC_IOM1, &isac->flags)) {
784 /* IOM 1 Mode */
785 isac->write_isac(isac, ISAC_ADF2, 0x0);
786 isac->write_isac(isac, ISAC_SPCR, 0xa);
787 isac->write_isac(isac, ISAC_ADF1, 0x2);
788 isac->write_isac(isac, ISAC_STCR, 0x70);
789 isac->write_isac(isac, ISAC_MODE, 0xc9);
790 } else {
791 /* IOM 2 Mode */
792 if (!isac->adf2)
793 isac->adf2 = 0x80;
794 isac->write_isac(isac, ISAC_ADF2, isac->adf2);
795 isac->write_isac(isac, ISAC_SQXR, 0x2f);
796 isac->write_isac(isac, ISAC_SPCR, 0x00);
797 isac->write_isac(isac, ISAC_STCR, 0x70);
798 isac->write_isac(isac, ISAC_MODE, 0xc9);
799 isac->write_isac(isac, ISAC_TIMR, 0x00);
800 isac->write_isac(isac, ISAC_ADF1, 0x00);
802 val = isac->read_isac(isac, ISAC_STAR);
803 DBG(2, "ISAC STAR %x", val);
804 val = isac->read_isac(isac, ISAC_MODE);
805 DBG(2, "ISAC MODE %x", val);
806 val = isac->read_isac(isac, ISAC_ADF2);
807 DBG(2, "ISAC ADF2 %x", val);
808 val = isac->read_isac(isac, ISAC_ISTA);
809 DBG(2, "ISAC ISTA %x", val);
810 if (val & 0x01) {
811 eval = isac->read_isac(isac, ISAC_EXIR);
812 DBG(2, "ISAC EXIR %x", eval);
814 val = isac->read_isac(isac, ISAC_CIR0);
815 DBG(2, "ISAC CIR0 %x", val);
816 FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
818 isac->write_isac(isac, ISAC_MASK, 0x0);
819 // RESET Receiver and Transmitter
820 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES);
823 void isacsx_setup(struct isac *isac)
825 isac->type = TYPE_ISACSX;
826 // clear LDD
827 isac->write_isac(isac, ISACSX_TR_CONF0, 0x00);
828 // enable transmitter
829 isac->write_isac(isac, ISACSX_TR_CONF2, 0x00);
830 // transparent mode 0, RAC, stop/go
831 isac->write_isac(isac, ISACSX_MODED, 0xc9);
832 // all HDLC IRQ unmasked
833 isac->write_isac(isac, ISACSX_MASKD, 0x03);
834 // unmask ICD, CID IRQs
835 isac->write_isac(isac, ISACSX_MASK,
836 ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
839 void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
841 struct isac *isac = hisax_d_if->priv;
842 struct sk_buff *skb = arg;
844 DBG(DBG_PR, "pr %#x", pr);
846 switch (pr) {
847 case PH_ACTIVATE | REQUEST:
848 FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL);
849 break;
850 case PH_DEACTIVATE | REQUEST:
851 FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL);
852 break;
853 case PH_DATA | REQUEST:
854 DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
855 DBG_SKB(DBG_XPACKET, skb);
856 if (isac->l1m.state != ST_L1_F7) {
857 DBG(1, "L1 wrong state %d\n", isac->l1m.state);
858 dev_kfree_skb(skb);
859 break;
861 BUG_ON(isac->tx_skb);
863 isac->tx_skb = skb;
864 isac_fill_fifo(isac);
865 break;
869 static int __init hisax_isac_init(void)
871 printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
873 l1fsm.state_count = L1_STATE_COUNT;
874 l1fsm.event_count = L1_EVENT_COUNT;
875 l1fsm.strState = strL1State;
876 l1fsm.strEvent = strL1Event;
877 return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
880 static void __exit hisax_isac_exit(void)
882 FsmFree(&l1fsm);
885 EXPORT_SYMBOL(isac_init);
886 EXPORT_SYMBOL(isac_d_l2l1);
888 EXPORT_SYMBOL(isacsx_setup);
889 EXPORT_SYMBOL(isacsx_irq);
891 EXPORT_SYMBOL(isac_setup);
892 EXPORT_SYMBOL(isac_irq);
894 module_init(hisax_isac_init);
895 module_exit(hisax_isac_exit);