1/* $Id: isac.c,v 1.1.1.1 2007/08/03 18:52:35 Exp $
2 *
3 * ISAC specific routines
4 *
5 * Author       Karsten Keil
6 * Copyright    by Karsten Keil      <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * For changes and modifications please read
12 * Documentation/isdn/HiSax.cert
13 *
14 */
15
16#include "hisax.h"
17#include "isac.h"
18#include "arcofi.h"
19#include "isdnl1.h"
20#include <linux/interrupt.h>
21#include <linux/init.h>
22
23#define DBUSY_TIMER_VALUE 80
24#define ARCOFI_USE 1
25
26static char *ISACVer[] __devinitdata =
27{"2086/2186 V1.1", "2085 B1", "2085 B2",
28 "2085 V2.3"};
29
30void
31ISACVersion(struct IsdnCardState *cs, char *s)
32{
33	int val;
34
35	val = cs->readisac(cs, ISAC_RBCH);
36	printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]);
37}
38
39static void
40ph_command(struct IsdnCardState *cs, unsigned int command)
41{
42	if (cs->debug & L1_DEB_ISAC)
43		debugl1(cs, "ph_command %x", command);
44	cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3);
45}
46
47
48static void
49isac_new_ph(struct IsdnCardState *cs)
50{
51	switch (cs->dc.isac.ph_state) {
52		case (ISAC_IND_RS):
53		case (ISAC_IND_EI):
54			ph_command(cs, ISAC_CMD_DUI);
55			l1_msg(cs, HW_RESET | INDICATION, NULL);
56			break;
57		case (ISAC_IND_DID):
58			l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
59			break;
60		case (ISAC_IND_DR):
61			l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
62			break;
63		case (ISAC_IND_PU):
64			l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
65			break;
66		case (ISAC_IND_RSY):
67			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
68			break;
69		case (ISAC_IND_ARD):
70			l1_msg(cs, HW_INFO2 | INDICATION, NULL);
71			break;
72		case (ISAC_IND_AI8):
73			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
74			break;
75		case (ISAC_IND_AI10):
76			l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
77			break;
78		default:
79			break;
80	}
81}
82
83static void
84isac_bh(struct work_struct *work)
85{
86	struct IsdnCardState *cs =
87		container_of(work, struct IsdnCardState, tqueue);
88	struct PStack *stptr;
89
90	if (!cs)
91		return;
92	if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
93		if (cs->debug)
94			debugl1(cs, "D-Channel Busy cleared");
95		stptr = cs->stlist;
96		while (stptr != NULL) {
97			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
98			stptr = stptr->next;
99		}
100	}
101	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
102		isac_new_ph(cs);
103	if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
104		DChannel_proc_rcv(cs);
105	if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
106		DChannel_proc_xmt(cs);
107#if ARCOFI_USE
108	if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
109		return;
110	if (test_and_clear_bit(D_RX_MON1, &cs->event))
111		arcofi_fsm(cs, ARCOFI_RX_END, NULL);
112	if (test_and_clear_bit(D_TX_MON1, &cs->event))
113		arcofi_fsm(cs, ARCOFI_TX_END, NULL);
114#endif
115}
116
117static void
118isac_empty_fifo(struct IsdnCardState *cs, int count)
119{
120	u_char *ptr;
121
122	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
123		debugl1(cs, "isac_empty_fifo");
124
125	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
126		if (cs->debug & L1_DEB_WARN)
127			debugl1(cs, "isac_empty_fifo overrun %d",
128				cs->rcvidx + count);
129		cs->writeisac(cs, ISAC_CMDR, 0x80);
130		cs->rcvidx = 0;
131		return;
132	}
133	ptr = cs->rcvbuf + cs->rcvidx;
134	cs->rcvidx += count;
135	cs->readisacfifo(cs, ptr, count);
136	cs->writeisac(cs, ISAC_CMDR, 0x80);
137	if (cs->debug & L1_DEB_ISAC_FIFO) {
138		char *t = cs->dlog;
139
140		t += sprintf(t, "isac_empty_fifo cnt %d", count);
141		QuickHex(t, ptr, count);
142		debugl1(cs, cs->dlog);
143	}
144}
145
146static void
147isac_fill_fifo(struct IsdnCardState *cs)
148{
149	int count, more;
150	u_char *ptr;
151
152	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
153		debugl1(cs, "isac_fill_fifo");
154
155	if (!cs->tx_skb)
156		return;
157
158	count = cs->tx_skb->len;
159	if (count <= 0)
160		return;
161
162	more = 0;
163	if (count > 32) {
164		more = !0;
165		count = 32;
166	}
167	ptr = cs->tx_skb->data;
168	skb_pull(cs->tx_skb, count);
169	cs->tx_cnt += count;
170	cs->writeisacfifo(cs, ptr, count);
171	cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa);
172	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
173		debugl1(cs, "isac_fill_fifo dbusytimer running");
174		del_timer(&cs->dbusytimer);
175	}
176	init_timer(&cs->dbusytimer);
177	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
178	add_timer(&cs->dbusytimer);
179	if (cs->debug & L1_DEB_ISAC_FIFO) {
180		char *t = cs->dlog;
181
182		t += sprintf(t, "isac_fill_fifo cnt %d", count);
183		QuickHex(t, ptr, count);
184		debugl1(cs, cs->dlog);
185	}
186}
187
188void
189isac_interrupt(struct IsdnCardState *cs, u_char val)
190{
191	u_char exval, v1;
192	struct sk_buff *skb;
193	unsigned int count;
194
195	if (cs->debug & L1_DEB_ISAC)
196		debugl1(cs, "ISAC interrupt %x", val);
197	if (val & 0x80) {	/* RME */
198		exval = cs->readisac(cs, ISAC_RSTA);
199		if ((exval & 0x70) != 0x20) {
200			if (exval & 0x40) {
201				if (cs->debug & L1_DEB_WARN)
202					debugl1(cs, "ISAC RDO");
203#ifdef ERROR_STATISTIC
204				cs->err_rx++;
205#endif
206			}
207			if (!(exval & 0x20)) {
208				if (cs->debug & L1_DEB_WARN)
209					debugl1(cs, "ISAC CRC error");
210#ifdef ERROR_STATISTIC
211				cs->err_crc++;
212#endif
213			}
214			cs->writeisac(cs, ISAC_CMDR, 0x80);
215		} else {
216			count = cs->readisac(cs, ISAC_RBCL) & 0x1f;
217			if (count == 0)
218				count = 32;
219			isac_empty_fifo(cs, count);
220			if ((count = cs->rcvidx) > 0) {
221				cs->rcvidx = 0;
222				if (!(skb = alloc_skb(count, GFP_ATOMIC)))
223					printk(KERN_WARNING "HiSax: D receive out of memory\n");
224				else {
225					memcpy(skb_put(skb, count), cs->rcvbuf, count);
226					skb_queue_tail(&cs->rq, skb);
227				}
228			}
229		}
230		cs->rcvidx = 0;
231		schedule_event(cs, D_RCVBUFREADY);
232	}
233	if (val & 0x40) {	/* RPF */
234		isac_empty_fifo(cs, 32);
235	}
236	if (val & 0x20) {	/* RSC */
237		/* never */
238		if (cs->debug & L1_DEB_WARN)
239			debugl1(cs, "ISAC RSC interrupt");
240	}
241	if (val & 0x10) {	/* XPR */
242		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
243			del_timer(&cs->dbusytimer);
244		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
245			schedule_event(cs, D_CLEARBUSY);
246		if (cs->tx_skb) {
247			if (cs->tx_skb->len) {
248				isac_fill_fifo(cs);
249				goto afterXPR;
250			} else {
251				dev_kfree_skb_irq(cs->tx_skb);
252				cs->tx_cnt = 0;
253				cs->tx_skb = NULL;
254			}
255		}
256		if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
257			cs->tx_cnt = 0;
258			isac_fill_fifo(cs);
259		} else
260			schedule_event(cs, D_XMTBUFREADY);
261	}
262      afterXPR:
263	if (val & 0x04) {	/* CISQ */
264		exval = cs->readisac(cs, ISAC_CIR0);
265		if (cs->debug & L1_DEB_ISAC)
266			debugl1(cs, "ISAC CIR0 %02X", exval );
267		if (exval & 2) {
268			cs->dc.isac.ph_state = (exval >> 2) & 0xf;
269			if (cs->debug & L1_DEB_ISAC)
270				debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state);
271			schedule_event(cs, D_L1STATECHANGE);
272		}
273		if (exval & 1) {
274			exval = cs->readisac(cs, ISAC_CIR1);
275			if (cs->debug & L1_DEB_ISAC)
276				debugl1(cs, "ISAC CIR1 %02X", exval );
277		}
278	}
279	if (val & 0x02) {	/* SIN */
280		/* never */
281		if (cs->debug & L1_DEB_WARN)
282			debugl1(cs, "ISAC SIN interrupt");
283	}
284	if (val & 0x01) {	/* EXI */
285		exval = cs->readisac(cs, ISAC_EXIR);
286		if (cs->debug & L1_DEB_WARN)
287			debugl1(cs, "ISAC EXIR %02x", exval);
288		if (exval & 0x80) {  /* XMR */
289			debugl1(cs, "ISAC XMR");
290			printk(KERN_WARNING "HiSax: ISAC XMR\n");
291		}
292		if (exval & 0x40) {  /* XDU */
293			debugl1(cs, "ISAC XDU");
294			printk(KERN_WARNING "HiSax: ISAC XDU\n");
295#ifdef ERROR_STATISTIC
296			cs->err_tx++;
297#endif
298			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
299				del_timer(&cs->dbusytimer);
300			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
301				schedule_event(cs, D_CLEARBUSY);
302			if (cs->tx_skb) { /* Restart frame */
303				skb_push(cs->tx_skb, cs->tx_cnt);
304				cs->tx_cnt = 0;
305				isac_fill_fifo(cs);
306			} else {
307				printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
308				debugl1(cs, "ISAC XDU no skb");
309			}
310		}
311		if (exval & 0x04) {  /* MOS */
312			v1 = cs->readisac(cs, ISAC_MOSR);
313			if (cs->debug & L1_DEB_MONITOR)
314				debugl1(cs, "ISAC MOSR %02x", v1);
315#if ARCOFI_USE
316			if (v1 & 0x08) {
317				if (!cs->dc.isac.mon_rx) {
318					if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
319						if (cs->debug & L1_DEB_WARN)
320							debugl1(cs, "ISAC MON RX out of memory!");
321						cs->dc.isac.mocr &= 0xf0;
322						cs->dc.isac.mocr |= 0x0a;
323						cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
324						goto afterMONR0;
325					} else
326						cs->dc.isac.mon_rxp = 0;
327				}
328				if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
329					cs->dc.isac.mocr &= 0xf0;
330					cs->dc.isac.mocr |= 0x0a;
331					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
332					cs->dc.isac.mon_rxp = 0;
333					if (cs->debug & L1_DEB_WARN)
334						debugl1(cs, "ISAC MON RX overflow!");
335					goto afterMONR0;
336				}
337				cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
338				if (cs->debug & L1_DEB_MONITOR)
339					debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]);
340				if (cs->dc.isac.mon_rxp == 1) {
341					cs->dc.isac.mocr |= 0x04;
342					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
343				}
344			}
345		      afterMONR0:
346			if (v1 & 0x80) {
347				if (!cs->dc.isac.mon_rx) {
348					if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
349						if (cs->debug & L1_DEB_WARN)
350							debugl1(cs, "ISAC MON RX out of memory!");
351						cs->dc.isac.mocr &= 0x0f;
352						cs->dc.isac.mocr |= 0xa0;
353						cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
354						goto afterMONR1;
355					} else
356						cs->dc.isac.mon_rxp = 0;
357				}
358				if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
359					cs->dc.isac.mocr &= 0x0f;
360					cs->dc.isac.mocr |= 0xa0;
361					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
362					cs->dc.isac.mon_rxp = 0;
363					if (cs->debug & L1_DEB_WARN)
364						debugl1(cs, "ISAC MON RX overflow!");
365					goto afterMONR1;
366				}
367				cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
368				if (cs->debug & L1_DEB_MONITOR)
369					debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]);
370				cs->dc.isac.mocr |= 0x40;
371				cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
372			}
373		      afterMONR1:
374			if (v1 & 0x04) {
375				cs->dc.isac.mocr &= 0xf0;
376				cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
377				cs->dc.isac.mocr |= 0x0a;
378				cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
379				schedule_event(cs, D_RX_MON0);
380			}
381			if (v1 & 0x40) {
382				cs->dc.isac.mocr &= 0x0f;
383				cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
384				cs->dc.isac.mocr |= 0xa0;
385				cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
386				schedule_event(cs, D_RX_MON1);
387			}
388			if (v1 & 0x02) {
389				if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
390					(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
391					!(v1 & 0x08))) {
392					cs->dc.isac.mocr &= 0xf0;
393					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
394					cs->dc.isac.mocr |= 0x0a;
395					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
396					if (cs->dc.isac.mon_txc &&
397						(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
398						schedule_event(cs, D_TX_MON0);
399					goto AfterMOX0;
400				}
401				if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
402					schedule_event(cs, D_TX_MON0);
403					goto AfterMOX0;
404				}
405				cs->writeisac(cs, ISAC_MOX0,
406					cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
407				if (cs->debug & L1_DEB_MONITOR)
408					debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]);
409			}
410		      AfterMOX0:
411			if (v1 & 0x20) {
412				if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
413					(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
414					!(v1 & 0x80))) {
415					cs->dc.isac.mocr &= 0x0f;
416					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
417					cs->dc.isac.mocr |= 0xa0;
418					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
419					if (cs->dc.isac.mon_txc &&
420						(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
421						schedule_event(cs, D_TX_MON1);
422					goto AfterMOX1;
423				}
424				if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
425					schedule_event(cs, D_TX_MON1);
426					goto AfterMOX1;
427				}
428				cs->writeisac(cs, ISAC_MOX1,
429					cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
430				if (cs->debug & L1_DEB_MONITOR)
431					debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]);
432			}
433		      AfterMOX1:;
434#endif
435		}
436	}
437}
438
439static void
440ISAC_l1hw(struct PStack *st, int pr, void *arg)
441{
442	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
443	struct sk_buff *skb = arg;
444	u_long flags;
445	int  val;
446
447	switch (pr) {
448		case (PH_DATA |REQUEST):
449			if (cs->debug & DEB_DLOG_HEX)
450				LogFrame(cs, skb->data, skb->len);
451			if (cs->debug & DEB_DLOG_VERBOSE)
452				dlogframe(cs, skb, 0);
453			spin_lock_irqsave(&cs->lock, flags);
454			if (cs->tx_skb) {
455				skb_queue_tail(&cs->sq, skb);
456#ifdef L2FRAME_DEBUG		    /* psa */
457				if (cs->debug & L1_DEB_LAPD)
458					Logl2Frame(cs, skb, "PH_DATA Queued", 0);
459#endif
460			} else {
461				cs->tx_skb = skb;
462				cs->tx_cnt = 0;
463#ifdef L2FRAME_DEBUG		    /* psa */
464				if (cs->debug & L1_DEB_LAPD)
465					Logl2Frame(cs, skb, "PH_DATA", 0);
466#endif
467				isac_fill_fifo(cs);
468			}
469			spin_unlock_irqrestore(&cs->lock, flags);
470			break;
471		case (PH_PULL |INDICATION):
472			spin_lock_irqsave(&cs->lock, flags);
473			if (cs->tx_skb) {
474				if (cs->debug & L1_DEB_WARN)
475					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
476				skb_queue_tail(&cs->sq, skb);
477			} else {
478				if (cs->debug & DEB_DLOG_HEX)
479					LogFrame(cs, skb->data, skb->len);
480				if (cs->debug & DEB_DLOG_VERBOSE)
481					dlogframe(cs, skb, 0);
482				cs->tx_skb = skb;
483				cs->tx_cnt = 0;
484#ifdef L2FRAME_DEBUG		    /* psa */
485				if (cs->debug & L1_DEB_LAPD)
486					Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
487#endif
488				isac_fill_fifo(cs);
489			}
490			spin_unlock_irqrestore(&cs->lock, flags);
491			break;
492		case (PH_PULL | REQUEST):
493#ifdef L2FRAME_DEBUG		    /* psa */
494			if (cs->debug & L1_DEB_LAPD)
495				debugl1(cs, "-> PH_REQUEST_PULL");
496#endif
497			if (!cs->tx_skb) {
498				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
499				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
500			} else
501				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
502			break;
503		case (HW_RESET | REQUEST):
504			spin_lock_irqsave(&cs->lock, flags);
505			if ((cs->dc.isac.ph_state == ISAC_IND_EI) ||
506				(cs->dc.isac.ph_state == ISAC_IND_DR) ||
507				(cs->dc.isac.ph_state == ISAC_IND_RS))
508			        ph_command(cs, ISAC_CMD_TIM);
509			else
510				ph_command(cs, ISAC_CMD_RS);
511			spin_unlock_irqrestore(&cs->lock, flags);
512			break;
513		case (HW_ENABLE | REQUEST):
514			spin_lock_irqsave(&cs->lock, flags);
515			ph_command(cs, ISAC_CMD_TIM);
516			spin_unlock_irqrestore(&cs->lock, flags);
517			break;
518		case (HW_INFO3 | REQUEST):
519			spin_lock_irqsave(&cs->lock, flags);
520			ph_command(cs, ISAC_CMD_AR8);
521			spin_unlock_irqrestore(&cs->lock, flags);
522			break;
523		case (HW_TESTLOOP | REQUEST):
524			spin_lock_irqsave(&cs->lock, flags);
525			val = 0;
526			if (1 & (long) arg)
527				val |= 0x0c;
528			if (2 & (long) arg)
529				val |= 0x3;
530			if (test_bit(HW_IOM1, &cs->HW_Flags)) {
531				/* IOM 1 Mode */
532				if (!val) {
533					cs->writeisac(cs, ISAC_SPCR, 0xa);
534					cs->writeisac(cs, ISAC_ADF1, 0x2);
535				} else {
536					cs->writeisac(cs, ISAC_SPCR, val);
537					cs->writeisac(cs, ISAC_ADF1, 0xa);
538				}
539			} else {
540				/* IOM 2 Mode */
541				cs->writeisac(cs, ISAC_SPCR, val);
542				if (val)
543					cs->writeisac(cs, ISAC_ADF1, 0x8);
544				else
545					cs->writeisac(cs, ISAC_ADF1, 0x0);
546			}
547			spin_unlock_irqrestore(&cs->lock, flags);
548			break;
549		case (HW_DEACTIVATE | RESPONSE):
550			skb_queue_purge(&cs->rq);
551			skb_queue_purge(&cs->sq);
552			if (cs->tx_skb) {
553				dev_kfree_skb_any(cs->tx_skb);
554				cs->tx_skb = NULL;
555			}
556			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
557				del_timer(&cs->dbusytimer);
558			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
559				schedule_event(cs, D_CLEARBUSY);
560			break;
561		default:
562			if (cs->debug & L1_DEB_WARN)
563				debugl1(cs, "isac_l1hw unknown %04x", pr);
564			break;
565	}
566}
567
568static void
569setstack_isac(struct PStack *st, struct IsdnCardState *cs)
570{
571	st->l1.l1hw = ISAC_l1hw;
572}
573
574static void
575DC_Close_isac(struct IsdnCardState *cs)
576{
577	kfree(cs->dc.isac.mon_rx);
578	cs->dc.isac.mon_rx = NULL;
579	kfree(cs->dc.isac.mon_tx);
580	cs->dc.isac.mon_tx = NULL;
581}
582
583static void
584dbusy_timer_handler(struct IsdnCardState *cs)
585{
586	struct PStack *stptr;
587	int	rbch, star;
588
589	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
590		rbch = cs->readisac(cs, ISAC_RBCH);
591		star = cs->readisac(cs, ISAC_STAR);
592		if (cs->debug)
593			debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
594				rbch, star);
595		if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */
596			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
597			stptr = cs->stlist;
598			while (stptr != NULL) {
599				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
600				stptr = stptr->next;
601			}
602		} else {
603			/* discard frame; reset transceiver */
604			test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
605			if (cs->tx_skb) {
606				dev_kfree_skb_any(cs->tx_skb);
607				cs->tx_cnt = 0;
608				cs->tx_skb = NULL;
609			} else {
610				printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
611				debugl1(cs, "D-Channel Busy no skb");
612			}
613			cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
614			cs->irq_func(cs->irq, cs);
615		}
616	}
617}
618
619void __devinit
620initisac(struct IsdnCardState *cs)
621{
622	cs->setstack_d = setstack_isac;
623	cs->DC_Close = DC_Close_isac;
624	cs->dc.isac.mon_tx = NULL;
625	cs->dc.isac.mon_rx = NULL;
626  	cs->writeisac(cs, ISAC_MASK, 0xff);
627  	cs->dc.isac.mocr = 0xaa;
628	if (test_bit(HW_IOM1, &cs->HW_Flags)) {
629		/* IOM 1 Mode */
630		cs->writeisac(cs, ISAC_ADF2, 0x0);
631		cs->writeisac(cs, ISAC_SPCR, 0xa);
632		cs->writeisac(cs, ISAC_ADF1, 0x2);
633		cs->writeisac(cs, ISAC_STCR, 0x70);
634		cs->writeisac(cs, ISAC_MODE, 0xc9);
635	} else {
636		/* IOM 2 Mode */
637		if (!cs->dc.isac.adf2)
638			cs->dc.isac.adf2 = 0x80;
639		cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2);
640		cs->writeisac(cs, ISAC_SQXR, 0x2f);
641		cs->writeisac(cs, ISAC_SPCR, 0x00);
642		cs->writeisac(cs, ISAC_STCR, 0x70);
643		cs->writeisac(cs, ISAC_MODE, 0xc9);
644		cs->writeisac(cs, ISAC_TIMR, 0x00);
645		cs->writeisac(cs, ISAC_ADF1, 0x00);
646	}
647	ph_command(cs, ISAC_CMD_RS);
648	cs->writeisac(cs, ISAC_MASK, 0x0);
649}
650
651void __devinit
652clear_pending_isac_ints(struct IsdnCardState *cs)
653{
654	int val, eval;
655
656	val = cs->readisac(cs, ISAC_STAR);
657	debugl1(cs, "ISAC STAR %x", val);
658	val = cs->readisac(cs, ISAC_MODE);
659	debugl1(cs, "ISAC MODE %x", val);
660	val = cs->readisac(cs, ISAC_ADF2);
661	debugl1(cs, "ISAC ADF2 %x", val);
662	val = cs->readisac(cs, ISAC_ISTA);
663	debugl1(cs, "ISAC ISTA %x", val);
664	if (val & 0x01) {
665		eval = cs->readisac(cs, ISAC_EXIR);
666		debugl1(cs, "ISAC EXIR %x", eval);
667	}
668	val = cs->readisac(cs, ISAC_CIR0);
669	debugl1(cs, "ISAC CIR0 %x", val);
670	cs->dc.isac.ph_state = (val >> 2) & 0xf;
671	schedule_event(cs, D_L1STATECHANGE);
672	/* Disable all IRQ */
673	cs->writeisac(cs, ISAC_MASK, 0xFF);
674}
675
676void __devinit
677setup_isac(struct IsdnCardState *cs)
678{
679	INIT_WORK(&cs->tqueue, isac_bh);
680	cs->dbusytimer.function = (void *) dbusy_timer_handler;
681	cs->dbusytimer.data = (long) cs;
682	init_timer(&cs->dbusytimer);
683}
684