diff options
Diffstat (limited to 'drivers/isdn/hisax/jade_irq.c')
-rw-r--r-- | drivers/isdn/hisax/jade_irq.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c new file mode 100644 index 000000000000..08563400e4fd --- /dev/null +++ b/drivers/isdn/hisax/jade_irq.c | |||
@@ -0,0 +1,236 @@ | |||
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 inline 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 | } | ||