tty-ldisc: be more careful in 'put_ldisc' locking
[linux-2.6] / 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 work_struct *work)
81 {
82         struct IsdnCardState *cs =
83                 container_of(work, struct IsdnCardState, tqueue);
84         struct PStack *stptr;
85         
86         if (!cs)
87                 return;
88         if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
89                 if (cs->debug)
90                         debugl1(cs, "D-Channel Busy cleared");
91                 stptr = cs->stlist;
92                 while (stptr != NULL) {
93                         stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
94                         stptr = stptr->next;
95                 }
96         }
97         if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
98                 icc_new_ph(cs);         
99         if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
100                 DChannel_proc_rcv(cs);
101         if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
102                 DChannel_proc_xmt(cs);
103 #if ARCOFI_USE
104         if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
105                 return;
106         if (test_and_clear_bit(D_RX_MON1, &cs->event))
107                 arcofi_fsm(cs, ARCOFI_RX_END, NULL);
108         if (test_and_clear_bit(D_TX_MON1, &cs->event))
109                 arcofi_fsm(cs, ARCOFI_TX_END, NULL);
110 #endif
111 }
112
113 static void
114 icc_empty_fifo(struct IsdnCardState *cs, int count)
115 {
116         u_char *ptr;
117
118         if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
119                 debugl1(cs, "icc_empty_fifo");
120
121         if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
122                 if (cs->debug & L1_DEB_WARN)
123                         debugl1(cs, "icc_empty_fifo overrun %d",
124                                 cs->rcvidx + count);
125                 cs->writeisac(cs, ICC_CMDR, 0x80);
126                 cs->rcvidx = 0;
127                 return;
128         }
129         ptr = cs->rcvbuf + cs->rcvidx;
130         cs->rcvidx += count;
131         cs->readisacfifo(cs, ptr, count);
132         cs->writeisac(cs, ICC_CMDR, 0x80);
133         if (cs->debug & L1_DEB_ISAC_FIFO) {
134                 char *t = cs->dlog;
135
136                 t += sprintf(t, "icc_empty_fifo cnt %d", count);
137                 QuickHex(t, ptr, count);
138                 debugl1(cs, cs->dlog);
139         }
140 }
141
142 static void
143 icc_fill_fifo(struct IsdnCardState *cs)
144 {
145         int count, more;
146         u_char *ptr;
147
148         if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
149                 debugl1(cs, "icc_fill_fifo");
150
151         if (!cs->tx_skb)
152                 return;
153
154         count = cs->tx_skb->len;
155         if (count <= 0)
156                 return;
157
158         more = 0;
159         if (count > 32) {
160                 more = !0;
161                 count = 32;
162         }
163         ptr = cs->tx_skb->data;
164         skb_pull(cs->tx_skb, count);
165         cs->tx_cnt += count;
166         cs->writeisacfifo(cs, ptr, count);
167         cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa);
168         if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
169                 debugl1(cs, "icc_fill_fifo dbusytimer running");
170                 del_timer(&cs->dbusytimer);
171         }
172         init_timer(&cs->dbusytimer);
173         cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
174         add_timer(&cs->dbusytimer);
175         if (cs->debug & L1_DEB_ISAC_FIFO) {
176                 char *t = cs->dlog;
177
178                 t += sprintf(t, "icc_fill_fifo cnt %d", count);
179                 QuickHex(t, ptr, count);
180                 debugl1(cs, cs->dlog);
181         }
182 }
183
184 void
185 icc_interrupt(struct IsdnCardState *cs, u_char val)
186 {
187         u_char exval, v1;
188         struct sk_buff *skb;
189         unsigned int count;
190
191         if (cs->debug & L1_DEB_ISAC)
192                 debugl1(cs, "ICC interrupt %x", val);
193         if (val & 0x80) {       /* RME */
194                 exval = cs->readisac(cs, ICC_RSTA);
195                 if ((exval & 0x70) != 0x20) {
196                         if (exval & 0x40) {
197                                 if (cs->debug & L1_DEB_WARN)
198                                         debugl1(cs, "ICC RDO");
199 #ifdef ERROR_STATISTIC
200                                 cs->err_rx++;
201 #endif
202                         }
203                         if (!(exval & 0x20)) {
204                                 if (cs->debug & L1_DEB_WARN)
205                                         debugl1(cs, "ICC CRC error");
206 #ifdef ERROR_STATISTIC
207                                 cs->err_crc++;
208 #endif
209                         }
210                         cs->writeisac(cs, ICC_CMDR, 0x80);
211                 } else {
212                         count = cs->readisac(cs, ICC_RBCL) & 0x1f;
213                         if (count == 0)
214                                 count = 32;
215                         icc_empty_fifo(cs, count);
216                         if ((count = cs->rcvidx) > 0) {
217                                 cs->rcvidx = 0;
218                                 if (!(skb = alloc_skb(count, GFP_ATOMIC)))
219                                         printk(KERN_WARNING "HiSax: D receive out of memory\n");
220                                 else {
221                                         memcpy(skb_put(skb, count), cs->rcvbuf, count);
222                                         skb_queue_tail(&cs->rq, skb);
223                                 }
224                         }
225                 }
226                 cs->rcvidx = 0;
227                 schedule_event(cs, D_RCVBUFREADY);
228         }
229         if (val & 0x40) {       /* RPF */
230                 icc_empty_fifo(cs, 32);
231         }
232         if (val & 0x20) {       /* RSC */
233                 /* never */
234                 if (cs->debug & L1_DEB_WARN)
235                         debugl1(cs, "ICC RSC interrupt");
236         }
237         if (val & 0x10) {       /* XPR */
238                 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
239                         del_timer(&cs->dbusytimer);
240                 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
241                         schedule_event(cs, D_CLEARBUSY);
242                 if (cs->tx_skb) {
243                         if (cs->tx_skb->len) {
244                                 icc_fill_fifo(cs);
245                                 goto afterXPR;
246                         } else {
247                                 dev_kfree_skb_irq(cs->tx_skb);
248                                 cs->tx_cnt = 0;
249                                 cs->tx_skb = NULL;
250                         }
251                 }
252                 if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
253                         cs->tx_cnt = 0;
254                         icc_fill_fifo(cs);
255                 } else
256                         schedule_event(cs, D_XMTBUFREADY);
257         }
258       afterXPR:
259         if (val & 0x04) {       /* CISQ */
260                 exval = cs->readisac(cs, ICC_CIR0);
261                 if (cs->debug & L1_DEB_ISAC)
262                         debugl1(cs, "ICC CIR0 %02X", exval );
263                 if (exval & 2) {
264                         cs->dc.icc.ph_state = (exval >> 2) & 0xf;
265                         if (cs->debug & L1_DEB_ISAC)
266                                 debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state);
267                         schedule_event(cs, D_L1STATECHANGE);
268                 }
269                 if (exval & 1) {
270                         exval = cs->readisac(cs, ICC_CIR1);
271                         if (cs->debug & L1_DEB_ISAC)
272                                 debugl1(cs, "ICC CIR1 %02X", exval );
273                 }
274         }
275         if (val & 0x02) {       /* SIN */
276                 /* never */
277                 if (cs->debug & L1_DEB_WARN)
278                         debugl1(cs, "ICC SIN interrupt");
279         }
280         if (val & 0x01) {       /* EXI */
281                 exval = cs->readisac(cs, ICC_EXIR);
282                 if (cs->debug & L1_DEB_WARN)
283                         debugl1(cs, "ICC EXIR %02x", exval);
284                 if (exval & 0x80) {  /* XMR */
285                         debugl1(cs, "ICC XMR");
286                         printk(KERN_WARNING "HiSax: ICC XMR\n");
287                 }
288                 if (exval & 0x40) {  /* XDU */
289                         debugl1(cs, "ICC XDU");
290                         printk(KERN_WARNING "HiSax: ICC XDU\n");
291 #ifdef ERROR_STATISTIC
292                         cs->err_tx++;
293 #endif
294                         if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
295                                 del_timer(&cs->dbusytimer);
296                         if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
297                                 schedule_event(cs, D_CLEARBUSY);
298                         if (cs->tx_skb) { /* Restart frame */
299                                 skb_push(cs->tx_skb, cs->tx_cnt);
300                                 cs->tx_cnt = 0;
301                                 icc_fill_fifo(cs);
302                         } else {
303                                 printk(KERN_WARNING "HiSax: ICC XDU no skb\n");
304                                 debugl1(cs, "ICC XDU no skb");
305                         }
306                 }
307                 if (exval & 0x04) {  /* MOS */
308                         v1 = cs->readisac(cs, ICC_MOSR);
309                         if (cs->debug & L1_DEB_MONITOR)
310                                 debugl1(cs, "ICC MOSR %02x", v1);
311 #if ARCOFI_USE
312                         if (v1 & 0x08) {
313                                 if (!cs->dc.icc.mon_rx) {
314                                         if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
315                                                 if (cs->debug & L1_DEB_WARN)
316                                                         debugl1(cs, "ICC MON RX out of memory!");
317                                                 cs->dc.icc.mocr &= 0xf0;
318                                                 cs->dc.icc.mocr |= 0x0a;
319                                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
320                                                 goto afterMONR0;
321                                         } else
322                                                 cs->dc.icc.mon_rxp = 0;
323                                 }
324                                 if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
325                                         cs->dc.icc.mocr &= 0xf0;
326                                         cs->dc.icc.mocr |= 0x0a;
327                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
328                                         cs->dc.icc.mon_rxp = 0;
329                                         if (cs->debug & L1_DEB_WARN)
330                                                 debugl1(cs, "ICC MON RX overflow!");
331                                         goto afterMONR0;
332                                 }
333                                 cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0);
334                                 if (cs->debug & L1_DEB_MONITOR)
335                                         debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
336                                 if (cs->dc.icc.mon_rxp == 1) {
337                                         cs->dc.icc.mocr |= 0x04;
338                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
339                                 }
340                         }
341                       afterMONR0:
342                         if (v1 & 0x80) {
343                                 if (!cs->dc.icc.mon_rx) {
344                                         if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
345                                                 if (cs->debug & L1_DEB_WARN)
346                                                         debugl1(cs, "ICC MON RX out of memory!");
347                                                 cs->dc.icc.mocr &= 0x0f;
348                                                 cs->dc.icc.mocr |= 0xa0;
349                                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
350                                                 goto afterMONR1;
351                                         } else
352                                                 cs->dc.icc.mon_rxp = 0;
353                                 }
354                                 if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
355                                         cs->dc.icc.mocr &= 0x0f;
356                                         cs->dc.icc.mocr |= 0xa0;
357                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
358                                         cs->dc.icc.mon_rxp = 0;
359                                         if (cs->debug & L1_DEB_WARN)
360                                                 debugl1(cs, "ICC MON RX overflow!");
361                                         goto afterMONR1;
362                                 }
363                                 cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1);
364                                 if (cs->debug & L1_DEB_MONITOR)
365                                         debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
366                                 cs->dc.icc.mocr |= 0x40;
367                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
368                         }
369                       afterMONR1:
370                         if (v1 & 0x04) {
371                                 cs->dc.icc.mocr &= 0xf0;
372                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
373                                 cs->dc.icc.mocr |= 0x0a;
374                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
375                                 schedule_event(cs, D_RX_MON0);
376                         }
377                         if (v1 & 0x40) {
378                                 cs->dc.icc.mocr &= 0x0f;
379                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
380                                 cs->dc.icc.mocr |= 0xa0;
381                                 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
382                                 schedule_event(cs, D_RX_MON1);
383                         }
384                         if (v1 & 0x02) {
385                                 if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && 
386                                         (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && 
387                                         !(v1 & 0x08))) {
388                                         cs->dc.icc.mocr &= 0xf0;
389                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
390                                         cs->dc.icc.mocr |= 0x0a;
391                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
392                                         if (cs->dc.icc.mon_txc &&
393                                                 (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
394                                                 schedule_event(cs, D_TX_MON0);
395                                         goto AfterMOX0;
396                                 }
397                                 if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
398                                         schedule_event(cs, D_TX_MON0);
399                                         goto AfterMOX0;
400                                 }
401                                 cs->writeisac(cs, ICC_MOX0,
402                                         cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
403                                 if (cs->debug & L1_DEB_MONITOR)
404                                         debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
405                         }
406                       AfterMOX0:
407                         if (v1 & 0x20) {
408                                 if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && 
409                                         (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && 
410                                         !(v1 & 0x80))) {
411                                         cs->dc.icc.mocr &= 0x0f;
412                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
413                                         cs->dc.icc.mocr |= 0xa0;
414                                         cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
415                                         if (cs->dc.icc.mon_txc &&
416                                                 (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
417                                                 schedule_event(cs, D_TX_MON1);
418                                         goto AfterMOX1;
419                                 }
420                                 if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
421                                         schedule_event(cs, D_TX_MON1);
422                                         goto AfterMOX1;
423                                 }
424                                 cs->writeisac(cs, ICC_MOX1,
425                                         cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
426                                 if (cs->debug & L1_DEB_MONITOR)
427                                         debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
428                         }
429                       AfterMOX1:
430 #endif
431                 }
432         }
433 }
434
435 static void
436 ICC_l1hw(struct PStack *st, int pr, void *arg)
437 {
438         struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
439         struct sk_buff *skb = arg;
440         u_long flags;
441         int  val;
442
443         switch (pr) {
444                 case (PH_DATA |REQUEST):
445                         if (cs->debug & DEB_DLOG_HEX)
446                                 LogFrame(cs, skb->data, skb->len);
447                         if (cs->debug & DEB_DLOG_VERBOSE)
448                                 dlogframe(cs, skb, 0);
449                         spin_lock_irqsave(&cs->lock, flags);
450                         if (cs->tx_skb) {
451                                 skb_queue_tail(&cs->sq, skb);
452 #ifdef L2FRAME_DEBUG            /* psa */
453                                 if (cs->debug & L1_DEB_LAPD)
454                                         Logl2Frame(cs, skb, "PH_DATA Queued", 0);
455 #endif
456                         } else {
457                                 cs->tx_skb = skb;
458                                 cs->tx_cnt = 0;
459 #ifdef L2FRAME_DEBUG            /* psa */
460                                 if (cs->debug & L1_DEB_LAPD)
461                                         Logl2Frame(cs, skb, "PH_DATA", 0);
462 #endif
463                                 icc_fill_fifo(cs);
464                         }
465                         spin_unlock_irqrestore(&cs->lock, flags);
466                         break;
467                 case (PH_PULL |INDICATION):
468                         spin_lock_irqsave(&cs->lock, flags);
469                         if (cs->tx_skb) {
470                                 if (cs->debug & L1_DEB_WARN)
471                                         debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
472                                 skb_queue_tail(&cs->sq, skb);
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 __devinit
677 setup_icc(struct IsdnCardState *cs)
678 {
679         INIT_WORK(&cs->tqueue, icc_bh);
680         cs->dbusytimer.function = (void *) dbusy_timer_handler;
681         cs->dbusytimer.data = (long) cs;
682         init_timer(&cs->dbusytimer);
683 }