aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/hisax/hisax_isac.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/hisax/hisax_isac.c')
-rw-r--r--drivers/isdn/hisax/hisax_isac.c897
1 files changed, 897 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c
new file mode 100644
index 000000000000..f4972f6c1f5d
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_isac.c
@@ -0,0 +1,897 @@
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
34static int debug = 1;
35module_param(debug, int, 0);
36
37static char *ISACVer[] = {
38 "2086/2186 V1.1",
39 "2085 B1",
40 "2085 B2",
41 "2085 V2.3"
42};
43#endif
44
45MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
46MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
47MODULE_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
166static struct Fsm l1fsm;
167
168enum {
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
182static 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
195enum {
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
219static 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
242static 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
250static 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
265static 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
273static 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
282static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
283{
284 FsmChangeState(fi, ST_L1_F3_PDOWN);
285}
286
287static 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
296static 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
304static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
305{
306 FsmChangeState(fi, ST_L1_F4);
307}
308
309static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
310{
311 FsmChangeState(fi, ST_L1_F5);
312}
313
314static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
315{
316 FsmChangeState(fi, ST_L1_F6);
317}
318
319static 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
327static 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
337static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
338{
339 FsmChangeState(fi, ST_L1_F8);
340}
341
342static 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
350static 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
358static 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
368static 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
430static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
431{
432 va_list args;
433 char buf[256];
434
435 va_start(args, fmt);
436 vsprintf(buf, fmt, args);
437 DBG(DBG_L1M, "%s", buf);
438 va_end(args);
439}
440
441static 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
449static 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
470static 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 if (!isac->tx_skb)
480 BUG();
481
482 count = isac->tx_skb->len;
483 if (count <= 0)
484 BUG();
485
486 DBG(DBG_IRQ, "count %d", count);
487
488 if (count > 0x20) {
489 count = 0x20;
490 cmd = ISAC_CMDR_XTF;
491 } else {
492 cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
493 }
494
495 ptr = isac->tx_skb->data;
496 skb_pull(isac->tx_skb, count);
497 isac->tx_cnt += count;
498 DBG_PACKET(DBG_XFIFO, ptr, count);
499 isac->write_isac_fifo(isac, ptr, count);
500 isac->write_isac(isac, ISAC_CMDR, cmd);
501}
502
503static void isac_retransmit(struct isac *isac)
504{
505 if (!isac->tx_skb) {
506 DBG(DBG_WARN, "no skb");
507 return;
508 }
509 skb_push(isac->tx_skb, isac->tx_cnt);
510 isac->tx_cnt = 0;
511}
512
513
514static inline void isac_cisq_interrupt(struct isac *isac)
515{
516 unsigned char val;
517
518 val = isac->read_isac(isac, ISAC_CIR0);
519 DBG(DBG_IRQ, "CIR0 %#x", val);
520 if (val & ISAC_CIR0_CIC0) {
521 DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf);
522 FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
523 }
524 if (val & ISAC_CIR0_CIC1) {
525 val = isac->read_isac(isac, ISAC_CIR1);
526 DBG(DBG_WARN, "ISAC CIR1 %#x", val );
527 }
528}
529
530static inline void isac_rme_interrupt(struct isac *isac)
531{
532 unsigned char val;
533 int count;
534 struct sk_buff *skb;
535
536 val = isac->read_isac(isac, ISAC_RSTA);
537 if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB) )
538 != ISAC_RSTA_CRC) {
539 DBG(DBG_WARN, "RSTA %#x, dropped", val);
540 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
541 goto out;
542 }
543
544 count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
545 DBG(DBG_IRQ, "RBCL %#x", count);
546 if (count == 0)
547 count = 0x20;
548
549 isac_empty_fifo(isac, count);
550 count = isac->rcvidx;
551 if (count < 1) {
552 DBG(DBG_WARN, "count %d < 1", count);
553 goto out;
554 }
555
556 skb = alloc_skb(count, GFP_ATOMIC);
557 if (!skb) {
558 DBG(DBG_WARN, "no memory, dropping\n");
559 goto out;
560 }
561 memcpy(skb_put(skb, count), isac->rcvbuf, count);
562 DBG_SKB(DBG_RPACKET, skb);
563 D_L1L2(isac, PH_DATA | INDICATION, skb);
564 out:
565 isac->rcvidx = 0;
566}
567
568static inline void isac_xpr_interrupt(struct isac *isac)
569{
570 if (!isac->tx_skb)
571 return;
572
573 if (isac->tx_skb->len > 0) {
574 isac_fill_fifo(isac);
575 return;
576 }
577 dev_kfree_skb_irq(isac->tx_skb);
578 isac->tx_cnt = 0;
579 isac->tx_skb = NULL;
580 D_L1L2(isac, PH_DATA | CONFIRM, NULL);
581}
582
583static inline void isac_exi_interrupt(struct isac *isac)
584{
585 unsigned char val;
586
587 val = isac->read_isac(isac, ISAC_EXIR);
588 DBG(2, "EXIR %#x", val);
589
590 if (val & ISAC_EXIR_XMR) {
591 DBG(DBG_WARN, "ISAC XMR");
592 isac_retransmit(isac);
593 }
594 if (val & ISAC_EXIR_XDU) {
595 DBG(DBG_WARN, "ISAC XDU");
596 isac_retransmit(isac);
597 }
598 if (val & ISAC_EXIR_MOS) { /* MOS */
599 DBG(DBG_WARN, "MOS");
600 val = isac->read_isac(isac, ISAC_MOSR);
601 DBG(2, "ISAC MOSR %#x", val);
602 }
603}
604
605void isac_irq(struct isac *isac)
606{
607 unsigned char val;
608
609 val = isac->read_isac(isac, ISAC_ISTA);
610 DBG(DBG_IRQ, "ISTA %#x", val);
611
612 if (val & ISAC_ISTA_EXI) {
613 DBG(DBG_IRQ, "EXI");
614 isac_exi_interrupt(isac);
615 }
616 if (val & ISAC_ISTA_XPR) {
617 DBG(DBG_IRQ, "XPR");
618 isac_xpr_interrupt(isac);
619 }
620 if (val & ISAC_ISTA_RME) {
621 DBG(DBG_IRQ, "RME");
622 isac_rme_interrupt(isac);
623 }
624 if (val & ISAC_ISTA_RPF) {
625 DBG(DBG_IRQ, "RPF");
626 isac_empty_fifo(isac, 0x20);
627 }
628 if (val & ISAC_ISTA_CISQ) {
629 DBG(DBG_IRQ, "CISQ");
630 isac_cisq_interrupt(isac);
631 }
632 if (val & ISAC_ISTA_RSC) {
633 DBG(DBG_WARN, "RSC");
634 }
635 if (val & ISAC_ISTA_SIN) {
636 DBG(DBG_WARN, "SIN");
637 }
638 isac->write_isac(isac, ISAC_MASK, 0xff);
639 isac->write_isac(isac, ISAC_MASK, 0x00);
640}
641
642// ======================================================================
643
644static inline void isacsx_cic_interrupt(struct isac *isac)
645{
646 unsigned char val;
647
648 val = isac->read_isac(isac, ISACSX_CIR0);
649 DBG(DBG_IRQ, "CIR0 %#x", val);
650 if (val & ISACSX_CIR0_CIC0) {
651 DBG(DBG_IRQ, "CODR0 %#x", val >> 4);
652 FsmEvent(&isac->l1m, val >> 4, NULL);
653 }
654}
655
656static inline void isacsx_rme_interrupt(struct isac *isac)
657{
658 int count;
659 struct sk_buff *skb;
660 unsigned char val;
661
662 val = isac->read_isac(isac, ISACSX_RSTAD);
663 if ((val & (ISACSX_RSTAD_VFR |
664 ISACSX_RSTAD_RDO |
665 ISACSX_RSTAD_CRC |
666 ISACSX_RSTAD_RAB))
667 != (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) {
668 DBG(DBG_WARN, "RSTAD %#x, dropped", val);
669 isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
670 goto out;
671 }
672
673 count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
674 DBG(DBG_IRQ, "RBCLD %#x", count);
675 if (count == 0)
676 count = 0x20;
677
678 isac_empty_fifo(isac, count);
679 // strip trailing status byte
680 count = isac->rcvidx - 1;
681 if (count < 1) {
682 DBG(DBG_WARN, "count %d < 1", count);
683 goto out;
684 }
685
686 skb = dev_alloc_skb(count);
687 if (!skb) {
688 DBG(DBG_WARN, "no memory, dropping");
689 goto out;
690 }
691 memcpy(skb_put(skb, count), isac->rcvbuf, count);
692 DBG_SKB(DBG_RPACKET, skb);
693 D_L1L2(isac, PH_DATA | INDICATION, skb);
694 out:
695 isac->rcvidx = 0;
696}
697
698static inline void isacsx_xpr_interrupt(struct isac *isac)
699{
700 if (!isac->tx_skb)
701 return;
702
703 if (isac->tx_skb->len > 0) {
704 isac_fill_fifo(isac);
705 return;
706 }
707 dev_kfree_skb_irq(isac->tx_skb);
708 isac->tx_skb = NULL;
709 isac->tx_cnt = 0;
710 D_L1L2(isac, PH_DATA | CONFIRM, NULL);
711}
712
713static inline void isacsx_icd_interrupt(struct isac *isac)
714{
715 unsigned char val;
716
717 val = isac->read_isac(isac, ISACSX_ISTAD);
718 DBG(DBG_IRQ, "ISTAD %#x", val);
719 if (val & ISACSX_ISTAD_XDU) {
720 DBG(DBG_WARN, "ISTAD XDU");
721 isac_retransmit(isac);
722 }
723 if (val & ISACSX_ISTAD_XMR) {
724 DBG(DBG_WARN, "ISTAD XMR");
725 isac_retransmit(isac);
726 }
727 if (val & ISACSX_ISTAD_XPR) {
728 DBG(DBG_IRQ, "ISTAD XPR");
729 isacsx_xpr_interrupt(isac);
730 }
731 if (val & ISACSX_ISTAD_RFO) {
732 DBG(DBG_WARN, "ISTAD RFO");
733 isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
734 }
735 if (val & ISACSX_ISTAD_RME) {
736 DBG(DBG_IRQ, "ISTAD RME");
737 isacsx_rme_interrupt(isac);
738 }
739 if (val & ISACSX_ISTAD_RPF) {
740 DBG(DBG_IRQ, "ISTAD RPF");
741 isac_empty_fifo(isac, 0x20);
742 }
743}
744
745void isacsx_irq(struct isac *isac)
746{
747 unsigned char val;
748
749 val = isac->read_isac(isac, ISACSX_ISTA);
750 DBG(DBG_IRQ, "ISTA %#x", val);
751
752 if (val & ISACSX_ISTA_ICD)
753 isacsx_icd_interrupt(isac);
754 if (val & ISACSX_ISTA_CIC)
755 isacsx_cic_interrupt(isac);
756}
757
758void isac_init(struct isac *isac)
759{
760 isac->tx_skb = NULL;
761 isac->l1m.fsm = &l1fsm;
762 isac->l1m.state = ST_L1_RESET;
763#ifdef CONFIG_HISAX_DEBUG
764 isac->l1m.debug = 1;
765#else
766 isac->l1m.debug = 0;
767#endif
768 isac->l1m.userdata = isac;
769 isac->l1m.printdebug = l1m_debug;
770 FsmInitTimer(&isac->l1m, &isac->timer);
771}
772
773void isac_setup(struct isac *isac)
774{
775 int val, eval;
776
777 isac->type = TYPE_ISAC;
778 isac_version(isac);
779
780 ph_command(isac, ISAC_CMD_RES);
781
782 isac->write_isac(isac, ISAC_MASK, 0xff);
783 isac->mocr = 0xaa;
784 if (test_bit(ISAC_IOM1, &isac->flags)) {
785 /* IOM 1 Mode */
786 isac->write_isac(isac, ISAC_ADF2, 0x0);
787 isac->write_isac(isac, ISAC_SPCR, 0xa);
788 isac->write_isac(isac, ISAC_ADF1, 0x2);
789 isac->write_isac(isac, ISAC_STCR, 0x70);
790 isac->write_isac(isac, ISAC_MODE, 0xc9);
791 } else {
792 /* IOM 2 Mode */
793 if (!isac->adf2)
794 isac->adf2 = 0x80;
795 isac->write_isac(isac, ISAC_ADF2, isac->adf2);
796 isac->write_isac(isac, ISAC_SQXR, 0x2f);
797 isac->write_isac(isac, ISAC_SPCR, 0x00);
798 isac->write_isac(isac, ISAC_STCR, 0x70);
799 isac->write_isac(isac, ISAC_MODE, 0xc9);
800 isac->write_isac(isac, ISAC_TIMR, 0x00);
801 isac->write_isac(isac, ISAC_ADF1, 0x00);
802 }
803 val = isac->read_isac(isac, ISAC_STAR);
804 DBG(2, "ISAC STAR %x", val);
805 val = isac->read_isac(isac, ISAC_MODE);
806 DBG(2, "ISAC MODE %x", val);
807 val = isac->read_isac(isac, ISAC_ADF2);
808 DBG(2, "ISAC ADF2 %x", val);
809 val = isac->read_isac(isac, ISAC_ISTA);
810 DBG(2, "ISAC ISTA %x", val);
811 if (val & 0x01) {
812 eval = isac->read_isac(isac, ISAC_EXIR);
813 DBG(2, "ISAC EXIR %x", eval);
814 }
815 val = isac->read_isac(isac, ISAC_CIR0);
816 DBG(2, "ISAC CIR0 %x", val);
817 FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
818
819 isac->write_isac(isac, ISAC_MASK, 0x0);
820 // RESET Receiver and Transmitter
821 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES);
822}
823
824void isacsx_setup(struct isac *isac)
825{
826 isac->type = TYPE_ISACSX;
827 // clear LDD
828 isac->write_isac(isac, ISACSX_TR_CONF0, 0x00);
829 // enable transmitter
830 isac->write_isac(isac, ISACSX_TR_CONF2, 0x00);
831 // transparent mode 0, RAC, stop/go
832 isac->write_isac(isac, ISACSX_MODED, 0xc9);
833 // all HDLC IRQ unmasked
834 isac->write_isac(isac, ISACSX_MASKD, 0x03);
835 // unmask ICD, CID IRQs
836 isac->write_isac(isac, ISACSX_MASK,
837 ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
838}
839
840void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
841{
842 struct isac *isac = hisax_d_if->priv;
843 struct sk_buff *skb = arg;
844
845 DBG(DBG_PR, "pr %#x", pr);
846
847 switch (pr) {
848 case PH_ACTIVATE | REQUEST:
849 FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL);
850 break;
851 case PH_DEACTIVATE | REQUEST:
852 FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL);
853 break;
854 case PH_DATA | REQUEST:
855 DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
856 DBG_SKB(DBG_XPACKET, skb);
857 if (isac->l1m.state != ST_L1_F7) {
858 DBG(1, "L1 wrong state %d\n", isac->l1m.state);
859 dev_kfree_skb(skb);
860 break;
861 }
862 if (isac->tx_skb)
863 BUG();
864
865 isac->tx_skb = skb;
866 isac_fill_fifo(isac);
867 break;
868 }
869}
870
871static int __init hisax_isac_init(void)
872{
873 printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
874
875 l1fsm.state_count = L1_STATE_COUNT;
876 l1fsm.event_count = L1_EVENT_COUNT;
877 l1fsm.strState = strL1State;
878 l1fsm.strEvent = strL1Event;
879 return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
880}
881
882static void __exit hisax_isac_exit(void)
883{
884 FsmFree(&l1fsm);
885}
886
887EXPORT_SYMBOL(isac_init);
888EXPORT_SYMBOL(isac_d_l2l1);
889
890EXPORT_SYMBOL(isacsx_setup);
891EXPORT_SYMBOL(isacsx_irq);
892
893EXPORT_SYMBOL(isac_setup);
894EXPORT_SYMBOL(isac_irq);
895
896module_init(hisax_isac_init);
897module_exit(hisax_isac_exit);