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
D_L1L2(struct isac * isac,int pr,void * arg)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
ph_command(struct isac * isac,unsigned int command)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
l1_di(struct FsmInst * fi,int event,void * arg)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
l1_di_deact_ind(struct FsmInst * fi,int event,void * arg)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
l1_go_f3pdown(struct FsmInst * fi,int event,void * arg)283 static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
284 {
285 FsmChangeState(fi, ST_L1_F3_PDOWN);
286 }
287
l1_go_f3pend_deact_ind(struct FsmInst * fi,int event,void * arg)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
l1_go_f3pend(struct FsmInst * fi,int event,void * arg)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
l1_go_f4(struct FsmInst * fi,int event,void * arg)305 static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
306 {
307 FsmChangeState(fi, ST_L1_F4);
308 }
309
l1_go_f5(struct FsmInst * fi,int event,void * arg)310 static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
311 {
312 FsmChangeState(fi, ST_L1_F5);
313 }
314
l1_go_f6(struct FsmInst * fi,int event,void * arg)315 static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
316 {
317 FsmChangeState(fi, ST_L1_F6);
318 }
319
l1_go_f6_deact_ind(struct FsmInst * fi,int event,void * arg)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
l1_go_f7_act_ind(struct FsmInst * fi,int event,void * arg)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
l1_go_f8(struct FsmInst * fi,int event,void * arg)338 static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
339 {
340 FsmChangeState(fi, ST_L1_F8);
341 }
342
l1_go_f8_deact_ind(struct FsmInst * fi,int event,void * arg)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
l1_ar8(struct FsmInst * fi,int event,void * arg)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
l1_timer3(struct FsmInst * fi,int event,void * arg)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
l1m_debug(struct FsmInst * fi,char * fmt,...)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
isac_version(struct isac * cs)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
isac_empty_fifo(struct isac * isac,int count)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
isac_fill_fifo(struct isac * isac)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
isac_retransmit(struct isac * isac)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
isac_cisq_interrupt(struct isac * isac)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
isac_rme_interrupt(struct isac * isac)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 skb_put_data(skb, 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
isac_xpr_interrupt(struct isac * isac)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
isac_exi_interrupt(struct isac * isac)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
isac_irq(struct isac * isac)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
isacsx_cic_interrupt(struct isac * isac)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
isacsx_rme_interrupt(struct isac * isac)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 skb_put_data(skb, 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
isacsx_xpr_interrupt(struct isac * isac)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
isacsx_icd_interrupt(struct isac * isac)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
isacsx_irq(struct isac * isac)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
isac_init(struct isac * isac)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
isac_setup(struct isac * isac)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
isacsx_setup(struct isac * isac)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
isac_d_l2l1(struct hisax_if * hisax_d_if,int pr,void * arg)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
hisax_isac_init(void)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
hisax_isac_exit(void)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);
896