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/isac.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/isac.c')
-rw-r--r-- | drivers/isdn/hisax/isac.c | 684 |
1 files changed, 684 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c new file mode 100644 index 000000000000..20b949952952 --- /dev/null +++ b/drivers/isdn/hisax/isac.c | |||
@@ -0,0 +1,684 @@ | |||
1 | /* $Id: isac.c,v 1.31.2.3 2004/01/13 14:31:25 keil Exp $ | ||
2 | * | ||
3 | * ISAC specific routines | ||
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 | * For changes and modifications please read | ||
12 | * Documentation/isdn/HiSax.cert | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include "hisax.h" | ||
17 | #include "isac.h" | ||
18 | #include "arcofi.h" | ||
19 | #include "isdnl1.h" | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/init.h> | ||
22 | |||
23 | #define DBUSY_TIMER_VALUE 80 | ||
24 | #define ARCOFI_USE 1 | ||
25 | |||
26 | static char *ISACVer[] __devinitdata = | ||
27 | {"2086/2186 V1.1", "2085 B1", "2085 B2", | ||
28 | "2085 V2.3"}; | ||
29 | |||
30 | void | ||
31 | ISACVersion(struct IsdnCardState *cs, char *s) | ||
32 | { | ||
33 | int val; | ||
34 | |||
35 | val = cs->readisac(cs, ISAC_RBCH); | ||
36 | printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(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, ISAC_CIX0, (command << 2) | 3); | ||
45 | } | ||
46 | |||
47 | |||
48 | static void | ||
49 | isac_new_ph(struct IsdnCardState *cs) | ||
50 | { | ||
51 | switch (cs->dc.isac.ph_state) { | ||
52 | case (ISAC_IND_RS): | ||
53 | case (ISAC_IND_EI): | ||
54 | ph_command(cs, ISAC_CMD_DUI); | ||
55 | l1_msg(cs, HW_RESET | INDICATION, NULL); | ||
56 | break; | ||
57 | case (ISAC_IND_DID): | ||
58 | l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); | ||
59 | break; | ||
60 | case (ISAC_IND_DR): | ||
61 | l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); | ||
62 | break; | ||
63 | case (ISAC_IND_PU): | ||
64 | l1_msg(cs, HW_POWERUP | CONFIRM, NULL); | ||
65 | break; | ||
66 | case (ISAC_IND_RSY): | ||
67 | l1_msg(cs, HW_RSYNC | INDICATION, NULL); | ||
68 | break; | ||
69 | case (ISAC_IND_ARD): | ||
70 | l1_msg(cs, HW_INFO2 | INDICATION, NULL); | ||
71 | break; | ||
72 | case (ISAC_IND_AI8): | ||
73 | l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); | ||
74 | break; | ||
75 | case (ISAC_IND_AI10): | ||
76 | l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL); | ||
77 | break; | ||
78 | default: | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | static void | ||
84 | isac_bh(struct IsdnCardState *cs) | ||
85 | { | ||
86 | struct PStack *stptr; | ||
87 | |||
88 | if (!cs) | ||
89 | return; | ||
90 | if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { | ||
91 | if (cs->debug) | ||
92 | debugl1(cs, "D-Channel Busy cleared"); | ||
93 | stptr = cs->stlist; | ||
94 | while (stptr != NULL) { | ||
95 | stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); | ||
96 | stptr = stptr->next; | ||
97 | } | ||
98 | } | ||
99 | if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) | ||
100 | isac_new_ph(cs); | ||
101 | if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) | ||
102 | DChannel_proc_rcv(cs); | ||
103 | if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) | ||
104 | DChannel_proc_xmt(cs); | ||
105 | #if ARCOFI_USE | ||
106 | if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) | ||
107 | return; | ||
108 | if (test_and_clear_bit(D_RX_MON1, &cs->event)) | ||
109 | arcofi_fsm(cs, ARCOFI_RX_END, NULL); | ||
110 | if (test_and_clear_bit(D_TX_MON1, &cs->event)) | ||
111 | arcofi_fsm(cs, ARCOFI_TX_END, NULL); | ||
112 | #endif | ||
113 | } | ||
114 | |||
115 | void | ||
116 | isac_empty_fifo(struct IsdnCardState *cs, int count) | ||
117 | { | ||
118 | u_char *ptr; | ||
119 | |||
120 | if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) | ||
121 | debugl1(cs, "isac_empty_fifo"); | ||
122 | |||
123 | if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { | ||
124 | if (cs->debug & L1_DEB_WARN) | ||
125 | debugl1(cs, "isac_empty_fifo overrun %d", | ||
126 | cs->rcvidx + count); | ||
127 | cs->writeisac(cs, ISAC_CMDR, 0x80); | ||
128 | cs->rcvidx = 0; | ||
129 | return; | ||
130 | } | ||
131 | ptr = cs->rcvbuf + cs->rcvidx; | ||
132 | cs->rcvidx += count; | ||
133 | cs->readisacfifo(cs, ptr, count); | ||
134 | cs->writeisac(cs, ISAC_CMDR, 0x80); | ||
135 | if (cs->debug & L1_DEB_ISAC_FIFO) { | ||
136 | char *t = cs->dlog; | ||
137 | |||
138 | t += sprintf(t, "isac_empty_fifo cnt %d", count); | ||
139 | QuickHex(t, ptr, count); | ||
140 | debugl1(cs, cs->dlog); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | static void | ||
145 | isac_fill_fifo(struct IsdnCardState *cs) | ||
146 | { | ||
147 | int count, more; | ||
148 | u_char *ptr; | ||
149 | |||
150 | if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) | ||
151 | debugl1(cs, "isac_fill_fifo"); | ||
152 | |||
153 | if (!cs->tx_skb) | ||
154 | return; | ||
155 | |||
156 | count = cs->tx_skb->len; | ||
157 | if (count <= 0) | ||
158 | return; | ||
159 | |||
160 | more = 0; | ||
161 | if (count > 32) { | ||
162 | more = !0; | ||
163 | count = 32; | ||
164 | } | ||
165 | ptr = cs->tx_skb->data; | ||
166 | skb_pull(cs->tx_skb, count); | ||
167 | cs->tx_cnt += count; | ||
168 | cs->writeisacfifo(cs, ptr, count); | ||
169 | cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa); | ||
170 | if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { | ||
171 | debugl1(cs, "isac_fill_fifo dbusytimer running"); | ||
172 | del_timer(&cs->dbusytimer); | ||
173 | } | ||
174 | init_timer(&cs->dbusytimer); | ||
175 | cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); | ||
176 | add_timer(&cs->dbusytimer); | ||
177 | if (cs->debug & L1_DEB_ISAC_FIFO) { | ||
178 | char *t = cs->dlog; | ||
179 | |||
180 | t += sprintf(t, "isac_fill_fifo cnt %d", count); | ||
181 | QuickHex(t, ptr, count); | ||
182 | debugl1(cs, cs->dlog); | ||
183 | } | ||
184 | } | ||
185 | |||
186 | void | ||
187 | isac_interrupt(struct IsdnCardState *cs, u_char val) | ||
188 | { | ||
189 | u_char exval, v1; | ||
190 | struct sk_buff *skb; | ||
191 | unsigned int count; | ||
192 | |||
193 | if (cs->debug & L1_DEB_ISAC) | ||
194 | debugl1(cs, "ISAC interrupt %x", val); | ||
195 | if (val & 0x80) { /* RME */ | ||
196 | exval = cs->readisac(cs, ISAC_RSTA); | ||
197 | if ((exval & 0x70) != 0x20) { | ||
198 | if (exval & 0x40) { | ||
199 | if (cs->debug & L1_DEB_WARN) | ||
200 | debugl1(cs, "ISAC RDO"); | ||
201 | #ifdef ERROR_STATISTIC | ||
202 | cs->err_rx++; | ||
203 | #endif | ||
204 | } | ||
205 | if (!(exval & 0x20)) { | ||
206 | if (cs->debug & L1_DEB_WARN) | ||
207 | debugl1(cs, "ISAC CRC error"); | ||
208 | #ifdef ERROR_STATISTIC | ||
209 | cs->err_crc++; | ||
210 | #endif | ||
211 | } | ||
212 | cs->writeisac(cs, ISAC_CMDR, 0x80); | ||
213 | } else { | ||
214 | count = cs->readisac(cs, ISAC_RBCL) & 0x1f; | ||
215 | if (count == 0) | ||
216 | count = 32; | ||
217 | isac_empty_fifo(cs, count); | ||
218 | if ((count = cs->rcvidx) > 0) { | ||
219 | cs->rcvidx = 0; | ||
220 | if (!(skb = alloc_skb(count, GFP_ATOMIC))) | ||
221 | printk(KERN_WARNING "HiSax: D receive out of memory\n"); | ||
222 | else { | ||
223 | memcpy(skb_put(skb, count), cs->rcvbuf, count); | ||
224 | skb_queue_tail(&cs->rq, skb); | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | cs->rcvidx = 0; | ||
229 | schedule_event(cs, D_RCVBUFREADY); | ||
230 | } | ||
231 | if (val & 0x40) { /* RPF */ | ||
232 | isac_empty_fifo(cs, 32); | ||
233 | } | ||
234 | if (val & 0x20) { /* RSC */ | ||
235 | /* never */ | ||
236 | if (cs->debug & L1_DEB_WARN) | ||
237 | debugl1(cs, "ISAC RSC interrupt"); | ||
238 | } | ||
239 | if (val & 0x10) { /* XPR */ | ||
240 | if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) | ||
241 | del_timer(&cs->dbusytimer); | ||
242 | if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) | ||
243 | schedule_event(cs, D_CLEARBUSY); | ||
244 | if (cs->tx_skb) { | ||
245 | if (cs->tx_skb->len) { | ||
246 | isac_fill_fifo(cs); | ||
247 | goto afterXPR; | ||
248 | } else { | ||
249 | dev_kfree_skb_irq(cs->tx_skb); | ||
250 | cs->tx_cnt = 0; | ||
251 | cs->tx_skb = NULL; | ||
252 | } | ||
253 | } | ||
254 | if ((cs->tx_skb = skb_dequeue(&cs->sq))) { | ||
255 | cs->tx_cnt = 0; | ||
256 | isac_fill_fifo(cs); | ||
257 | } else | ||
258 | schedule_event(cs, D_XMTBUFREADY); | ||
259 | } | ||
260 | afterXPR: | ||
261 | if (val & 0x04) { /* CISQ */ | ||
262 | exval = cs->readisac(cs, ISAC_CIR0); | ||
263 | if (cs->debug & L1_DEB_ISAC) | ||
264 | debugl1(cs, "ISAC CIR0 %02X", exval ); | ||
265 | if (exval & 2) { | ||
266 | cs->dc.isac.ph_state = (exval >> 2) & 0xf; | ||
267 | if (cs->debug & L1_DEB_ISAC) | ||
268 | debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state); | ||
269 | schedule_event(cs, D_L1STATECHANGE); | ||
270 | } | ||
271 | if (exval & 1) { | ||
272 | exval = cs->readisac(cs, ISAC_CIR1); | ||
273 | if (cs->debug & L1_DEB_ISAC) | ||
274 | debugl1(cs, "ISAC CIR1 %02X", exval ); | ||
275 | } | ||
276 | } | ||
277 | if (val & 0x02) { /* SIN */ | ||
278 | /* never */ | ||
279 | if (cs->debug & L1_DEB_WARN) | ||
280 | debugl1(cs, "ISAC SIN interrupt"); | ||
281 | } | ||
282 | if (val & 0x01) { /* EXI */ | ||
283 | exval = cs->readisac(cs, ISAC_EXIR); | ||
284 | if (cs->debug & L1_DEB_WARN) | ||
285 | debugl1(cs, "ISAC EXIR %02x", exval); | ||
286 | if (exval & 0x80) { /* XMR */ | ||
287 | debugl1(cs, "ISAC XMR"); | ||
288 | printk(KERN_WARNING "HiSax: ISAC XMR\n"); | ||
289 | } | ||
290 | if (exval & 0x40) { /* XDU */ | ||
291 | debugl1(cs, "ISAC XDU"); | ||
292 | printk(KERN_WARNING "HiSax: ISAC XDU\n"); | ||
293 | #ifdef ERROR_STATISTIC | ||
294 | cs->err_tx++; | ||
295 | #endif | ||
296 | if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) | ||
297 | del_timer(&cs->dbusytimer); | ||
298 | if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) | ||
299 | schedule_event(cs, D_CLEARBUSY); | ||
300 | if (cs->tx_skb) { /* Restart frame */ | ||
301 | skb_push(cs->tx_skb, cs->tx_cnt); | ||
302 | cs->tx_cnt = 0; | ||
303 | isac_fill_fifo(cs); | ||
304 | } else { | ||
305 | printk(KERN_WARNING "HiSax: ISAC XDU no skb\n"); | ||
306 | debugl1(cs, "ISAC XDU no skb"); | ||
307 | } | ||
308 | } | ||
309 | if (exval & 0x04) { /* MOS */ | ||
310 | v1 = cs->readisac(cs, ISAC_MOSR); | ||
311 | if (cs->debug & L1_DEB_MONITOR) | ||
312 | debugl1(cs, "ISAC MOSR %02x", v1); | ||
313 | #if ARCOFI_USE | ||
314 | if (v1 & 0x08) { | ||
315 | if (!cs->dc.isac.mon_rx) { | ||
316 | if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { | ||
317 | if (cs->debug & L1_DEB_WARN) | ||
318 | debugl1(cs, "ISAC MON RX out of memory!"); | ||
319 | cs->dc.isac.mocr &= 0xf0; | ||
320 | cs->dc.isac.mocr |= 0x0a; | ||
321 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
322 | goto afterMONR0; | ||
323 | } else | ||
324 | cs->dc.isac.mon_rxp = 0; | ||
325 | } | ||
326 | if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) { | ||
327 | cs->dc.isac.mocr &= 0xf0; | ||
328 | cs->dc.isac.mocr |= 0x0a; | ||
329 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
330 | cs->dc.isac.mon_rxp = 0; | ||
331 | if (cs->debug & L1_DEB_WARN) | ||
332 | debugl1(cs, "ISAC MON RX overflow!"); | ||
333 | goto afterMONR0; | ||
334 | } | ||
335 | cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0); | ||
336 | if (cs->debug & L1_DEB_MONITOR) | ||
337 | debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]); | ||
338 | if (cs->dc.isac.mon_rxp == 1) { | ||
339 | cs->dc.isac.mocr |= 0x04; | ||
340 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
341 | } | ||
342 | } | ||
343 | afterMONR0: | ||
344 | if (v1 & 0x80) { | ||
345 | if (!cs->dc.isac.mon_rx) { | ||
346 | if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { | ||
347 | if (cs->debug & L1_DEB_WARN) | ||
348 | debugl1(cs, "ISAC MON RX out of memory!"); | ||
349 | cs->dc.isac.mocr &= 0x0f; | ||
350 | cs->dc.isac.mocr |= 0xa0; | ||
351 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
352 | goto afterMONR1; | ||
353 | } else | ||
354 | cs->dc.isac.mon_rxp = 0; | ||
355 | } | ||
356 | if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) { | ||
357 | cs->dc.isac.mocr &= 0x0f; | ||
358 | cs->dc.isac.mocr |= 0xa0; | ||
359 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
360 | cs->dc.isac.mon_rxp = 0; | ||
361 | if (cs->debug & L1_DEB_WARN) | ||
362 | debugl1(cs, "ISAC MON RX overflow!"); | ||
363 | goto afterMONR1; | ||
364 | } | ||
365 | cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1); | ||
366 | if (cs->debug & L1_DEB_MONITOR) | ||
367 | debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]); | ||
368 | cs->dc.isac.mocr |= 0x40; | ||
369 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
370 | } | ||
371 | afterMONR1: | ||
372 | if (v1 & 0x04) { | ||
373 | cs->dc.isac.mocr &= 0xf0; | ||
374 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
375 | cs->dc.isac.mocr |= 0x0a; | ||
376 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
377 | schedule_event(cs, D_RX_MON0); | ||
378 | } | ||
379 | if (v1 & 0x40) { | ||
380 | cs->dc.isac.mocr &= 0x0f; | ||
381 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
382 | cs->dc.isac.mocr |= 0xa0; | ||
383 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
384 | schedule_event(cs, D_RX_MON1); | ||
385 | } | ||
386 | if (v1 & 0x02) { | ||
387 | if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && | ||
388 | (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && | ||
389 | !(v1 & 0x08))) { | ||
390 | cs->dc.isac.mocr &= 0xf0; | ||
391 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
392 | cs->dc.isac.mocr |= 0x0a; | ||
393 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
394 | if (cs->dc.isac.mon_txc && | ||
395 | (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) | ||
396 | schedule_event(cs, D_TX_MON0); | ||
397 | goto AfterMOX0; | ||
398 | } | ||
399 | if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) { | ||
400 | schedule_event(cs, D_TX_MON0); | ||
401 | goto AfterMOX0; | ||
402 | } | ||
403 | cs->writeisac(cs, ISAC_MOX0, | ||
404 | cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); | ||
405 | if (cs->debug & L1_DEB_MONITOR) | ||
406 | debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]); | ||
407 | } | ||
408 | AfterMOX0: | ||
409 | if (v1 & 0x20) { | ||
410 | if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && | ||
411 | (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && | ||
412 | !(v1 & 0x80))) { | ||
413 | cs->dc.isac.mocr &= 0x0f; | ||
414 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
415 | cs->dc.isac.mocr |= 0xa0; | ||
416 | cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); | ||
417 | if (cs->dc.isac.mon_txc && | ||
418 | (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) | ||
419 | schedule_event(cs, D_TX_MON1); | ||
420 | goto AfterMOX1; | ||
421 | } | ||
422 | if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) { | ||
423 | schedule_event(cs, D_TX_MON1); | ||
424 | goto AfterMOX1; | ||
425 | } | ||
426 | cs->writeisac(cs, ISAC_MOX1, | ||
427 | cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); | ||
428 | if (cs->debug & L1_DEB_MONITOR) | ||
429 | debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]); | ||
430 | } | ||
431 | AfterMOX1:; | ||
432 | #endif | ||
433 | } | ||
434 | } | ||
435 | } | ||
436 | |||
437 | static void | ||
438 | ISAC_l1hw(struct PStack *st, int pr, void *arg) | ||
439 | { | ||
440 | struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; | ||
441 | struct sk_buff *skb = arg; | ||
442 | u_long flags; | ||
443 | int val; | ||
444 | |||
445 | switch (pr) { | ||
446 | case (PH_DATA |REQUEST): | ||
447 | if (cs->debug & DEB_DLOG_HEX) | ||
448 | LogFrame(cs, skb->data, skb->len); | ||
449 | if (cs->debug & DEB_DLOG_VERBOSE) | ||
450 | dlogframe(cs, skb, 0); | ||
451 | spin_lock_irqsave(&cs->lock, flags); | ||
452 | if (cs->tx_skb) { | ||
453 | skb_queue_tail(&cs->sq, skb); | ||
454 | #ifdef L2FRAME_DEBUG /* psa */ | ||
455 | if (cs->debug & L1_DEB_LAPD) | ||
456 | Logl2Frame(cs, skb, "PH_DATA Queued", 0); | ||
457 | #endif | ||
458 | } else { | ||
459 | cs->tx_skb = skb; | ||
460 | cs->tx_cnt = 0; | ||
461 | #ifdef L2FRAME_DEBUG /* psa */ | ||
462 | if (cs->debug & L1_DEB_LAPD) | ||
463 | Logl2Frame(cs, skb, "PH_DATA", 0); | ||
464 | #endif | ||
465 | isac_fill_fifo(cs); | ||
466 | } | ||
467 | spin_unlock_irqrestore(&cs->lock, flags); | ||
468 | break; | ||
469 | case (PH_PULL |INDICATION): | ||
470 | spin_lock_irqsave(&cs->lock, flags); | ||
471 | if (cs->tx_skb) { | ||
472 | if (cs->debug & L1_DEB_WARN) | ||
473 | debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); | ||
474 | skb_queue_tail(&cs->sq, skb); | ||
475 | } else { | ||
476 | if (cs->debug & DEB_DLOG_HEX) | ||
477 | LogFrame(cs, skb->data, skb->len); | ||
478 | if (cs->debug & DEB_DLOG_VERBOSE) | ||
479 | dlogframe(cs, skb, 0); | ||
480 | cs->tx_skb = skb; | ||
481 | cs->tx_cnt = 0; | ||
482 | #ifdef L2FRAME_DEBUG /* psa */ | ||
483 | if (cs->debug & L1_DEB_LAPD) | ||
484 | Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); | ||
485 | #endif | ||
486 | isac_fill_fifo(cs); | ||
487 | } | ||
488 | spin_unlock_irqrestore(&cs->lock, flags); | ||
489 | break; | ||
490 | case (PH_PULL | REQUEST): | ||
491 | #ifdef L2FRAME_DEBUG /* psa */ | ||
492 | if (cs->debug & L1_DEB_LAPD) | ||
493 | debugl1(cs, "-> PH_REQUEST_PULL"); | ||
494 | #endif | ||
495 | if (!cs->tx_skb) { | ||
496 | test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | ||
497 | st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); | ||
498 | } else | ||
499 | test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | ||
500 | break; | ||
501 | case (HW_RESET | REQUEST): | ||
502 | spin_lock_irqsave(&cs->lock, flags); | ||
503 | if ((cs->dc.isac.ph_state == ISAC_IND_EI) || | ||
504 | (cs->dc.isac.ph_state == ISAC_IND_DR) || | ||
505 | (cs->dc.isac.ph_state == ISAC_IND_RS)) | ||
506 | ph_command(cs, ISAC_CMD_TIM); | ||
507 | else | ||
508 | ph_command(cs, ISAC_CMD_RS); | ||
509 | spin_unlock_irqrestore(&cs->lock, flags); | ||
510 | break; | ||
511 | case (HW_ENABLE | REQUEST): | ||
512 | spin_lock_irqsave(&cs->lock, flags); | ||
513 | ph_command(cs, ISAC_CMD_TIM); | ||
514 | spin_unlock_irqrestore(&cs->lock, flags); | ||
515 | break; | ||
516 | case (HW_INFO3 | REQUEST): | ||
517 | spin_lock_irqsave(&cs->lock, flags); | ||
518 | ph_command(cs, ISAC_CMD_AR8); | ||
519 | spin_unlock_irqrestore(&cs->lock, flags); | ||
520 | break; | ||
521 | case (HW_TESTLOOP | REQUEST): | ||
522 | spin_lock_irqsave(&cs->lock, flags); | ||
523 | val = 0; | ||
524 | if (1 & (long) arg) | ||
525 | val |= 0x0c; | ||
526 | if (2 & (long) arg) | ||
527 | val |= 0x3; | ||
528 | if (test_bit(HW_IOM1, &cs->HW_Flags)) { | ||
529 | /* IOM 1 Mode */ | ||
530 | if (!val) { | ||
531 | cs->writeisac(cs, ISAC_SPCR, 0xa); | ||
532 | cs->writeisac(cs, ISAC_ADF1, 0x2); | ||
533 | } else { | ||
534 | cs->writeisac(cs, ISAC_SPCR, val); | ||
535 | cs->writeisac(cs, ISAC_ADF1, 0xa); | ||
536 | } | ||
537 | } else { | ||
538 | /* IOM 2 Mode */ | ||
539 | cs->writeisac(cs, ISAC_SPCR, val); | ||
540 | if (val) | ||
541 | cs->writeisac(cs, ISAC_ADF1, 0x8); | ||
542 | else | ||
543 | cs->writeisac(cs, ISAC_ADF1, 0x0); | ||
544 | } | ||
545 | spin_unlock_irqrestore(&cs->lock, flags); | ||
546 | break; | ||
547 | case (HW_DEACTIVATE | RESPONSE): | ||
548 | skb_queue_purge(&cs->rq); | ||
549 | skb_queue_purge(&cs->sq); | ||
550 | if (cs->tx_skb) { | ||
551 | dev_kfree_skb_any(cs->tx_skb); | ||
552 | cs->tx_skb = NULL; | ||
553 | } | ||
554 | if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) | ||
555 | del_timer(&cs->dbusytimer); | ||
556 | if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) | ||
557 | schedule_event(cs, D_CLEARBUSY); | ||
558 | break; | ||
559 | default: | ||
560 | if (cs->debug & L1_DEB_WARN) | ||
561 | debugl1(cs, "isac_l1hw unknown %04x", pr); | ||
562 | break; | ||
563 | } | ||
564 | } | ||
565 | |||
566 | void | ||
567 | setstack_isac(struct PStack *st, struct IsdnCardState *cs) | ||
568 | { | ||
569 | st->l1.l1hw = ISAC_l1hw; | ||
570 | } | ||
571 | |||
572 | void | ||
573 | DC_Close_isac(struct IsdnCardState *cs) { | ||
574 | if (cs->dc.isac.mon_rx) { | ||
575 | kfree(cs->dc.isac.mon_rx); | ||
576 | cs->dc.isac.mon_rx = NULL; | ||
577 | } | ||
578 | if (cs->dc.isac.mon_tx) { | ||
579 | kfree(cs->dc.isac.mon_tx); | ||
580 | cs->dc.isac.mon_tx = NULL; | ||
581 | } | ||
582 | } | ||
583 | |||
584 | static void | ||
585 | dbusy_timer_handler(struct IsdnCardState *cs) | ||
586 | { | ||
587 | struct PStack *stptr; | ||
588 | int rbch, star; | ||
589 | |||
590 | if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { | ||
591 | rbch = cs->readisac(cs, ISAC_RBCH); | ||
592 | star = cs->readisac(cs, ISAC_STAR); | ||
593 | if (cs->debug) | ||
594 | debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", | ||
595 | rbch, star); | ||
596 | if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */ | ||
597 | test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); | ||
598 | stptr = cs->stlist; | ||
599 | while (stptr != NULL) { | ||
600 | stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); | ||
601 | stptr = stptr->next; | ||
602 | } | ||
603 | } else { | ||
604 | /* discard frame; reset transceiver */ | ||
605 | test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); | ||
606 | if (cs->tx_skb) { | ||
607 | dev_kfree_skb_any(cs->tx_skb); | ||
608 | cs->tx_cnt = 0; | ||
609 | cs->tx_skb = NULL; | ||
610 | } else { | ||
611 | printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n"); | ||
612 | debugl1(cs, "D-Channel Busy no skb"); | ||
613 | } | ||
614 | cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */ | ||
615 | cs->irq_func(cs->irq, cs, NULL); | ||
616 | } | ||
617 | } | ||
618 | } | ||
619 | |||
620 | void __devinit | ||
621 | initisac(struct IsdnCardState *cs) | ||
622 | { | ||
623 | cs->setstack_d = setstack_isac; | ||
624 | cs->DC_Close = DC_Close_isac; | ||
625 | cs->dc.isac.mon_tx = NULL; | ||
626 | cs->dc.isac.mon_rx = NULL; | ||
627 | cs->writeisac(cs, ISAC_MASK, 0xff); | ||
628 | cs->dc.isac.mocr = 0xaa; | ||
629 | if (test_bit(HW_IOM1, &cs->HW_Flags)) { | ||
630 | /* IOM 1 Mode */ | ||
631 | cs->writeisac(cs, ISAC_ADF2, 0x0); | ||
632 | cs->writeisac(cs, ISAC_SPCR, 0xa); | ||
633 | cs->writeisac(cs, ISAC_ADF1, 0x2); | ||
634 | cs->writeisac(cs, ISAC_STCR, 0x70); | ||
635 | cs->writeisac(cs, ISAC_MODE, 0xc9); | ||
636 | } else { | ||
637 | /* IOM 2 Mode */ | ||
638 | if (!cs->dc.isac.adf2) | ||
639 | cs->dc.isac.adf2 = 0x80; | ||
640 | cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2); | ||
641 | cs->writeisac(cs, ISAC_SQXR, 0x2f); | ||
642 | cs->writeisac(cs, ISAC_SPCR, 0x00); | ||
643 | cs->writeisac(cs, ISAC_STCR, 0x70); | ||
644 | cs->writeisac(cs, ISAC_MODE, 0xc9); | ||
645 | cs->writeisac(cs, ISAC_TIMR, 0x00); | ||
646 | cs->writeisac(cs, ISAC_ADF1, 0x00); | ||
647 | } | ||
648 | ph_command(cs, ISAC_CMD_RS); | ||
649 | cs->writeisac(cs, ISAC_MASK, 0x0); | ||
650 | } | ||
651 | |||
652 | void __devinit | ||
653 | clear_pending_isac_ints(struct IsdnCardState *cs) | ||
654 | { | ||
655 | int val, eval; | ||
656 | |||
657 | val = cs->readisac(cs, ISAC_STAR); | ||
658 | debugl1(cs, "ISAC STAR %x", val); | ||
659 | val = cs->readisac(cs, ISAC_MODE); | ||
660 | debugl1(cs, "ISAC MODE %x", val); | ||
661 | val = cs->readisac(cs, ISAC_ADF2); | ||
662 | debugl1(cs, "ISAC ADF2 %x", val); | ||
663 | val = cs->readisac(cs, ISAC_ISTA); | ||
664 | debugl1(cs, "ISAC ISTA %x", val); | ||
665 | if (val & 0x01) { | ||
666 | eval = cs->readisac(cs, ISAC_EXIR); | ||
667 | debugl1(cs, "ISAC EXIR %x", eval); | ||
668 | } | ||
669 | val = cs->readisac(cs, ISAC_CIR0); | ||
670 | debugl1(cs, "ISAC CIR0 %x", val); | ||
671 | cs->dc.isac.ph_state = (val >> 2) & 0xf; | ||
672 | schedule_event(cs, D_L1STATECHANGE); | ||
673 | /* Disable all IRQ */ | ||
674 | cs->writeisac(cs, ISAC_MASK, 0xFF); | ||
675 | } | ||
676 | |||
677 | void __devinit | ||
678 | setup_isac(struct IsdnCardState *cs) | ||
679 | { | ||
680 | INIT_WORK(&cs->tqueue, (void *)(void *) isac_bh, cs); | ||
681 | cs->dbusytimer.function = (void *) dbusy_timer_handler; | ||
682 | cs->dbusytimer.data = (long) cs; | ||
683 | init_timer(&cs->dbusytimer); | ||
684 | } | ||