IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
[linux-2.6.git] / drivers / isdn / hisax / icc.c
1 /* $Id: icc.c,v 1.8.2.3 2004/01/13 14:31:25 keil Exp $
2  *
3  * ICC specific routines
4  *
5  * Author       Matt Henderson & Guy Ellis
6  * Copyright    by Traverse Technologies Pty Ltd, www.travers.com.au
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  * 1999.6.25 Initial implementation of routines for Siemens ISDN
12  * Communication Controller PEB 2070 based on the ISAC routines
13  * written by Karsten Keil.
14  *
15  */
16
17 #include <linux/init.h>
18 #include "hisax.h"
19 #include "icc.h"
20 // #include "arcofi.h"
21 #include "isdnl1.h"
22 #include <linux/interrupt.h>
23
24 #define DBUSY_TIMER_VALUE 80
25 #define ARCOFI_USE 0
26
27 static char *ICCVer[] =
28 {"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
29
30 void
31 ICCVersion(struct IsdnCardState *cs, char *s)
32 {
33         int val;
34
35         val = cs->readisac(cs, ICC_RBCH);
36         printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(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, ICC_CIX0, (command << 2) | 3);
45 }
46
47
48 static void
49 icc_new_ph(struct IsdnCardState *cs)
50 {
51         switch (cs->dc.icc.ph_state) {
52                 case (ICC_IND_EI1):
53                         ph_command(cs, ICC_CMD_DI);
54                         l1_msg(cs, HW_RESET | INDICATION, NULL);
55                         break;
56                 case (ICC_IND_DC):
57                         l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
58                         break;
59                 case (ICC_IND_DR):
60                         l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
61                         break;
62                 case (ICC_IND_PU):
63                         l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
64                         break;
65                 case (ICC_IND_FJ):
66                         l1_msg(cs, HW_RSYNC | INDICATION, NULL);
67                         break;
68                 case (ICC_IND_AR):
69                         l1_msg(cs, HW_INFO2 | INDICATION, NULL);
70                         break;
71                 case (ICC_IND_AI):
72                         l1_msg(cs, HW_INFO4 | INDICATION, NULL);
73                         break;
74                 default:
75                         break;
76         }
77 }
78
79 static void
80 icc_bh(struct IsdnCardState *cs)
81 {
82         struct PStack *stptr;
83         
84         if (!cs)
85                 return;
86         if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
87                 if (cs->debug)
88                         debugl1(cs, "D-Channel Busy cleared");
89                 stptr = cs->stlist;
90                 while (stptr != NULL) {
91                         stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
92                         stptr = stptr->next;
93                 }
94         }
95         if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
96                 icc_new_ph(cs);         
97         if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
98                 DChannel_proc_rcv(cs);
99         if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
100                 DChannel_proc_xmt(cs);
101 #if ARCOFI_USE
102         if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
103                 return;
104         if (test_and_clear_bit(D_RX_MON1, &cs->event))
105                 arcofi_fsm(cs, ARCOFI_RX_END, NULL);
106         if (test_and_clear_bit(D_TX_MON1, &cs->event))
107                 arcofi_fsm(cs, ARCOFI_TX_END, NULL);
108 #endif
109 }
110
111 static void
112 icc_empty_fifo(struct IsdnCardState *cs, int count)
113 {
114         u_char *ptr;
115
116         if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
117                 debugl1(cs, "icc_empty_fifo");
118
119         if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
120                 if (cs->debug & L1_DEB_WARN)
121                         debugl1(cs, "icc_empty_fifo overrun %d",
122                                 cs->rcvidx + count);
123                 cs->writeisac(cs, ICC_CMDR, 0x80);
124                 cs->rcvidx = 0;
125                 return;
126         }
127         ptr = cs->rcvbuf + cs->rcvidx;
128         cs->rcvidx += count;
129         cs->readisacfifo(cs, ptr, count);
130         cs->writeisac(cs, ICC_CMDR, 0x80);
131         if (cs->debug & L1_DEB_ISAC_FIFO) {
132                 char *t = cs->dlog;
133
134                 t += sprintf(t, "icc_empty_fifo cnt %d", count);
135                 QuickHex(t, ptr, count);
136                 debugl1(cs, cs->dlog);
137         }
138 }
139
140 static void
141 icc_fill_fifo(struct IsdnCardState *cs)
142 {
143         int count, more;
144         u_char *ptr;
145
146         if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
147                 debugl1(cs, "icc_fill_fifo");
148
149         if (!cs->tx_skb)
150                 return;
151
152         count = cs->tx_skb->len;
153         if (count <= 0)
154                 return;
155
156         more = 0;
157         if (count > 32) {
158                 more = !0;
159                 count = 32;
160         }
161         ptr = cs->tx_skb->data;
162         skb_pull(cs->tx_skb, count);
163         cs->tx_cnt += count;
164         cs->writeisacfifo(cs, ptr, count);
165         cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa);
166         if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
167                 debugl1(cs, "icc_fill_fifo dbusytimer running");
168                 del_timer(&cs->dbusytimer);
169         }
170         init_timer(&cs->dbusytimer);
171         cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
172         add_timer(&cs->dbusytimer);
173         if (cs->debug & L1_DEB_ISAC_FIFO) {
174                 char *t = cs->dlog;
175
176                 t += sprintf(t, "icc_fill_fifo cnt %d", count);
177                 QuickHex(t, ptr, count);
178                 debugl1(cs, cs->dlog);
179         }
180 }
181
182 void
183 icc_interrupt(struct IsdnCardState *cs, u_char val)
184 {
185         u_char exval, v1;
186         struct sk_buff *skb;
187         unsigned int count;
188
189         if (cs->debug & L1_DEB_ISAC)
190                 debugl1(cs, "ICC interrupt %x", val);
191         if (val & 0x80) {       /* RME */
192                 exval = cs->readisac(cs, ICC_RSTA);
193                 if ((exval & 0x70) != 0x20) {
194                         if (exval & 0x40) {
195                                 if (cs->debug & L1_DEB_WARN)
196                                         debugl1(cs, "ICC RDO");
197 #ifdef ERROR_STATISTIC
198                                 cs->err_rx++;
199 #endif
200                         }
201                         if (!(exval & 0x20)) {
202                                 if (cs->debug & L1_DEB_WARN)
203                                         debugl1(cs, "ICC CRC error");
204 #ifdef ERROR_STATISTIC
205                                 cs->err_crc++;
206 #endif
207                         }
208                         cs->writeisac(cs, ICC_CMDR, 0x80);
209                 } else {
210                         count = cs->readisac(cs, ICC_RBCL) & 0x1f;
211                         if (count == 0)
212                                 count = 32;
213                         icc_empty_fifo(cs, count);
214                         if ((count = cs->rcvidx) > 0) {
215                                 cs->rcvidx = 0;
216                                 if (!(skb = alloc_skb(count, GFP_ATOMIC)))
217                                         printk(KERN_WARNING "HiSax: D receive out of memory\n");
218                                 else {
219                                         memcpy(skb_put(skb, count), cs->rcvbuf, count);
220                                         skb_queue_tail(&cs->rq, skb);
221                                 }
222                         }
223                 }
224                 cs->rcvidx = 0;
225                 schedule_event(cs, D_RCVBUFREADY);
226         }
227         if (val & 0x40) {       /* RPF */
228                 icc_empty_fifo(cs, 32);
229         }
230         if (val & 0x20) {       /* RSC */
231                 /* never */
232                 if (cs->debug & L1_DEB_WARN)
233                         debugl1(cs, "ICC RSC interrupt");
234         }
235         if (val & 0x10) {       /* XPR */
236                 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
237                         del_timer(&cs->dbusytimer);
238                 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
239                         schedule_event(cs, D_CLEARBUSY);
240                 if (cs->tx_skb) {
241                         if (cs->tx_skb->len) {
242                                 icc_fill_fifo(cs);
243                                 goto afterXPR;
244                         } else {
245                                 dev_kfree_skb_irq(cs->tx_skb);
246                                 cs->tx_cnt = 0;
247                                 cs->tx_skb = NULL;
248                         }
249                 }
250                 if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
251                         cs->tx_cnt = 0;
252                         icc_fill_fifo(cs);
253                 } else
254                         schedule_event(cs, D_XMTBUFREADY);
255         }
256       afterXPR:
257         if (val & 0x04) {       /* CISQ */
258                 exval = cs->readisac(cs, ICC_CIR0);
259                 if (cs->debug & L1_DEB_ISAC)
260                         debugl1(cs, "ICC CIR0 %02X", exval );
261                 if (exval & 2) {
262                         cs->dc.icc.ph_state = (exval >> 2) & 0xf;
263                         if (cs->debug & L1_DEB_ISAC)
264                                 debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state);
265                         schedule_event(cs, D_L1STATECHANGE);
266                 }
267                 if (exval & 1) {
268                         exval = cs->readisac(cs, ICC_CIR1);
269                         if (cs->debug & L1_DEB_ISAC)
270                                 debugl1(cs, "ICC CIR1 %02X", exval );
271                 }
272         }
273         if (val & 0x02) {       /* SIN */
274                 /* never */
275                 if (cs->debug & L1_DEB_WARN)
276                         debugl1(cs, "ICC SIN interrupt");
277         }
278         if (val & 0x01) {       /* EXI */
279                 exval = cs->readisac(cs, ICC_EXIR);
280                 if (cs->debug & L1_DEB_WARN)
281                         debugl1(cs, "ICC EXIR %02x", exval);
282                 if (exval & 0x80) {  /* XMR */
283                         debugl1(cs, "ICC XMR");
284                         printk(KERN_WARNING "HiSax: ICC XMR\n");
285                 }
286                 if (exval & 0x40) {  /* XDU */
287                         debugl1(cs, "ICC XDU");
288                         printk(KERN_WARNING "HiSax: ICC XDU\n");
289 #ifdef ERROR_STATISTIC
290                         cs->err_tx++;
291 #endif
292                         if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
293                                 del_timer(&cs->dbusytimer);
294                         if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
295                                 schedule_event(cs, D_CLEARBUSY);
296                         if (cs->tx_skb) { /* Restart frame */
297                                 skb_push(cs->tx_skb, cs->tx_cnt);
298                                 cs->tx_cnt = 0;
299                                 icc_fill_fifo(cs);
300                         } else {
301                                 printk(KERN_WARNING "HiSax: ICC XDU no skb\n");
302                                 debugl1(cs, "ICC XDU no skb");
303                         }
304                 }
305                 if (exval & 0x04) {  /* MOS */
306                         v1 = cs->readisac(cs, ICC_MOSR);
307                         if (cs->debug & L1_DEB_MONITOR)
308                                 debugl1(cs, "ICC MOSR %02x", v1);
309 #if ARCOFI_USE
310                         if (v1 & 0x08) {
311                                 if (!cs->dc.icc.mon_rx) {
312                                         if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
313                                                 if (cs->debug & L1_DEB_WARN)
314                                                         debugl1(cs, "ICC MON RX out of memory!");
315                                                 cs->dc.icc.mocr &= 0xf0;
316                                                 cs->dc.icc.mocr |= 0x0a;
317                                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
318                                                 goto afterMONR0;
319                                         } else
320                                                 cs->dc.icc.mon_rxp = 0;
321                                 }
322                                 if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
323                                         cs->dc.icc.mocr &= 0xf0;
324                                         cs->dc.icc.mocr |= 0x0a;
325                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
326                                         cs->dc.icc.mon_rxp = 0;
327                                         if (cs->debug & L1_DEB_WARN)
328                                                 debugl1(cs, "ICC MON RX overflow!");
329                                         goto afterMONR0;
330                                 }
331                                 cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0);
332                                 if (cs->debug & L1_DEB_MONITOR)
333                                         debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
334                                 if (cs->dc.icc.mon_rxp == 1) {
335                                         cs->dc.icc.mocr |= 0x04;
336                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
337                                 }
338                         }
339                       afterMONR0:
340                         if (v1 & 0x80) {
341                                 if (!cs->dc.icc.mon_rx) {
342                                         if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
343                                                 if (cs->debug & L1_DEB_WARN)
344                                                         debugl1(cs, "ICC MON RX out of memory!");
345                                                 cs->dc.icc.mocr &= 0x0f;
346                                                 cs->dc.icc.mocr |= 0xa0;
347                                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
348                                                 goto afterMONR1;
349                                         } else
350                                                 cs->dc.icc.mon_rxp = 0;
351                                 }
352                                 if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
353                                         cs->dc.icc.mocr &= 0x0f;
354                                         cs->dc.icc.mocr |= 0xa0;
355                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
356                                         cs->dc.icc.mon_rxp = 0;
357                                         if (cs->debug & L1_DEB_WARN)
358                                                 debugl1(cs, "ICC MON RX overflow!");
359                                         goto afterMONR1;
360                                 }
361                                 cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1);
362                                 if (cs->debug & L1_DEB_MONITOR)
363                                         debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
364                                 cs->dc.icc.mocr |= 0x40;
365                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
366                         }
367                       afterMONR1:
368                         if (v1 & 0x04) {
369                                 cs->dc.icc.mocr &= 0xf0;
370                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
371                                 cs->dc.icc.mocr |= 0x0a;
372                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
373                                 schedule_event(cs, D_RX_MON0);
374                         }
375                         if (v1 & 0x40) {
376                                 cs->dc.icc.mocr &= 0x0f;
377                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
378                                 cs->dc.icc.mocr |= 0xa0;
379                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
380                                 schedule_event(cs, D_RX_MON1);
381                         }
382                         if (v1 & 0x02) {
383                                 if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && 
384                                         (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && 
385                                         !(v1 & 0x08))) {
386                                         cs->dc.icc.mocr &= 0xf0;
387                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
388                                         cs->dc.icc.mocr |= 0x0a;
389                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
390                                         if (cs->dc.icc.mon_txc &&
391                                                 (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
392                                                 schedule_event(cs, D_TX_MON0);
393                                         goto AfterMOX0;
394                                 }
395                                 if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
396                                         schedule_event(cs, D_TX_MON0);
397                                         goto AfterMOX0;
398                                 }
399                                 cs->writeisac(cs, ICC_MOX0,
400                                         cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
401                                 if (cs->debug & L1_DEB_MONITOR)
402                                         debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
403                         }
404                       AfterMOX0:
405                         if (v1 & 0x20) {
406                                 if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && 
407                                         (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && 
408                                         !(v1 & 0x80))) {
409                                         cs->dc.icc.mocr &= 0x0f;
410                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
411                                         cs->dc.icc.mocr |= 0xa0;
412                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
413                                         if (cs->dc.icc.mon_txc &&
414                                                 (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
415                                                 schedule_event(cs, D_TX_MON1);
416                                         goto AfterMOX1;
417                                 }
418                                 if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
419                                         schedule_event(cs, D_TX_MON1);
420                                         goto AfterMOX1;
421                                 }
422                                 cs->writeisac(cs, ICC_MOX1,
423                                         cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
424                                 if (cs->debug & L1_DEB_MONITOR)
425                                         debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
426                         }
427                       AfterMOX1:
428 #endif
429                 }
430         }
431 }
432
433 static void
434 ICC_l1hw(struct PStack *st, int pr, void *arg)
435 {
436         struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
437         struct sk_buff *skb = arg;
438         u_long flags;
439         int  val;
440
441         switch (pr) {
442                 case (PH_DATA |REQUEST):
443                         if (cs->debug & DEB_DLOG_HEX)
444                                 LogFrame(cs, skb->data, skb->len);
445                         if (cs->debug & DEB_DLOG_VERBOSE)
446                                 dlogframe(cs, skb, 0);
447                         spin_lock_irqsave(&cs->lock, flags);
448                         if (cs->tx_skb) {
449                                 skb_queue_tail(&cs->sq, skb);
450 #ifdef L2FRAME_DEBUG            /* psa */
451                                 if (cs->debug & L1_DEB_LAPD)
452                                         Logl2Frame(cs, skb, "PH_DATA Queued", 0);
453 #endif
454                         } else {
455                                 cs->tx_skb = skb;
456                                 cs->tx_cnt = 0;
457 #ifdef L2FRAME_DEBUG            /* psa */
458                                 if (cs->debug & L1_DEB_LAPD)
459                                         Logl2Frame(cs, skb, "PH_DATA", 0);
460 #endif
461                                 icc_fill_fifo(cs);
462                         }
463                         spin_unlock_irqrestore(&cs->lock, flags);
464                         break;
465                 case (PH_PULL |INDICATION):
466                         spin_lock_irqsave(&cs->lock, flags);
467                         if (cs->tx_skb) {
468                                 if (cs->debug & L1_DEB_WARN)
469                                         debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
470                                 skb_queue_tail(&cs->sq, skb);
471                                 break;
472                         }
473                         if (cs->debug & DEB_DLOG_HEX)
474                                 LogFrame(cs, skb->data, skb->len);
475                         if (cs->debug & DEB_DLOG_VERBOSE)
476                                 dlogframe(cs, skb, 0);
477                         cs->tx_skb = skb;
478                         cs->tx_cnt = 0;
479 #ifdef L2FRAME_DEBUG            /* psa */
480                         if (cs->debug & L1_DEB_LAPD)
481                                 Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
482 #endif
483                         icc_fill_fifo(cs);
484                         spin_unlock_irqrestore(&cs->lock, flags);
485                         break;
486                 case (PH_PULL | REQUEST):
487 #ifdef L2FRAME_DEBUG            /* psa */
488                         if (cs->debug & L1_DEB_LAPD)
489                                 debugl1(cs, "-> PH_REQUEST_PULL");
490 #endif
491                         if (!cs->tx_skb) {
492                                 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
493                                 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
494                         } else
495                                 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
496                         break;
497                 case (HW_RESET | REQUEST):
498                         spin_lock_irqsave(&cs->lock, flags);
499                         if ((cs->dc.icc.ph_state == ICC_IND_EI1) ||
500                                 (cs->dc.icc.ph_state == ICC_IND_DR))
501                                 ph_command(cs, ICC_CMD_DI);
502                         else
503                                 ph_command(cs, ICC_CMD_RES);
504                         spin_unlock_irqrestore(&cs->lock, flags);
505                         break;
506                 case (HW_ENABLE | REQUEST):
507                         spin_lock_irqsave(&cs->lock, flags);
508                         ph_command(cs, ICC_CMD_DI);
509                         spin_unlock_irqrestore(&cs->lock, flags);
510                         break;
511                 case (HW_INFO1 | REQUEST):
512                         spin_lock_irqsave(&cs->lock, flags);
513                         ph_command(cs, ICC_CMD_AR);
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, ICC_CMD_AI);
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, ICC_SPCR, 0xa);
532                                         cs->writeisac(cs, ICC_ADF1, 0x2);
533                                 } else {
534                                         cs->writeisac(cs, ICC_SPCR, val);
535                                         cs->writeisac(cs, ICC_ADF1, 0xa);
536                                 }
537                         } else {
538                                 /* IOM 2 Mode */
539                                 cs->writeisac(cs, ICC_SPCR, val);
540                                 if (val)
541                                         cs->writeisac(cs, ICC_ADF1, 0x8);
542                                 else
543                                         cs->writeisac(cs, ICC_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, "icc_l1hw unknown %04x", pr);
562                         break;
563         }
564 }
565
566 static void
567 setstack_icc(struct PStack *st, struct IsdnCardState *cs)
568 {
569         st->l1.l1hw = ICC_l1hw;
570 }
571
572 static void
573 DC_Close_icc(struct IsdnCardState *cs) {
574         kfree(cs->dc.icc.mon_rx);
575         cs->dc.icc.mon_rx = NULL;
576         kfree(cs->dc.icc.mon_tx);
577         cs->dc.icc.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, ICC_RBCH);
588                 star = cs->readisac(cs, ICC_STAR);
589                 if (cs->debug) 
590                         debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
591                                 rbch, star);
592                 if (rbch & ICC_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: ICC D-Channel Busy no skb\n");
608                                 debugl1(cs, "D-Channel Busy no skb");
609                         }
610                         cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */
611                         cs->irq_func(cs->irq, cs);
612                 }
613         }
614 }
615
616 void
617 initicc(struct IsdnCardState *cs)
618 {
619         cs->setstack_d = setstack_icc;
620         cs->DC_Close = DC_Close_icc;
621         cs->dc.icc.mon_tx = NULL;
622         cs->dc.icc.mon_rx = NULL;
623         cs->writeisac(cs, ICC_MASK, 0xff);
624         cs->dc.icc.mocr = 0xaa;
625         if (test_bit(HW_IOM1, &cs->HW_Flags)) {
626                 /* IOM 1 Mode */
627                 cs->writeisac(cs, ICC_ADF2, 0x0);
628                 cs->writeisac(cs, ICC_SPCR, 0xa);
629                 cs->writeisac(cs, ICC_ADF1, 0x2);
630                 cs->writeisac(cs, ICC_STCR, 0x70);
631                 cs->writeisac(cs, ICC_MODE, 0xc9);
632         } else {
633                 /* IOM 2 Mode */
634                 if (!cs->dc.icc.adf2)
635                         cs->dc.icc.adf2 = 0x80;
636                 cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2);
637                 cs->writeisac(cs, ICC_SQXR, 0xa0);
638                 cs->writeisac(cs, ICC_SPCR, 0x20);
639                 cs->writeisac(cs, ICC_STCR, 0x70);
640                 cs->writeisac(cs, ICC_MODE, 0xca);
641                 cs->writeisac(cs, ICC_TIMR, 0x00);
642                 cs->writeisac(cs, ICC_ADF1, 0x20);
643         }
644         ph_command(cs, ICC_CMD_RES);
645         cs->writeisac(cs, ICC_MASK, 0x0);
646         ph_command(cs, ICC_CMD_DI);
647 }
648
649 void
650 clear_pending_icc_ints(struct IsdnCardState *cs)
651 {
652         int val, eval;
653
654         val = cs->readisac(cs, ICC_STAR);
655         debugl1(cs, "ICC STAR %x", val);
656         val = cs->readisac(cs, ICC_MODE);
657         debugl1(cs, "ICC MODE %x", val);
658         val = cs->readisac(cs, ICC_ADF2);
659         debugl1(cs, "ICC ADF2 %x", val);
660         val = cs->readisac(cs, ICC_ISTA);
661         debugl1(cs, "ICC ISTA %x", val);
662         if (val & 0x01) {
663                 eval = cs->readisac(cs, ICC_EXIR);
664                 debugl1(cs, "ICC EXIR %x", eval);
665         }
666         val = cs->readisac(cs, ICC_CIR0);
667         debugl1(cs, "ICC CIR0 %x", val);
668         cs->dc.icc.ph_state = (val >> 2) & 0xf;
669         schedule_event(cs, D_L1STATECHANGE);
670         /* Disable all IRQ */
671         cs->writeisac(cs, ICC_MASK, 0xFF);
672 }
673
674 void __devinit
675 setup_icc(struct IsdnCardState *cs)
676 {
677         INIT_WORK(&cs->tqueue, (void *)(void *) icc_bh, cs);
678         cs->dbusytimer.function = (void *) dbusy_timer_handler;
679         cs->dbusytimer.data = (long) cs;
680         init_timer(&cs->dbusytimer);
681 }