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