GNU Linux-libre 4.19.286-gnu1
[releases.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 #include <linux/slab.h>
24
25 #define DBUSY_TIMER_VALUE 80
26 #define ARCOFI_USE 0
27
28 static char *ICCVer[] =
29 {"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
30
31 void
32 ICCVersion(struct IsdnCardState *cs, char *s)
33 {
34         int val;
35
36         val = cs->readisac(cs, ICC_RBCH);
37         printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]);
38 }
39
40 static void
41 ph_command(struct IsdnCardState *cs, unsigned int command)
42 {
43         if (cs->debug & L1_DEB_ISAC)
44                 debugl1(cs, "ph_command %x", command);
45         cs->writeisac(cs, ICC_CIX0, (command << 2) | 3);
46 }
47
48
49 static void
50 icc_new_ph(struct IsdnCardState *cs)
51 {
52         switch (cs->dc.icc.ph_state) {
53         case (ICC_IND_EI1):
54                 ph_command(cs, ICC_CMD_DI);
55                 l1_msg(cs, HW_RESET | INDICATION, NULL);
56                 break;
57         case (ICC_IND_DC):
58                 l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
59                 break;
60         case (ICC_IND_DR):
61                 l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
62                 break;
63         case (ICC_IND_PU):
64                 l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
65                 break;
66         case (ICC_IND_FJ):
67                 l1_msg(cs, HW_RSYNC | INDICATION, NULL);
68                 break;
69         case (ICC_IND_AR):
70                 l1_msg(cs, HW_INFO2 | INDICATION, NULL);
71                 break;
72         case (ICC_IND_AI):
73                 l1_msg(cs, HW_INFO4 | INDICATION, NULL);
74                 break;
75         default:
76                 break;
77         }
78 }
79
80 static void
81 icc_bh(struct work_struct *work)
82 {
83         struct IsdnCardState *cs =
84                 container_of(work, struct IsdnCardState, tqueue);
85         struct PStack *stptr;
86
87         if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
88                 if (cs->debug)
89                         debugl1(cs, "D-Channel Busy cleared");
90                 stptr = cs->stlist;
91                 while (stptr != NULL) {
92                         stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
93                         stptr = stptr->next;
94                 }
95         }
96         if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
97                 icc_new_ph(cs);
98         if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
99                 DChannel_proc_rcv(cs);
100         if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
101                 DChannel_proc_xmt(cs);
102 #if ARCOFI_USE
103         if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
104                 return;
105         if (test_and_clear_bit(D_RX_MON1, &cs->event))
106                 arcofi_fsm(cs, ARCOFI_RX_END, NULL);
107         if (test_and_clear_bit(D_TX_MON1, &cs->event))
108                 arcofi_fsm(cs, ARCOFI_TX_END, NULL);
109 #endif
110 }
111
112 static void
113 icc_empty_fifo(struct IsdnCardState *cs, int count)
114 {
115         u_char *ptr;
116
117         if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
118                 debugl1(cs, "icc_empty_fifo");
119
120         if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
121                 if (cs->debug & L1_DEB_WARN)
122                         debugl1(cs, "icc_empty_fifo overrun %d",
123                                 cs->rcvidx + count);
124                 cs->writeisac(cs, ICC_CMDR, 0x80);
125                 cs->rcvidx = 0;
126                 return;
127         }
128         ptr = cs->rcvbuf + cs->rcvidx;
129         cs->rcvidx += count;
130         cs->readisacfifo(cs, ptr, count);
131         cs->writeisac(cs, ICC_CMDR, 0x80);
132         if (cs->debug & L1_DEB_ISAC_FIFO) {
133                 char *t = cs->dlog;
134
135                 t += sprintf(t, "icc_empty_fifo cnt %d", count);
136                 QuickHex(t, ptr, count);
137                 debugl1(cs, "%s", cs->dlog);
138         }
139 }
140
141 static void
142 icc_fill_fifo(struct IsdnCardState *cs)
143 {
144         int count, more;
145         u_char *ptr;
146
147         if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
148                 debugl1(cs, "icc_fill_fifo");
149
150         if (!cs->tx_skb)
151                 return;
152
153         count = cs->tx_skb->len;
154         if (count <= 0)
155                 return;
156
157         more = 0;
158         if (count > 32) {
159                 more = !0;
160                 count = 32;
161         }
162         ptr = cs->tx_skb->data;
163         skb_pull(cs->tx_skb, count);
164         cs->tx_cnt += count;
165         cs->writeisacfifo(cs, ptr, count);
166         cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa);
167         if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
168                 debugl1(cs, "icc_fill_fifo dbusytimer running");
169                 del_timer(&cs->dbusytimer);
170         }
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, "%s", 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                                         skb_put_data(skb, 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                         spin_unlock_irqrestore(&cs->lock, flags);
472                         break;
473                 }
474                 if (cs->debug & DEB_DLOG_HEX)
475                         LogFrame(cs, skb->data, skb->len);
476                 if (cs->debug & DEB_DLOG_VERBOSE)
477                         dlogframe(cs, skb, 0);
478                 cs->tx_skb = skb;
479                 cs->tx_cnt = 0;
480 #ifdef L2FRAME_DEBUG            /* psa */
481                 if (cs->debug & L1_DEB_LAPD)
482                         Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
483 #endif
484                 icc_fill_fifo(cs);
485                 spin_unlock_irqrestore(&cs->lock, flags);
486                 break;
487         case (PH_PULL | REQUEST):
488 #ifdef L2FRAME_DEBUG            /* psa */
489                 if (cs->debug & L1_DEB_LAPD)
490                         debugl1(cs, "-> PH_REQUEST_PULL");
491 #endif
492                 if (!cs->tx_skb) {
493                         test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
494                         st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
495                 } else
496                         test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
497                 break;
498         case (HW_RESET | REQUEST):
499                 spin_lock_irqsave(&cs->lock, flags);
500                 if ((cs->dc.icc.ph_state == ICC_IND_EI1) ||
501                     (cs->dc.icc.ph_state == ICC_IND_DR))
502                         ph_command(cs, ICC_CMD_DI);
503                 else
504                         ph_command(cs, ICC_CMD_RES);
505                 spin_unlock_irqrestore(&cs->lock, flags);
506                 break;
507         case (HW_ENABLE | REQUEST):
508                 spin_lock_irqsave(&cs->lock, flags);
509                 ph_command(cs, ICC_CMD_DI);
510                 spin_unlock_irqrestore(&cs->lock, flags);
511                 break;
512         case (HW_INFO1 | REQUEST):
513                 spin_lock_irqsave(&cs->lock, flags);
514                 ph_command(cs, ICC_CMD_AR);
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, ICC_CMD_AI);
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, ICC_SPCR, 0xa);
533                                 cs->writeisac(cs, ICC_ADF1, 0x2);
534                         } else {
535                                 cs->writeisac(cs, ICC_SPCR, val);
536                                 cs->writeisac(cs, ICC_ADF1, 0xa);
537                         }
538                 } else {
539                         /* IOM 2 Mode */
540                         cs->writeisac(cs, ICC_SPCR, val);
541                         if (val)
542                                 cs->writeisac(cs, ICC_ADF1, 0x8);
543                         else
544                                 cs->writeisac(cs, ICC_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, "icc_l1hw unknown %04x", pr);
563                 break;
564         }
565 }
566
567 static void
568 setstack_icc(struct PStack *st, struct IsdnCardState *cs)
569 {
570         st->l1.l1hw = ICC_l1hw;
571 }
572
573 static void
574 DC_Close_icc(struct IsdnCardState *cs) {
575         kfree(cs->dc.icc.mon_rx);
576         cs->dc.icc.mon_rx = NULL;
577         kfree(cs->dc.icc.mon_tx);
578         cs->dc.icc.mon_tx = NULL;
579 }
580
581 static void
582 dbusy_timer_handler(struct timer_list *t)
583 {
584         struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
585         struct PStack *stptr;
586         int     rbch, star;
587
588         if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
589                 rbch = cs->readisac(cs, ICC_RBCH);
590                 star = cs->readisac(cs, ICC_STAR);
591                 if (cs->debug)
592                         debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
593                                 rbch, star);
594                 if (rbch & ICC_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: ICC D-Channel Busy no skb\n");
610                                 debugl1(cs, "D-Channel Busy no skb");
611                         }
612                         cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */
613                         cs->irq_func(cs->irq, cs);
614                 }
615         }
616 }
617
618 void
619 initicc(struct IsdnCardState *cs)
620 {
621         cs->setstack_d = setstack_icc;
622         cs->DC_Close = DC_Close_icc;
623         cs->dc.icc.mon_tx = NULL;
624         cs->dc.icc.mon_rx = NULL;
625         cs->writeisac(cs, ICC_MASK, 0xff);
626         cs->dc.icc.mocr = 0xaa;
627         if (test_bit(HW_IOM1, &cs->HW_Flags)) {
628                 /* IOM 1 Mode */
629                 cs->writeisac(cs, ICC_ADF2, 0x0);
630                 cs->writeisac(cs, ICC_SPCR, 0xa);
631                 cs->writeisac(cs, ICC_ADF1, 0x2);
632                 cs->writeisac(cs, ICC_STCR, 0x70);
633                 cs->writeisac(cs, ICC_MODE, 0xc9);
634         } else {
635                 /* IOM 2 Mode */
636                 if (!cs->dc.icc.adf2)
637                         cs->dc.icc.adf2 = 0x80;
638                 cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2);
639                 cs->writeisac(cs, ICC_SQXR, 0xa0);
640                 cs->writeisac(cs, ICC_SPCR, 0x20);
641                 cs->writeisac(cs, ICC_STCR, 0x70);
642                 cs->writeisac(cs, ICC_MODE, 0xca);
643                 cs->writeisac(cs, ICC_TIMR, 0x00);
644                 cs->writeisac(cs, ICC_ADF1, 0x20);
645         }
646         ph_command(cs, ICC_CMD_RES);
647         cs->writeisac(cs, ICC_MASK, 0x0);
648         ph_command(cs, ICC_CMD_DI);
649 }
650
651 void
652 clear_pending_icc_ints(struct IsdnCardState *cs)
653 {
654         int val, eval;
655
656         val = cs->readisac(cs, ICC_STAR);
657         debugl1(cs, "ICC STAR %x", val);
658         val = cs->readisac(cs, ICC_MODE);
659         debugl1(cs, "ICC MODE %x", val);
660         val = cs->readisac(cs, ICC_ADF2);
661         debugl1(cs, "ICC ADF2 %x", val);
662         val = cs->readisac(cs, ICC_ISTA);
663         debugl1(cs, "ICC ISTA %x", val);
664         if (val & 0x01) {
665                 eval = cs->readisac(cs, ICC_EXIR);
666                 debugl1(cs, "ICC EXIR %x", eval);
667         }
668         val = cs->readisac(cs, ICC_CIR0);
669         debugl1(cs, "ICC CIR0 %x", val);
670         cs->dc.icc.ph_state = (val >> 2) & 0xf;
671         schedule_event(cs, D_L1STATECHANGE);
672         /* Disable all IRQ */
673         cs->writeisac(cs, ICC_MASK, 0xFF);
674 }
675
676 void setup_icc(struct IsdnCardState *cs)
677 {
678         INIT_WORK(&cs->tqueue, icc_bh);
679         timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
680 }