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