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