diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/hisax/hscx_irq.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/hisax/hscx_irq.c')
-rw-r--r-- | drivers/isdn/hisax/hscx_irq.c | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c new file mode 100644 index 000000000000..5fe9d42d03a3 --- /dev/null +++ b/drivers/isdn/hisax/hscx_irq.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $ | ||
2 | * | ||
3 | * low level b-channel stuff for Siemens HSCX | ||
4 | * | ||
5 | * Author Karsten Keil | ||
6 | * Copyright by Karsten Keil <keil@isdn4linux.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 | * This is an include file for fast inline IRQ stuff | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | |||
16 | static inline void | ||
17 | waitforCEC(struct IsdnCardState *cs, int hscx) | ||
18 | { | ||
19 | int to = 50; | ||
20 | |||
21 | while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) { | ||
22 | udelay(1); | ||
23 | to--; | ||
24 | } | ||
25 | if (!to) | ||
26 | printk(KERN_WARNING "HiSax: waitforCEC timeout\n"); | ||
27 | } | ||
28 | |||
29 | |||
30 | static inline void | ||
31 | waitforXFW(struct IsdnCardState *cs, int hscx) | ||
32 | { | ||
33 | int to = 50; | ||
34 | |||
35 | while ((!(READHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) { | ||
36 | udelay(1); | ||
37 | to--; | ||
38 | } | ||
39 | if (!to) | ||
40 | printk(KERN_WARNING "HiSax: waitforXFW timeout\n"); | ||
41 | } | ||
42 | |||
43 | static inline void | ||
44 | WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data) | ||
45 | { | ||
46 | waitforCEC(cs, hscx); | ||
47 | WRITEHSCX(cs, hscx, HSCX_CMDR, data); | ||
48 | } | ||
49 | |||
50 | |||
51 | |||
52 | static void | ||
53 | hscx_empty_fifo(struct BCState *bcs, int count) | ||
54 | { | ||
55 | u_char *ptr; | ||
56 | struct IsdnCardState *cs = bcs->cs; | ||
57 | |||
58 | if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) | ||
59 | debugl1(cs, "hscx_empty_fifo"); | ||
60 | |||
61 | if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { | ||
62 | if (cs->debug & L1_DEB_WARN) | ||
63 | debugl1(cs, "hscx_empty_fifo: incoming packet too large"); | ||
64 | WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); | ||
65 | bcs->hw.hscx.rcvidx = 0; | ||
66 | return; | ||
67 | } | ||
68 | ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; | ||
69 | bcs->hw.hscx.rcvidx += count; | ||
70 | READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); | ||
71 | WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); | ||
72 | if (cs->debug & L1_DEB_HSCX_FIFO) { | ||
73 | char *t = bcs->blog; | ||
74 | |||
75 | t += sprintf(t, "hscx_empty_fifo %c cnt %d", | ||
76 | bcs->hw.hscx.hscx ? 'B' : 'A', count); | ||
77 | QuickHex(t, ptr, count); | ||
78 | debugl1(cs, bcs->blog); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static void | ||
83 | hscx_fill_fifo(struct BCState *bcs) | ||
84 | { | ||
85 | struct IsdnCardState *cs = bcs->cs; | ||
86 | int more, count; | ||
87 | int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; | ||
88 | u_char *ptr; | ||
89 | |||
90 | if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) | ||
91 | debugl1(cs, "hscx_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 | ptr = bcs->tx_skb->data; | ||
107 | skb_pull(bcs->tx_skb, count); | ||
108 | bcs->tx_cnt -= count; | ||
109 | bcs->hw.hscx.count += count; | ||
110 | WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); | ||
111 | WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa); | ||
112 | if (cs->debug & L1_DEB_HSCX_FIFO) { | ||
113 | char *t = bcs->blog; | ||
114 | |||
115 | t += sprintf(t, "hscx_fill_fifo %c cnt %d", | ||
116 | bcs->hw.hscx.hscx ? 'B' : 'A', count); | ||
117 | QuickHex(t, ptr, count); | ||
118 | debugl1(cs, bcs->blog); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | static inline void | ||
123 | hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) | ||
124 | { | ||
125 | u_char r; | ||
126 | struct BCState *bcs = cs->bcs + hscx; | ||
127 | struct sk_buff *skb; | ||
128 | int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; | ||
129 | int count; | ||
130 | |||
131 | if (!test_bit(BC_FLG_INIT, &bcs->Flag)) | ||
132 | return; | ||
133 | |||
134 | if (val & 0x80) { /* RME */ | ||
135 | r = READHSCX(cs, hscx, HSCX_RSTA); | ||
136 | if ((r & 0xf0) != 0xa0) { | ||
137 | if (!(r & 0x80)) { | ||
138 | if (cs->debug & L1_DEB_WARN) | ||
139 | debugl1(cs, "HSCX invalid frame"); | ||
140 | #ifdef ERROR_STATISTIC | ||
141 | bcs->err_inv++; | ||
142 | #endif | ||
143 | } | ||
144 | if ((r & 0x40) && bcs->mode) { | ||
145 | if (cs->debug & L1_DEB_WARN) | ||
146 | debugl1(cs, "HSCX RDO mode=%d", | ||
147 | bcs->mode); | ||
148 | #ifdef ERROR_STATISTIC | ||
149 | bcs->err_rdo++; | ||
150 | #endif | ||
151 | } | ||
152 | if (!(r & 0x20)) { | ||
153 | if (cs->debug & L1_DEB_WARN) | ||
154 | debugl1(cs, "HSCX CRC error"); | ||
155 | #ifdef ERROR_STATISTIC | ||
156 | bcs->err_crc++; | ||
157 | #endif | ||
158 | } | ||
159 | WriteHSCXCMDR(cs, hscx, 0x80); | ||
160 | } else { | ||
161 | count = READHSCX(cs, hscx, HSCX_RBCL) & ( | ||
162 | test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f); | ||
163 | if (count == 0) | ||
164 | count = fifo_size; | ||
165 | hscx_empty_fifo(bcs, count); | ||
166 | if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { | ||
167 | if (cs->debug & L1_DEB_HSCX_FIFO) | ||
168 | debugl1(cs, "HX Frame %d", count); | ||
169 | if (!(skb = dev_alloc_skb(count))) | ||
170 | printk(KERN_WARNING "HSCX: receive out of memory\n"); | ||
171 | else { | ||
172 | memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); | ||
173 | skb_queue_tail(&bcs->rqueue, skb); | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | bcs->hw.hscx.rcvidx = 0; | ||
178 | schedule_event(bcs, B_RCVBUFREADY); | ||
179 | } | ||
180 | if (val & 0x40) { /* RPF */ | ||
181 | hscx_empty_fifo(bcs, fifo_size); | ||
182 | if (bcs->mode == L1_MODE_TRANS) { | ||
183 | /* receive audio data */ | ||
184 | if (!(skb = dev_alloc_skb(fifo_size))) | ||
185 | printk(KERN_WARNING "HiSax: receive out of memory\n"); | ||
186 | else { | ||
187 | memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); | ||
188 | skb_queue_tail(&bcs->rqueue, skb); | ||
189 | } | ||
190 | bcs->hw.hscx.rcvidx = 0; | ||
191 | schedule_event(bcs, B_RCVBUFREADY); | ||
192 | } | ||
193 | } | ||
194 | if (val & 0x10) { /* XPR */ | ||
195 | if (bcs->tx_skb) { | ||
196 | if (bcs->tx_skb->len) { | ||
197 | hscx_fill_fifo(bcs); | ||
198 | return; | ||
199 | } else { | ||
200 | if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && | ||
201 | (PACKET_NOACK != bcs->tx_skb->pkt_type)) { | ||
202 | u_long flags; | ||
203 | spin_lock_irqsave(&bcs->aclock, flags); | ||
204 | bcs->ackcnt += bcs->hw.hscx.count; | ||
205 | spin_unlock_irqrestore(&bcs->aclock, flags); | ||
206 | schedule_event(bcs, B_ACKPENDING); | ||
207 | } | ||
208 | dev_kfree_skb_irq(bcs->tx_skb); | ||
209 | bcs->hw.hscx.count = 0; | ||
210 | bcs->tx_skb = NULL; | ||
211 | } | ||
212 | } | ||
213 | if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { | ||
214 | bcs->hw.hscx.count = 0; | ||
215 | test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); | ||
216 | hscx_fill_fifo(bcs); | ||
217 | } else { | ||
218 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | ||
219 | schedule_event(bcs, B_XMTBUFREADY); | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | static inline void | ||
225 | hscx_int_main(struct IsdnCardState *cs, u_char val) | ||
226 | { | ||
227 | |||
228 | u_char exval; | ||
229 | struct BCState *bcs; | ||
230 | |||
231 | if (val & 0x01) { | ||
232 | bcs = cs->bcs + 1; | ||
233 | exval = READHSCX(cs, 1, HSCX_EXIR); | ||
234 | if (exval & 0x40) { | ||
235 | if (bcs->mode == 1) | ||
236 | hscx_fill_fifo(bcs); | ||
237 | else { | ||
238 | #ifdef ERROR_STATISTIC | ||
239 | bcs->err_tx++; | ||
240 | #endif | ||
241 | /* Here we lost an TX interrupt, so | ||
242 | * restart transmitting the whole frame. | ||
243 | */ | ||
244 | if (bcs->tx_skb) { | ||
245 | skb_push(bcs->tx_skb, bcs->hw.hscx.count); | ||
246 | bcs->tx_cnt += bcs->hw.hscx.count; | ||
247 | bcs->hw.hscx.count = 0; | ||
248 | } | ||
249 | WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); | ||
250 | if (cs->debug & L1_DEB_WARN) | ||
251 | debugl1(cs, "HSCX B EXIR %x Lost TX", exval); | ||
252 | } | ||
253 | } else if (cs->debug & L1_DEB_HSCX) | ||
254 | debugl1(cs, "HSCX B EXIR %x", exval); | ||
255 | } | ||
256 | if (val & 0xf8) { | ||
257 | if (cs->debug & L1_DEB_HSCX) | ||
258 | debugl1(cs, "HSCX B interrupt %x", val); | ||
259 | hscx_interrupt(cs, val, 1); | ||
260 | } | ||
261 | if (val & 0x02) { | ||
262 | bcs = cs->bcs; | ||
263 | exval = READHSCX(cs, 0, HSCX_EXIR); | ||
264 | if (exval & 0x40) { | ||
265 | if (bcs->mode == L1_MODE_TRANS) | ||
266 | hscx_fill_fifo(bcs); | ||
267 | else { | ||
268 | /* Here we lost an TX interrupt, so | ||
269 | * restart transmitting the whole frame. | ||
270 | */ | ||
271 | #ifdef ERROR_STATISTIC | ||
272 | bcs->err_tx++; | ||
273 | #endif | ||
274 | if (bcs->tx_skb) { | ||
275 | skb_push(bcs->tx_skb, bcs->hw.hscx.count); | ||
276 | bcs->tx_cnt += bcs->hw.hscx.count; | ||
277 | bcs->hw.hscx.count = 0; | ||
278 | } | ||
279 | WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); | ||
280 | if (cs->debug & L1_DEB_WARN) | ||
281 | debugl1(cs, "HSCX A EXIR %x Lost TX", exval); | ||
282 | } | ||
283 | } else if (cs->debug & L1_DEB_HSCX) | ||
284 | debugl1(cs, "HSCX A EXIR %x", exval); | ||
285 | } | ||
286 | if (val & 0x04) { | ||
287 | exval = READHSCX(cs, 0, HSCX_ISTA); | ||
288 | if (cs->debug & L1_DEB_HSCX) | ||
289 | debugl1(cs, "HSCX A interrupt %x", exval); | ||
290 | hscx_interrupt(cs, exval, 0); | ||
291 | } | ||
292 | } | ||