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