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
34 static int debug = 1;
35 MODULE_PARM(debug, "i");
36 
37 static char *ISACVer[] = {
38   "2086/2186 V1.1",
39   "2085 B1",
40   "2085 B2",
41   "2085 V2.3"
42 };
43 #endif
44 
45 MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
46 MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
47 MODULE_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 
166 static struct Fsm l1fsm;
167 
168 enum {
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 
182 static 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 
195 enum {
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 
219 static 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 
D_L1L2(struct isac * isac,int pr,void * arg)242 static 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 
ph_command(struct isac * isac,unsigned int command)250 static 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 
l1_di(struct FsmInst * fi,int event,void * arg)265 static 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 
l1_di_deact_ind(struct FsmInst * fi,int event,void * arg)273 static 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 
l1_go_f3pdown(struct FsmInst * fi,int event,void * arg)282 static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
283 {
284 	FsmChangeState(fi, ST_L1_F3_PDOWN);
285 }
286 
l1_go_f3pend_deact_ind(struct FsmInst * fi,int event,void * arg)287 static 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 
l1_go_f3pend(struct FsmInst * fi,int event,void * arg)296 static 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 
l1_go_f4(struct FsmInst * fi,int event,void * arg)304 static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
305 {
306 	FsmChangeState(fi, ST_L1_F4);
307 }
308 
l1_go_f5(struct FsmInst * fi,int event,void * arg)309 static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
310 {
311 	FsmChangeState(fi, ST_L1_F5);
312 }
313 
l1_go_f6(struct FsmInst * fi,int event,void * arg)314 static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
315 {
316 	FsmChangeState(fi, ST_L1_F6);
317 }
318 
l1_go_f6_deact_ind(struct FsmInst * fi,int event,void * arg)319 static 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 
l1_go_f7_act_ind(struct FsmInst * fi,int event,void * arg)327 static 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 
l1_go_f8(struct FsmInst * fi,int event,void * arg)337 static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
338 {
339 	FsmChangeState(fi, ST_L1_F8);
340 }
341 
l1_go_f8_deact_ind(struct FsmInst * fi,int event,void * arg)342 static 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 
l1_ar8(struct FsmInst * fi,int event,void * arg)350 static 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 
l1_timer3(struct FsmInst * fi,int event,void * arg)358 static 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 
368 static 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 
l1m_debug(struct FsmInst * fi,char * fmt,...)430 static 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 
isac_version(struct isac * cs)441 static 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 
isac_empty_fifo(struct isac * isac,int count)449 static 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 
isac_fill_fifo(struct isac * isac)470 static 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 
isac_retransmit(struct isac * isac)503 static 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 
isac_cisq_interrupt(struct isac * isac)514 static 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 
isac_rme_interrupt(struct isac * isac)530 static 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 
isac_xpr_interrupt(struct isac * isac)568 static 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 
isac_exi_interrupt(struct isac * isac)583 static 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 
isac_irq(struct isac * isac)605 void 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 
isacsx_cic_interrupt(struct isac * isac)644 static 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 
isacsx_rme_interrupt(struct isac * isac)656 static 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 
isacsx_xpr_interrupt(struct isac * isac)698 static 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 
isacsx_icd_interrupt(struct isac * isac)713 static 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 
isacsx_irq(struct isac * isac)745 void 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 
isac_init(struct isac * isac)758 void 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 
isac_setup(struct isac * isac)773 void 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 
isacsx_setup(struct isac * isac)824 void 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 
isac_d_l2l1(struct hisax_if * hisax_d_if,int pr,void * arg)840 void 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 
hisax_isac_init(void)871 static 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 
hisax_isac_exit(void)882 static void __exit hisax_isac_exit(void)
883 {
884 	FsmFree(&l1fsm);
885 }
886 
887 EXPORT_SYMBOL(isac_init);
888 EXPORT_SYMBOL(isac_d_l2l1);
889 
890 EXPORT_SYMBOL(isacsx_setup);
891 EXPORT_SYMBOL(isacsx_irq);
892 
893 EXPORT_SYMBOL(isac_setup);
894 EXPORT_SYMBOL(isac_irq);
895 
896 module_init(hisax_isac_init);
897 module_exit(hisax_isac_exit);
898