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
35static int debug = 1;
36module_param(debug, int, 0);
37
38static char *ISACVer[] = {
39	"2086/2186 V1.1",
40	"2085 B1",
41	"2085 B2",
42	"2085 V2.3"
43};
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
181#define L1_STATE_COUNT (ST_L1_F8 + 1)
182
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},
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
431static 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
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
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
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);
525		DBG(DBG_WARN, "ISAC CIR1 %#x", val);
526	}
527}
528
529static 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	memcpy(skb_put(skb, count), isac->rcvbuf, count);
561	DBG_SKB(DBG_RPACKET, skb);
562	D_L1L2(isac, PH_DATA | INDICATION, skb);
563out:
564	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);
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	memcpy(skb_put(skb, count), isac->rcvbuf, count);
691	DBG_SKB(DBG_RPACKET, skb);
692	D_L1L2(isac, PH_DATA | INDICATION, skb);
693out:
694	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
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
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
835	isac->write_isac(isac, ISACSX_MASK,
836			 ~(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		}
861		BUG_ON(isac->tx_skb);
862
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);
896