]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/isdn/hisax/hisax_isac.c
Merge branch 'bcmring/cleanup' into bcmring/removal
[karo-tx-linux.git] / 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/gfp.h>
25 #include <linux/init.h>
26 #include <linux/netdevice.h>
27 #include "hisax_isac.h"
28
29 // debugging cruft
30
31 #define __debug_variable debug
32 #include "hisax_debug.h"
33
34 #ifdef CONFIG_HISAX_DEBUG
35 static int debug = 1;
36 module_param(debug, int, 0);
37
38 static char *ISACVer[] = {
39         "2086/2186 V1.1",
40         "2085 B1",
41         "2085 B2",
42         "2085 V2.3"
43 };
44 #endif
45
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");
49
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
58
59 // we need to distinguish ISAC-S and ISAC-SX
60 #define TYPE_ISAC        0x00
61 #define TYPE_ISACSX      0x01
62
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
73
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
81
82 #define ISAC_EXIR        0x24
83 #define ISAC_EXIR_MOS    0x04
84 #define ISAC_EXIR_XDU    0x40
85 #define ISAC_EXIR_XMR    0x80
86
87 #define ISAC_ADF2        0x39
88 #define ISAC_SPCR        0x30
89 #define ISAC_ADF1        0x38
90
91 #define ISAC_CIR0        0x31
92 #define ISAC_CIX0        0x31
93 #define ISAC_CIR0_CIC0   0x02
94 #define ISAC_CIR0_CIC1   0x01
95
96 #define ISAC_CIR1        0x33
97 #define ISAC_CIX1        0x33
98 #define ISAC_STCR        0x37
99 #define ISAC_MODE        0x22
100
101 #define ISAC_RSTA        0x27
102 #define ISAC_RSTA_RDO    0x40
103 #define ISAC_RSTA_CRC    0x20
104 #define ISAC_RSTA_RAB    0x10
105
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
116
117 #define ISAC_RBCH_XAC 0x80
118
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
127
128 #define ISACSX_MASK       0x60
129 #define ISACSX_ISTA       0x60
130 #define ISACSX_ISTA_ICD   0x01
131 #define ISACSX_ISTA_CIC   0x10
132
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
141
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
148
149 #define ISACSX_MODED      0x22
150
151 #define ISACSX_RBCLD      0x26
152
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
158
159 #define ISACSX_CIR0       0x2e
160 #define ISACSX_CIR0_CIC0  0x08
161 #define ISACSX_CIX0       0x2e
162
163 #define ISACSX_TR_CONF0   0x30
164
165 #define ISACSX_TR_CONF2   0x32
166
167 static struct Fsm l1fsm;
168
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,
179 };
180
181 #define L1_STATE_COUNT (ST_L1_F8 + 1)
182
183 static char *strL1State[] =
184 {
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",
194 };
195
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,
216 };
217
218 #define L1_EVENT_COUNT (EV_TIMER3 + 1)
219
220 static char *strL1Event[] =
221 {
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",
241 };
242
243 static inline void D_L1L2(struct isac *isac, int pr, void *arg)
244 {
245         struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if;
246
247         DBG(DBG_PR, "pr %#x", pr);
248         ifc->l1l2(ifc, pr, arg);
249 }
250
251 static void ph_command(struct isac *isac, unsigned int command)
252 {
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;
261         }
262 }
263
264 // ----------------------------------------------------------------------
265
266 static void l1_di(struct FsmInst *fi, int event, void *arg)
267 {
268         struct isac *isac = fi->userdata;
269
270         FsmChangeState(fi, ST_L1_RESET);
271         ph_command(isac, ISAC_CMD_DI);
272 }
273
274 static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg)
275 {
276         struct isac *isac = fi->userdata;
277
278         FsmChangeState(fi, ST_L1_RESET);
279         D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
280         ph_command(isac, ISAC_CMD_DI);
281 }
282
283 static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
284 {
285         FsmChangeState(fi, ST_L1_F3_PDOWN);
286 }
287
288 static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg)
289 {
290         struct isac *isac = fi->userdata;
291
292         FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
293         D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
294         ph_command(isac, ISAC_CMD_DI);
295 }
296
297 static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg)
298 {
299         struct isac *isac = fi->userdata;
300
301         FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
302         ph_command(isac, ISAC_CMD_DI);
303 }
304
305 static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
306 {
307         FsmChangeState(fi, ST_L1_F4);
308 }
309
310 static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
311 {
312         FsmChangeState(fi, ST_L1_F5);
313 }
314
315 static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
316 {
317         FsmChangeState(fi, ST_L1_F6);
318 }
319
320 static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
321 {
322         struct isac *isac = fi->userdata;
323
324         FsmChangeState(fi, ST_L1_F6);
325         D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
326 }
327
328 static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
329 {
330         struct isac *isac = fi->userdata;
331
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);
336 }
337
338 static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
339 {
340         FsmChangeState(fi, ST_L1_F8);
341 }
342
343 static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
344 {
345         struct isac *isac = fi->userdata;
346
347         FsmChangeState(fi, ST_L1_F8);
348         D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
349 }
350
351 static void l1_ar8(struct FsmInst *fi, int event, void *arg)
352 {
353         struct isac *isac = fi->userdata;
354
355         FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
356         ph_command(isac, ISAC_CMD_AR8);
357 }
358
359 static void l1_timer3(struct FsmInst *fi, int event, void *arg)
360 {
361         struct isac *isac = fi->userdata;
362
363         ph_command(isac, ISAC_CMD_DI);
364         D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
365 }
366
367 // state machines according to data sheet PSB 2186 / 3186
368
369 static struct FsmNode L1FnList[] __initdata =
370 {
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},
376
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},
385
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},
392
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},
399
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},
407
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},
415
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},
421
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},
429 };
430
431 static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
432 {
433         va_list args;
434         char buf[256];
435
436         va_start(args, fmt);
437         vsnprintf(buf, sizeof(buf), fmt, args);
438         DBG(DBG_L1M, "%s", buf);
439         va_end(args);
440 }
441
442 static void isac_version(struct isac *cs)
443 {
444         int val;
445
446         val = cs->read_isac(cs, ISAC_RBCH);
447         DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);
448 }
449
450 static void isac_empty_fifo(struct isac *isac, int count)
451 {
452         // this also works for isacsx, since
453         // CMDR(D) register works the same
454         u_char *ptr;
455
456         DBG(DBG_IRQ, "count %d", count);
457
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;
463         }
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);
469 }
470
471 static void isac_fill_fifo(struct isac *isac)
472 {
473         // this also works for isacsx, since
474         // CMDR(D) register works the same
475
476         int count;
477         unsigned char cmd;
478         u_char *ptr;
479
480         BUG_ON(!isac->tx_skb);
481
482         count = isac->tx_skb->len;
483         BUG_ON(count <= 0);
484
485         DBG(DBG_IRQ, "count %d", count);
486
487         if (count > 0x20) {
488                 count = 0x20;
489                 cmd = ISAC_CMDR_XTF;
490         } else {
491                 cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
492         }
493
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);
500 }
501
502 static void isac_retransmit(struct isac *isac)
503 {
504         if (!isac->tx_skb) {
505                 DBG(DBG_WARN, "no skb");
506                 return;
507         }
508         skb_push(isac->tx_skb, isac->tx_cnt);
509         isac->tx_cnt = 0;
510 }
511
512
513 static inline void isac_cisq_interrupt(struct isac *isac)
514 {
515         unsigned char val;
516
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);
522         }
523         if (val & ISAC_CIR0_CIC1) {
524                 val = isac->read_isac(isac, ISAC_CIR1);
525                 DBG(DBG_WARN, "ISAC CIR1 %#x", val);
526         }
527 }
528
529 static inline void isac_rme_interrupt(struct isac *isac)
530 {
531         unsigned char val;
532         int count;
533         struct sk_buff *skb;
534
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;
541         }
542
543         count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
544         DBG(DBG_IRQ, "RBCL %#x", count);
545         if (count == 0)
546                 count = 0x20;
547
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;
553         }
554
555         skb = alloc_skb(count, GFP_ATOMIC);
556         if (!skb) {
557                 DBG(DBG_WARN, "no memory, dropping\n");
558                 goto out;
559         }
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;
565 }
566
567 static inline void isac_xpr_interrupt(struct isac *isac)
568 {
569         if (!isac->tx_skb)
570                 return;
571
572         if (isac->tx_skb->len > 0) {
573                 isac_fill_fifo(isac);
574                 return;
575         }
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);
580 }
581
582 static inline void isac_exi_interrupt(struct isac *isac)
583 {
584         unsigned char val;
585
586         val = isac->read_isac(isac, ISAC_EXIR);
587         DBG(2, "EXIR %#x", val);
588
589         if (val & ISAC_EXIR_XMR) {
590                 DBG(DBG_WARN, "ISAC XMR");
591                 isac_retransmit(isac);
592         }
593         if (val & ISAC_EXIR_XDU) {
594                 DBG(DBG_WARN, "ISAC XDU");
595                 isac_retransmit(isac);
596         }
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);
601         }
602 }
603
604 void isac_irq(struct isac *isac)
605 {
606         unsigned char val;
607
608         val = isac->read_isac(isac, ISAC_ISTA);
609         DBG(DBG_IRQ, "ISTA %#x", val);
610
611         if (val & ISAC_ISTA_EXI) {
612                 DBG(DBG_IRQ, "EXI");
613                 isac_exi_interrupt(isac);
614         }
615         if (val & ISAC_ISTA_XPR) {
616                 DBG(DBG_IRQ, "XPR");
617                 isac_xpr_interrupt(isac);
618         }
619         if (val & ISAC_ISTA_RME) {
620                 DBG(DBG_IRQ, "RME");
621                 isac_rme_interrupt(isac);
622         }
623         if (val & ISAC_ISTA_RPF) {
624                 DBG(DBG_IRQ, "RPF");
625                 isac_empty_fifo(isac, 0x20);
626         }
627         if (val & ISAC_ISTA_CISQ) {
628                 DBG(DBG_IRQ, "CISQ");
629                 isac_cisq_interrupt(isac);
630         }
631         if (val & ISAC_ISTA_RSC) {
632                 DBG(DBG_WARN, "RSC");
633         }
634         if (val & ISAC_ISTA_SIN) {
635                 DBG(DBG_WARN, "SIN");
636         }
637         isac->write_isac(isac, ISAC_MASK, 0xff);
638         isac->write_isac(isac, ISAC_MASK, 0x00);
639 }
640
641 // ======================================================================
642
643 static inline void isacsx_cic_interrupt(struct isac *isac)
644 {
645         unsigned char val;
646
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);
652         }
653 }
654
655 static inline void isacsx_rme_interrupt(struct isac *isac)
656 {
657         int count;
658         struct sk_buff *skb;
659         unsigned char val;
660
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;
670         }
671
672         count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
673         DBG(DBG_IRQ, "RBCLD %#x", count);
674         if (count == 0)
675                 count = 0x20;
676
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;
683         }
684
685         skb = dev_alloc_skb(count);
686         if (!skb) {
687                 DBG(DBG_WARN, "no memory, dropping");
688                 goto out;
689         }
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;
695 }
696
697 static inline void isacsx_xpr_interrupt(struct isac *isac)
698 {
699         if (!isac->tx_skb)
700                 return;
701
702         if (isac->tx_skb->len > 0) {
703                 isac_fill_fifo(isac);
704                 return;
705         }
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);
710 }
711
712 static inline void isacsx_icd_interrupt(struct isac *isac)
713 {
714         unsigned char val;
715
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);
721         }
722         if (val & ISACSX_ISTAD_XMR) {
723                 DBG(DBG_WARN, "ISTAD XMR");
724                 isac_retransmit(isac);
725         }
726         if (val & ISACSX_ISTAD_XPR) {
727                 DBG(DBG_IRQ, "ISTAD XPR");
728                 isacsx_xpr_interrupt(isac);
729         }
730         if (val & ISACSX_ISTAD_RFO) {
731                 DBG(DBG_WARN, "ISTAD RFO");
732                 isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
733         }
734         if (val & ISACSX_ISTAD_RME) {
735                 DBG(DBG_IRQ, "ISTAD RME");
736                 isacsx_rme_interrupt(isac);
737         }
738         if (val & ISACSX_ISTAD_RPF) {
739                 DBG(DBG_IRQ, "ISTAD RPF");
740                 isac_empty_fifo(isac, 0x20);
741         }
742 }
743
744 void isacsx_irq(struct isac *isac)
745 {
746         unsigned char val;
747
748         val = isac->read_isac(isac, ISACSX_ISTA);
749         DBG(DBG_IRQ, "ISTA %#x", val);
750
751         if (val & ISACSX_ISTA_ICD)
752                 isacsx_icd_interrupt(isac);
753         if (val & ISACSX_ISTA_CIC)
754                 isacsx_cic_interrupt(isac);
755 }
756
757 void isac_init(struct isac *isac)
758 {
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);
770 }
771
772 void isac_setup(struct isac *isac)
773 {
774         int val, eval;
775
776         isac->type = TYPE_ISAC;
777         isac_version(isac);
778
779         ph_command(isac, ISAC_CMD_RES);
780
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);
801         }
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);
813         }
814         val = isac->read_isac(isac, ISAC_CIR0);
815         DBG(2, "ISAC CIR0 %x", val);
816         FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
817
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);
821 }
822
823 void isacsx_setup(struct isac *isac)
824 {
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));
837 }
838
839 void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
840 {
841         struct isac *isac = hisax_d_if->priv;
842         struct sk_buff *skb = arg;
843
844         DBG(DBG_PR, "pr %#x", pr);
845
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;
860                 }
861                 BUG_ON(isac->tx_skb);
862
863                 isac->tx_skb = skb;
864                 isac_fill_fifo(isac);
865                 break;
866         }
867 }
868
869 static int __init hisax_isac_init(void)
870 {
871         printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
872
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));
878 }
879
880 static void __exit hisax_isac_exit(void)
881 {
882         FsmFree(&l1fsm);
883 }
884
885 EXPORT_SYMBOL(isac_init);
886 EXPORT_SYMBOL(isac_d_l2l1);
887
888 EXPORT_SYMBOL(isacsx_setup);
889 EXPORT_SYMBOL(isacsx_irq);
890
891 EXPORT_SYMBOL(isac_setup);
892 EXPORT_SYMBOL(isac_irq);
893
894 module_init(hisax_isac_init);
895 module_exit(hisax_isac_exit);