import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / drivers / isdn / hisax / jade_irq.c
1 /* $Id: jade_irq.c,v 1.1.4.1 2001/11/20 14:19:36 kai 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         long flags;
37
38         save_flags(flags);
39         cli();
40         waitforCEC(cs, jade, reg);
41         WRITEJADE(cs, jade, reg, data);
42         restore_flags(flags);
43 }
44
45
46
47 static void
48 jade_empty_fifo(struct BCState *bcs, int count)
49 {
50         u_char *ptr;
51         struct IsdnCardState *cs = bcs->cs;
52         long flags;
53
54         if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
55                 debugl1(cs, "jade_empty_fifo");
56
57         if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
58                 if (cs->debug & L1_DEB_WARN)
59                         debugl1(cs, "jade_empty_fifo: incoming packet too large");
60                 WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
61                 bcs->hw.hscx.rcvidx = 0;
62                 return;
63         }
64         ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
65         bcs->hw.hscx.rcvidx += count;
66         save_flags(flags);
67         cli();
68         READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
69         WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
70         restore_flags(flags);
71         if (cs->debug & L1_DEB_HSCX_FIFO) {
72                 char *t = bcs->blog;
73
74                 t += sprintf(t, "jade_empty_fifo %c cnt %d",
75                              bcs->hw.hscx.hscx ? 'B' : 'A', count);
76                 QuickHex(t, ptr, count);
77                 debugl1(cs, bcs->blog);
78         }
79 }
80
81 static void
82 jade_fill_fifo(struct BCState *bcs)
83 {
84         struct IsdnCardState *cs = bcs->cs;
85         int more, count;
86         int fifo_size = 32;
87         u_char *ptr;
88         long flags;
89
90         if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
91                 debugl1(cs, "jade_fill_fifo");
92
93         if (!bcs->tx_skb)
94                 return;
95         if (bcs->tx_skb->len <= 0)
96                 return;
97
98         more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
99         if (bcs->tx_skb->len > fifo_size) {
100                 more = !0;
101                 count = fifo_size;
102         } else
103                 count = bcs->tx_skb->len;
104
105         waitforXFW(cs, bcs->hw.hscx.hscx);
106         save_flags(flags);
107         cli();
108         ptr = bcs->tx_skb->data;
109         skb_pull(bcs->tx_skb, count);
110         bcs->tx_cnt -= count;
111         bcs->hw.hscx.count += count;
112         WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
113         WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME));
114         restore_flags(flags);
115         if (cs->debug & L1_DEB_HSCX_FIFO) {
116                 char *t = bcs->blog;
117
118                 t += sprintf(t, "jade_fill_fifo %c cnt %d",
119                              bcs->hw.hscx.hscx ? 'B' : 'A', count);
120                 QuickHex(t, ptr, count);
121                 debugl1(cs, bcs->blog);
122         }
123 }
124
125
126 static inline void
127 jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
128 {
129         u_char r;
130         struct BCState *bcs = cs->bcs + jade;
131         struct sk_buff *skb;
132         int fifo_size = 32;
133         int count;
134         int i_jade = (int) jade; /* To satisfy the compiler */
135         
136         if (!test_bit(BC_FLG_INIT, &bcs->Flag))
137                 return;
138
139         if (val & 0x80) {       /* RME */
140                 r = READJADE(cs, i_jade, jade_HDLC_RSTA);
141                 if ((r & 0xf0) != 0xa0) {
142                         if (!(r & 0x80))
143                                 if (cs->debug & L1_DEB_WARN)
144                                         debugl1(cs, "JADE %s invalid frame", (jade ? "B":"A"));
145                         if ((r & 0x40) && bcs->mode)
146                                 if (cs->debug & L1_DEB_WARN)
147                                         debugl1(cs, "JADE %c RDO mode=%d", 'A'+jade, bcs->mode);
148                         if (!(r & 0x20))
149                                 if (cs->debug & L1_DEB_WARN)
150                                         debugl1(cs, "JADE %c CRC error", 'A'+jade);
151                         WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC);
152                 } else {
153                         count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F;
154                         if (count == 0)
155                                 count = fifo_size;
156                         jade_empty_fifo(bcs, count);
157                         if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
158                                 if (cs->debug & L1_DEB_HSCX_FIFO)
159                                         debugl1(cs, "HX Frame %d", count);
160                                 if (!(skb = dev_alloc_skb(count)))
161                                         printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B":"A"));
162                                 else {
163                                         memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
164                                         skb_queue_tail(&bcs->rqueue, skb);
165                                 }
166                         }
167                 }
168                 bcs->hw.hscx.rcvidx = 0;
169                 jade_sched_event(bcs, B_RCVBUFREADY);
170         }
171         if (val & 0x40) {       /* RPF */
172                 jade_empty_fifo(bcs, fifo_size);
173                 if (bcs->mode == L1_MODE_TRANS) {
174                         /* receive audio data */
175                         if (!(skb = dev_alloc_skb(fifo_size)))
176                                 printk(KERN_WARNING "HiSax: receive out of memory\n");
177                         else {
178                                 memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
179                                 skb_queue_tail(&bcs->rqueue, skb);
180                         }
181                         bcs->hw.hscx.rcvidx = 0;
182                         jade_sched_event(bcs, B_RCVBUFREADY);
183                 }
184         }
185         if (val & 0x10) {       /* XPR */
186                 if (bcs->tx_skb) {
187                         if (bcs->tx_skb->len) {
188                                 jade_fill_fifo(bcs);
189                                 return;
190                         } else {
191                                 if (bcs->st->lli.l1writewakeup &&
192                                         (PACKET_NOACK != bcs->tx_skb->pkt_type))
193                                         bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
194                                 dev_kfree_skb_irq(bcs->tx_skb);
195                                 bcs->hw.hscx.count = 0;
196                                 bcs->tx_skb = NULL;
197                         }
198                 }
199                 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
200                         bcs->hw.hscx.count = 0;
201                         test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
202                         jade_fill_fifo(bcs);
203                 } else {
204                         test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
205                         jade_sched_event(bcs, B_XMTBUFREADY);
206                 }
207         }
208 }
209
210 static inline void
211 jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
212 {
213         struct BCState *bcs;
214         bcs = cs->bcs + jade;
215         
216         if (val & jadeISR_RFO) {
217                 /* handled with RDO */
218                 val &= ~jadeISR_RFO;
219         }
220         if (val & jadeISR_XDU) {
221                 /* relevant in HDLC mode only */
222                 /* don't reset XPR here */
223                 if (bcs->mode == 1)
224                         jade_fill_fifo(bcs);
225                 else {
226                         /* Here we lost an TX interrupt, so
227                            * restart transmitting the whole frame.
228                          */
229                         if (bcs->tx_skb) {
230                                 skb_push(bcs->tx_skb, bcs->hw.hscx.count);
231                                 bcs->tx_cnt += bcs->hw.hscx.count;
232                                 bcs->hw.hscx.count = 0;
233                         }
234                         WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES);
235                         if (cs->debug & L1_DEB_WARN)
236                                 debugl1(cs, "JADE %c EXIR %x Lost TX", 'A'+jade, val);
237                 }
238         }
239         if (val & (jadeISR_RME|jadeISR_RPF|jadeISR_XPR)) {
240                 if (cs->debug & L1_DEB_HSCX)
241                         debugl1(cs, "JADE %c interrupt %x", 'A'+jade, val);
242                 jade_interrupt(cs, val, jade);
243         }
244 }