tty-ldisc: be more careful in 'put_ldisc' locking
[linux-2.6] / drivers / isdn / hisax / jade_irq.c
1 /* $Id: jade_irq.c,v 1.7.2.4 2004/02/11 13:21:34 keil Exp $
2  *
3  * Low level JADE IRQ stuff (derived from original hscx_irq.c)
4  *
5  * Author       Roland Klabunde
6  * Copyright    by Roland Klabunde   <R.Klabunde@Berkom.de>
7  * 
8  * This software may be used and distributed according to the terms
9  * of the GNU General Public License, incorporated herein by reference.
10  *
11  */
12
13 static inline void
14 waitforCEC(struct IsdnCardState *cs, int jade, int reg)
15 {
16         int to = 50;
17         int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC);
18         while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) {
19                 udelay(1);
20                 to--;
21         }
22         if (!to)
23                 printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n");
24 }
25
26
27 static inline void
28 waitforXFW(struct IsdnCardState *cs, int jade)
29 {
30         /* Does not work on older jade versions, don't care */
31 }
32
33 static inline void
34 WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data)
35 {
36         waitforCEC(cs, jade, reg);
37         WRITEJADE(cs, jade, reg, data);
38 }
39
40
41
42 static void
43 jade_empty_fifo(struct BCState *bcs, int count)
44 {
45         u_char *ptr;
46         struct IsdnCardState *cs = bcs->cs;
47
48         if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
49                 debugl1(cs, "jade_empty_fifo");
50
51         if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
52                 if (cs->debug & L1_DEB_WARN)
53                         debugl1(cs, "jade_empty_fifo: incoming packet too large");
54                 WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
55                 bcs->hw.hscx.rcvidx = 0;
56                 return;
57         }
58         ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
59         bcs->hw.hscx.rcvidx += count;
60         READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
61         WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
62         if (cs->debug & L1_DEB_HSCX_FIFO) {
63                 char *t = bcs->blog;
64
65                 t += sprintf(t, "jade_empty_fifo %c cnt %d",
66                              bcs->hw.hscx.hscx ? 'B' : 'A', count);
67                 QuickHex(t, ptr, count);
68                 debugl1(cs, bcs->blog);
69         }
70 }
71
72 static void
73 jade_fill_fifo(struct BCState *bcs)
74 {
75         struct IsdnCardState *cs = bcs->cs;
76         int more, count;
77         int fifo_size = 32;
78         u_char *ptr;
79
80         if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
81                 debugl1(cs, "jade_fill_fifo");
82
83         if (!bcs->tx_skb)
84                 return;
85         if (bcs->tx_skb->len <= 0)
86                 return;
87
88         more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
89         if (bcs->tx_skb->len > fifo_size) {
90                 more = !0;
91                 count = fifo_size;
92         } else
93                 count = bcs->tx_skb->len;
94
95         waitforXFW(cs, bcs->hw.hscx.hscx);
96         ptr = bcs->tx_skb->data;
97         skb_pull(bcs->tx_skb, count);
98         bcs->tx_cnt -= count;
99         bcs->hw.hscx.count += count;
100         WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
101         WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME));
102         if (cs->debug & L1_DEB_HSCX_FIFO) {
103                 char *t = bcs->blog;
104
105                 t += sprintf(t, "jade_fill_fifo %c cnt %d",
106                              bcs->hw.hscx.hscx ? 'B' : 'A', count);
107                 QuickHex(t, ptr, count);
108                 debugl1(cs, bcs->blog);
109         }
110 }
111
112
113 static void
114 jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
115 {
116         u_char r;
117         struct BCState *bcs = cs->bcs + jade;
118         struct sk_buff *skb;
119         int fifo_size = 32;
120         int count;
121         int i_jade = (int) jade; /* To satisfy the compiler */
122         
123         if (!test_bit(BC_FLG_INIT, &bcs->Flag))
124                 return;
125
126         if (val & 0x80) {       /* RME */
127                 r = READJADE(cs, i_jade, jade_HDLC_RSTA);
128                 if ((r & 0xf0) != 0xa0) {
129                         if (!(r & 0x80))
130                                 if (cs->debug & L1_DEB_WARN)
131                                         debugl1(cs, "JADE %s invalid frame", (jade ? "B":"A"));
132                         if ((r & 0x40) && bcs->mode)
133                                 if (cs->debug & L1_DEB_WARN)
134                                         debugl1(cs, "JADE %c RDO mode=%d", 'A'+jade, bcs->mode);
135                         if (!(r & 0x20))
136                                 if (cs->debug & L1_DEB_WARN)
137                                         debugl1(cs, "JADE %c CRC error", 'A'+jade);
138                         WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC);
139                 } else {
140                         count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F;
141                         if (count == 0)
142                                 count = fifo_size;
143                         jade_empty_fifo(bcs, count);
144                         if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
145                                 if (cs->debug & L1_DEB_HSCX_FIFO)
146                                         debugl1(cs, "HX Frame %d", count);
147                                 if (!(skb = dev_alloc_skb(count)))
148                                         printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B":"A"));
149                                 else {
150                                         memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
151                                         skb_queue_tail(&bcs->rqueue, skb);
152                                 }
153                         }
154                 }
155                 bcs->hw.hscx.rcvidx = 0;
156                 schedule_event(bcs, B_RCVBUFREADY);
157         }
158         if (val & 0x40) {       /* RPF */
159                 jade_empty_fifo(bcs, fifo_size);
160                 if (bcs->mode == L1_MODE_TRANS) {
161                         /* receive audio data */
162                         if (!(skb = dev_alloc_skb(fifo_size)))
163                                 printk(KERN_WARNING "HiSax: receive out of memory\n");
164                         else {
165                                 memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
166                                 skb_queue_tail(&bcs->rqueue, skb);
167                         }
168                         bcs->hw.hscx.rcvidx = 0;
169                         schedule_event(bcs, B_RCVBUFREADY);
170                 }
171         }
172         if (val & 0x10) {       /* XPR */
173                 if (bcs->tx_skb) {
174                         if (bcs->tx_skb->len) {
175                                 jade_fill_fifo(bcs);
176                                 return;
177                         } else {
178                                 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
179                                         (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
180                                         u_long  flags;
181                                         spin_lock_irqsave(&bcs->aclock, flags);
182                                         bcs->ackcnt += bcs->hw.hscx.count;
183                                         spin_unlock_irqrestore(&bcs->aclock, flags);
184                                         schedule_event(bcs, B_ACKPENDING);
185                                 }
186                                 dev_kfree_skb_irq(bcs->tx_skb);
187                                 bcs->hw.hscx.count = 0;
188                                 bcs->tx_skb = NULL;
189                         }
190                 }
191                 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
192                         bcs->hw.hscx.count = 0;
193                         test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
194                         jade_fill_fifo(bcs);
195                 } else {
196                         test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
197                         schedule_event(bcs, B_XMTBUFREADY);
198                 }
199         }
200 }
201
202 static inline void
203 jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
204 {
205         struct BCState *bcs;
206         bcs = cs->bcs + jade;
207         
208         if (val & jadeISR_RFO) {
209                 /* handled with RDO */
210                 val &= ~jadeISR_RFO;
211         }
212         if (val & jadeISR_XDU) {
213                 /* relevant in HDLC mode only */
214                 /* don't reset XPR here */
215                 if (bcs->mode == 1)
216                         jade_fill_fifo(bcs);
217                 else {
218                         /* Here we lost an TX interrupt, so
219                            * restart transmitting the whole frame.
220                          */
221                         if (bcs->tx_skb) {
222                                 skb_push(bcs->tx_skb, bcs->hw.hscx.count);
223                                 bcs->tx_cnt += bcs->hw.hscx.count;
224                                 bcs->hw.hscx.count = 0;
225                         }
226                         WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES);
227                         if (cs->debug & L1_DEB_WARN)
228                                 debugl1(cs, "JADE %c EXIR %x Lost TX", 'A'+jade, val);
229                 }
230         }
231         if (val & (jadeISR_RME|jadeISR_RPF|jadeISR_XPR)) {
232                 if (cs->debug & L1_DEB_HSCX)
233                         debugl1(cs, "JADE %c interrupt %x", 'A'+jade, val);
234                 jade_interrupt(cs, val, jade);
235         }
236 }