]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/isdn/hisax/icc.c
regulator: max8952: Make of_device_id array const
[karo-tx-linux.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         init_timer(&cs->dbusytimer);
172         cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
173         add_timer(&cs->dbusytimer);
174         if (cs->debug & L1_DEB_ISAC_FIFO) {
175                 char *t = cs->dlog;
176
177                 t += sprintf(t, "icc_fill_fifo cnt %d", count);
178                 QuickHex(t, ptr, count);
179                 debugl1(cs, "%s", cs->dlog);
180         }
181 }
182
183 void
184 icc_interrupt(struct IsdnCardState *cs, u_char val)
185 {
186         u_char exval, v1;
187         struct sk_buff *skb;
188         unsigned int count;
189
190         if (cs->debug & L1_DEB_ISAC)
191                 debugl1(cs, "ICC interrupt %x", val);
192         if (val & 0x80) {       /* RME */
193                 exval = cs->readisac(cs, ICC_RSTA);
194                 if ((exval & 0x70) != 0x20) {
195                         if (exval & 0x40) {
196                                 if (cs->debug & L1_DEB_WARN)
197                                         debugl1(cs, "ICC RDO");
198 #ifdef ERROR_STATISTIC
199                                 cs->err_rx++;
200 #endif
201                         }
202                         if (!(exval & 0x20)) {
203                                 if (cs->debug & L1_DEB_WARN)
204                                         debugl1(cs, "ICC CRC error");
205 #ifdef ERROR_STATISTIC
206                                 cs->err_crc++;
207 #endif
208                         }
209                         cs->writeisac(cs, ICC_CMDR, 0x80);
210                 } else {
211                         count = cs->readisac(cs, ICC_RBCL) & 0x1f;
212                         if (count == 0)
213                                 count = 32;
214                         icc_empty_fifo(cs, count);
215                         if ((count = cs->rcvidx) > 0) {
216                                 cs->rcvidx = 0;
217                                 if (!(skb = alloc_skb(count, GFP_ATOMIC)))
218                                         printk(KERN_WARNING "HiSax: D receive out of memory\n");
219                                 else {
220                                         memcpy(skb_put(skb, count), cs->rcvbuf, count);
221                                         skb_queue_tail(&cs->rq, skb);
222                                 }
223                         }
224                 }
225                 cs->rcvidx = 0;
226                 schedule_event(cs, D_RCVBUFREADY);
227         }
228         if (val & 0x40) {       /* RPF */
229                 icc_empty_fifo(cs, 32);
230         }
231         if (val & 0x20) {       /* RSC */
232                 /* never */
233                 if (cs->debug & L1_DEB_WARN)
234                         debugl1(cs, "ICC RSC interrupt");
235         }
236         if (val & 0x10) {       /* XPR */
237                 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
238                         del_timer(&cs->dbusytimer);
239                 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
240                         schedule_event(cs, D_CLEARBUSY);
241                 if (cs->tx_skb) {
242                         if (cs->tx_skb->len) {
243                                 icc_fill_fifo(cs);
244                                 goto afterXPR;
245                         } else {
246                                 dev_kfree_skb_irq(cs->tx_skb);
247                                 cs->tx_cnt = 0;
248                                 cs->tx_skb = NULL;
249                         }
250                 }
251                 if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
252                         cs->tx_cnt = 0;
253                         icc_fill_fifo(cs);
254                 } else
255                         schedule_event(cs, D_XMTBUFREADY);
256         }
257 afterXPR:
258         if (val & 0x04) {       /* CISQ */
259                 exval = cs->readisac(cs, ICC_CIR0);
260                 if (cs->debug & L1_DEB_ISAC)
261                         debugl1(cs, "ICC CIR0 %02X", exval);
262                 if (exval & 2) {
263                         cs->dc.icc.ph_state = (exval >> 2) & 0xf;
264                         if (cs->debug & L1_DEB_ISAC)
265                                 debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state);
266                         schedule_event(cs, D_L1STATECHANGE);
267                 }
268                 if (exval & 1) {
269                         exval = cs->readisac(cs, ICC_CIR1);
270                         if (cs->debug & L1_DEB_ISAC)
271                                 debugl1(cs, "ICC CIR1 %02X", exval);
272                 }
273         }
274         if (val & 0x02) {       /* SIN */
275                 /* never */
276                 if (cs->debug & L1_DEB_WARN)
277                         debugl1(cs, "ICC SIN interrupt");
278         }
279         if (val & 0x01) {       /* EXI */
280                 exval = cs->readisac(cs, ICC_EXIR);
281                 if (cs->debug & L1_DEB_WARN)
282                         debugl1(cs, "ICC EXIR %02x", exval);
283                 if (exval & 0x80) {  /* XMR */
284                         debugl1(cs, "ICC XMR");
285                         printk(KERN_WARNING "HiSax: ICC XMR\n");
286                 }
287                 if (exval & 0x40) {  /* XDU */
288                         debugl1(cs, "ICC XDU");
289                         printk(KERN_WARNING "HiSax: ICC XDU\n");
290 #ifdef ERROR_STATISTIC
291                         cs->err_tx++;
292 #endif
293                         if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
294                                 del_timer(&cs->dbusytimer);
295                         if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
296                                 schedule_event(cs, D_CLEARBUSY);
297                         if (cs->tx_skb) { /* Restart frame */
298                                 skb_push(cs->tx_skb, cs->tx_cnt);
299                                 cs->tx_cnt = 0;
300                                 icc_fill_fifo(cs);
301                         } else {
302                                 printk(KERN_WARNING "HiSax: ICC XDU no skb\n");
303                                 debugl1(cs, "ICC XDU no skb");
304                         }
305                 }
306                 if (exval & 0x04) {  /* MOS */
307                         v1 = cs->readisac(cs, ICC_MOSR);
308                         if (cs->debug & L1_DEB_MONITOR)
309                                 debugl1(cs, "ICC MOSR %02x", v1);
310 #if ARCOFI_USE
311                         if (v1 & 0x08) {
312                                 if (!cs->dc.icc.mon_rx) {
313                                         if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
314                                                 if (cs->debug & L1_DEB_WARN)
315                                                         debugl1(cs, "ICC MON RX out of memory!");
316                                                 cs->dc.icc.mocr &= 0xf0;
317                                                 cs->dc.icc.mocr |= 0x0a;
318                                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
319                                                 goto afterMONR0;
320                                         } else
321                                                 cs->dc.icc.mon_rxp = 0;
322                                 }
323                                 if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
324                                         cs->dc.icc.mocr &= 0xf0;
325                                         cs->dc.icc.mocr |= 0x0a;
326                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
327                                         cs->dc.icc.mon_rxp = 0;
328                                         if (cs->debug & L1_DEB_WARN)
329                                                 debugl1(cs, "ICC MON RX overflow!");
330                                         goto afterMONR0;
331                                 }
332                                 cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0);
333                                 if (cs->debug & L1_DEB_MONITOR)
334                                         debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]);
335                                 if (cs->dc.icc.mon_rxp == 1) {
336                                         cs->dc.icc.mocr |= 0x04;
337                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
338                                 }
339                         }
340                 afterMONR0:
341                         if (v1 & 0x80) {
342                                 if (!cs->dc.icc.mon_rx) {
343                                         if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
344                                                 if (cs->debug & L1_DEB_WARN)
345                                                         debugl1(cs, "ICC MON RX out of memory!");
346                                                 cs->dc.icc.mocr &= 0x0f;
347                                                 cs->dc.icc.mocr |= 0xa0;
348                                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
349                                                 goto afterMONR1;
350                                         } else
351                                                 cs->dc.icc.mon_rxp = 0;
352                                 }
353                                 if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
354                                         cs->dc.icc.mocr &= 0x0f;
355                                         cs->dc.icc.mocr |= 0xa0;
356                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
357                                         cs->dc.icc.mon_rxp = 0;
358                                         if (cs->debug & L1_DEB_WARN)
359                                                 debugl1(cs, "ICC MON RX overflow!");
360                                         goto afterMONR1;
361                                 }
362                                 cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1);
363                                 if (cs->debug & L1_DEB_MONITOR)
364                                         debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]);
365                                 cs->dc.icc.mocr |= 0x40;
366                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
367                         }
368                 afterMONR1:
369                         if (v1 & 0x04) {
370                                 cs->dc.icc.mocr &= 0xf0;
371                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
372                                 cs->dc.icc.mocr |= 0x0a;
373                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
374                                 schedule_event(cs, D_RX_MON0);
375                         }
376                         if (v1 & 0x40) {
377                                 cs->dc.icc.mocr &= 0x0f;
378                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
379                                 cs->dc.icc.mocr |= 0xa0;
380                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
381                                 schedule_event(cs, D_RX_MON1);
382                         }
383                         if (v1 & 0x02) {
384                                 if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
385                                                              (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
386                                                              !(v1 & 0x08))) {
387                                         cs->dc.icc.mocr &= 0xf0;
388                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
389                                         cs->dc.icc.mocr |= 0x0a;
390                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
391                                         if (cs->dc.icc.mon_txc &&
392                                             (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
393                                                 schedule_event(cs, D_TX_MON0);
394                                         goto AfterMOX0;
395                                 }
396                                 if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
397                                         schedule_event(cs, D_TX_MON0);
398                                         goto AfterMOX0;
399                                 }
400                                 cs->writeisac(cs, ICC_MOX0,
401                                               cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
402                                 if (cs->debug & L1_DEB_MONITOR)
403                                         debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]);
404                         }
405                 AfterMOX0:
406                         if (v1 & 0x20) {
407                                 if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
408                                                              (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
409                                                              !(v1 & 0x80))) {
410                                         cs->dc.icc.mocr &= 0x0f;
411                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
412                                         cs->dc.icc.mocr |= 0xa0;
413                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
414                                         if (cs->dc.icc.mon_txc &&
415                                             (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
416                                                 schedule_event(cs, D_TX_MON1);
417                                         goto AfterMOX1;
418                                 }
419                                 if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
420                                         schedule_event(cs, D_TX_MON1);
421                                         goto AfterMOX1;
422                                 }
423                                 cs->writeisac(cs, ICC_MOX1,
424                                               cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
425                                 if (cs->debug & L1_DEB_MONITOR)
426                                         debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]);
427                         }
428                 AfterMOX1:
429 #endif
430                 }
431         }
432 }
433
434 static void
435 ICC_l1hw(struct PStack *st, int pr, void *arg)
436 {
437         struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
438         struct sk_buff *skb = arg;
439         u_long flags;
440         int  val;
441
442         switch (pr) {
443         case (PH_DATA | REQUEST):
444                 if (cs->debug & DEB_DLOG_HEX)
445                         LogFrame(cs, skb->data, skb->len);
446                 if (cs->debug & DEB_DLOG_VERBOSE)
447                         dlogframe(cs, skb, 0);
448                 spin_lock_irqsave(&cs->lock, flags);
449                 if (cs->tx_skb) {
450                         skb_queue_tail(&cs->sq, skb);
451 #ifdef L2FRAME_DEBUG            /* psa */
452                         if (cs->debug & L1_DEB_LAPD)
453                                 Logl2Frame(cs, skb, "PH_DATA Queued", 0);
454 #endif
455                 } else {
456                         cs->tx_skb = skb;
457                         cs->tx_cnt = 0;
458 #ifdef L2FRAME_DEBUG            /* psa */
459                         if (cs->debug & L1_DEB_LAPD)
460                                 Logl2Frame(cs, skb, "PH_DATA", 0);
461 #endif
462                         icc_fill_fifo(cs);
463                 }
464                 spin_unlock_irqrestore(&cs->lock, flags);
465                 break;
466         case (PH_PULL | INDICATION):
467                 spin_lock_irqsave(&cs->lock, flags);
468                 if (cs->tx_skb) {
469                         if (cs->debug & L1_DEB_WARN)
470                                 debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
471                         skb_queue_tail(&cs->sq, skb);
472                         spin_unlock_irqrestore(&cs->lock, flags);
473                         break;
474                 }
475                 if (cs->debug & DEB_DLOG_HEX)
476                         LogFrame(cs, skb->data, skb->len);
477                 if (cs->debug & DEB_DLOG_VERBOSE)
478                         dlogframe(cs, skb, 0);
479                 cs->tx_skb = skb;
480                 cs->tx_cnt = 0;
481 #ifdef L2FRAME_DEBUG            /* psa */
482                 if (cs->debug & L1_DEB_LAPD)
483                         Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
484 #endif
485                 icc_fill_fifo(cs);
486                 spin_unlock_irqrestore(&cs->lock, flags);
487                 break;
488         case (PH_PULL | REQUEST):
489 #ifdef L2FRAME_DEBUG            /* psa */
490                 if (cs->debug & L1_DEB_LAPD)
491                         debugl1(cs, "-> PH_REQUEST_PULL");
492 #endif
493                 if (!cs->tx_skb) {
494                         test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
495                         st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
496                 } else
497                         test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
498                 break;
499         case (HW_RESET | REQUEST):
500                 spin_lock_irqsave(&cs->lock, flags);
501                 if ((cs->dc.icc.ph_state == ICC_IND_EI1) ||
502                     (cs->dc.icc.ph_state == ICC_IND_DR))
503                         ph_command(cs, ICC_CMD_DI);
504                 else
505                         ph_command(cs, ICC_CMD_RES);
506                 spin_unlock_irqrestore(&cs->lock, flags);
507                 break;
508         case (HW_ENABLE | REQUEST):
509                 spin_lock_irqsave(&cs->lock, flags);
510                 ph_command(cs, ICC_CMD_DI);
511                 spin_unlock_irqrestore(&cs->lock, flags);
512                 break;
513         case (HW_INFO1 | REQUEST):
514                 spin_lock_irqsave(&cs->lock, flags);
515                 ph_command(cs, ICC_CMD_AR);
516                 spin_unlock_irqrestore(&cs->lock, flags);
517                 break;
518         case (HW_INFO3 | REQUEST):
519                 spin_lock_irqsave(&cs->lock, flags);
520                 ph_command(cs, ICC_CMD_AI);
521                 spin_unlock_irqrestore(&cs->lock, flags);
522                 break;
523         case (HW_TESTLOOP | REQUEST):
524                 spin_lock_irqsave(&cs->lock, flags);
525                 val = 0;
526                 if (1 & (long) arg)
527                         val |= 0x0c;
528                 if (2 & (long) arg)
529                         val |= 0x3;
530                 if (test_bit(HW_IOM1, &cs->HW_Flags)) {
531                         /* IOM 1 Mode */
532                         if (!val) {
533                                 cs->writeisac(cs, ICC_SPCR, 0xa);
534                                 cs->writeisac(cs, ICC_ADF1, 0x2);
535                         } else {
536                                 cs->writeisac(cs, ICC_SPCR, val);
537                                 cs->writeisac(cs, ICC_ADF1, 0xa);
538                         }
539                 } else {
540                         /* IOM 2 Mode */
541                         cs->writeisac(cs, ICC_SPCR, val);
542                         if (val)
543                                 cs->writeisac(cs, ICC_ADF1, 0x8);
544                         else
545                                 cs->writeisac(cs, ICC_ADF1, 0x0);
546                 }
547                 spin_unlock_irqrestore(&cs->lock, flags);
548                 break;
549         case (HW_DEACTIVATE | RESPONSE):
550                 skb_queue_purge(&cs->rq);
551                 skb_queue_purge(&cs->sq);
552                 if (cs->tx_skb) {
553                         dev_kfree_skb_any(cs->tx_skb);
554                         cs->tx_skb = NULL;
555                 }
556                 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
557                         del_timer(&cs->dbusytimer);
558                 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
559                         schedule_event(cs, D_CLEARBUSY);
560                 break;
561         default:
562                 if (cs->debug & L1_DEB_WARN)
563                         debugl1(cs, "icc_l1hw unknown %04x", pr);
564                 break;
565         }
566 }
567
568 static void
569 setstack_icc(struct PStack *st, struct IsdnCardState *cs)
570 {
571         st->l1.l1hw = ICC_l1hw;
572 }
573
574 static void
575 DC_Close_icc(struct IsdnCardState *cs) {
576         kfree(cs->dc.icc.mon_rx);
577         cs->dc.icc.mon_rx = NULL;
578         kfree(cs->dc.icc.mon_tx);
579         cs->dc.icc.mon_tx = NULL;
580 }
581
582 static void
583 dbusy_timer_handler(struct IsdnCardState *cs)
584 {
585         struct PStack *stptr;
586         int     rbch, star;
587
588         if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
589                 rbch = cs->readisac(cs, 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         cs->dbusytimer.function = (void *) dbusy_timer_handler;
680         cs->dbusytimer.data = (long) cs;
681         init_timer(&cs->dbusytimer);
682 }