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