blob: 5154c252a25fe73e8d4af8de96955f2a2f245a69 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Joe Perches475be4d2012-02-19 19:52:38 -08002 * Driver for ISAC-S and ISAC-SX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * 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>
Joe Perches475be4d2012-02-19 19:52:38 -08008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * 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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090024#include <linux/gfp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#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
35static int debug = 1;
36module_param(debug, int, 0);
37
38static char *ISACVer[] = {
Joe Perches475be4d2012-02-19 19:52:38 -080039 "2086/2186 V1.1",
40 "2085 B1",
41 "2085 B2",
42 "2085 V2.3"
Linus Torvalds1da177e2005-04-16 15:20:36 -070043};
44#endif
45
46MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
47MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
48MODULE_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
167static struct Fsm l1fsm;
168
169enum {
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
Joe Perches475be4d2012-02-19 19:52:38 -0800181#define L1_STATE_COUNT (ST_L1_F8 + 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183static 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
196enum {
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
220static 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
243static 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
251static 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
266static 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
274static 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
283static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
284{
285 FsmChangeState(fi, ST_L1_F3_PDOWN);
286}
287
288static 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
297static 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
305static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
306{
307 FsmChangeState(fi, ST_L1_F4);
308}
309
310static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
311{
312 FsmChangeState(fi, ST_L1_F5);
313}
314
315static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
316{
317 FsmChangeState(fi, ST_L1_F6);
318}
319
320static 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
328static 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
338static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
339{
340 FsmChangeState(fi, ST_L1_F8);
341}
342
343static 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
351static 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
359static 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
369static 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},
Joe Perches475be4d2012-02-19 19:52:38 -0800385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 {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
431static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
432{
433 va_list args;
434 char buf[256];
Joe Perches475be4d2012-02-19 19:52:38 -0800435
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 va_start(args, fmt);
Alexey Dobriyan0b2dd132006-12-08 02:39:34 -0800437 vsnprintf(buf, sizeof(buf), fmt, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 DBG(DBG_L1M, "%s", buf);
439 va_end(args);
440}
441
442static 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
450static 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
471static 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
Eric Sesterhenn6dd44a72006-03-26 18:19:26 +0200480 BUG_ON(!isac->tx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
482 count = isac->tx_skb->len;
Eric Sesterhenn6dd44a72006-03-26 18:19:26 +0200483 BUG_ON(count <= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
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
502static 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
513static 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);
Joe Perches475be4d2012-02-19 19:52:38 -0800525 DBG(DBG_WARN, "ISAC CIR1 %#x", val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 }
527}
528
529static inline void isac_rme_interrupt(struct isac *isac)
530{
531 unsigned char val;
532 int count;
533 struct sk_buff *skb;
Joe Perches475be4d2012-02-19 19:52:38 -0800534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 val = isac->read_isac(isac, ISAC_RSTA);
Joe Perches475be4d2012-02-19 19:52:38 -0800536 if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB))
537 != ISAC_RSTA_CRC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 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);
Joe Perches475be4d2012-02-19 19:52:38 -0800563out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 isac->rcvidx = 0;
565}
566
567static 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
582static 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
604void 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
643static 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
655static 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);
Joe Perches475be4d2012-02-19 19:52:38 -0800662 if ((val & (ISACSX_RSTAD_VFR |
663 ISACSX_RSTAD_RDO |
664 ISACSX_RSTAD_CRC |
665 ISACSX_RSTAD_RAB))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 != (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);
Joe Perches475be4d2012-02-19 19:52:38 -0800693out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 isac->rcvidx = 0;
695}
696
697static 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
712static 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
744void 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
757void 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
772void 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
Joe Perches475be4d2012-02-19 19:52:38 -0800781 isac->write_isac(isac, ISAC_MASK, 0xff);
782 isac->mocr = 0xaa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 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
823void 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
Joe Perches475be4d2012-02-19 19:52:38 -0800835 isac->write_isac(isac, ISACSX_MASK,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
837}
838
839void 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 }
Eric Sesterhenn6dd44a72006-03-26 18:19:26 +0200861 BUG_ON(isac->tx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
863 isac->tx_skb = skb;
864 isac_fill_fifo(isac);
865 break;
866 }
867}
868
869static 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
880static void __exit hisax_isac_exit(void)
881{
882 FsmFree(&l1fsm);
883}
884
885EXPORT_SYMBOL(isac_init);
886EXPORT_SYMBOL(isac_d_l2l1);
887
888EXPORT_SYMBOL(isacsx_setup);
889EXPORT_SYMBOL(isacsx_irq);
890
891EXPORT_SYMBOL(isac_setup);
892EXPORT_SYMBOL(isac_irq);
893
894module_init(hisax_isac_init);
895module_exit(hisax_isac_exit);